summaryrefslogtreecommitdiffstats
path: root/dom/events/TextComposition.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/events/TextComposition.h
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/events/TextComposition.h')
-rw-r--r--dom/events/TextComposition.h631
1 files changed, 631 insertions, 0 deletions
diff --git a/dom/events/TextComposition.h b/dom/events/TextComposition.h
new file mode 100644
index 0000000000..7199171068
--- /dev/null
+++ b/dom/events/TextComposition.h
@@ -0,0 +1,631 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_TextComposition_h
+#define mozilla_TextComposition_h
+
+#include "nsCOMPtr.h"
+#include "nsINode.h"
+#include "nsIWidget.h"
+#include "nsTArray.h"
+#include "nsThreadUtils.h"
+#include "nsPresContext.h"
+#include "mozilla/AlreadyAddRefed.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/EventForwards.h"
+#include "mozilla/RangeBoundary.h"
+#include "mozilla/TextRange.h"
+#include "mozilla/dom/BrowserParent.h"
+#include "mozilla/dom/Text.h"
+
+class nsRange;
+
+struct CharacterDataChangeInfo;
+
+namespace mozilla {
+
+class EditorBase;
+class EventDispatchingCallback;
+class IMEStateManager;
+
+/**
+ * TextComposition represents a text composition. This class stores the
+ * composition event target and its presContext. At dispatching the event via
+ * this class, the instances use the stored event target.
+ */
+
+class TextComposition final {
+ friend class IMEStateManager;
+
+ NS_INLINE_DECL_REFCOUNTING(TextComposition)
+
+ public:
+ typedef dom::BrowserParent BrowserParent;
+ typedef dom::Text Text;
+
+ static bool IsHandlingSelectionEvent() { return sHandlingSelectionEvent; }
+
+ TextComposition(nsPresContext* aPresContext, nsINode* aNode,
+ BrowserParent* aBrowserParent,
+ WidgetCompositionEvent* aCompositionEvent);
+
+ bool Destroyed() const { return !mPresContext; }
+ nsPresContext* GetPresContext() const { return mPresContext; }
+ nsINode* GetEventTargetNode() const { return mNode; }
+ // The text node which includes composition string.
+ Text* GetContainerTextNode() const { return mContainerTextNode; }
+ // The latest CompositionEvent.data value except compositionstart event.
+ // This value is modified at dispatching compositionupdate.
+ const nsString& LastData() const { return mLastData; }
+ // Returns commit string if it'll be commited as-is.
+ nsString CommitStringIfCommittedAsIs() const;
+ // The composition string which is already handled by the focused editor.
+ // I.e., this value must be same as the composition string on the focused
+ // editor. This value is modified at a call of
+ // EditorDidHandleCompositionChangeEvent().
+ // Note that mString and mLastData are different between dispatcing
+ // compositionupdate and compositionchange event handled by focused editor.
+ const nsString& String() const { return mString; }
+ // The latest clauses range of the composition string.
+ // During compositionupdate event, GetRanges() returns old ranges.
+ // So if getting on compositionupdate, Use GetLastRange instead of GetRange().
+ TextRangeArray* GetLastRanges() const { return mLastRanges; }
+ // Returns the clauses and/or caret range of the composition string.
+ // This is modified at a call of EditorWillHandleCompositionChangeEvent().
+ // This may return null if there is no clauses and caret.
+ // XXX We should return |const TextRangeArray*| here, but it causes compile
+ // error due to inaccessible Release() method.
+ TextRangeArray* GetRanges() const { return mRanges; }
+ // Returns the widget which is proper to call NotifyIME().
+ already_AddRefed<nsIWidget> GetWidget() const {
+ if (!mPresContext) {
+ return nullptr;
+ }
+ return do_AddRef(mPresContext->GetRootWidget());
+ }
+ // Returns the tab parent which has this composition in its remote process.
+ BrowserParent* GetBrowserParent() const { return mBrowserParent; }
+ // Returns true if the composition is started with synthesized event which
+ // came from nsDOMWindowUtils.
+ bool IsSynthesizedForTests() const { return mIsSynthesizedForTests; }
+
+ const widget::NativeIMEContext& GetNativeIMEContext() const {
+ return mNativeContext;
+ }
+
+ /**
+ * This is called when IMEStateManager stops managing the instance.
+ */
+ void Destroy();
+
+ /**
+ * Request to commit (or cancel) the composition to IME. This method should
+ * be called only by IMEStateManager::NotifyIME().
+ */
+ nsresult RequestToCommit(nsIWidget* aWidget, bool aDiscard);
+
+ /**
+ * IsRequestingCommitOrCancelComposition() returns true if the instance is
+ * requesting widget to commit or cancel composition.
+ */
+ bool IsRequestingCommitOrCancelComposition() const {
+ return mIsRequestingCancel || mIsRequestingCommit;
+ }
+
+ /**
+ * Send a notification to IME. It depends on the IME or platform spec what
+ * will occur (or not occur).
+ */
+ nsresult NotifyIME(widget::IMEMessage aMessage);
+
+ /**
+ * the offset of first composition string
+ */
+ uint32_t NativeOffsetOfStartComposition() const {
+ return mCompositionStartOffset;
+ }
+
+ /**
+ * the offset of first selected clause or start of composition
+ */
+ uint32_t NativeOffsetOfTargetClause() const {
+ return mCompositionStartOffset + mTargetClauseOffsetInComposition;
+ }
+
+ /**
+ * Return current composition start and end point in the DOM tree.
+ * Note that one of or both of those result container may be different
+ * from GetContainerTextNode() if the DOM tree was modified by the web
+ * app. If there is no composition string the DOM tree, these return
+ * unset range boundaries.
+ */
+ RawRangeBoundary FirstIMESelectionStartRef() const;
+ RawRangeBoundary LastIMESelectionEndRef() const;
+
+ /**
+ * The offset of composition string in the text node. If composition string
+ * hasn't been inserted in any text node yet, this returns UINT32_MAX.
+ */
+ uint32_t XPOffsetInTextNode() const {
+ return mCompositionStartOffsetInTextNode;
+ }
+
+ /**
+ * The length of composition string in the text node. If composition string
+ * hasn't been inserted in any text node yet, this returns 0.
+ */
+ uint32_t XPLengthInTextNode() const {
+ return mCompositionLengthInTextNode == UINT32_MAX
+ ? 0
+ : mCompositionLengthInTextNode;
+ }
+
+ /**
+ * The end offset of composition string in the text node. If composition
+ * string hasn't been inserted in any text node yet, this returns UINT32_MAX.
+ */
+ uint32_t XPEndOffsetInTextNode() const {
+ if (mCompositionStartOffsetInTextNode == UINT32_MAX ||
+ mCompositionLengthInTextNode == UINT32_MAX) {
+ return UINT32_MAX;
+ }
+ return mCompositionStartOffsetInTextNode + mCompositionLengthInTextNode;
+ }
+
+ /**
+ * Returns true if there is non-empty composition string and it's not fixed.
+ * Otherwise, false.
+ */
+ bool IsComposing() const { return mIsComposing; }
+
+ /**
+ * Returns true while editor is handling an event which is modifying the
+ * composition string.
+ */
+ bool IsEditorHandlingEvent() const { return mIsEditorHandlingEvent; }
+
+ /**
+ * IsMovingToNewTextNode() returns true if editor detects the text node
+ * has been removed and still not insert the composition string into
+ * new text node.
+ */
+ bool IsMovingToNewTextNode() const {
+ return !mContainerTextNode && mCompositionLengthInTextNode &&
+ mCompositionLengthInTextNode != UINT32_MAX;
+ }
+
+ /**
+ * StartHandlingComposition() and EndHandlingComposition() are called by
+ * editor when it holds a TextComposition instance and release it.
+ */
+ void StartHandlingComposition(EditorBase* aEditorBase);
+ void EndHandlingComposition(EditorBase* aEditorBase);
+
+ /**
+ * OnEditorDestroyed() is called when the editor is destroyed but there is
+ * active composition.
+ */
+ void OnEditorDestroyed();
+
+ /**
+ * CompositionChangeEventHandlingMarker class should be created at starting
+ * to handle text event in focused editor. This calls
+ * EditorWillHandleCompositionChangeEvent() and
+ * EditorDidHandleCompositionChangeEvent() automatically.
+ */
+ class MOZ_STACK_CLASS CompositionChangeEventHandlingMarker {
+ public:
+ CompositionChangeEventHandlingMarker(
+ TextComposition* aComposition,
+ const WidgetCompositionEvent* aCompositionChangeEvent)
+ : mComposition(aComposition) {
+ mComposition->EditorWillHandleCompositionChangeEvent(
+ aCompositionChangeEvent);
+ }
+
+ ~CompositionChangeEventHandlingMarker() {
+ mComposition->EditorDidHandleCompositionChangeEvent();
+ }
+
+ private:
+ RefPtr<TextComposition> mComposition;
+ CompositionChangeEventHandlingMarker();
+ CompositionChangeEventHandlingMarker(
+ const CompositionChangeEventHandlingMarker& aOther);
+ };
+
+ /**
+ * OnUpdateCompositionInEditor() is called when editor updates composition
+ * string in the DOM tree.
+ *
+ * @param aStringToInsert The string to insert the text node actually.
+ * This may be different from the data of
+ * dispatching composition event because it may
+ * be replaced with different character for
+ * passwords, or truncated due to maxlength.
+ * @param aTextNode The text node which includes composition string.
+ * @param aOffset The offset of composition string in aTextNode.
+ */
+ void OnUpdateCompositionInEditor(const nsAString& aStringToInsert,
+ Text& aTextNode, uint32_t aOffset) {
+ mContainerTextNode = &aTextNode;
+ mCompositionStartOffsetInTextNode = aOffset;
+ NS_WARNING_ASSERTION(mCompositionStartOffsetInTextNode != UINT32_MAX,
+ "The text node is really too long.");
+ mCompositionLengthInTextNode = aStringToInsert.Length();
+ NS_WARNING_ASSERTION(mCompositionLengthInTextNode != UINT32_MAX,
+ "The string to insert is really too long.");
+ }
+
+ /**
+ * OnTextNodeRemoved() is called when focused editor is reframed and
+ * mContainerTextNode may be (or have been) replaced with different text
+ * node, or just removes the text node due to empty.
+ */
+ void OnTextNodeRemoved() {
+ mContainerTextNode = nullptr;
+ // Don't reset mCompositionStartOffsetInTextNode nor
+ // mCompositionLengthInTextNode because editor needs them to restore
+ // composition in new text node.
+ }
+
+ /**
+ * OnCharacterDataChanged() is called when IMEContentObserver receives
+ * character data change notifications.
+ */
+ void OnCharacterDataChanged(Text& aText,
+ const CharacterDataChangeInfo& aInfo);
+
+ private:
+ // Private destructor, to discourage deletion outside of Release():
+ ~TextComposition() {
+ // WARNING: mPresContext may be destroying, so, be careful if you touch it.
+ }
+
+ // sHandlingSelectionEvent is true while TextComposition sends a selection
+ // event to ContentEventHandler.
+ static bool sHandlingSelectionEvent;
+
+ // This class holds nsPresContext weak. This instance shouldn't block
+ // destroying it. When the presContext is being destroyed, it's notified to
+ // IMEStateManager::OnDestroyPresContext(), and then, it destroy
+ // this instance.
+ nsPresContext* mPresContext;
+ RefPtr<nsINode> mNode;
+ RefPtr<BrowserParent> mBrowserParent;
+
+ // The text node which includes the composition string.
+ RefPtr<Text> mContainerTextNode;
+
+ // This is the clause and caret range information which is managed by
+ // the focused editor. This may be null if there is no clauses or caret.
+ RefPtr<TextRangeArray> mRanges;
+ // Same as mRange, but mRange will have old data during compositionupdate.
+ // So this will be valied during compositionupdate.
+ RefPtr<TextRangeArray> mLastRanges;
+
+ // mNativeContext stores a opaque pointer. This works as the "ID" for this
+ // composition. Don't access the instance, it may not be available.
+ widget::NativeIMEContext mNativeContext;
+
+ // mEditorBaseWeak is a weak reference to the focused editor handling
+ // composition.
+ nsWeakPtr mEditorBaseWeak;
+
+ // mLastData stores the data attribute of the latest composition event (except
+ // the compositionstart event).
+ nsString mLastData;
+
+ // mString stores the composition text which has been handled by the focused
+ // editor.
+ nsString mString;
+
+ // Offset of the composition string from start of the editor
+ uint32_t mCompositionStartOffset;
+ // Offset of the selected clause of the composition string from
+ // mCompositionStartOffset
+ uint32_t mTargetClauseOffsetInComposition;
+ // Offset of the composition string in mContainerTextNode.
+ // NOTE: This is NOT valid in the main process if focused editor is in a
+ // remote process.
+ uint32_t mCompositionStartOffsetInTextNode;
+ // Length of the composition string in mContainerTextNode. If this instance
+ // has already dispatched eCompositionCommit(AsIs) and
+ // EditorDidHandleCompositionChangeEvent() has already been called,
+ // this may be different from length of mString because committed string
+ // may be truncated by maxlength attribute of <input> or <textarea>.
+ // NOTE: This is NOT valid in the main process if focused editor is in a
+ // remote process.
+ uint32_t mCompositionLengthInTextNode;
+
+ // See the comment for IsSynthesizedForTests().
+ bool mIsSynthesizedForTests;
+
+ // See the comment for IsComposing().
+ bool mIsComposing;
+
+ // mIsEditorHandlingEvent is true while editor is modifying the composition
+ // string.
+ bool mIsEditorHandlingEvent;
+
+ // mIsRequestingCommit or mIsRequestingCancel is true *only* while we're
+ // requesting commit or canceling the composition. In other words, while
+ // one of these values is true, we're handling the request.
+ bool mIsRequestingCommit;
+ bool mIsRequestingCancel;
+
+ // mRequestedToCommitOrCancel is true *after* we requested IME to commit or
+ // cancel the composition. In other words, we already requested of IME that
+ // it commits or cancels current composition.
+ // NOTE: Before this is set to true, both mIsRequestingCommit and
+ // mIsRequestingCancel are set to false.
+ bool mRequestedToCommitOrCancel;
+
+ // Set to true if the instance dispatches an eCompositionChange event.
+ bool mHasDispatchedDOMTextEvent;
+
+ // Before this dispatches commit event into the tree, this is set to true.
+ // So, this means if native IME already commits the composition.
+ bool mHasReceivedCommitEvent;
+
+ // mWasNativeCompositionEndEventDiscarded is true if this composition was
+ // requested commit or cancel itself but native compositionend event is
+ // discarded by PresShell due to not safe to dispatch events.
+ bool mWasNativeCompositionEndEventDiscarded;
+
+ // Allow control characters appear in composition string.
+ // When this is false, control characters except
+ // CHARACTER TABULATION (horizontal tab) are removed from
+ // both composition string and data attribute of compositionupdate
+ // and compositionend events.
+ bool mAllowControlCharacters;
+
+ // mWasCompositionStringEmpty is true if the composition string was empty
+ // when DispatchCompositionEvent() is called.
+ bool mWasCompositionStringEmpty;
+
+ // Hide the default constructor and copy constructor.
+ TextComposition()
+ : mPresContext(nullptr),
+ mNativeContext(nullptr),
+ mCompositionStartOffset(0),
+ mTargetClauseOffsetInComposition(0),
+ mCompositionStartOffsetInTextNode(UINT32_MAX),
+ mCompositionLengthInTextNode(UINT32_MAX),
+ mIsSynthesizedForTests(false),
+ mIsComposing(false),
+ mIsEditorHandlingEvent(false),
+ mIsRequestingCommit(false),
+ mIsRequestingCancel(false),
+ mRequestedToCommitOrCancel(false),
+ mHasReceivedCommitEvent(false),
+ mWasNativeCompositionEndEventDiscarded(false),
+ mAllowControlCharacters(false),
+ mWasCompositionStringEmpty(true) {}
+ TextComposition(const TextComposition& aOther);
+
+ /**
+ * If we're requesting IME to commit or cancel composition, or we've already
+ * requested it, or we've already known this composition has been ended in
+ * IME, we don't need to request commit nor cancel composition anymore and
+ * shouldn't do so if we're in content process for not committing/canceling
+ * "current" composition in native IME. So, when this returns true,
+ * RequestIMEToCommit() does nothing.
+ */
+ bool CanRequsetIMEToCommitOrCancelComposition() const {
+ return !mIsRequestingCommit && !mIsRequestingCancel &&
+ !mRequestedToCommitOrCancel && !mHasReceivedCommitEvent;
+ }
+
+ /**
+ * GetEditorBase() returns EditorBase pointer of mEditorBaseWeak.
+ */
+ already_AddRefed<EditorBase> GetEditorBase() const;
+
+ /**
+ * HasEditor() returns true if mEditorBaseWeak holds EditorBase instance
+ * which is alive. Otherwise, false.
+ */
+ bool HasEditor() const;
+
+ /**
+ * EditorWillHandleCompositionChangeEvent() must be called before the focused
+ * editor handles the compositionchange event.
+ */
+ void EditorWillHandleCompositionChangeEvent(
+ const WidgetCompositionEvent* aCompositionChangeEvent);
+
+ /**
+ * EditorDidHandleCompositionChangeEvent() must be called after the focused
+ * editor handles a compositionchange event.
+ */
+ void EditorDidHandleCompositionChangeEvent();
+
+ /**
+ * IsValidStateForComposition() returns true if it's safe to dispatch an event
+ * to the DOM tree. Otherwise, false.
+ * WARNING: This doesn't check script blocker state. It should be checked
+ * before dispatching the first event.
+ */
+ bool IsValidStateForComposition(nsIWidget* aWidget) const;
+
+ /**
+ * DispatchCompositionEvent() dispatches the aCompositionEvent to the mContent
+ * synchronously. The caller must ensure that it's safe to dispatch the event.
+ */
+ MOZ_CAN_RUN_SCRIPT void DispatchCompositionEvent(
+ WidgetCompositionEvent* aCompositionEvent, nsEventStatus* aStatus,
+ EventDispatchingCallback* aCallBack, bool aIsSynthesized);
+
+ /**
+ * Simply calling EventDispatcher::Dispatch() with plugin event.
+ * If dispatching event has no orginal clone, aOriginalEvent can be null.
+ */
+ MOZ_CAN_RUN_SCRIPT void DispatchEvent(
+ WidgetCompositionEvent* aDispatchEvent, nsEventStatus* aStatus,
+ EventDispatchingCallback* aCallback,
+ const WidgetCompositionEvent* aOriginalEvent = nullptr);
+
+ /**
+ * HandleSelectionEvent() sends the selection event to ContentEventHandler
+ * or dispatches it to the focused child process.
+ */
+ MOZ_CAN_RUN_SCRIPT
+ void HandleSelectionEvent(WidgetSelectionEvent* aSelectionEvent) {
+ RefPtr<nsPresContext> presContext(mPresContext);
+ RefPtr<BrowserParent> browserParent(mBrowserParent);
+ HandleSelectionEvent(presContext, browserParent, aSelectionEvent);
+ }
+ MOZ_CAN_RUN_SCRIPT
+ static void HandleSelectionEvent(nsPresContext* aPresContext,
+ BrowserParent* aBrowserParent,
+ WidgetSelectionEvent* aSelectionEvent);
+
+ /**
+ * MaybeDispatchCompositionUpdate() may dispatch a compositionupdate event
+ * if aCompositionEvent changes composition string.
+ * @return Returns false if dispatching the compositionupdate event caused
+ * destroying this composition.
+ */
+ MOZ_CAN_RUN_SCRIPT bool MaybeDispatchCompositionUpdate(
+ const WidgetCompositionEvent* aCompositionEvent);
+
+ /**
+ * CloneAndDispatchAs() dispatches a composition event which is
+ * duplicateed from aCompositionEvent and set the aMessage.
+ *
+ * @return Returns BaseEventFlags which is the result of dispatched event.
+ */
+ MOZ_CAN_RUN_SCRIPT BaseEventFlags
+ CloneAndDispatchAs(const WidgetCompositionEvent* aCompositionEvent,
+ EventMessage aMessage, nsEventStatus* aStatus = nullptr,
+ EventDispatchingCallback* aCallBack = nullptr);
+
+ /**
+ * If IME has already dispatched compositionend event but it was discarded
+ * by PresShell due to not safe to dispatch, this returns true.
+ */
+ bool WasNativeCompositionEndEventDiscarded() const {
+ return mWasNativeCompositionEndEventDiscarded;
+ }
+
+ /**
+ * OnCompositionEventDiscarded() is called when PresShell discards
+ * compositionupdate, compositionend or compositionchange event due to not
+ * safe to dispatch event.
+ */
+ void OnCompositionEventDiscarded(WidgetCompositionEvent* aCompositionEvent);
+
+ /**
+ * OnCompositionEventDispatched() is called after a composition event is
+ * dispatched.
+ */
+ MOZ_CAN_RUN_SCRIPT void OnCompositionEventDispatched(
+ const WidgetCompositionEvent* aDispatchEvent);
+
+ /**
+ * MaybeNotifyIMEOfCompositionEventHandled() notifies IME of composition
+ * event handled. This should be called after dispatching a composition
+ * event which came from widget.
+ */
+ void MaybeNotifyIMEOfCompositionEventHandled(
+ const WidgetCompositionEvent* aCompositionEvent);
+
+ /**
+ * GetSelectionStartOffset() returns normal selection start offset in the
+ * editor which has this composition.
+ * If it failed or lost focus, this would return 0.
+ */
+ MOZ_CAN_RUN_SCRIPT uint32_t GetSelectionStartOffset();
+
+ /**
+ * OnStartOffsetUpdatedInChild() is called when composition start offset
+ * is updated in the child process. I.e., this is called and never called
+ * if the composition is in this process.
+ * @param aStartOffset New composition start offset with native
+ * linebreaks.
+ */
+ void OnStartOffsetUpdatedInChild(uint32_t aStartOffset);
+
+ /**
+ * CompositionEventDispatcher dispatches the specified composition (or text)
+ * event.
+ */
+ class CompositionEventDispatcher : public Runnable {
+ public:
+ CompositionEventDispatcher(TextComposition* aTextComposition,
+ nsINode* aEventTarget,
+ EventMessage aEventMessage,
+ const nsAString& aData,
+ bool aIsSynthesizedEvent = false);
+ MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override;
+
+ private:
+ RefPtr<TextComposition> mTextComposition;
+ nsCOMPtr<nsINode> mEventTarget;
+ nsString mData;
+ EventMessage mEventMessage;
+ bool mIsSynthesizedEvent;
+
+ CompositionEventDispatcher()
+ : Runnable("TextComposition::CompositionEventDispatcher"),
+ mEventMessage(eVoidEvent),
+ mIsSynthesizedEvent(false){};
+ };
+
+ /**
+ * DispatchCompositionEventRunnable() dispatches a composition event to the
+ * content. Be aware, if you use this method, nsPresShellEventCB isn't used.
+ * That means that nsIFrame::HandleEvent() is never called.
+ * WARNING: The instance which is managed by IMEStateManager may be
+ * destroyed by this method call.
+ *
+ * @param aEventMessage Must be one of composition events.
+ * @param aData Used for mData value.
+ * @param aIsSynthesizingCommit true if this is called for synthesizing
+ * commit or cancel composition. Otherwise,
+ * false.
+ */
+ void DispatchCompositionEventRunnable(EventMessage aEventMessage,
+ const nsAString& aData,
+ bool aIsSynthesizingCommit = false);
+};
+
+/**
+ * TextCompositionArray manages the instances of TextComposition class.
+ * Managing with array is enough because only one composition is typically
+ * there. Even if user switches native IME context, it's very rare that
+ * second or more composition is started.
+ * It's assumed that this is used by IMEStateManager for storing all active
+ * compositions in the process. If the instance is it, each TextComposition
+ * in the array can be destroyed by calling some methods of itself.
+ */
+
+class TextCompositionArray final
+ : public AutoTArray<RefPtr<TextComposition>, 2> {
+ public:
+ // Looking for per native IME context.
+ index_type IndexOf(const widget::NativeIMEContext& aNativeIMEContext);
+ index_type IndexOf(nsIWidget* aWidget);
+
+ TextComposition* GetCompositionFor(nsIWidget* aWidget);
+ TextComposition* GetCompositionFor(
+ const WidgetCompositionEvent* aCompositionEvent);
+
+ // Looking for per nsPresContext
+ index_type IndexOf(nsPresContext* aPresContext);
+ index_type IndexOf(nsPresContext* aPresContext, nsINode* aNode);
+
+ TextComposition* GetCompositionFor(nsPresContext* aPresContext);
+ TextComposition* GetCompositionFor(nsPresContext* aPresContext,
+ nsINode* aNode);
+ TextComposition* GetCompositionInContent(nsPresContext* aPresContext,
+ nsIContent* aContent);
+};
+
+} // namespace mozilla
+
+#endif // #ifndef mozilla_TextComposition_h