--- a/dom/events/IMEContentObserver.cpp
+++ b/dom/events/IMEContentObserver.cpp
@@ -130,18 +130,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IM
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelection)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRootContent)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditableNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditor)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEndOfAddedTextCache.mContainerNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mStartOfRemovingTextRangeCache.mContainerNode)
- tmp->mIMENotificationRequests.mWantUpdates =
- IMENotificationRequests::NOTIFY_NOTHING;
+ tmp->mIMENotificationRequests = nullptr;
tmp->mESM = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IMEContentObserver)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWidget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedWidget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelection)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRootContent)
@@ -163,16 +162,17 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISelectionListener)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(IMEContentObserver)
NS_IMPL_CYCLE_COLLECTING_RELEASE(IMEContentObserver)
IMEContentObserver::IMEContentObserver()
: mESM(nullptr)
+ , mIMENotificationRequests(nullptr)
, mSuppressNotifications(0)
, mPreCharacterDataChangeLength(-1)
, mSendingNotification(NOTIFY_IME_OF_NOTHING)
, mIsObserving(false)
, mIMEHasFocus(false)
, mNeedsToNotifyIMEOfFocusSet(false)
, mNeedsToNotifyIMEOfTextChange(false)
, mNeedsToNotifyIMEOfSelectionChange(false)
@@ -204,16 +204,17 @@ IMEContentObserver::Init(nsIWidget* aWid
// Clear members which may not be initialized again.
Clear();
}
mESM = aPresContext->EventStateManager();
mESM->OnStartToObserveContent(this);
mWidget = aWidget;
+ mIMENotificationRequests = &mWidget->IMENotificationRequestsRef();
if (aWidget->GetInputContext().mIMEState.mEnabled == IMEState::PLUGIN) {
if (!InitWithPlugin(aPresContext, aContent)) {
Clear();
return;
}
} else {
if (!InitWithEditor(aPresContext, aContent, aEditor)) {
@@ -413,61 +414,60 @@ void
IMEContentObserver::ObserveEditableNode()
{
MOZ_RELEASE_ASSERT(mSelection);
MOZ_RELEASE_ASSERT(mRootContent);
MOZ_RELEASE_ASSERT(GetState() != eState_Observing);
// If this is called before sending NOTIFY_IME_OF_FOCUS (it's possible when
// the editor is reframed before sending NOTIFY_IME_OF_FOCUS asynchronously),
- // the update preference of mWidget may be different from after the widget
+ // the notification requests of mWidget may be different from after the widget
// receives NOTIFY_IME_OF_FOCUS. So, this should be called again by
// OnIMEReceivedFocus() which is called after sending NOTIFY_IME_OF_FOCUS.
if (!mIMEHasFocus) {
MOZ_ASSERT(!mWidget || mNeedsToNotifyIMEOfFocusSet ||
mSendingNotification == NOTIFY_IME_OF_FOCUS,
"Wow, OnIMEReceivedFocus() won't be called?");
return;
}
mIsObserving = true;
if (mEditor) {
mEditor->AddEditorObserver(this);
}
- mIMENotificationRequests = mWidget->IMENotificationRequestsRef();
if (!WasInitializedWithPlugin()) {
// Add selection change listener only when this starts to observe
// non-plugin content since we cannot detect selection changes in
// plugins.
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSelection));
NS_ENSURE_TRUE_VOID(selPrivate);
nsresult rv = selPrivate->AddSelectionListener(this);
NS_ENSURE_SUCCESS_VOID(rv);
- }
-
- if (mIMENotificationRequests.WantTextChange()) {
- // add text change observer
+ // Add text change observer only when this starts to observe
+ // non-plugin content since we cannot detect text changes in
+ // plugins.
mRootContent->AddMutationObserver(this);
}
- if (mIMENotificationRequests.WantPositionChanged() && mDocShell) {
- // Add scroll position listener and reflow observer to detect position and
- // size changes
+ if (mDocShell) {
+ // Add scroll position listener and reflow observer to detect position
+ // and size changes
mDocShell->AddWeakScrollObserver(this);
mDocShell->AddWeakReflowObserver(this);
}
}
void
IMEContentObserver::NotifyIMEOfBlur()
{
// Prevent any notifications to be sent IME.
nsCOMPtr<nsIWidget> widget;
mWidget.swap(widget);
+ mIMENotificationRequests = nullptr;
// If we hasn't been set focus, we shouldn't send blur notification to IME.
if (!mIMEHasFocus) {
return;
}
// mWidget must have been non-nullptr if IME has focus.
MOZ_RELEASE_ASSERT(widget);
@@ -510,21 +510,21 @@ IMEContentObserver::UnregisterObservers(
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSelection));
if (selPrivate) {
selPrivate->RemoveSelectionListener(this);
}
mSelectionData.Clear();
mFocusedWidget = nullptr;
}
- if (mIMENotificationRequests.WantTextChange() && mRootContent) {
+ if (mRootContent) {
mRootContent->RemoveMutationObserver(this);
}
- if (mIMENotificationRequests.WantPositionChanged() && mDocShell) {
+ if (mDocShell) {
mDocShell->RemoveWeakScrollObserver(this);
mDocShell->RemoveWeakReflowObserver(this);
}
}
nsPresContext*
IMEContentObserver::GetPresContext() const
{
@@ -536,18 +536,17 @@ IMEContentObserver::Destroy()
{
// WARNING: When you change this method, you have to check Unlink() too.
NotifyIMEOfBlur();
UnregisterObservers();
Clear();
mWidget = nullptr;
- mIMENotificationRequests.mWantUpdates =
- IMENotificationRequests::NOTIFY_NOTHING;
+ mIMENotificationRequests = nullptr;
if (mESM) {
mESM->OnStopObservingContent(this);
mESM = nullptr;
}
}
void
@@ -685,31 +684,43 @@ IMEContentObserver::NotifySelectionChang
duringComposition);
}
return NS_OK;
}
void
IMEContentObserver::ScrollPositionChanged()
{
+ if (!NeedsPositionChangeNotification()) {
+ return;
+ }
+
MaybeNotifyIMEOfPositionChange();
}
NS_IMETHODIMP
IMEContentObserver::Reflow(DOMHighResTimeStamp aStart,
DOMHighResTimeStamp aEnd)
{
+ if (!NeedsPositionChangeNotification()) {
+ return NS_OK;
+ }
+
MaybeNotifyIMEOfPositionChange();
return NS_OK;
}
NS_IMETHODIMP
IMEContentObserver::ReflowInterruptible(DOMHighResTimeStamp aStart,
DOMHighResTimeStamp aEnd)
{
+ if (!NeedsPositionChangeNotification()) {
+ return NS_OK;
+ }
+
MaybeNotifyIMEOfPositionChange();
return NS_OK;
}
nsresult
IMEContentObserver::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent)
{
// If the instance has normal selection cache and the query event queries
@@ -781,17 +792,18 @@ IMEContentObserver::HandleQueryContentEv
}
return rv;
}
bool
IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext,
WidgetMouseEvent* aMouseEvent)
{
- if (!mIMENotificationRequests.WantMouseButtonEventOnChar()) {
+ if (!mIMENotificationRequests ||
+ !mIMENotificationRequests->WantMouseButtonEventOnChar()) {
return false;
}
if (!aMouseEvent->IsTrusted() ||
aMouseEvent->DefaultPrevented() ||
!aMouseEvent->mWidget) {
return false;
}
// Now, we need to notify only mouse down and mouse up event.
@@ -868,16 +880,20 @@ IMEContentObserver::CharacterDataWillCha
CharacterDataChangeInfo* aInfo)
{
NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
"character data changed for non-text node");
MOZ_ASSERT(mPreCharacterDataChangeLength < 0,
"CharacterDataChanged() should've reset "
"mPreCharacterDataChangeLength");
+ if (!NeedsTextChangeNotification()) {
+ return;
+ }
+
mEndOfAddedTextCache.Clear();
mStartOfRemovingTextRangeCache.Clear();
mPreCharacterDataChangeLength =
ContentEventHandler::GetNativeTextLength(aContent, aInfo->mChangeStart,
aInfo->mChangeEnd);
MOZ_ASSERT(mPreCharacterDataChangeLength >=
aInfo->mChangeEnd - aInfo->mChangeStart,
"The computed length must be same as or larger than XP length");
@@ -886,16 +902,20 @@ IMEContentObserver::CharacterDataWillCha
void
IMEContentObserver::CharacterDataChanged(nsIDocument* aDocument,
nsIContent* aContent,
CharacterDataChangeInfo* aInfo)
{
NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
"character data changed for non-text node");
+ if (!NeedsTextChangeNotification()) {
+ return;
+ }
+
mEndOfAddedTextCache.Clear();
mStartOfRemovingTextRangeCache.Clear();
int64_t removedLength = mPreCharacterDataChangeLength;
mPreCharacterDataChangeLength = -1;
MOZ_ASSERT(removedLength >= 0,
"mPreCharacterDataChangeLength should've been set by "
@@ -926,16 +946,20 @@ IMEContentObserver::CharacterDataChanged
MaybeNotifyIMEOfTextChange(data);
}
void
IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
int32_t aStartIndex,
int32_t aEndIndex)
{
+ if (!NeedsTextChangeNotification()) {
+ return;
+ }
+
mStartOfRemovingTextRangeCache.Clear();
uint32_t offset = 0;
nsresult rv = NS_OK;
if (!mEndOfAddedTextCache.Match(aContainer, aStartIndex)) {
mEndOfAddedTextCache.Clear();
rv = ContentEventHandler::GetFlatTextLengthInRange(
NodePosition(mRootContent, 0),
@@ -998,16 +1022,20 @@ IMEContentObserver::ContentInserted(nsID
void
IMEContentObserver::ContentRemoved(nsIDocument* aDocument,
nsIContent* aContainer,
nsIContent* aChild,
int32_t aIndexInContainer,
nsIContent* aPreviousSibling)
{
+ if (!NeedsTextChangeNotification()) {
+ return;
+ }
+
mEndOfAddedTextCache.Clear();
nsINode* containerNode = NODE_FROM(aContainer, aDocument);
uint32_t offset = 0;
nsresult rv = NS_OK;
if (!mStartOfRemovingTextRangeCache.Match(containerNode, aIndexInContainer)) {
// At removing a child node of aContainer, we need the line break caused
@@ -1056,28 +1084,36 @@ IMEContentObserver::ContentRemoved(nsIDo
void
IMEContentObserver::AttributeWillChange(nsIDocument* aDocument,
dom::Element* aElement,
int32_t aNameSpaceID,
nsIAtom* aAttribute,
int32_t aModType,
const nsAttrValue* aNewValue)
{
+ if (!NeedsTextChangeNotification()) {
+ return;
+ }
+
mPreAttrChangeLength =
ContentEventHandler::GetNativeTextLengthBefore(aElement, mRootContent);
}
void
IMEContentObserver::AttributeChanged(nsIDocument* aDocument,
dom::Element* aElement,
int32_t aNameSpaceID,
nsIAtom* aAttribute,
int32_t aModType,
const nsAttrValue* aOldValue)
{
+ if (!NeedsTextChangeNotification()) {
+ return;
+ }
+
mEndOfAddedTextCache.Clear();
mStartOfRemovingTextRangeCache.Clear();
uint32_t postAttrChangeLength =
ContentEventHandler::GetNativeTextLengthBefore(aElement, mRootContent);
if (postAttrChangeLength == mPreAttrChangeLength) {
return;
}
@@ -1210,16 +1246,25 @@ IMEContentObserver::MaybeNotifyIMEOfText
this, TextChangeDataToString(aTextChangeData).get()));
mTextChangeData += aTextChangeData;
PostTextChangeNotification();
FlushMergeableNotifications();
}
void
+IMEContentObserver::CancelNotifyingIMEOfTextChange()
+{
+ MOZ_LOG(sIMECOLog, LogLevel::Debug,
+ ("0x%p IMEContentObserver::CancelNotifyingIMEOfTextChange()", this));
+ mTextChangeData.Clear();
+ mNeedsToNotifyIMEOfTextChange = false;
+}
+
+void
IMEContentObserver::MaybeNotifyIMEOfSelectionChange(
bool aCausedByComposition,
bool aCausedBySelectionEvent,
bool aOccurredDuringComposition)
{
MOZ_LOG(sIMECOLog, LogLevel::Debug,
("0x%p IMEContentObserver::MaybeNotifyIMEOfSelectionChange("
"aCausedByComposition=%s, aCausedBySelectionEvent=%s, "
@@ -1250,16 +1295,24 @@ IMEContentObserver::MaybeNotifyIMEOfPosi
"NOTIY_IME_OF_POSITION_CHANGE", this));
return;
}
PostPositionChangeNotification();
FlushMergeableNotifications();
}
void
+IMEContentObserver::CancelNotifyingIMEOfPositionChange()
+{
+ MOZ_LOG(sIMECOLog, LogLevel::Debug,
+ ("0x%p IMEContentObserver::CancelNotifyIMEOfPositionChange()", this));
+ mNeedsToNotifyIMEOfPositionChange = false;
+}
+
+void
IMEContentObserver::MaybeNotifyCompositionEventHandled()
{
MOZ_LOG(sIMECOLog, LogLevel::Debug,
("0x%p IMEContentObserver::MaybeNotifyCompositionEventHandled()",
this));
PostCompositionEventHandledNotification();
FlushMergeableNotifications();
@@ -1391,16 +1444,25 @@ IMEContentObserver::FlushMergeableNotifi
if (mQueuedSender) {
// So, if this is already called, this should do nothing.
MOZ_LOG(sIMECOLog, LogLevel::Debug,
("0x%p IMEContentObserver::FlushMergeableNotifications(), "
"FAILED, due to already flushing pending notifications", this));
return;
}
+ // If text change notification and/or position change notification becomes
+ // unnecessary, let's cancel them.
+ if (mNeedsToNotifyIMEOfTextChange && !NeedsTextChangeNotification()) {
+ CancelNotifyingIMEOfTextChange();
+ }
+ if (mNeedsToNotifyIMEOfPositionChange && !NeedsPositionChangeNotification()) {
+ CancelNotifyingIMEOfPositionChange();
+ }
+
if (!NeedsToNotifyIMEOfSomething()) {
MOZ_LOG(sIMECOLog, LogLevel::Debug,
("0x%p IMEContentObserver::FlushMergeableNotifications(), "
"FAILED, due to no pending notifications", this));
return;
}
// NOTE: Reset each pending flag because sending notification may cause
@@ -1775,16 +1837,26 @@ IMEContentObserver::IMENotificationSende
MOZ_LOG(sIMECOLog, LogLevel::Debug,
("0x%p IMEContentObserver::IMENotificationSender::"
"SendTextChange(), retrying to send NOTIFY_IME_OF_TEXT_CHANGE...",
this));
mIMEContentObserver->PostTextChangeNotification();
return;
}
+ // If text change notification is unnecessary anymore, just cancel it.
+ if (!mIMEContentObserver->NeedsTextChangeNotification()) {
+ MOZ_LOG(sIMECOLog, LogLevel::Warning,
+ ("0x%p IMEContentObserver::IMENotificationSender::"
+ "SendTextChange(), canceling sending NOTIFY_IME_OF_TEXT_CHANGE",
+ this));
+ mIMEContentObserver->CancelNotifyingIMEOfTextChange();
+ return;
+ }
+
MOZ_LOG(sIMECOLog, LogLevel::Info,
("0x%p IMEContentObserver::IMENotificationSender::"
"SendTextChange(), sending NOTIFY_IME_OF_TEXT_CHANGE... "
"mIMEContentObserver={ mTextChangeData=%s }",
this, TextChangeDataToString(mIMEContentObserver->mTextChangeData).get()));
IMENotification notification(NOTIFY_IME_OF_TEXT_CHANGE);
notification.SetData(mIMEContentObserver->mTextChangeData);
@@ -1816,16 +1888,26 @@ IMEContentObserver::IMENotificationSende
MOZ_LOG(sIMECOLog, LogLevel::Debug,
("0x%p IMEContentObserver::IMENotificationSender::"
"SendPositionChange(), retrying to send "
"NOTIFY_IME_OF_POSITION_CHANGE...", this));
mIMEContentObserver->PostPositionChangeNotification();
return;
}
+ // If position change notification is unnecessary anymore, just cancel it.
+ if (!mIMEContentObserver->NeedsPositionChangeNotification()) {
+ MOZ_LOG(sIMECOLog, LogLevel::Warning,
+ ("0x%p IMEContentObserver::IMENotificationSender::"
+ "SendPositionChange(), canceling sending NOTIFY_IME_OF_POSITION_CHANGE",
+ this));
+ mIMEContentObserver->CancelNotifyingIMEOfPositionChange();
+ return;
+ }
+
MOZ_LOG(sIMECOLog, LogLevel::Info,
("0x%p IMEContentObserver::IMENotificationSender::"
"SendPositionChange(), sending NOTIFY_IME_OF_POSITION_CHANGE...", this));
MOZ_RELEASE_ASSERT(mIMEContentObserver->mSendingNotification ==
NOTIFY_IME_OF_NOTHING);
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_POSITION_CHANGE;
IMEStateManager::NotifyIME(IMENotification(NOTIFY_IME_OF_POSITION_CHANGE),