LCOV - code coverage report
Current view: top level - dom/events - TextComposition.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 39 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 25 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       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             : #ifndef mozilla_TextComposition_h
       8             : #define mozilla_TextComposition_h
       9             : 
      10             : #include "nsCOMPtr.h"
      11             : #include "nsINode.h"
      12             : #include "nsIWeakReference.h"
      13             : #include "nsIWidget.h"
      14             : #include "nsTArray.h"
      15             : #include "nsThreadUtils.h"
      16             : #include "nsPresContext.h"
      17             : #include "mozilla/Attributes.h"
      18             : #include "mozilla/EventForwards.h"
      19             : #include "mozilla/TextRange.h"
      20             : #include "mozilla/dom/TabParent.h"
      21             : 
      22             : namespace mozilla {
      23             : 
      24             : class EditorBase;
      25             : class EventDispatchingCallback;
      26             : class IMEStateManager;
      27             : 
      28             : /**
      29             :  * TextComposition represents a text composition.  This class stores the
      30             :  * composition event target and its presContext.  At dispatching the event via
      31             :  * this class, the instances use the stored event target.
      32             :  */
      33             : 
      34             : class TextComposition final
      35             : {
      36             :   friend class IMEStateManager;
      37             : 
      38           0 :   NS_INLINE_DECL_REFCOUNTING(TextComposition)
      39             : 
      40             : public:
      41             :   typedef dom::TabParent TabParent;
      42             : 
      43           0 :   static bool IsHandlingSelectionEvent() { return sHandlingSelectionEvent; }
      44             : 
      45             :   TextComposition(nsPresContext* aPresContext,
      46             :                   nsINode* aNode,
      47             :                   TabParent* aTabParent,
      48             :                   WidgetCompositionEvent* aCompositionEvent);
      49             : 
      50           0 :   bool Destroyed() const { return !mPresContext; }
      51           0 :   nsPresContext* GetPresContext() const { return mPresContext; }
      52           0 :   nsINode* GetEventTargetNode() const { return mNode; }
      53             :   // The latest CompositionEvent.data value except compositionstart event.
      54             :   // This value is modified at dispatching compositionupdate.
      55           0 :   const nsString& LastData() const { return mLastData; }
      56             :   // The composition string which is already handled by the focused editor.
      57             :   // I.e., this value must be same as the composition string on the focused
      58             :   // editor.  This value is modified at a call of
      59             :   // EditorDidHandleCompositionChangeEvent().
      60             :   // Note that mString and mLastData are different between dispatcing
      61             :   // compositionupdate and compositionchange event handled by focused editor.
      62           0 :   const nsString& String() const { return mString; }
      63             :   // The latest clauses range of the composition string.
      64             :   // During compositionupdate event, GetRanges() returns old ranges.
      65             :   // So if getting on compositionupdate, Use GetLastRange instead of GetRange().
      66             :   TextRangeArray* GetLastRanges() const { return mLastRanges; }
      67             :   // Returns the clauses and/or caret range of the composition string.
      68             :   // This is modified at a call of EditorWillHandleCompositionChangeEvent().
      69             :   // This may return null if there is no clauses and caret.
      70             :   // XXX We should return |const TextRangeArray*| here, but it causes compile
      71             :   //     error due to inaccessible Release() method.
      72           0 :   TextRangeArray* GetRanges() const { return mRanges; }
      73             :   // Returns the widget which is proper to call NotifyIME().
      74           0 :   nsIWidget* GetWidget() const
      75             :   {
      76           0 :     return mPresContext ? mPresContext->GetRootWidget() : nullptr;
      77             :   }
      78             :   // Returns the tab parent which has this composition in its remote process.
      79           0 :   TabParent* GetTabParent() const
      80             :   {
      81           0 :     return mTabParent;
      82             :   }
      83             :   // Returns true if the composition is started with synthesized event which
      84             :   // came from nsDOMWindowUtils.
      85           0 :   bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; }
      86             : 
      87           0 :   const widget::NativeIMEContext& GetNativeIMEContext() const
      88             :   {
      89           0 :     return mNativeContext;
      90             :   }
      91             : 
      92             :   /**
      93             :    * This is called when IMEStateManager stops managing the instance.
      94             :    */
      95             :   void Destroy();
      96             : 
      97             :   /**
      98             :    * Request to commit (or cancel) the composition to IME.  This method should
      99             :    * be called only by IMEStateManager::NotifyIME().
     100             :    */
     101             :   nsresult RequestToCommit(nsIWidget* aWidget, bool aDiscard);
     102             : 
     103             :   /**
     104             :    * Send a notification to IME.  It depends on the IME or platform spec what
     105             :    * will occur (or not occur).
     106             :    */
     107             :   nsresult NotifyIME(widget::IMEMessage aMessage);
     108             : 
     109             :   /**
     110             :    * the offset of first composition string
     111             :    */
     112           0 :   uint32_t NativeOffsetOfStartComposition() const
     113             :   {
     114           0 :     return mCompositionStartOffset;
     115             :   }
     116             : 
     117             :   /**
     118             :    * the offset of first selected clause or start of composition
     119             :    */
     120             :   uint32_t NativeOffsetOfTargetClause() const
     121             :   {
     122             :     return mCompositionStartOffset + mTargetClauseOffsetInComposition;
     123             :   }
     124             : 
     125             :   /**
     126             :    * Returns true if there is non-empty composition string and it's not fixed.
     127             :    * Otherwise, false.
     128             :    */
     129           0 :   bool IsComposing() const { return mIsComposing; }
     130             : 
     131             :   /**
     132             :    * Returns true while editor is handling an event which is modifying the
     133             :    * composition string.
     134             :    */
     135           0 :   bool IsEditorHandlingEvent() const
     136             :   {
     137           0 :     return mIsEditorHandlingEvent;
     138             :   }
     139             : 
     140             :   /**
     141             :    * StartHandlingComposition() and EndHandlingComposition() are called by
     142             :    * editor when it holds a TextComposition instance and release it.
     143             :    */
     144             :   void StartHandlingComposition(EditorBase* aEditorBase);
     145             :   void EndHandlingComposition(EditorBase* aEditorBase);
     146             : 
     147             :   /**
     148             :    * OnEditorDestroyed() is called when the editor is destroyed but there is
     149             :    * active composition.
     150             :    */
     151             :   void OnEditorDestroyed();
     152             : 
     153             :   /**
     154             :    * CompositionChangeEventHandlingMarker class should be created at starting
     155             :    * to handle text event in focused editor.  This calls
     156             :    * EditorWillHandleCompositionChangeEvent() and
     157             :    * EditorDidHandleCompositionChangeEvent() automatically.
     158             :    */
     159             :   class MOZ_STACK_CLASS CompositionChangeEventHandlingMarker
     160             :   {
     161             :   public:
     162           0 :     CompositionChangeEventHandlingMarker(
     163             :       TextComposition* aComposition,
     164             :       const WidgetCompositionEvent* aCompositionChangeEvent)
     165           0 :       : mComposition(aComposition)
     166             :     {
     167           0 :       mComposition->EditorWillHandleCompositionChangeEvent(
     168           0 :                       aCompositionChangeEvent);
     169           0 :     }
     170             : 
     171           0 :     ~CompositionChangeEventHandlingMarker()
     172           0 :     {
     173           0 :       mComposition->EditorDidHandleCompositionChangeEvent();
     174           0 :     }
     175             : 
     176             :   private:
     177             :     RefPtr<TextComposition> mComposition;
     178             :     CompositionChangeEventHandlingMarker();
     179             :     CompositionChangeEventHandlingMarker(
     180             :       const CompositionChangeEventHandlingMarker& aOther);
     181             :   };
     182             : 
     183             : private:
     184             :   // Private destructor, to discourage deletion outside of Release():
     185           0 :   ~TextComposition()
     186           0 :   {
     187             :     // WARNING: mPresContext may be destroying, so, be careful if you touch it.
     188           0 :   }
     189             : 
     190             :   // sHandlingSelectionEvent is true while TextComposition sends a selection
     191             :   // event to ContentEventHandler.
     192             :   static bool sHandlingSelectionEvent;
     193             : 
     194             :   // This class holds nsPresContext weak.  This instance shouldn't block
     195             :   // destroying it.  When the presContext is being destroyed, it's notified to
     196             :   // IMEStateManager::OnDestroyPresContext(), and then, it destroy
     197             :   // this instance.
     198             :   nsPresContext* mPresContext;
     199             :   nsCOMPtr<nsINode> mNode;
     200             :   RefPtr<TabParent> mTabParent;
     201             : 
     202             :   // This is the clause and caret range information which is managed by
     203             :   // the focused editor.  This may be null if there is no clauses or caret.
     204             :   RefPtr<TextRangeArray> mRanges;
     205             :   // Same as mRange, but mRange will have old data during compositionupdate.
     206             :   // So this will be valied during compositionupdate.
     207             :   RefPtr<TextRangeArray> mLastRanges;
     208             : 
     209             :   // mNativeContext stores a opaque pointer.  This works as the "ID" for this
     210             :   // composition.  Don't access the instance, it may not be available.
     211             :   widget::NativeIMEContext mNativeContext;
     212             : 
     213             :   // mEditorBaseWeak is a weak reference to the focused editor handling
     214             :   // composition.
     215             :   nsWeakPtr mEditorBaseWeak;
     216             : 
     217             :   // mLastData stores the data attribute of the latest composition event (except
     218             :   // the compositionstart event).
     219             :   nsString mLastData;
     220             : 
     221             :   // mString stores the composition text which has been handled by the focused
     222             :   // editor.
     223             :   nsString mString;
     224             : 
     225             :   // Offset of the composition string from start of the editor
     226             :   uint32_t mCompositionStartOffset;
     227             :   // Offset of the selected clause of the composition string from
     228             :   // mCompositionStartOffset
     229             :   uint32_t mTargetClauseOffsetInComposition;
     230             : 
     231             :   // See the comment for IsSynthesizedForTests().
     232             :   bool mIsSynthesizedForTests;
     233             : 
     234             :   // See the comment for IsComposing().
     235             :   bool mIsComposing;
     236             : 
     237             :   // mIsEditorHandlingEvent is true while editor is modifying the composition
     238             :   // string.
     239             :   bool mIsEditorHandlingEvent;
     240             : 
     241             :   // mIsRequestingCommit or mIsRequestingCancel is true *only* while we're
     242             :   // requesting commit or canceling the composition.  In other words, while
     243             :   // one of these values is true, we're handling the request.
     244             :   bool mIsRequestingCommit;
     245             :   bool mIsRequestingCancel;
     246             : 
     247             :   // mRequestedToCommitOrCancel is true *after* we requested IME to commit or
     248             :   // cancel the composition.  In other words, we already requested of IME that
     249             :   // it commits or cancels current composition.
     250             :   // NOTE: Before this is set true, both mIsRequestingCommit and
     251             :   //       mIsRequestingCancel are set false.
     252             :   bool mRequestedToCommitOrCancel;
     253             : 
     254             :   // mWasNativeCompositionEndEventDiscarded is true if this composition was
     255             :   // requested commit or cancel itself but native compositionend event is
     256             :   // discarded by PresShell due to not safe to dispatch events.
     257             :   bool mWasNativeCompositionEndEventDiscarded;
     258             : 
     259             :   // Allow control characters appear in composition string.
     260             :   // When this is false, control characters except
     261             :   // CHARACTER TABULATION (horizontal tab) are removed from
     262             :   // both composition string and data attribute of compositionupdate
     263             :   // and compositionend events.
     264             :   bool mAllowControlCharacters;
     265             : 
     266             :   // mWasCompositionStringEmpty is true if the composition string was empty
     267             :   // when DispatchCompositionEvent() is called.
     268             :   bool mWasCompositionStringEmpty;
     269             : 
     270             :   // Hide the default constructor and copy constructor.
     271             :   TextComposition()
     272             :     : mPresContext(nullptr)
     273             :     , mNativeContext(nullptr)
     274             :     , mCompositionStartOffset(0)
     275             :     , mTargetClauseOffsetInComposition(0)
     276             :     , mIsSynthesizedForTests(false)
     277             :     , mIsComposing(false)
     278             :     , mIsEditorHandlingEvent(false)
     279             :     , mIsRequestingCommit(false)
     280             :     , mIsRequestingCancel(false)
     281             :     , mRequestedToCommitOrCancel(false)
     282             :     , mWasNativeCompositionEndEventDiscarded(false)
     283             :     , mAllowControlCharacters(false)
     284             :     , mWasCompositionStringEmpty(true)
     285             :   {}
     286             :   TextComposition(const TextComposition& aOther);
     287             : 
     288             :   /**
     289             :    * GetEditorBase() returns EditorBase pointer of mEditorBaseWeak.
     290             :    */
     291             :   already_AddRefed<EditorBase> GetEditorBase() const;
     292             : 
     293             :   /**
     294             :    * HasEditor() returns true if mEditorBaseWeak holds EditorBase instance
     295             :    * which is alive.  Otherwise, false.
     296             :    */
     297             :   bool HasEditor() const;
     298             : 
     299             :   /**
     300             :    * EditorWillHandleCompositionChangeEvent() must be called before the focused
     301             :    * editor handles the compositionchange event.
     302             :    */
     303             :   void EditorWillHandleCompositionChangeEvent(
     304             :          const WidgetCompositionEvent* aCompositionChangeEvent);
     305             : 
     306             :   /**
     307             :    * EditorDidHandleCompositionChangeEvent() must be called after the focused
     308             :    * editor handles a compositionchange event.
     309             :    */
     310             :   void EditorDidHandleCompositionChangeEvent();
     311             : 
     312             :   /**
     313             :    * IsValidStateForComposition() returns true if it's safe to dispatch an event
     314             :    * to the DOM tree.  Otherwise, false.
     315             :    * WARNING: This doesn't check script blocker state.  It should be checked
     316             :    *          before dispatching the first event.
     317             :    */
     318             :   bool IsValidStateForComposition(nsIWidget* aWidget) const;
     319             : 
     320             :   /**
     321             :    * DispatchCompositionEvent() dispatches the aCompositionEvent to the mContent
     322             :    * synchronously. The caller must ensure that it's safe to dispatch the event.
     323             :    */
     324             :   void DispatchCompositionEvent(WidgetCompositionEvent* aCompositionEvent,
     325             :                                 nsEventStatus* aStatus,
     326             :                                 EventDispatchingCallback* aCallBack,
     327             :                                 bool aIsSynthesized);
     328             : 
     329             :   /**
     330             :    * Simply calling EventDispatcher::Dispatch() with plugin event.
     331             :    * If dispatching event has no orginal clone, aOriginalEvent can be null.
     332             :    */
     333             :   void DispatchEvent(WidgetCompositionEvent* aDispatchEvent,
     334             :                      nsEventStatus* aStatus,
     335             :                      EventDispatchingCallback* aCallback,
     336             :                      const WidgetCompositionEvent *aOriginalEvent = nullptr);
     337             : 
     338             :   /**
     339             :    * HandleSelectionEvent() sends the selection event to ContentEventHandler
     340             :    * or dispatches it to the focused child process.
     341             :    */
     342           0 :   void HandleSelectionEvent(WidgetSelectionEvent* aSelectionEvent)
     343             :   {
     344           0 :     HandleSelectionEvent(mPresContext, mTabParent, aSelectionEvent);
     345           0 :   }
     346             :   static void HandleSelectionEvent(nsPresContext* aPresContext,
     347             :                                    TabParent* aTabParent,
     348             :                                    WidgetSelectionEvent* aSelectionEvent);
     349             : 
     350             :   /**
     351             :    * MaybeDispatchCompositionUpdate() may dispatch a compositionupdate event
     352             :    * if aCompositionEvent changes composition string.
     353             :    * @return Returns false if dispatching the compositionupdate event caused
     354             :    *         destroying this composition.
     355             :    */
     356             :   bool MaybeDispatchCompositionUpdate(
     357             :          const WidgetCompositionEvent* aCompositionEvent);
     358             : 
     359             :   /**
     360             :    * CloneAndDispatchAs() dispatches a composition event which is
     361             :    * duplicateed from aCompositionEvent and set the aMessage.
     362             :    *
     363             :    * @return Returns BaseEventFlags which is the result of dispatched event.
     364             :    */
     365             :   BaseEventFlags CloneAndDispatchAs(
     366             :                    const WidgetCompositionEvent* aCompositionEvent,
     367             :                    EventMessage aMessage,
     368             :                    nsEventStatus* aStatus = nullptr,
     369             :                    EventDispatchingCallback* aCallBack = nullptr);
     370             : 
     371             :   /**
     372             :    * If IME has already dispatched compositionend event but it was discarded
     373             :    * by PresShell due to not safe to dispatch, this returns true.
     374             :    */
     375           0 :   bool WasNativeCompositionEndEventDiscarded() const
     376             :   {
     377           0 :     return mWasNativeCompositionEndEventDiscarded;
     378             :   }
     379             : 
     380             :   /**
     381             :    * OnCompositionEventDiscarded() is called when PresShell discards
     382             :    * compositionupdate, compositionend or compositionchange event due to not
     383             :    * safe to dispatch event.
     384             :    */
     385             :   void OnCompositionEventDiscarded(WidgetCompositionEvent* aCompositionEvent);
     386             : 
     387             :   /**
     388             :    * OnCompositionEventDispatched() is called after a composition event is
     389             :    * dispatched.
     390             :    */
     391             :   void OnCompositionEventDispatched(
     392             :          const WidgetCompositionEvent* aDispatchEvent);
     393             : 
     394             :   /**
     395             :    * MaybeNotifyIMEOfCompositionEventHandled() notifies IME of composition
     396             :    * event handled.  This should be called after dispatching a composition
     397             :    * event which came from widget.
     398             :    */
     399             :   void MaybeNotifyIMEOfCompositionEventHandled(
     400             :          const WidgetCompositionEvent* aCompositionEvent);
     401             : 
     402             :   /**
     403             :    * GetSelectionStartOffset() returns normal selection start offset in the
     404             :    * editor which has this composition.
     405             :    * If it failed or lost focus, this would return 0.
     406             :    */
     407             :   uint32_t GetSelectionStartOffset();
     408             : 
     409             :   /**
     410             :    * OnStartOffsetUpdatedInChild() is called when composition start offset
     411             :    * is updated in the child process.  I.e., this is called and never called
     412             :    * if the composition is in this process.
     413             :    * @param aStartOffset        New composition start offset with native
     414             :    *                            linebreaks.
     415             :    */
     416             :   void OnStartOffsetUpdatedInChild(uint32_t aStartOffset);
     417             : 
     418             :   /**
     419             :    * CompositionEventDispatcher dispatches the specified composition (or text)
     420             :    * event.
     421             :    */
     422           0 :   class CompositionEventDispatcher : public Runnable
     423             :   {
     424             :   public:
     425             :     CompositionEventDispatcher(TextComposition* aTextComposition,
     426             :                                nsINode* aEventTarget,
     427             :                                EventMessage aEventMessage,
     428             :                                const nsAString& aData,
     429             :                                bool aIsSynthesizedEvent = false);
     430             :     NS_IMETHOD Run() override;
     431             : 
     432             :   private:
     433             :     RefPtr<TextComposition> mTextComposition;
     434             :     nsCOMPtr<nsINode> mEventTarget;
     435             :     nsString mData;
     436             :     EventMessage mEventMessage;
     437             :     bool mIsSynthesizedEvent;
     438             : 
     439             :     CompositionEventDispatcher()
     440             :       : Runnable("TextComposition::CompositionEventDispatcher")
     441             :       , mIsSynthesizedEvent(false){};
     442             :   };
     443             : 
     444             :   /**
     445             :    * DispatchCompositionEventRunnable() dispatches a composition event to the
     446             :    * content.  Be aware, if you use this method, nsPresShellEventCB isn't used.
     447             :    * That means that nsIFrame::HandleEvent() is never called.
     448             :    * WARNING: The instance which is managed by IMEStateManager may be
     449             :    *          destroyed by this method call.
     450             :    *
     451             :    * @param aEventMessage       Must be one of composition events.
     452             :    * @param aData               Used for mData value.
     453             :    * @param aIsSynthesizingCommit   true if this is called for synthesizing
     454             :    *                                commit or cancel composition.  Otherwise,
     455             :    *                                false.
     456             :    */
     457             :   void DispatchCompositionEventRunnable(EventMessage aEventMessage,
     458             :                                         const nsAString& aData,
     459             :                                         bool aIsSynthesizingCommit = false);
     460             : };
     461             : 
     462             : /**
     463             :  * TextCompositionArray manages the instances of TextComposition class.
     464             :  * Managing with array is enough because only one composition is typically
     465             :  * there.  Even if user switches native IME context, it's very rare that
     466             :  * second or more composition is started.
     467             :  * It's assumed that this is used by IMEStateManager for storing all active
     468             :  * compositions in the process.  If the instance is it, each TextComposition
     469             :  * in the array can be destroyed by calling some methods of itself.
     470             :  */
     471             : 
     472           0 : class TextCompositionArray final :
     473             :   public AutoTArray<RefPtr<TextComposition>, 2>
     474             : {
     475             : public:
     476             :   // Looking for per native IME context.
     477             :   index_type IndexOf(const widget::NativeIMEContext& aNativeIMEContext);
     478             :   index_type IndexOf(nsIWidget* aWidget);
     479             : 
     480             :   TextComposition* GetCompositionFor(nsIWidget* aWidget);
     481             :   TextComposition* GetCompositionFor(
     482             :                      const WidgetCompositionEvent* aCompositionEvent);
     483             : 
     484             :   // Looking for per nsPresContext
     485             :   index_type IndexOf(nsPresContext* aPresContext);
     486             :   index_type IndexOf(nsPresContext* aPresContext, nsINode* aNode);
     487             : 
     488             :   TextComposition* GetCompositionFor(nsPresContext* aPresContext);
     489             :   TextComposition* GetCompositionFor(nsPresContext* aPresContext,
     490             :                                      nsINode* aNode);
     491             :   TextComposition* GetCompositionInContent(nsPresContext* aPresContext,
     492             :                                            nsIContent* aContent);
     493             : };
     494             : 
     495             : } // namespace mozilla
     496             : 
     497             : #endif // #ifndef mozilla_TextComposition_h

Generated by: LCOV version 1.13