gecko-dev/widget/TextEventDispatcher.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

569 строки
24 KiB
C
Исходник Обычный вид История

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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_textcompositionsynthesizer_h_
#define mozilla_textcompositionsynthesizer_h_
#include "mozilla/RefPtr.h"
#include "nsString.h"
#include "mozilla/Attributes.h"
#include "mozilla/EventForwards.h"
#include "mozilla/Maybe.h"
#include "mozilla/TextEventDispatcherListener.h"
#include "mozilla/TextRange.h"
Bug 1217700 part.1 nsIWidget should return reference to IMENotificationRequests r=m_kato IMEContentObserver may need to change notifications to send when TextInputProcessor begins input transaction. In current design, IMEContentObserver needs to retrieve IMENotificationRequests at every change. However, if nsIWidget returns a reference to its IMENotificationRequests, IMEContentObserver can call it only once. For that purpose, this patch changes nsIWidget::GetIMENotificationRequests() to nsIWidget::IMENotificationRequestsRef() and make it return |const IMENotificationRequests&|. However, if the lifetime of the instance of IMENotificationRequest is shorter than the widget instance's, it's dangerous. Therefore, it always returns TextEventDispatcher::mIMENotificationRequests. TextEventDispatcher's lifetime is longer than the widget. Therefore, this guarantees the lifetime. On the other hand, widget needs to update TextEventDispatcher::mIMENotificationRequests before calls of nsIWidget::IMENotificationRequestsRef(). Therefore, this patch makes TextEventDispatcher update proper IMENotificationRequests when it gets focus or starts new input transaction and clear mIMENotificationRequests when it loses focus. Note that TextEventDispatcher gets proper requests both from native text event dispatcher listener (typically, implemented by native IME handler class) and TextInputProcessor when TextInputProcessor has input transaction because even if TextInputProcessor overrides native IME, native IME still needs to know the content changes since they may get new input transaction after that. However, there may not be native IME handler in content process. If it runs in Android, PuppetWidget may have native IME handler because widget directly handles IME in e10s mode for Android. Otherwise, native IME handler is in its parent process. So, if TextInputHandler has input transaction in content process, PuppetWidget needs to behave as native event handler. Therefore, this patch makes PuppetWidget inherit TextEventDispatcherListener and implements PuppetWidget::IMENotificationRequestsRef(). MozReview-Commit-ID: 2SW3moONTOX --HG-- extra : rebase_source : d2634ada6c33dbf7a966fadb68608411ee24bfab
2017-04-14 19:35:58 +03:00
#include "mozilla/widget/IMEData.h"
#include "WritingModes.h"
class nsIWidget;
namespace mozilla {
namespace widget {
Bug 1384027 - part1: PuppetWidget should have TextEventDispatcher like nsIWidget instance in the parent process r=m_kato In the parent process, every nsIWidget instance like nsWindow has TextEventDispatcher instance after dispatching a keyboard event or a composition event. Then, TextEventDispatcher manages whether there is composition and handles NotifyIME. However, PuppetWidget doesn't have it unless it synthesizes keyboard events or composition events for tests. This causes PuppetWidget implementing nsIWidget::NotifyIME() with nsBaseWidget::NotifyIMEInternal() which is a virtual method only implemented by PuppetWidget. For consistent implementation around here, we should move NotifyIMEInternal() implementation to TextEventDispatcherListener::NotifyIME() which is called by TextEventDispatcher::NotifyIME(). Then, PuppetWidget can handle NotifyIME() easier. This patch creates TextEventDispatcher::BeginInputTransactionFor() which takes pointer to a dispatching event and pointer to PuppetWidget. It emulates each corresponding event dispatcher method for managing composing state and begins input transaction for the dispatching event. Unfortunately, this implementation is ugly due to duplicated code. However, this is enough for now. When we need to make TextEventDispatcher manage more states, we should add methods which are shared by both BeginInputTransactionFor() and event dispatcher method. MozReview-Commit-ID: GeP028luZjR --HG-- extra : rebase_source : ce71ce4d7ba52aeb12bff2c403c9a6df47ea3a11
2017-07-25 17:27:31 +03:00
class PuppetWidget;
/**
* TextEventDispatcher is a helper class for dispatching widget events defined
* in TextEvents.h. Currently, this is a helper for dispatching
* WidgetCompositionEvent and WidgetKeyboardEvent. This manages the behavior
* of them for conforming to DOM Level 3 Events.
* An instance of this class is created by nsIWidget instance and owned by it.
* This is typically created only by the top level widgets because only they
* handle IME.
*/
class TextEventDispatcher final {
~TextEventDispatcher() = default;
NS_INLINE_DECL_REFCOUNTING(TextEventDispatcher)
public:
explicit TextEventDispatcher(nsIWidget* aWidget);
/**
* Initializes the instance for IME or automated test. Either IME or tests
* need to call one of them before starting composition. If they return
* NS_ERROR_ALREADY_INITIALIZED, it means that the listener already listens
* notifications from TextEventDispatcher for same purpose (for IME or tests).
* If this returns another error, the caller shouldn't keep starting
* composition.
*
* @param aListener Specify the listener to listen notifications and
* requests. This must not be null.
* NOTE: aListener is stored as weak reference in
* TextEventDispatcher. See mListener
* definition below.
*/
nsresult BeginInputTransaction(TextEventDispatcherListener* aListener);
nsresult BeginTestInputTransaction(TextEventDispatcherListener* aListener,
bool aIsAPZAware);
nsresult BeginNativeInputTransaction();
Bug 1384027 - part1: PuppetWidget should have TextEventDispatcher like nsIWidget instance in the parent process r=m_kato In the parent process, every nsIWidget instance like nsWindow has TextEventDispatcher instance after dispatching a keyboard event or a composition event. Then, TextEventDispatcher manages whether there is composition and handles NotifyIME. However, PuppetWidget doesn't have it unless it synthesizes keyboard events or composition events for tests. This causes PuppetWidget implementing nsIWidget::NotifyIME() with nsBaseWidget::NotifyIMEInternal() which is a virtual method only implemented by PuppetWidget. For consistent implementation around here, we should move NotifyIMEInternal() implementation to TextEventDispatcherListener::NotifyIME() which is called by TextEventDispatcher::NotifyIME(). Then, PuppetWidget can handle NotifyIME() easier. This patch creates TextEventDispatcher::BeginInputTransactionFor() which takes pointer to a dispatching event and pointer to PuppetWidget. It emulates each corresponding event dispatcher method for managing composing state and begins input transaction for the dispatching event. Unfortunately, this implementation is ugly due to duplicated code. However, this is enough for now. When we need to make TextEventDispatcher manage more states, we should add methods which are shared by both BeginInputTransactionFor() and event dispatcher method. MozReview-Commit-ID: GeP028luZjR --HG-- extra : rebase_source : ce71ce4d7ba52aeb12bff2c403c9a6df47ea3a11
2017-07-25 17:27:31 +03:00
/**
* BeginInputTransactionFor() should be used when aPuppetWidget dispatches
* a composition or keyboard event coming from its parent process.
*/
nsresult BeginInputTransactionFor(const WidgetGUIEvent* aEvent,
PuppetWidget* aPuppetWidget);
/**
* EndInputTransaction() should be called when the listener stops using
* the TextEventDispatcher.
*
* @param aListener The listener using the TextEventDispatcher instance.
*/
void EndInputTransaction(TextEventDispatcherListener* aListener);
/**
* OnDestroyWidget() is called when mWidget is being destroyed.
*/
void OnDestroyWidget();
nsIWidget* GetWidget() const { return mWidget; }
/**
* Return true starting from ending handling focus notification and until
* receiving blur notification.
*/
bool HasFocus() const { return mHasFocus; }
Bug 1217700 part.1 nsIWidget should return reference to IMENotificationRequests r=m_kato IMEContentObserver may need to change notifications to send when TextInputProcessor begins input transaction. In current design, IMEContentObserver needs to retrieve IMENotificationRequests at every change. However, if nsIWidget returns a reference to its IMENotificationRequests, IMEContentObserver can call it only once. For that purpose, this patch changes nsIWidget::GetIMENotificationRequests() to nsIWidget::IMENotificationRequestsRef() and make it return |const IMENotificationRequests&|. However, if the lifetime of the instance of IMENotificationRequest is shorter than the widget instance's, it's dangerous. Therefore, it always returns TextEventDispatcher::mIMENotificationRequests. TextEventDispatcher's lifetime is longer than the widget. Therefore, this guarantees the lifetime. On the other hand, widget needs to update TextEventDispatcher::mIMENotificationRequests before calls of nsIWidget::IMENotificationRequestsRef(). Therefore, this patch makes TextEventDispatcher update proper IMENotificationRequests when it gets focus or starts new input transaction and clear mIMENotificationRequests when it loses focus. Note that TextEventDispatcher gets proper requests both from native text event dispatcher listener (typically, implemented by native IME handler class) and TextInputProcessor when TextInputProcessor has input transaction because even if TextInputProcessor overrides native IME, native IME still needs to know the content changes since they may get new input transaction after that. However, there may not be native IME handler in content process. If it runs in Android, PuppetWidget may have native IME handler because widget directly handles IME in e10s mode for Android. Otherwise, native IME handler is in its parent process. So, if TextInputHandler has input transaction in content process, PuppetWidget needs to behave as native event handler. Therefore, this patch makes PuppetWidget inherit TextEventDispatcherListener and implements PuppetWidget::IMENotificationRequestsRef(). MozReview-Commit-ID: 2SW3moONTOX --HG-- extra : rebase_source : d2634ada6c33dbf7a966fadb68608411ee24bfab
2017-04-14 19:35:58 +03:00
const IMENotificationRequests& IMENotificationRequestsRef() const {
return mIMENotificationRequests;
}
/**
* OnWidgetChangeIMENotificationRequests() is called when aWidget's
* IMENotificationRequest is maybe modified by unusual path. E.g.,
* modified in an async path.
*/
void OnWidgetChangeIMENotificationRequests(nsIWidget* aWidget) {
MOZ_ASSERT(aWidget);
if (mWidget == aWidget) {
UpdateNotificationRequests();
}
}
/**
* GetState() returns current state of this class.
*
* @return NS_OK: Fine to compose text.
* NS_ERROR_NOT_INITIALIZED: BeginInputTransaction() or
* BeginInputTransactionForTests()
* should be called.
* NS_ERROR_NOT_AVAILABLE: The widget isn't available for
* composition.
*/
nsresult GetState() const;
/**
* IsComposing() returns true after calling StartComposition() and before
* calling CommitComposition(). In other words, native IME has composition
* when this returns true.
*/
bool IsComposing() const { return mIsComposing; }
/**
* IsHandlingComposition() returns true after calling StartComposition() and
* content has not handled eCompositionCommit(AsIs) event. In other words,
* our content has composition when this returns true.
*/
bool IsHandlingComposition() const { return mIsHandlingComposition; }
/**
* IsInNativeInputTransaction() returns true if native IME handler began a
* transaction and it's not finished yet.
*/
bool IsInNativeInputTransaction() const {
return mInputTransactionType == eNativeInputTransaction;
}
/**
* IsDispatchingEvent() returns true while this instance dispatching an event.
*/
bool IsDispatchingEvent() const { return mDispatchingEvent > 0; }
/**
* GetPseudoIMEContext() returns pseudo native IME context if there is an
* input transaction whose type is not for native event handler.
* Otherwise, returns nullptr.
*/
void* GetPseudoIMEContext() const {
if (mInputTransactionType == eNoInputTransaction ||
mInputTransactionType == eNativeInputTransaction) {
return nullptr;
}
return const_cast<TextEventDispatcher*>(this);
}
/**
* Return writing mode at selection while this has focus. Otherwise, or
* never exists selection ranges, this returns Nothing.
*/
const Maybe<WritingMode>& MaybeWritingModeRefAtSelection() const {
return mWritingMode;
}
/**
* MaybeQueryWritingModeAtSelection() returns writing mode at current
* selection even if this does not have focus. If this is not focused, this
* queries selection. Then, chrome script can run due to flushing the layout
* if an element in chrome has focus (but it should not cause any problem
* hopefully).
*/
MOZ_CAN_RUN_SCRIPT Maybe<WritingMode> MaybeQueryWritingModeAtSelection()
const;
/**
* StartComposition() starts composition explicitly.
*
* @param aEventTime If this is not nullptr, WidgetCompositionEvent will
* be initialized with this. Otherwise, initialized
* with the time at initializing.
*/
nsresult StartComposition(nsEventStatus& aStatus,
const WidgetEventTime* aEventTime = nullptr);
/**
* CommitComposition() commits composition.
*
* @param aCommitString If this is null, commits with the last composition
* string. Otherwise, commits the composition with
* this value.
* @param aEventTime If this is not nullptr, WidgetCompositionEvent will
* be initialized with this. Otherwise, initialized
* with the time at initializing.
*/
nsresult CommitComposition(nsEventStatus& aStatus,
const nsAString* aCommitString = nullptr,
const WidgetEventTime* aEventTime = nullptr);
/**
* SetPendingCompositionString() sets new composition string which will be
* dispatched with eCompositionChange event by calling Flush().
*
* @param aString New composition string.
*/
nsresult SetPendingCompositionString(const nsAString& aString) {
return mPendingComposition.SetString(aString);
}
/**
* AppendClauseToPendingComposition() appends a clause information to
* the pending composition string.
*
* @param aLength Length of the clause.
* @param aTextRangeType One of TextRangeType::eRawClause,
* TextRangeType::eSelectedRawClause,
* TextRangeType::eConvertedClause or
* TextRangeType::eSelectedClause.
*/
nsresult AppendClauseToPendingComposition(uint32_t aLength,
TextRangeType aTextRangeType) {
return mPendingComposition.AppendClause(aLength, aTextRangeType);
}
/**
* SetCaretInPendingComposition() sets caret position in the pending
* composition string and its length. This is optional. If IME doesn't
* want to show caret, it shouldn't need to call this.
*
* @param aOffset Offset of the caret in the pending composition
* string. This should not be larger than the length
* of the pending composition string.
* @param aLength Caret width. If this is 0, caret will be collapsed.
* Note that Gecko doesn't supported wide caret yet,
* therefore, this is ignored for now.
*/
nsresult SetCaretInPendingComposition(uint32_t aOffset, uint32_t aLength) {
return mPendingComposition.SetCaret(aOffset, aLength);
}
/**
* SetPendingComposition() is useful if native IME handler already creates
* array of clauses and/or caret information.
*
* @param aString Composition string. This may include native line
* breakers since they will be replaced with XP line
* breakers automatically.
* @param aRanges This should include the ranges of clauses and/or
* a range of caret. Note that this method allows
* some ranges overlap each other and the range order
* is not from start to end.
*/
nsresult SetPendingComposition(const nsAString& aString,
const TextRangeArray* aRanges) {
return mPendingComposition.Set(aString, aRanges);
}
/**
* FlushPendingComposition() sends the pending composition string
* to the widget of the store DOM window. Before calling this, IME needs to
* set pending composition string with SetPendingCompositionString(),
* AppendClauseToPendingComposition() and/or
* SetCaretInPendingComposition().
*
* @param aEventTime If this is not nullptr, WidgetCompositionEvent will
* be initialized with this. Otherwise, initialized
* with the time at initializing.
*/
nsresult FlushPendingComposition(
nsEventStatus& aStatus, const WidgetEventTime* aEventTime = nullptr) {
return mPendingComposition.Flush(this, aStatus, aEventTime);
}
/**
* ClearPendingComposition() makes this instance forget pending composition.
*/
void ClearPendingComposition() { mPendingComposition.Clear(); }
/**
* GetPendingCompositionClauses() returns text ranges which was appended by
* AppendClauseToPendingComposition() or SetPendingComposition().
*/
const TextRangeArray* GetPendingCompositionClauses() const {
return mPendingComposition.GetClauses();
}
/**
* @see nsIWidget::NotifyIME()
*/
// Calling NotifyIME may call OS's API so that everything could happen.
// We should mark it MOZ_CAN_RUN_SCRIPT later.
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsresult
NotifyIME(const IMENotification& aIMENotification);
/**
* DispatchKeyboardEvent() maybe dispatches aKeyboardEvent.
*
* @param aMessage Must be eKeyDown or eKeyUp.
* Use MaybeDispatchKeypressEvents() for dispatching
* eKeyPress.
* @param aKeyboardEvent A keyboard event.
* @param aStatus If dispatching event should be marked as consumed,
* set nsEventStatus_eConsumeNoDefault. Otherwise,
* set nsEventStatus_eIgnore. After dispatching
* a event and it's consumed this returns
* nsEventStatus_eConsumeNoDefault.
* @param aData Calling this method may cause calling
* WillDispatchKeyboardEvent() of the listener.
* aData will be set to its argument.
* @return true if an event is dispatched. Otherwise, false.
*/
bool DispatchKeyboardEvent(EventMessage aMessage,
const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus, void* aData = nullptr);
/**
* MaybeDispatchKeypressEvents() maybe dispatches a keypress event which is
* generated from aKeydownEvent.
*
* @param aKeyboardEvent A keyboard event.
* @param aStatus Sets the result when the caller dispatches
* aKeyboardEvent. Note that if the value is
* nsEventStatus_eConsumeNoDefault, this does NOT
* dispatch keypress events.
* When this method dispatches one or more keypress
* events and one of them is consumed, this returns
* nsEventStatus_eConsumeNoDefault.
* @param aData Calling this method may cause calling
* WillDispatchKeyboardEvent() of the listener.
* aData will be set to its argument.
Bug 1303273 part.3 Dispatch eKeyPress events without NativeKey::HandleCharMessage() when it handles WM_(SYS)KEYDOWN message and there are following WM_(SYS)CHAR messages which includes non-control character r=m_kato This patch creates NativeKey::DispatchKeyPressEventsWithRetrievedCharMessages() for dispatching eKeyPress event with mCommittedCharsAndModifiers when it stores following printable WM_(SYS)CHAR messages. Using loop for dispatching eKeyPress event for every WM_(SYS)CHAR message is wrong because WidgetKeyboardEvent::mKeyValue is initialized with mCommittedCharsAndModifiers and it causes TextEventDispatcher dispatching multiple eKeyPress events at every call of MaybeDispatchKeypressEvents(). Therefore, if mKeyValue is "^^", eKeyPress event is dispatched 4 times --for the first message, eKeyPress events are fired for each "^" and for the second message, eKeyPress events are fired again for each "^"--. Therefore, when it handles WM_(SYS)KEYDOWN and it causes inputting one or more printable characters, it's the easiest way not to use HandleCharMessage(). The new method calls TextEventDispatcher::MaybeDispatchKeypressEvents() only once and it requests to call the callback method with new argument of MaybeDispatchKeypressEvents() when it needs to dispatch 2 or more eKeyPress events. Then, NativeKey::WillDispatchKeyboardEvent() can set each eKeyPress event to raw information of the message and proper modifier state. With this change, we can dispatch multiple eKeyPress events with retrieved WM_(SYS)CHAR message information rather than retrieved information from active keyboard layout. Therefore, NeedsToHandleWithoutFollowingCharMessages() doesn't return true even when mCommittedCharsAndModifiers stores two or more characters. FYI: there is a bug in test_keycodes.xul. That is, Alt+'A' of Greek keyboard layout should cause WM_SYSCHAR with a corresponding Greek character but ASCII characters are specified. Therefore, this patch includes the fix of these bugs MozReview-Commit-ID: JVm7ZJVug0O --HG-- extra : rebase_source : 414ecbe2c01c53f294d1346414b1a289aa0abfe8
2016-10-06 14:52:03 +03:00
* @param aNeedsCallback Set true when caller needs to initialize each
* eKeyPress event immediately before dispatch.
* Then, WillDispatchKeyboardEvent() is always called.
* @return true if one or more events are dispatched.
* Otherwise, false.
*/
bool MaybeDispatchKeypressEvents(const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus,
Bug 1303273 part.3 Dispatch eKeyPress events without NativeKey::HandleCharMessage() when it handles WM_(SYS)KEYDOWN message and there are following WM_(SYS)CHAR messages which includes non-control character r=m_kato This patch creates NativeKey::DispatchKeyPressEventsWithRetrievedCharMessages() for dispatching eKeyPress event with mCommittedCharsAndModifiers when it stores following printable WM_(SYS)CHAR messages. Using loop for dispatching eKeyPress event for every WM_(SYS)CHAR message is wrong because WidgetKeyboardEvent::mKeyValue is initialized with mCommittedCharsAndModifiers and it causes TextEventDispatcher dispatching multiple eKeyPress events at every call of MaybeDispatchKeypressEvents(). Therefore, if mKeyValue is "^^", eKeyPress event is dispatched 4 times --for the first message, eKeyPress events are fired for each "^" and for the second message, eKeyPress events are fired again for each "^"--. Therefore, when it handles WM_(SYS)KEYDOWN and it causes inputting one or more printable characters, it's the easiest way not to use HandleCharMessage(). The new method calls TextEventDispatcher::MaybeDispatchKeypressEvents() only once and it requests to call the callback method with new argument of MaybeDispatchKeypressEvents() when it needs to dispatch 2 or more eKeyPress events. Then, NativeKey::WillDispatchKeyboardEvent() can set each eKeyPress event to raw information of the message and proper modifier state. With this change, we can dispatch multiple eKeyPress events with retrieved WM_(SYS)CHAR message information rather than retrieved information from active keyboard layout. Therefore, NeedsToHandleWithoutFollowingCharMessages() doesn't return true even when mCommittedCharsAndModifiers stores two or more characters. FYI: there is a bug in test_keycodes.xul. That is, Alt+'A' of Greek keyboard layout should cause WM_SYSCHAR with a corresponding Greek character but ASCII characters are specified. Therefore, this patch includes the fix of these bugs MozReview-Commit-ID: JVm7ZJVug0O --HG-- extra : rebase_source : 414ecbe2c01c53f294d1346414b1a289aa0abfe8
2016-10-06 14:52:03 +03:00
void* aData = nullptr,
bool aNeedsCallback = false);
private:
// mWidget is owner of the instance. When this is created, this is set.
// And when mWidget is released, this is cleared by OnDestroyWidget().
// Note that mWidget may be destroyed already (i.e., mWidget->Destroyed() may
// return true).
nsIWidget* mWidget;
// mListener is a weak reference to TextEventDispatcherListener. That might
// be referred by JS. Therefore, the listener might be difficult to release
// itself if this is a strong reference. Additionally, it's difficult to
// check if a method to uninstall the listener is called by valid instance.
// So, using weak reference is the best way in this case.
nsWeakPtr mListener;
Bug 1217700 part.1 nsIWidget should return reference to IMENotificationRequests r=m_kato IMEContentObserver may need to change notifications to send when TextInputProcessor begins input transaction. In current design, IMEContentObserver needs to retrieve IMENotificationRequests at every change. However, if nsIWidget returns a reference to its IMENotificationRequests, IMEContentObserver can call it only once. For that purpose, this patch changes nsIWidget::GetIMENotificationRequests() to nsIWidget::IMENotificationRequestsRef() and make it return |const IMENotificationRequests&|. However, if the lifetime of the instance of IMENotificationRequest is shorter than the widget instance's, it's dangerous. Therefore, it always returns TextEventDispatcher::mIMENotificationRequests. TextEventDispatcher's lifetime is longer than the widget. Therefore, this guarantees the lifetime. On the other hand, widget needs to update TextEventDispatcher::mIMENotificationRequests before calls of nsIWidget::IMENotificationRequestsRef(). Therefore, this patch makes TextEventDispatcher update proper IMENotificationRequests when it gets focus or starts new input transaction and clear mIMENotificationRequests when it loses focus. Note that TextEventDispatcher gets proper requests both from native text event dispatcher listener (typically, implemented by native IME handler class) and TextInputProcessor when TextInputProcessor has input transaction because even if TextInputProcessor overrides native IME, native IME still needs to know the content changes since they may get new input transaction after that. However, there may not be native IME handler in content process. If it runs in Android, PuppetWidget may have native IME handler because widget directly handles IME in e10s mode for Android. Otherwise, native IME handler is in its parent process. So, if TextInputHandler has input transaction in content process, PuppetWidget needs to behave as native event handler. Therefore, this patch makes PuppetWidget inherit TextEventDispatcherListener and implements PuppetWidget::IMENotificationRequestsRef(). MozReview-Commit-ID: 2SW3moONTOX --HG-- extra : rebase_source : d2634ada6c33dbf7a966fadb68608411ee24bfab
2017-04-14 19:35:58 +03:00
// mIMENotificationRequests should store current IME's notification requests.
// So, this may be invalid when IME doesn't have focus.
IMENotificationRequests mIMENotificationRequests;
// mWritingMode stores writing mode at current selection starting from
// receiving focus notification and until receiving blur notification. When
// selection is changed, this is updated by every selection change
// notification.
Maybe<WritingMode> mWritingMode;
// mPendingComposition stores new composition string temporarily.
// These values will be used for dispatching eCompositionChange event
// in Flush(). When Flush() is called, the members will be cleared
// automatically.
class PendingComposition {
public:
PendingComposition();
nsresult SetString(const nsAString& aString);
nsresult AppendClause(uint32_t aLength, TextRangeType aTextRangeType);
nsresult SetCaret(uint32_t aOffset, uint32_t aLength);
nsresult Set(const nsAString& aString, const TextRangeArray* aRanges);
nsresult Flush(TextEventDispatcher* aDispatcher, nsEventStatus& aStatus,
const WidgetEventTime* aEventTime);
const TextRangeArray* GetClauses() const { return mClauses; }
void Clear();
private:
nsString mString;
Bug 1207245 - part 6 - rename nsRefPtr<T> to RefPtr<T>; r=ehsan; a=Tomcat The bulk of this commit was generated with a script, executed at the top level of a typical source code checkout. The only non-machine-generated part was modifying MFBT's moz.build to reflect the new naming. CLOSED TREE makes big refactorings like this a piece of cake. # The main substitution. find . -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.mm' -o -name '*.idl'| \ xargs perl -p -i -e ' s/nsRefPtr\.h/RefPtr\.h/g; # handle includes s/nsRefPtr ?</RefPtr</g; # handle declarations and variables ' # Handle a special friend declaration in gfx/layers/AtomicRefCountedWithFinalize.h. perl -p -i -e 's/::nsRefPtr;/::RefPtr;/' gfx/layers/AtomicRefCountedWithFinalize.h # Handle nsRefPtr.h itself, a couple places that define constructors # from nsRefPtr, and code generators specially. We do this here, rather # than indiscriminantly s/nsRefPtr/RefPtr/, because that would rename # things like nsRefPtrHashtable. perl -p -i -e 's/nsRefPtr/RefPtr/g' \ mfbt/nsRefPtr.h \ xpcom/glue/nsCOMPtr.h \ xpcom/base/OwningNonNull.h \ ipc/ipdl/ipdl/lower.py \ ipc/ipdl/ipdl/builtin.py \ dom/bindings/Codegen.py \ python/lldbutils/lldbutils/utils.py # In our indiscriminate substitution above, we renamed # nsRefPtrGetterAddRefs, the class behind getter_AddRefs. Fix that up. find . -name '*.cpp' -o -name '*.h' -o -name '*.idl' | \ xargs perl -p -i -e 's/nsRefPtrGetterAddRefs/RefPtrGetterAddRefs/g' if [ -d .git ]; then git mv mfbt/nsRefPtr.h mfbt/RefPtr.h else hg mv mfbt/nsRefPtr.h mfbt/RefPtr.h fi --HG-- rename : mfbt/nsRefPtr.h => mfbt/RefPtr.h
2015-10-18 08:24:48 +03:00
RefPtr<TextRangeArray> mClauses;
TextRange mCaret;
bool mReplacedNativeLineBreakers;
void EnsureClauseArray();
/**
* ReplaceNativeLineBreakers() replaces "\r\n" and "\r" to "\n" and adjust
* each clause information and the caret information.
*/
void ReplaceNativeLineBreakers();
/**
* AdjustRange() adjusts aRange as in the string with XP line breakers.
*
* @param aRange The reference to a range in aNativeString.
* This will be modified.
* @param aNativeString The string with native line breakers.
* This may include "\r\n" and/or "\r".
*/
static void AdjustRange(TextRange& aRange, const nsAString& aNativeString);
};
PendingComposition mPendingComposition;
// While dispatching an event, this is incremented.
uint16_t mDispatchingEvent;
enum InputTransactionType : uint8_t {
// No input transaction has been started.
eNoInputTransaction,
// Input transaction for native IME or keyboard event handler. Note that
// keyboard events may be dispatched via parent process if there is.
Bug 1384027 - part1: PuppetWidget should have TextEventDispatcher like nsIWidget instance in the parent process r=m_kato In the parent process, every nsIWidget instance like nsWindow has TextEventDispatcher instance after dispatching a keyboard event or a composition event. Then, TextEventDispatcher manages whether there is composition and handles NotifyIME. However, PuppetWidget doesn't have it unless it synthesizes keyboard events or composition events for tests. This causes PuppetWidget implementing nsIWidget::NotifyIME() with nsBaseWidget::NotifyIMEInternal() which is a virtual method only implemented by PuppetWidget. For consistent implementation around here, we should move NotifyIMEInternal() implementation to TextEventDispatcherListener::NotifyIME() which is called by TextEventDispatcher::NotifyIME(). Then, PuppetWidget can handle NotifyIME() easier. This patch creates TextEventDispatcher::BeginInputTransactionFor() which takes pointer to a dispatching event and pointer to PuppetWidget. It emulates each corresponding event dispatcher method for managing composing state and begins input transaction for the dispatching event. Unfortunately, this implementation is ugly due to duplicated code. However, this is enough for now. When we need to make TextEventDispatcher manage more states, we should add methods which are shared by both BeginInputTransactionFor() and event dispatcher method. MozReview-Commit-ID: GeP028luZjR --HG-- extra : rebase_source : ce71ce4d7ba52aeb12bff2c403c9a6df47ea3a11
2017-07-25 17:27:31 +03:00
// In remote processes, this is also used when events come from the parent
// process and are not for tests because we cannot distinguish if
// TextEventDispatcher has which type of transaction when it dispatches
// (eNativeInputTransaction or eSameProcessSyncInputTransaction).
eNativeInputTransaction,
// Input transaction for automated tests which are APZ-aware. Note that
// keyboard events may be dispatched via parent process if there is.
eAsyncTestInputTransaction,
// Input transaction for automated tests which assume events are fired
// synchronously. I.e., keyboard events are always dispatched in the
// current process.
Bug 1384027 - part1: PuppetWidget should have TextEventDispatcher like nsIWidget instance in the parent process r=m_kato In the parent process, every nsIWidget instance like nsWindow has TextEventDispatcher instance after dispatching a keyboard event or a composition event. Then, TextEventDispatcher manages whether there is composition and handles NotifyIME. However, PuppetWidget doesn't have it unless it synthesizes keyboard events or composition events for tests. This causes PuppetWidget implementing nsIWidget::NotifyIME() with nsBaseWidget::NotifyIMEInternal() which is a virtual method only implemented by PuppetWidget. For consistent implementation around here, we should move NotifyIMEInternal() implementation to TextEventDispatcherListener::NotifyIME() which is called by TextEventDispatcher::NotifyIME(). Then, PuppetWidget can handle NotifyIME() easier. This patch creates TextEventDispatcher::BeginInputTransactionFor() which takes pointer to a dispatching event and pointer to PuppetWidget. It emulates each corresponding event dispatcher method for managing composing state and begins input transaction for the dispatching event. Unfortunately, this implementation is ugly due to duplicated code. However, this is enough for now. When we need to make TextEventDispatcher manage more states, we should add methods which are shared by both BeginInputTransactionFor() and event dispatcher method. MozReview-Commit-ID: GeP028luZjR --HG-- extra : rebase_source : ce71ce4d7ba52aeb12bff2c403c9a6df47ea3a11
2017-07-25 17:27:31 +03:00
// In remote processes, this is also used when events come from the parent
// process and are not dispatched by the instance itself for APZ-aware
// tests because this instance won't dispatch the events via the parent
// process again.
eSameProcessSyncTestInputTransaction,
// Input transaction for others (currently, only FuzzingFunctions).
// Events are fired synchronously in the process.
// XXX Should we make this async for testing default action handlers in
// the main process?
eSameProcessSyncInputTransaction
};
InputTransactionType mInputTransactionType;
bool IsForTests() const {
return mInputTransactionType == eAsyncTestInputTransaction ||
mInputTransactionType == eSameProcessSyncTestInputTransaction;
}
// ShouldSendInputEventToAPZ() returns true when WidgetInputEvent should
// be dispatched via its parent process (if there is) for APZ. Otherwise,
// when the input transaction is for IME of B2G or automated tests which
// isn't APZ-aware, WidgetInputEvent should be dispatched form current
// process directly.
bool ShouldSendInputEventToAPZ() const {
switch (mInputTransactionType) {
case eNativeInputTransaction:
case eAsyncTestInputTransaction:
return true;
case eSameProcessSyncTestInputTransaction:
case eSameProcessSyncInputTransaction:
return false;
case eNoInputTransaction:
NS_WARNING(
"Why does the caller need to dispatch an event when "
"there is no input transaction?");
return true;
default:
MOZ_CRASH("Define the behavior of new InputTransactionType");
}
}
// See IsComposing().
bool mIsComposing;
// See IsHandlingComposition().
bool mIsHandlingComposition;
Bug 1217700 part.1 nsIWidget should return reference to IMENotificationRequests r=m_kato IMEContentObserver may need to change notifications to send when TextInputProcessor begins input transaction. In current design, IMEContentObserver needs to retrieve IMENotificationRequests at every change. However, if nsIWidget returns a reference to its IMENotificationRequests, IMEContentObserver can call it only once. For that purpose, this patch changes nsIWidget::GetIMENotificationRequests() to nsIWidget::IMENotificationRequestsRef() and make it return |const IMENotificationRequests&|. However, if the lifetime of the instance of IMENotificationRequest is shorter than the widget instance's, it's dangerous. Therefore, it always returns TextEventDispatcher::mIMENotificationRequests. TextEventDispatcher's lifetime is longer than the widget. Therefore, this guarantees the lifetime. On the other hand, widget needs to update TextEventDispatcher::mIMENotificationRequests before calls of nsIWidget::IMENotificationRequestsRef(). Therefore, this patch makes TextEventDispatcher update proper IMENotificationRequests when it gets focus or starts new input transaction and clear mIMENotificationRequests when it loses focus. Note that TextEventDispatcher gets proper requests both from native text event dispatcher listener (typically, implemented by native IME handler class) and TextInputProcessor when TextInputProcessor has input transaction because even if TextInputProcessor overrides native IME, native IME still needs to know the content changes since they may get new input transaction after that. However, there may not be native IME handler in content process. If it runs in Android, PuppetWidget may have native IME handler because widget directly handles IME in e10s mode for Android. Otherwise, native IME handler is in its parent process. So, if TextInputHandler has input transaction in content process, PuppetWidget needs to behave as native event handler. Therefore, this patch makes PuppetWidget inherit TextEventDispatcherListener and implements PuppetWidget::IMENotificationRequestsRef(). MozReview-Commit-ID: 2SW3moONTOX --HG-- extra : rebase_source : d2634ada6c33dbf7a966fadb68608411ee24bfab
2017-04-14 19:35:58 +03:00
// true while NOTIFY_IME_OF_FOCUS is received but NOTIFY_IME_OF_BLUR has not
// received yet. Otherwise, false.
bool mHasFocus;
nsresult BeginInputTransactionInternal(TextEventDispatcherListener* aListener,
InputTransactionType aType);
/**
* InitEvent() initializes aEvent. This must be called before dispatching
* the event.
*/
void InitEvent(WidgetGUIEvent& aEvent) const;
/**
* DispatchEvent() dispatches aEvent on aWidget.
*/
nsresult DispatchEvent(nsIWidget* aWidget, WidgetGUIEvent& aEvent,
nsEventStatus& aStatus);
/**
* DispatchInputEvent() dispatches aEvent on aWidget.
*/
nsresult DispatchInputEvent(nsIWidget* aWidget, WidgetInputEvent& aEvent,
nsEventStatus& aStatus);
/**
* StartCompositionAutomaticallyIfNecessary() starts composition if it hasn't
* been started it yet.
*
* @param aStatus If it succeeded to start composition normally, this
* returns nsEventStatus_eIgnore. Otherwise, e.g.,
* the composition is canceled during dispatching
* compositionstart event, this returns
* nsEventStatus_eConsumeNoDefault. In this case,
* the caller shouldn't keep doing its job.
* @param aEventTime If this is not nullptr, WidgetCompositionEvent will
* be initialized with this. Otherwise, initialized
* with the time at initializing.
* @return Only when something unexpected occurs, this returns
* an error. Otherwise, returns NS_OK even if aStatus
* is nsEventStatus_eConsumeNoDefault.
*/
nsresult StartCompositionAutomaticallyIfNecessary(
nsEventStatus& aStatus, const WidgetEventTime* aEventTime);
/**
* DispatchKeyboardEventInternal() maybe dispatches aKeyboardEvent.
*
* @param aMessage Must be eKeyDown, eKeyUp or eKeyPress.
* @param aKeyboardEvent A keyboard event. If aMessage is eKeyPress and
* the event is for second or later character, its
* mKeyValue should be empty string.
* @param aStatus If dispatching event should be marked as consumed,
* set nsEventStatus_eConsumeNoDefault. Otherwise,
* set nsEventStatus_eIgnore. After dispatching
* a event and it's consumed this returns
* nsEventStatus_eConsumeNoDefault.
* @param aData Calling this method may cause calling
* WillDispatchKeyboardEvent() of the listener.
* aData will be set to its argument.
* @param aIndexOfKeypress This must be 0 if aMessage isn't eKeyPress or
* aKeyboard.mKeyNameIndex isn't
* KEY_NAME_INDEX_USE_STRING. Otherwise, i.e.,
* when an eKeyPress event causes inputting
* text, this must be between 0 and
* mKeyValue.Length() - 1 since keypress events
* sending only one character per event.
Bug 1303273 part.3 Dispatch eKeyPress events without NativeKey::HandleCharMessage() when it handles WM_(SYS)KEYDOWN message and there are following WM_(SYS)CHAR messages which includes non-control character r=m_kato This patch creates NativeKey::DispatchKeyPressEventsWithRetrievedCharMessages() for dispatching eKeyPress event with mCommittedCharsAndModifiers when it stores following printable WM_(SYS)CHAR messages. Using loop for dispatching eKeyPress event for every WM_(SYS)CHAR message is wrong because WidgetKeyboardEvent::mKeyValue is initialized with mCommittedCharsAndModifiers and it causes TextEventDispatcher dispatching multiple eKeyPress events at every call of MaybeDispatchKeypressEvents(). Therefore, if mKeyValue is "^^", eKeyPress event is dispatched 4 times --for the first message, eKeyPress events are fired for each "^" and for the second message, eKeyPress events are fired again for each "^"--. Therefore, when it handles WM_(SYS)KEYDOWN and it causes inputting one or more printable characters, it's the easiest way not to use HandleCharMessage(). The new method calls TextEventDispatcher::MaybeDispatchKeypressEvents() only once and it requests to call the callback method with new argument of MaybeDispatchKeypressEvents() when it needs to dispatch 2 or more eKeyPress events. Then, NativeKey::WillDispatchKeyboardEvent() can set each eKeyPress event to raw information of the message and proper modifier state. With this change, we can dispatch multiple eKeyPress events with retrieved WM_(SYS)CHAR message information rather than retrieved information from active keyboard layout. Therefore, NeedsToHandleWithoutFollowingCharMessages() doesn't return true even when mCommittedCharsAndModifiers stores two or more characters. FYI: there is a bug in test_keycodes.xul. That is, Alt+'A' of Greek keyboard layout should cause WM_SYSCHAR with a corresponding Greek character but ASCII characters are specified. Therefore, this patch includes the fix of these bugs MozReview-Commit-ID: JVm7ZJVug0O --HG-- extra : rebase_source : 414ecbe2c01c53f294d1346414b1a289aa0abfe8
2016-10-06 14:52:03 +03:00
* @param aNeedsCallback Set true when caller needs to initialize each
* eKeyPress event immediately before dispatch.
* Then, WillDispatchKeyboardEvent() is always called.
* @return true if an event is dispatched. Otherwise, false.
*/
// TODO: Mark this as MOZ_CAN_RUN_SCRIPT instead.
MOZ_CAN_RUN_SCRIPT_BOUNDARY bool DispatchKeyboardEventInternal(
EventMessage aMessage, const WidgetKeyboardEvent& aKeyboardEvent,
nsEventStatus& aStatus, void* aData, uint32_t aIndexOfKeypress = 0,
bool aNeedsCallback = false);
Bug 1217700 part.1 nsIWidget should return reference to IMENotificationRequests r=m_kato IMEContentObserver may need to change notifications to send when TextInputProcessor begins input transaction. In current design, IMEContentObserver needs to retrieve IMENotificationRequests at every change. However, if nsIWidget returns a reference to its IMENotificationRequests, IMEContentObserver can call it only once. For that purpose, this patch changes nsIWidget::GetIMENotificationRequests() to nsIWidget::IMENotificationRequestsRef() and make it return |const IMENotificationRequests&|. However, if the lifetime of the instance of IMENotificationRequest is shorter than the widget instance's, it's dangerous. Therefore, it always returns TextEventDispatcher::mIMENotificationRequests. TextEventDispatcher's lifetime is longer than the widget. Therefore, this guarantees the lifetime. On the other hand, widget needs to update TextEventDispatcher::mIMENotificationRequests before calls of nsIWidget::IMENotificationRequestsRef(). Therefore, this patch makes TextEventDispatcher update proper IMENotificationRequests when it gets focus or starts new input transaction and clear mIMENotificationRequests when it loses focus. Note that TextEventDispatcher gets proper requests both from native text event dispatcher listener (typically, implemented by native IME handler class) and TextInputProcessor when TextInputProcessor has input transaction because even if TextInputProcessor overrides native IME, native IME still needs to know the content changes since they may get new input transaction after that. However, there may not be native IME handler in content process. If it runs in Android, PuppetWidget may have native IME handler because widget directly handles IME in e10s mode for Android. Otherwise, native IME handler is in its parent process. So, if TextInputHandler has input transaction in content process, PuppetWidget needs to behave as native event handler. Therefore, this patch makes PuppetWidget inherit TextEventDispatcherListener and implements PuppetWidget::IMENotificationRequestsRef(). MozReview-Commit-ID: 2SW3moONTOX --HG-- extra : rebase_source : d2634ada6c33dbf7a966fadb68608411ee24bfab
2017-04-14 19:35:58 +03:00
/**
* ClearNotificationRequests() clears mIMENotificationRequests.
*/
void ClearNotificationRequests();
/**
* UpdateNotificationRequests() updates mIMENotificationRequests with
* current state. If the instance doesn't have focus, this clears
* mIMENotificationRequests. Otherwise, updates it with both requests of
* current listener and native listener.
*/
void UpdateNotificationRequests();
};
} // namespace widget
} // namespace mozilla
#endif // #ifndef mozilla_widget_textcompositionsynthesizer_h_