2015-05-03 22:32:37 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2014-03-08 05:20:07 +04:00
|
|
|
/* 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/. */
|
|
|
|
|
2015-09-08 06:54:14 +03:00
|
|
|
#include "mozilla/Logging.h"
|
|
|
|
|
2014-03-11 09:08:02 +04:00
|
|
|
#include "ContentEventHandler.h"
|
2014-03-08 05:20:07 +04:00
|
|
|
#include "IMEContentObserver.h"
|
2014-03-17 10:56:54 +04:00
|
|
|
#include "mozilla/AsyncEventDispatcher.h"
|
2014-08-13 15:25:14 +04:00
|
|
|
#include "mozilla/AutoRestore.h"
|
2014-04-24 04:36:15 +04:00
|
|
|
#include "mozilla/EventStateManager.h"
|
2014-03-08 05:20:07 +04:00
|
|
|
#include "mozilla/IMEStateManager.h"
|
2014-08-29 14:08:43 +04:00
|
|
|
#include "mozilla/MouseEvents.h"
|
2019-04-03 15:40:26 +03:00
|
|
|
#include "mozilla/PresShell.h"
|
2014-04-03 08:18:37 +04:00
|
|
|
#include "mozilla/TextComposition.h"
|
2014-08-29 14:08:43 +04:00
|
|
|
#include "mozilla/TextEvents.h"
|
2014-03-08 05:20:07 +04:00
|
|
|
#include "mozilla/dom/Element.h"
|
2017-07-21 05:55:46 +03:00
|
|
|
#include "mozilla/dom/Selection.h"
|
2014-03-08 05:20:07 +04:00
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsGkAtoms.h"
|
2017-10-03 01:05:19 +03:00
|
|
|
#include "nsAtom.h"
|
2014-03-08 05:20:07 +04:00
|
|
|
#include "nsIContent.h"
|
2019-01-02 16:05:23 +03:00
|
|
|
#include "mozilla/dom/Document.h"
|
2014-03-08 05:20:07 +04:00
|
|
|
#include "nsIFrame.h"
|
|
|
|
#include "nsINode.h"
|
|
|
|
#include "nsISelectionController.h"
|
|
|
|
#include "nsISupports.h"
|
2018-10-31 23:39:03 +03:00
|
|
|
#include "nsIWeakReferenceUtils.h"
|
2014-03-08 05:20:07 +04:00
|
|
|
#include "nsIWidget.h"
|
|
|
|
#include "nsPresContext.h"
|
2018-05-17 19:01:38 +03:00
|
|
|
#include "nsRange.h"
|
2017-06-29 14:46:11 +03:00
|
|
|
#include "nsRefreshDriver.h"
|
2015-05-15 04:18:08 +03:00
|
|
|
#include "WritingModes.h"
|
2014-03-08 05:20:07 +04:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
2018-01-24 08:10:18 +03:00
|
|
|
typedef ContentEventHandler::NodePosition NodePosition;
|
|
|
|
typedef ContentEventHandler::NodePositionBefore NodePositionBefore;
|
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
using namespace widget;
|
|
|
|
|
2015-11-23 22:09:25 +03:00
|
|
|
LazyLogModule sIMECOLog("IMEContentObserver");
|
2015-09-08 06:54:14 +03:00
|
|
|
|
|
|
|
static const char* ToChar(bool aBool) { return aBool ? "true" : "false"; }
|
|
|
|
|
2017-09-06 20:47:09 +03:00
|
|
|
// This method determines the node to use for the point before the current node.
|
|
|
|
// If you have the following aContent and aContainer, and want to represent the
|
|
|
|
// following point for `NodePosition` or `RangeBoundary`:
|
|
|
|
//
|
|
|
|
// <parent> {node} {node} | {node} </parent>
|
|
|
|
// ^ ^ ^
|
|
|
|
// aContainer point aContent
|
|
|
|
//
|
|
|
|
// This function will shift `aContent` to the left into the format which
|
|
|
|
// `NodePosition` and `RangeBoundary` use:
|
|
|
|
//
|
|
|
|
// <parent> {node} {node} | {node} </parent>
|
|
|
|
// ^ ^ ^
|
|
|
|
// aContainer result point
|
|
|
|
static nsIContent* PointBefore(nsINode* aContainer, nsIContent* aContent) {
|
|
|
|
if (aContent) {
|
|
|
|
return aContent->GetPreviousSibling();
|
|
|
|
}
|
|
|
|
return aContainer->GetLastChild();
|
|
|
|
}
|
|
|
|
|
2015-09-08 06:54:14 +03:00
|
|
|
class WritingModeToString final : public nsAutoCString {
|
|
|
|
public:
|
|
|
|
explicit WritingModeToString(const WritingMode& aWritingMode) {
|
|
|
|
if (!aWritingMode.IsVertical()) {
|
|
|
|
AssignLiteral("Horizontal");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (aWritingMode.IsVerticalLR()) {
|
|
|
|
AssignLiteral("Vertical (LR)");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
AssignLiteral("Vertical (RL)");
|
|
|
|
}
|
|
|
|
virtual ~WritingModeToString() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class SelectionChangeDataToString final : public nsAutoCString {
|
|
|
|
public:
|
|
|
|
explicit SelectionChangeDataToString(
|
|
|
|
const IMENotification::SelectionChangeDataBase& aData) {
|
|
|
|
if (!aData.IsValid()) {
|
|
|
|
AppendLiteral("{ IsValid()=false }");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
AppendPrintf("{ mOffset=%u, ", aData.mOffset);
|
|
|
|
if (aData.mString->Length() > 20) {
|
|
|
|
AppendPrintf("mString.Length()=%u, ", aData.mString->Length());
|
|
|
|
} else {
|
|
|
|
AppendPrintf("mString=\"%s\" (Length()=%u), ",
|
|
|
|
NS_ConvertUTF16toUTF8(*aData.mString).get(),
|
|
|
|
aData.mString->Length());
|
|
|
|
}
|
|
|
|
AppendPrintf(
|
|
|
|
"GetWritingMode()=%s, mReversed=%s, mCausedByComposition=%s, "
|
|
|
|
"mCausedBySelectionEvent=%s }",
|
|
|
|
WritingModeToString(aData.GetWritingMode()).get(),
|
|
|
|
ToChar(aData.mReversed), ToChar(aData.mCausedByComposition),
|
|
|
|
ToChar(aData.mCausedBySelectionEvent));
|
|
|
|
}
|
|
|
|
virtual ~SelectionChangeDataToString() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
class TextChangeDataToString final : public nsAutoCString {
|
|
|
|
public:
|
|
|
|
explicit TextChangeDataToString(
|
|
|
|
const IMENotification::TextChangeDataBase& aData) {
|
|
|
|
if (!aData.IsValid()) {
|
|
|
|
AppendLiteral("{ IsValid()=false }");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
AppendPrintf(
|
|
|
|
"{ mStartOffset=%u, mRemovedEndOffset=%u, mAddedEndOffset=%u, "
|
2016-01-28 07:28:53 +03:00
|
|
|
"mCausedOnlyByComposition=%s, "
|
2016-01-28 07:28:54 +03:00
|
|
|
"mIncludingChangesDuringComposition=%s, "
|
|
|
|
"mIncludingChangesWithoutComposition=%s }",
|
2016-01-28 07:28:53 +03:00
|
|
|
aData.mStartOffset, aData.mRemovedEndOffset, aData.mAddedEndOffset,
|
|
|
|
ToChar(aData.mCausedOnlyByComposition),
|
2016-01-28 07:28:54 +03:00
|
|
|
ToChar(aData.mIncludingChangesDuringComposition),
|
|
|
|
ToChar(aData.mIncludingChangesWithoutComposition));
|
2015-09-08 06:54:14 +03:00
|
|
|
}
|
|
|
|
virtual ~TextChangeDataToString() {}
|
|
|
|
};
|
|
|
|
|
2015-06-17 04:03:57 +03:00
|
|
|
/******************************************************************************
|
|
|
|
* mozilla::IMEContentObserver
|
|
|
|
******************************************************************************/
|
|
|
|
|
2014-07-31 08:37:59 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(IMEContentObserver)
|
|
|
|
|
2017-09-06 20:47:09 +03:00
|
|
|
// Note that we don't need to add mFirstAddedContainer nor
|
|
|
|
// mLastAddedContainer to cycle collection because they are non-null only
|
2017-06-08 05:24:58 +03:00
|
|
|
// during short time and shouldn't be touched while they are non-null.
|
|
|
|
|
2014-07-31 08:37:59 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IMEContentObserver)
|
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
|
|
|
|
2015-05-26 10:45:26 +03:00
|
|
|
tmp->NotifyIMEOfBlur();
|
2015-05-26 10:45:26 +03:00
|
|
|
tmp->UnregisterObservers();
|
2014-07-31 08:37:59 +04:00
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSelection)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRootContent)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditableNode)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)
|
2017-06-20 13:23:44 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditorBase)
|
2017-06-08 05:21:28 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentObserver)
|
2014-07-31 08:38:00 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEndOfAddedTextCache.mContainerNode)
|
2014-07-31 08:38:00 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mStartOfRemovingTextRangeCache.mContainerNode)
|
2014-07-31 08:37:59 +04:00
|
|
|
|
2017-04-13 08:32:12 +03:00
|
|
|
tmp->mIMENotificationRequests = nullptr;
|
2014-07-31 08:37:59 +04:00
|
|
|
tmp->mESM = nullptr;
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IMEContentObserver)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWidget)
|
2015-09-08 06:54:14 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedWidget)
|
2014-07-31 08:37:59 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSelection)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRootContent)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEditableNode)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell)
|
2017-06-20 13:23:44 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEditorBase)
|
2017-06-08 05:21:28 +03:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentObserver)
|
2014-07-31 08:38:00 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEndOfAddedTextCache.mContainerNode)
|
2014-07-31 08:38:00 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
|
|
|
|
mStartOfRemovingTextRangeCache.mContainerNode)
|
2014-07-31 08:37:59 +04:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
2014-04-24 04:36:14 +04:00
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IMEContentObserver)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIReflowObserver)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIScrollObserver)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
2018-01-26 11:25:45 +03:00
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIReflowObserver)
|
2014-04-24 04:36:14 +04:00
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(IMEContentObserver)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(IMEContentObserver)
|
2014-03-08 05:20:07 +04:00
|
|
|
|
|
|
|
IMEContentObserver::IMEContentObserver()
|
2017-09-06 20:47:09 +03:00
|
|
|
: mESM(nullptr),
|
2017-04-13 08:32:12 +03:00
|
|
|
mIMENotificationRequests(nullptr),
|
2015-06-04 20:06:10 +03:00
|
|
|
mSuppressNotifications(0),
|
2014-07-31 08:38:01 +04:00
|
|
|
mPreCharacterDataChangeLength(-1),
|
2015-09-16 11:48:24 +03:00
|
|
|
mSendingNotification(NOTIFY_IME_OF_NOTHING),
|
2015-05-26 10:45:26 +03:00
|
|
|
mIsObserving(false),
|
2015-06-17 04:03:57 +03:00
|
|
|
mIMEHasFocus(false),
|
2015-09-16 11:48:24 +03:00
|
|
|
mNeedsToNotifyIMEOfFocusSet(false),
|
|
|
|
mNeedsToNotifyIMEOfTextChange(false),
|
|
|
|
mNeedsToNotifyIMEOfSelectionChange(false),
|
|
|
|
mNeedsToNotifyIMEOfPositionChange(false),
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
mNeedsToNotifyIMEOfCompositionEventHandled(false),
|
2015-09-16 11:48:24 +03:00
|
|
|
mIsHandlingQueryContentEvent(false) {
|
2014-07-31 08:37:59 +04:00
|
|
|
#ifdef DEBUG
|
2015-07-11 04:53:56 +03:00
|
|
|
mTextChangeData.Test();
|
2014-07-31 08:37:59 +04:00
|
|
|
#endif
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::Init(nsIWidget* aWidget, nsPresContext* aPresContext,
|
2017-06-20 13:23:44 +03:00
|
|
|
nsIContent* aContent, EditorBase* aEditorBase) {
|
2015-05-26 10:45:26 +03:00
|
|
|
State state = GetState();
|
|
|
|
if (NS_WARN_IF(state == eState_Observing)) {
|
|
|
|
return; // Nothing to do.
|
|
|
|
}
|
|
|
|
|
|
|
|
bool firstInitialization = state != eState_StoppedObserving;
|
2015-05-26 10:45:26 +03:00
|
|
|
if (!firstInitialization) {
|
|
|
|
// If this is now trying to initialize with new contents, all observers
|
|
|
|
// should be registered again for simpler implementation.
|
|
|
|
UnregisterObservers();
|
2015-10-10 04:21:01 +03:00
|
|
|
Clear();
|
2015-05-26 10:45:26 +03:00
|
|
|
}
|
|
|
|
|
2014-04-24 04:36:15 +04:00
|
|
|
mESM = aPresContext->EventStateManager();
|
|
|
|
mESM->OnStartToObserveContent(this);
|
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
mWidget = aWidget;
|
2017-04-13 08:32:12 +03:00
|
|
|
mIMENotificationRequests = &mWidget->IMENotificationRequestsRef();
|
2015-05-26 10:45:26 +03:00
|
|
|
|
2015-10-10 04:21:01 +03:00
|
|
|
if (aWidget->GetInputContext().mIMEState.mEnabled == IMEState::PLUGIN) {
|
|
|
|
if (!InitWithPlugin(aPresContext, aContent)) {
|
|
|
|
Clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
2017-06-20 13:23:44 +03:00
|
|
|
if (!InitWithEditor(aPresContext, aContent, aEditorBase)) {
|
2015-10-10 04:21:01 +03:00
|
|
|
Clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (firstInitialization) {
|
2015-11-10 05:49:04 +03:00
|
|
|
// Now, try to send NOTIFY_IME_OF_FOCUS to IME via the widget.
|
2015-10-10 04:21:01 +03:00
|
|
|
MaybeNotifyIMEOfFocusSet();
|
2015-11-10 05:49:04 +03:00
|
|
|
// When this is called first time, IME has not received NOTIFY_IME_OF_FOCUS
|
|
|
|
// yet since NOTIFY_IME_OF_FOCUS will be sent to widget asynchronously.
|
|
|
|
// So, we need to do nothing here. After NOTIFY_IME_OF_FOCUS has been
|
|
|
|
// sent, OnIMEReceivedFocus() will be called and content, selection and/or
|
|
|
|
// position changes will be observed
|
|
|
|
return;
|
|
|
|
}
|
2015-10-10 04:21:01 +03:00
|
|
|
|
2015-11-10 05:49:04 +03:00
|
|
|
// When this is called after editor reframing (i.e., the root editable node
|
|
|
|
// is also recreated), IME has usually received NOTIFY_IME_OF_FOCUS. In this
|
|
|
|
// case, we need to restart to observe content, selection and/or position
|
|
|
|
// changes in new root editable node.
|
|
|
|
ObserveEditableNode();
|
2015-10-10 04:21:01 +03:00
|
|
|
|
2015-11-10 05:49:04 +03:00
|
|
|
if (!NeedsToNotifyIMEOfSomething()) {
|
|
|
|
return;
|
2015-10-10 04:21:01 +03:00
|
|
|
}
|
|
|
|
|
2015-11-10 05:49:04 +03:00
|
|
|
// Some change events may wait to notify IME because this was being
|
|
|
|
// initialized. It is the time to flush them.
|
|
|
|
FlushMergeableNotifications();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::OnIMEReceivedFocus() {
|
|
|
|
// While Init() notifies IME of focus, pending layout may be flushed
|
|
|
|
// because the notification may cause querying content. Then, recursive
|
|
|
|
// call of Init() with the latest content may occur. In such case, we
|
|
|
|
// shouldn't keep first initialization which notified IME of focus.
|
|
|
|
if (GetState() != eState_Initializing) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTIFY_IME_OF_FOCUS might cause recreating IMEContentObserver
|
|
|
|
// instance via IMEStateManager::UpdateIMEState(). So, this
|
|
|
|
// instance might already have been destroyed, check it.
|
|
|
|
if (!mRootContent) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start to observe which is needed by IME when IME actually has focus.
|
2015-10-10 04:21:01 +03:00
|
|
|
ObserveEditableNode();
|
|
|
|
|
2015-11-10 05:49:04 +03:00
|
|
|
if (!NeedsToNotifyIMEOfSomething()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-10 04:21:01 +03:00
|
|
|
// Some change events may wait to notify IME because this was being
|
|
|
|
// initialized. It is the time to flush them.
|
|
|
|
FlushMergeableNotifications();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IMEContentObserver::InitWithEditor(nsPresContext* aPresContext,
|
|
|
|
nsIContent* aContent,
|
2017-06-20 13:23:44 +03:00
|
|
|
EditorBase* aEditorBase) {
|
|
|
|
MOZ_ASSERT(aEditorBase);
|
2015-10-10 04:21:01 +03:00
|
|
|
|
2015-05-26 10:45:26 +03:00
|
|
|
mEditableNode = IMEStateManager::GetRootEditableNode(aPresContext, aContent);
|
2015-10-10 04:21:01 +03:00
|
|
|
if (NS_WARN_IF(!mEditableNode)) {
|
|
|
|
return false;
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
2017-06-20 13:23:44 +03:00
|
|
|
mEditorBase = aEditorBase;
|
|
|
|
if (NS_WARN_IF(!mEditorBase)) {
|
2015-10-10 04:21:01 +03:00
|
|
|
return false;
|
|
|
|
}
|
2014-07-31 08:37:59 +04:00
|
|
|
|
2019-04-03 15:40:26 +03:00
|
|
|
PresShell* presShell = aPresContext->GetPresShell();
|
2014-03-08 05:20:07 +04:00
|
|
|
|
|
|
|
// get selection and root content
|
|
|
|
nsCOMPtr<nsISelectionController> selCon;
|
2017-10-25 18:19:11 +03:00
|
|
|
if (mEditableNode->IsContent()) {
|
|
|
|
nsIFrame* frame = mEditableNode->AsContent()->GetPrimaryFrame();
|
2015-10-10 04:21:01 +03:00
|
|
|
if (NS_WARN_IF(!frame)) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
|
|
|
frame->GetSelectionController(aPresContext, getter_AddRefs(selCon));
|
|
|
|
} else {
|
|
|
|
// mEditableNode is a document
|
2019-04-03 15:40:26 +03:00
|
|
|
selCon = presShell;
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
2015-10-10 04:21:01 +03:00
|
|
|
|
|
|
|
if (NS_WARN_IF(!selCon)) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
2018-05-08 20:52:36 +03:00
|
|
|
mSelection = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL);
|
2015-10-10 04:21:01 +03:00
|
|
|
if (NS_WARN_IF(!mSelection)) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
2017-10-12 12:11:09 +03:00
|
|
|
if (nsRange* selRange = mSelection->GetRangeAt(0)) {
|
2017-07-21 05:55:46 +03:00
|
|
|
if (NS_WARN_IF(!selRange->GetStartContainer())) {
|
2015-10-10 04:21:01 +03:00
|
|
|
return false;
|
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
2017-07-11 14:53:04 +03:00
|
|
|
mRootContent =
|
|
|
|
selRange->GetStartContainer()->GetSelectionRootContent(presShell);
|
2014-03-08 05:20:07 +04:00
|
|
|
} else {
|
|
|
|
mRootContent = mEditableNode->GetSelectionRootContent(presShell);
|
|
|
|
}
|
2018-04-15 12:43:15 +03:00
|
|
|
if (!mRootContent && mEditableNode->IsDocument()) {
|
2014-03-08 05:20:07 +04:00
|
|
|
// The document node is editable, but there are no contents, this document
|
|
|
|
// is not editable.
|
2015-10-10 04:21:01 +03:00
|
|
|
return false;
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
2015-10-10 04:21:01 +03:00
|
|
|
if (NS_WARN_IF(!mRootContent)) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-05-24 07:40:21 +03:00
|
|
|
|
2015-10-10 04:21:01 +03:00
|
|
|
mDocShell = aPresContext->GetDocShell();
|
|
|
|
if (NS_WARN_IF(!mDocShell)) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-05-26 10:45:26 +03:00
|
|
|
|
2017-06-08 05:21:28 +03:00
|
|
|
mDocumentObserver = new DocumentObserver(*this);
|
|
|
|
|
2016-06-28 09:23:12 +03:00
|
|
|
MOZ_ASSERT(!WasInitializedWithPlugin());
|
|
|
|
|
2015-10-10 04:21:01 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IMEContentObserver::InitWithPlugin(nsPresContext* aPresContext,
|
|
|
|
nsIContent* aContent) {
|
|
|
|
if (NS_WARN_IF(!aContent) ||
|
|
|
|
NS_WARN_IF(aContent->GetDesiredIMEState().mEnabled != IMEState::PLUGIN)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nsIFrame* frame = aContent->GetPrimaryFrame();
|
|
|
|
if (NS_WARN_IF(!frame)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsISelectionController> selCon;
|
|
|
|
frame->GetSelectionController(aPresContext, getter_AddRefs(selCon));
|
|
|
|
if (NS_WARN_IF(!selCon)) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-05-08 20:52:36 +03:00
|
|
|
mSelection = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL);
|
2015-10-10 04:21:01 +03:00
|
|
|
if (NS_WARN_IF(!mSelection)) {
|
|
|
|
return false;
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
2017-06-20 13:23:44 +03:00
|
|
|
mEditorBase = nullptr;
|
2015-10-10 04:21:01 +03:00
|
|
|
mEditableNode = aContent;
|
|
|
|
mRootContent = aContent;
|
2017-06-08 05:21:28 +03:00
|
|
|
// Should be safe to clear mDocumentObserver here even though it *might*
|
|
|
|
// grab this instance because this is called by Init() and the callers of
|
|
|
|
// it and MaybeReinitialize() grabs this instance with local RefPtr.
|
|
|
|
// So, this won't cause refcount of this instance become 0.
|
|
|
|
mDocumentObserver = nullptr;
|
2015-10-10 04:21:01 +03:00
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
mDocShell = aPresContext->GetDocShell();
|
2015-10-10 04:21:01 +03:00
|
|
|
if (NS_WARN_IF(!mDocShell)) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
2016-06-28 09:23:12 +03:00
|
|
|
MOZ_ASSERT(WasInitializedWithPlugin());
|
|
|
|
|
2015-10-10 04:21:01 +03:00
|
|
|
return true;
|
|
|
|
}
|
2015-06-17 04:03:57 +03:00
|
|
|
|
2016-06-28 09:23:12 +03:00
|
|
|
bool IMEContentObserver::WasInitializedWithPlugin() const {
|
2017-06-20 13:23:44 +03:00
|
|
|
return mDocShell && !mEditorBase;
|
2016-06-28 09:23:12 +03:00
|
|
|
}
|
|
|
|
|
2015-10-10 04:21:01 +03:00
|
|
|
void IMEContentObserver::Clear() {
|
2017-06-20 13:23:44 +03:00
|
|
|
mEditorBase = nullptr;
|
2015-10-10 04:21:01 +03:00
|
|
|
mSelection = nullptr;
|
|
|
|
mEditableNode = nullptr;
|
|
|
|
mRootContent = nullptr;
|
|
|
|
mDocShell = nullptr;
|
2017-06-08 05:21:28 +03:00
|
|
|
// Should be safe to clear mDocumentObserver here even though it grabs
|
|
|
|
// this instance in most cases because this is called by Init() or Destroy().
|
|
|
|
// The callers of Init() grab this instance with local RefPtr.
|
|
|
|
// The caller of Destroy() also grabs this instance with local RefPtr.
|
|
|
|
// So, this won't cause refcount of this instance become 0.
|
|
|
|
mDocumentObserver = nullptr;
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::ObserveEditableNode() {
|
2015-05-26 10:45:26 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mSelection);
|
|
|
|
MOZ_RELEASE_ASSERT(mRootContent);
|
|
|
|
MOZ_RELEASE_ASSERT(GetState() != eState_Observing);
|
|
|
|
|
2015-11-10 05:49:04 +03:00
|
|
|
// 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),
|
2017-04-13 08:32:12 +03:00
|
|
|
// the notification requests of mWidget may be different from after the widget
|
2015-11-10 05:49:04 +03:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2015-05-26 10:45:26 +03:00
|
|
|
mIsObserving = true;
|
2017-06-20 13:23:44 +03:00
|
|
|
if (mEditorBase) {
|
2018-01-24 08:10:18 +03:00
|
|
|
mEditorBase->SetIMEContentObserver(this);
|
2015-10-10 04:21:01 +03:00
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
2016-06-28 09:23:12 +03:00
|
|
|
if (!WasInitializedWithPlugin()) {
|
2017-04-13 08:32:12 +03:00
|
|
|
// Add text change observer only when this starts to observe
|
|
|
|
// non-plugin content since we cannot detect text changes in
|
|
|
|
// plugins.
|
2014-03-08 05:20:07 +04:00
|
|
|
mRootContent->AddMutationObserver(this);
|
2017-06-08 05:21:28 +03:00
|
|
|
// If it's in a document (should be so), we can use document observer to
|
|
|
|
// reduce redundant computation of text change offsets.
|
2019-01-02 16:05:23 +03:00
|
|
|
Document* doc = mRootContent->GetComposedDoc();
|
2017-06-08 05:21:28 +03:00
|
|
|
if (doc) {
|
|
|
|
RefPtr<DocumentObserver> documentObserver = mDocumentObserver;
|
|
|
|
documentObserver->Observe(doc);
|
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
2017-04-13 08:32:12 +03:00
|
|
|
if (mDocShell) {
|
|
|
|
// Add scroll position listener and reflow observer to detect position
|
|
|
|
// and size changes
|
2014-03-08 05:20:07 +04:00
|
|
|
mDocShell->AddWeakScrollObserver(this);
|
|
|
|
mDocShell->AddWeakReflowObserver(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-26 10:45:26 +03:00
|
|
|
void IMEContentObserver::NotifyIMEOfBlur() {
|
2015-06-17 04:03:57 +03:00
|
|
|
// Prevent any notifications to be sent IME.
|
|
|
|
nsCOMPtr<nsIWidget> widget;
|
|
|
|
mWidget.swap(widget);
|
2017-04-13 08:32:12 +03:00
|
|
|
mIMENotificationRequests = nullptr;
|
2015-06-17 04:03:57 +03:00
|
|
|
|
|
|
|
// If we hasn't been set focus, we shouldn't send blur notification to IME.
|
|
|
|
if (!mIMEHasFocus) {
|
2015-05-26 10:45:26 +03:00
|
|
|
return;
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
2014-07-31 08:37:59 +04:00
|
|
|
|
2015-06-17 04:03:57 +03:00
|
|
|
// mWidget must have been non-nullptr if IME has focus.
|
|
|
|
MOZ_RELEASE_ASSERT(widget);
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IMEContentObserver> kungFuDeathGrip(this);
|
2015-09-08 06:54:14 +03:00
|
|
|
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Info,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::NotifyIMEOfBlur(), "
|
2015-09-08 06:54:14 +03:00
|
|
|
"sending NOTIFY_IME_OF_BLUR",
|
|
|
|
this));
|
|
|
|
|
2015-06-17 04:03:57 +03:00
|
|
|
// For now, we need to send blur notification in any condition because
|
|
|
|
// we don't have any simple ways to send blur notification asynchronously.
|
|
|
|
// After this call, Destroy() or Unlink() will stop observing the content
|
|
|
|
// and forget everything. Therefore, if it's not safe to send notification
|
|
|
|
// when script blocker is unlocked, we cannot send blur notification after
|
|
|
|
// that and before next focus notification.
|
|
|
|
// Anyway, as far as we know, IME doesn't try to query content when it loses
|
|
|
|
// focus. So, this may not cause any problem.
|
|
|
|
mIMEHasFocus = false;
|
2015-06-27 03:23:31 +03:00
|
|
|
IMEStateManager::NotifyIME(IMENotification(NOTIFY_IME_OF_BLUR), widget);
|
2015-09-08 06:54:14 +03:00
|
|
|
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::NotifyIMEOfBlur(), "
|
2015-09-08 06:54:14 +03:00
|
|
|
"sent NOTIFY_IME_OF_BLUR",
|
|
|
|
this));
|
2015-05-26 10:45:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::UnregisterObservers() {
|
2015-05-26 10:45:26 +03:00
|
|
|
if (!mIsObserving) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mIsObserving = false;
|
|
|
|
|
2017-06-20 13:23:44 +03:00
|
|
|
if (mEditorBase) {
|
2018-01-24 08:10:18 +03:00
|
|
|
mEditorBase->SetIMEContentObserver(nullptr);
|
2015-05-24 07:40:21 +03:00
|
|
|
}
|
|
|
|
|
2016-06-28 09:23:12 +03:00
|
|
|
if (mSelection) {
|
2015-09-08 06:54:14 +03:00
|
|
|
mSelectionData.Clear();
|
|
|
|
mFocusedWidget = nullptr;
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
2014-07-31 08:37:59 +04:00
|
|
|
|
2017-04-13 08:32:12 +03:00
|
|
|
if (mRootContent) {
|
2014-03-08 05:20:07 +04:00
|
|
|
mRootContent->RemoveMutationObserver(this);
|
|
|
|
}
|
2014-07-31 08:37:59 +04:00
|
|
|
|
2017-06-08 05:21:28 +03:00
|
|
|
if (mDocumentObserver) {
|
|
|
|
RefPtr<DocumentObserver> documentObserver = mDocumentObserver;
|
|
|
|
documentObserver->StopObserving();
|
|
|
|
}
|
|
|
|
|
2017-04-13 08:32:12 +03:00
|
|
|
if (mDocShell) {
|
2014-03-08 05:20:07 +04:00
|
|
|
mDocShell->RemoveWeakScrollObserver(this);
|
|
|
|
mDocShell->RemoveWeakReflowObserver(this);
|
|
|
|
}
|
2014-07-31 08:37:59 +04:00
|
|
|
}
|
|
|
|
|
2015-05-15 04:18:08 +03:00
|
|
|
nsPresContext* IMEContentObserver::GetPresContext() const {
|
|
|
|
return mESM ? mESM->GetPresContext() : nullptr;
|
|
|
|
}
|
|
|
|
|
2014-07-31 08:37:59 +04:00
|
|
|
void IMEContentObserver::Destroy() {
|
|
|
|
// WARNING: When you change this method, you have to check Unlink() too.
|
|
|
|
|
2015-05-26 10:45:26 +03:00
|
|
|
NotifyIMEOfBlur();
|
2015-05-26 10:45:26 +03:00
|
|
|
UnregisterObservers();
|
2015-10-10 04:21:01 +03:00
|
|
|
Clear();
|
2014-07-31 08:37:59 +04:00
|
|
|
|
|
|
|
mWidget = nullptr;
|
2017-04-13 08:32:12 +03:00
|
|
|
mIMENotificationRequests = nullptr;
|
2014-04-24 04:36:15 +04:00
|
|
|
|
|
|
|
if (mESM) {
|
|
|
|
mESM->OnStopObservingContent(this);
|
|
|
|
mESM = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-28 14:09:55 +03:00
|
|
|
bool IMEContentObserver::Destroyed() const { return !mWidget; }
|
|
|
|
|
2014-04-24 04:36:15 +04:00
|
|
|
void IMEContentObserver::DisconnectFromEventStateManager() { mESM = nullptr; }
|
2014-03-08 05:20:07 +04:00
|
|
|
|
2015-05-26 10:45:26 +03:00
|
|
|
bool IMEContentObserver::MaybeReinitialize(nsIWidget* aWidget,
|
|
|
|
nsPresContext* aPresContext,
|
|
|
|
nsIContent* aContent,
|
2017-06-20 13:23:44 +03:00
|
|
|
EditorBase* aEditorBase) {
|
2015-05-26 10:45:26 +03:00
|
|
|
if (!IsObservingContent(aPresContext, aContent)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (GetState() == eState_StoppedObserving) {
|
2017-06-20 13:23:44 +03:00
|
|
|
Init(aWidget, aPresContext, aContent, aEditorBase);
|
2015-05-26 10:45:26 +03:00
|
|
|
}
|
|
|
|
return IsManaging(aPresContext, aContent);
|
|
|
|
}
|
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
bool IMEContentObserver::IsManaging(nsPresContext* aPresContext,
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
nsIContent* aContent) const {
|
2015-05-26 10:45:26 +03:00
|
|
|
return GetState() == eState_Observing &&
|
|
|
|
IsObservingContent(aPresContext, aContent);
|
|
|
|
}
|
|
|
|
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
bool IMEContentObserver::IsManaging(const TextComposition* aComposition) const {
|
|
|
|
if (GetState() != eState_Observing) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
nsPresContext* presContext = aComposition->GetPresContext();
|
|
|
|
if (NS_WARN_IF(!presContext)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (presContext != GetPresContext()) {
|
|
|
|
return false; // observing different document
|
|
|
|
}
|
|
|
|
nsINode* targetNode = aComposition->GetEventTargetNode();
|
|
|
|
nsIContent* targetContent =
|
|
|
|
targetNode && targetNode->IsContent() ? targetNode->AsContent() : nullptr;
|
|
|
|
return IsObservingContent(presContext, targetContent);
|
|
|
|
}
|
|
|
|
|
2015-05-26 10:45:26 +03:00
|
|
|
IMEContentObserver::State IMEContentObserver::GetState() const {
|
2014-03-08 05:20:07 +04:00
|
|
|
if (!mSelection || !mRootContent || !mEditableNode) {
|
2015-05-26 10:45:26 +03:00
|
|
|
return eState_NotObserving; // failed to initialize or finalized.
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
2014-08-06 03:23:02 +04:00
|
|
|
if (!mRootContent->IsInComposedDoc()) {
|
2015-05-26 10:45:26 +03:00
|
|
|
// the focused editor has already been reframed.
|
|
|
|
return eState_StoppedObserving;
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
2015-05-26 10:45:26 +03:00
|
|
|
return mIsObserving ? eState_Observing : eState_Initializing;
|
2015-05-26 10:45:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool IMEContentObserver::IsObservingContent(nsPresContext* aPresContext,
|
|
|
|
nsIContent* aContent) const {
|
2015-10-10 04:21:01 +03:00
|
|
|
return IsInitializedWithPlugin()
|
|
|
|
? mRootContent == aContent && mRootContent != nullptr
|
|
|
|
: mEditableNode ==
|
|
|
|
IMEStateManager::GetRootEditableNode(aPresContext, aContent);
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool IMEContentObserver::IsEditorHandlingEventForComposition() const {
|
|
|
|
if (!mWidget) {
|
|
|
|
return false;
|
|
|
|
}
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<TextComposition> composition =
|
2014-03-08 05:20:07 +04:00
|
|
|
IMEStateManager::GetTextCompositionFor(mWidget);
|
2014-03-08 05:20:07 +04:00
|
|
|
if (!composition) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return composition->IsEditorHandlingEvent();
|
|
|
|
}
|
|
|
|
|
2015-10-27 01:21:37 +03:00
|
|
|
bool IMEContentObserver::IsEditorComposing() const {
|
|
|
|
// Note that don't use TextComposition here. The important thing is,
|
|
|
|
// whether the editor already started to handle composition because
|
|
|
|
// web contents can change selection, text content and/or something from
|
2016-07-08 07:10:13 +03:00
|
|
|
// compositionstart event listener which is run before EditorBase handles it.
|
2017-06-20 13:23:44 +03:00
|
|
|
if (NS_WARN_IF(!mEditorBase)) {
|
2015-10-27 01:21:37 +03:00
|
|
|
return false;
|
|
|
|
}
|
2017-06-20 13:23:44 +03:00
|
|
|
return mEditorBase->IsIMEComposing();
|
2015-10-27 01:21:37 +03:00
|
|
|
}
|
|
|
|
|
2018-05-08 20:52:42 +03:00
|
|
|
nsresult IMEContentObserver::GetSelectionAndRoot(
|
2014-03-08 05:20:07 +04:00
|
|
|
dom::Selection** aSelection, nsIContent** aRootContent) const {
|
|
|
|
if (!mEditableNode || !mSelection) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ASSERTION(mSelection && mRootContent, "uninitialized content observer");
|
|
|
|
NS_ADDREF(*aSelection = mSelection);
|
|
|
|
NS_ADDREF(*aRootContent = mRootContent);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2018-01-26 11:25:45 +03:00
|
|
|
void IMEContentObserver::OnSelectionChange(Selection& aSelection) {
|
|
|
|
if (!mIsObserving) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aSelection.RangeCount() && mWidget) {
|
2015-08-21 19:43:42 +03:00
|
|
|
bool causedByComposition = IsEditorHandlingEventForComposition();
|
2015-07-17 05:25:00 +03:00
|
|
|
bool causedBySelectionEvent = TextComposition::IsHandlingSelectionEvent();
|
2015-10-27 01:21:37 +03:00
|
|
|
bool duringComposition = IsEditorComposing();
|
2015-07-17 05:25:00 +03:00
|
|
|
MaybeNotifyIMEOfSelectionChange(causedByComposition, causedBySelectionEvent,
|
2015-10-27 01:21:37 +03:00
|
|
|
duringComposition);
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::ScrollPositionChanged() {
|
2017-04-13 08:32:12 +03:00
|
|
|
if (!NeedsPositionChangeNotification()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-31 08:38:00 +04:00
|
|
|
MaybeNotifyIMEOfPositionChange();
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
IMEContentObserver::Reflow(DOMHighResTimeStamp aStart,
|
|
|
|
DOMHighResTimeStamp aEnd) {
|
2017-04-13 08:32:12 +03:00
|
|
|
if (!NeedsPositionChangeNotification()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-07-31 08:38:00 +04:00
|
|
|
MaybeNotifyIMEOfPositionChange();
|
2014-03-08 05:20:07 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
IMEContentObserver::ReflowInterruptible(DOMHighResTimeStamp aStart,
|
|
|
|
DOMHighResTimeStamp aEnd) {
|
2017-04-13 08:32:12 +03:00
|
|
|
if (!NeedsPositionChangeNotification()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2014-07-31 08:38:00 +04:00
|
|
|
MaybeNotifyIMEOfPositionChange();
|
2014-03-08 05:20:07 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-09-08 06:54:14 +03:00
|
|
|
nsresult IMEContentObserver::HandleQueryContentEvent(
|
|
|
|
WidgetQueryContentEvent* aEvent) {
|
2016-06-21 07:13:11 +03:00
|
|
|
// If the instance has normal selection cache and the query event queries
|
|
|
|
// normal selection's range, it should use the cached selection which was
|
2015-11-10 05:49:05 +03:00
|
|
|
// sent to the widget. However, if this instance has already received new
|
|
|
|
// selection change notification but hasn't updated the cache yet (i.e.,
|
|
|
|
// not sending selection change notification to IME, don't use the cached
|
|
|
|
// value. Note that don't update selection cache here since if you update
|
|
|
|
// selection cache here, IMENotificationSender won't notify IME of selection
|
|
|
|
// change because it looks like that the selection isn't actually changed.
|
2016-06-20 09:57:38 +03:00
|
|
|
bool isSelectionCacheAvailable = aEvent->mUseNativeLineBreak &&
|
|
|
|
mSelectionData.IsValid() &&
|
|
|
|
!mNeedsToNotifyIMEOfSelectionChange;
|
|
|
|
if (isSelectionCacheAvailable && aEvent->mMessage == eQuerySelectedText &&
|
|
|
|
aEvent->mInput.mSelectionType == SelectionType::eNormal) {
|
2015-09-08 06:54:14 +03:00
|
|
|
aEvent->mReply.mContentsRoot = mRootContent;
|
|
|
|
aEvent->mReply.mHasSelection = !mSelectionData.IsCollapsed();
|
|
|
|
aEvent->mReply.mOffset = mSelectionData.mOffset;
|
|
|
|
aEvent->mReply.mString = mSelectionData.String();
|
|
|
|
aEvent->mReply.mWritingMode = mSelectionData.GetWritingMode();
|
|
|
|
aEvent->mReply.mReversed = mSelectionData.mReversed;
|
|
|
|
aEvent->mSucceeded = true;
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::HandleQueryContentEvent(aEvent={ "
|
2015-09-08 06:54:14 +03:00
|
|
|
"mMessage=%s })",
|
|
|
|
this, ToChar(aEvent->mMessage)));
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::HandleQueryContentEvent(aEvent={ "
|
2015-09-16 11:48:24 +03:00
|
|
|
"mMessage=%s })",
|
|
|
|
this, ToChar(aEvent->mMessage)));
|
|
|
|
|
2016-06-20 09:57:38 +03:00
|
|
|
// If we can make the event's input offset absolute with TextComposition or
|
|
|
|
// mSelection, we should set it here for reducing the cost of computing
|
|
|
|
// selection start offset. If ContentEventHandler receives a
|
|
|
|
// WidgetQueryContentEvent whose input offset is relative to insertion point,
|
|
|
|
// it computes current selection start offset (this may be expensive) and
|
|
|
|
// make the offset absolute value itself.
|
|
|
|
// Note that calling MakeOffsetAbsolute() makes the event a query event with
|
|
|
|
// absolute offset. So, ContentEventHandler doesn't pay any additional cost
|
|
|
|
// after calling MakeOffsetAbsolute() here.
|
|
|
|
if (aEvent->mInput.mRelativeToInsertionPoint &&
|
|
|
|
aEvent->mInput.IsValidEventMessage(aEvent->mMessage)) {
|
|
|
|
RefPtr<TextComposition> composition =
|
|
|
|
IMEStateManager::GetTextCompositionFor(aEvent->mWidget);
|
|
|
|
if (composition) {
|
|
|
|
uint32_t compositionStart = composition->NativeOffsetOfStartComposition();
|
|
|
|
if (NS_WARN_IF(!aEvent->mInput.MakeOffsetAbsolute(compositionStart))) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
} else if (isSelectionCacheAvailable) {
|
|
|
|
uint32_t selectionStart = mSelectionData.mOffset;
|
|
|
|
if (NS_WARN_IF(!aEvent->mInput.MakeOffsetAbsolute(selectionStart))) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
AutoRestore<bool> handling(mIsHandlingQueryContentEvent);
|
|
|
|
mIsHandlingQueryContentEvent = true;
|
2015-09-08 06:54:14 +03:00
|
|
|
ContentEventHandler handler(GetPresContext());
|
2015-09-08 06:54:14 +03:00
|
|
|
nsresult rv = handler.HandleQueryContentEvent(aEvent);
|
2017-04-28 14:09:55 +03:00
|
|
|
if (NS_WARN_IF(Destroyed())) {
|
|
|
|
// If this has already destroyed during querying the content, the query
|
|
|
|
// is outdated even if it's succeeded. So, make the query fail.
|
|
|
|
aEvent->mSucceeded = false;
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Warning,
|
|
|
|
("0x%p IMEContentObserver::HandleQueryContentEvent(), WARNING, "
|
|
|
|
"IMEContentObserver has been destroyed during the query, "
|
|
|
|
"making the query fail",
|
|
|
|
this));
|
|
|
|
return rv;
|
|
|
|
}
|
2016-03-16 21:20:30 +03:00
|
|
|
|
|
|
|
if (!IsInitializedWithPlugin() &&
|
|
|
|
NS_WARN_IF(aEvent->mReply.mContentsRoot != mRootContent)) {
|
|
|
|
// Focus has changed unexpectedly, so make the query fail.
|
|
|
|
aEvent->mSucceeded = false;
|
2015-09-08 06:54:14 +03:00
|
|
|
}
|
|
|
|
return rv;
|
2015-09-08 06:54:14 +03:00
|
|
|
}
|
|
|
|
|
2014-08-29 14:08:43 +04:00
|
|
|
bool IMEContentObserver::OnMouseButtonEvent(nsPresContext* aPresContext,
|
|
|
|
WidgetMouseEvent* aMouseEvent) {
|
2017-04-13 08:32:12 +03:00
|
|
|
if (!mIMENotificationRequests ||
|
|
|
|
!mIMENotificationRequests->WantMouseButtonEventOnChar()) {
|
2014-08-29 14:08:43 +04:00
|
|
|
return false;
|
|
|
|
}
|
2016-03-22 10:47:52 +03:00
|
|
|
if (!aMouseEvent->IsTrusted() || aMouseEvent->DefaultPrevented() ||
|
2016-04-14 11:03:14 +03:00
|
|
|
!aMouseEvent->mWidget) {
|
2014-08-29 14:08:43 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Now, we need to notify only mouse down and mouse up event.
|
2015-08-22 04:34:51 +03:00
|
|
|
switch (aMouseEvent->mMessage) {
|
2015-08-29 02:58:30 +03:00
|
|
|
case eMouseUp:
|
2015-08-29 02:58:30 +03:00
|
|
|
case eMouseDown:
|
2014-08-29 14:08:43 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
2015-02-17 16:20:08 +03:00
|
|
|
if (NS_WARN_IF(!mWidget) || NS_WARN_IF(mWidget->Destroyed())) {
|
2014-08-29 14:08:43 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<IMEContentObserver> kungFuDeathGrip(this);
|
2015-02-17 16:20:08 +03:00
|
|
|
|
2015-09-10 04:40:06 +03:00
|
|
|
WidgetQueryContentEvent charAtPt(true, eQueryCharacterAtPoint,
|
2016-04-14 11:03:14 +03:00
|
|
|
aMouseEvent->mWidget);
|
2016-04-18 17:09:02 +03:00
|
|
|
charAtPt.mRefPoint = aMouseEvent->mRefPoint;
|
2014-08-29 14:08:43 +04:00
|
|
|
ContentEventHandler handler(aPresContext);
|
|
|
|
handler.OnQueryCharacterAtPoint(&charAtPt);
|
|
|
|
if (NS_WARN_IF(!charAtPt.mSucceeded) ||
|
|
|
|
charAtPt.mReply.mOffset == WidgetQueryContentEvent::NOT_FOUND) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-17 16:20:08 +03:00
|
|
|
// The widget might be destroyed during querying the content since it
|
|
|
|
// causes flushing layout.
|
|
|
|
if (!mWidget || NS_WARN_IF(mWidget->Destroyed())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-08-29 14:08:43 +04:00
|
|
|
// The result character rect is relative to the top level widget.
|
|
|
|
// We should notify it with offset in the widget.
|
|
|
|
nsIWidget* topLevelWidget = mWidget->GetTopLevelWidget();
|
|
|
|
if (topLevelWidget && topLevelWidget != mWidget) {
|
2015-02-04 23:21:03 +03:00
|
|
|
charAtPt.mReply.mRect.MoveBy(topLevelWidget->WidgetToScreenOffset() -
|
|
|
|
mWidget->WidgetToScreenOffset());
|
2014-08-29 14:08:43 +04:00
|
|
|
}
|
|
|
|
// The refPt is relative to its widget.
|
|
|
|
// We should notify it with offset in the widget.
|
2016-04-14 11:03:14 +03:00
|
|
|
if (aMouseEvent->mWidget != mWidget) {
|
2016-04-18 17:09:02 +03:00
|
|
|
charAtPt.mRefPoint += aMouseEvent->mWidget->WidgetToScreenOffset() -
|
2015-02-04 23:21:03 +03:00
|
|
|
mWidget->WidgetToScreenOffset();
|
2014-08-29 14:08:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
IMENotification notification(NOTIFY_IME_OF_MOUSE_BUTTON_EVENT);
|
2015-08-22 04:34:51 +03:00
|
|
|
notification.mMouseButtonEventData.mEventMessage = aMouseEvent->mMessage;
|
2014-08-29 14:08:43 +04:00
|
|
|
notification.mMouseButtonEventData.mOffset = charAtPt.mReply.mOffset;
|
|
|
|
notification.mMouseButtonEventData.mCursorPos.Set(
|
2016-04-18 17:09:02 +03:00
|
|
|
charAtPt.mRefPoint.ToUnknownPoint());
|
2015-02-04 23:21:03 +03:00
|
|
|
notification.mMouseButtonEventData.mCharRect.Set(
|
2015-11-07 06:13:40 +03:00
|
|
|
charAtPt.mReply.mRect.ToUnknownRect());
|
2019-04-21 21:17:10 +03:00
|
|
|
notification.mMouseButtonEventData.mButton = aMouseEvent->mButton;
|
2019-04-21 22:42:37 +03:00
|
|
|
notification.mMouseButtonEventData.mButtons = aMouseEvent->mButtons;
|
2016-03-31 11:03:00 +03:00
|
|
|
notification.mMouseButtonEventData.mModifiers = aMouseEvent->mModifiers;
|
2014-08-29 14:08:43 +04:00
|
|
|
|
2015-06-27 03:23:31 +03:00
|
|
|
nsresult rv = IMEStateManager::NotifyIME(notification, mWidget);
|
2014-08-29 14:08:43 +04:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool consumed = (rv == NS_SUCCESS_EVENT_CONSUMED);
|
2016-03-22 10:26:27 +03:00
|
|
|
if (consumed) {
|
|
|
|
aMouseEvent->PreventDefault();
|
|
|
|
}
|
2014-08-29 14:08:43 +04:00
|
|
|
return consumed;
|
|
|
|
}
|
|
|
|
|
2018-03-01 14:36:58 +03:00
|
|
|
void IMEContentObserver::CharacterDataWillChange(
|
2018-02-27 17:30:27 +03:00
|
|
|
nsIContent* aContent, const CharacterDataChangeInfo& aInfo) {
|
2014-07-31 08:38:01 +04:00
|
|
|
NS_ASSERTION(aContent->IsText(), "character data changed for non-text node");
|
|
|
|
MOZ_ASSERT(mPreCharacterDataChangeLength < 0,
|
|
|
|
"CharacterDataChanged() should've reset "
|
|
|
|
"mPreCharacterDataChangeLength");
|
|
|
|
|
2017-12-08 01:01:51 +03:00
|
|
|
if (!NeedsTextChangeNotification() ||
|
|
|
|
!nsContentUtils::IsInSameAnonymousTree(mRootContent, aContent)) {
|
2017-04-13 08:32:12 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-31 08:38:01 +04:00
|
|
|
mEndOfAddedTextCache.Clear();
|
|
|
|
mStartOfRemovingTextRangeCache.Clear();
|
2017-06-08 05:24:58 +03:00
|
|
|
|
|
|
|
// Although we don't assume this change occurs while this is storing
|
|
|
|
// the range of added consecutive nodes, if it actually happens, we need to
|
|
|
|
// flush them since this change may occur before or in the range. So, it's
|
|
|
|
// safe to flush pending computation of mTextChangeData before handling this.
|
|
|
|
MaybeNotifyIMEOfAddedTextDuringDocumentChange();
|
|
|
|
|
2018-02-27 17:30:27 +03:00
|
|
|
mPreCharacterDataChangeLength = ContentEventHandler::GetNativeTextLength(
|
|
|
|
aContent, aInfo.mChangeStart, aInfo.mChangeEnd);
|
2014-07-31 08:38:01 +04:00
|
|
|
MOZ_ASSERT(
|
2018-02-27 17:30:27 +03:00
|
|
|
mPreCharacterDataChangeLength >= aInfo.mChangeEnd - aInfo.mChangeStart,
|
2014-07-31 08:38:01 +04:00
|
|
|
"The computed length must be same as or larger than XP length");
|
|
|
|
}
|
|
|
|
|
2018-03-01 14:36:58 +03:00
|
|
|
void IMEContentObserver::CharacterDataChanged(
|
2018-02-27 17:30:27 +03:00
|
|
|
nsIContent* aContent, const CharacterDataChangeInfo& aInfo) {
|
2014-03-08 05:20:07 +04:00
|
|
|
NS_ASSERTION(aContent->IsText(), "character data changed for non-text node");
|
|
|
|
|
2017-12-08 01:01:51 +03:00
|
|
|
if (!NeedsTextChangeNotification() ||
|
|
|
|
!nsContentUtils::IsInSameAnonymousTree(mRootContent, aContent)) {
|
2017-04-13 08:32:12 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-31 08:38:00 +04:00
|
|
|
mEndOfAddedTextCache.Clear();
|
2014-07-31 08:38:00 +04:00
|
|
|
mStartOfRemovingTextRangeCache.Clear();
|
2017-06-08 05:24:58 +03:00
|
|
|
MOZ_ASSERT(
|
|
|
|
!HasAddedNodesDuringDocumentChange(),
|
|
|
|
"The stored range should be flushed before actually the data is changed");
|
2014-07-31 08:38:00 +04:00
|
|
|
|
2014-07-31 08:38:01 +04:00
|
|
|
int64_t removedLength = mPreCharacterDataChangeLength;
|
|
|
|
mPreCharacterDataChangeLength = -1;
|
|
|
|
|
|
|
|
MOZ_ASSERT(removedLength >= 0,
|
|
|
|
"mPreCharacterDataChangeLength should've been set by "
|
|
|
|
"CharacterDataWillChange()");
|
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
uint32_t offset = 0;
|
|
|
|
// get offsets of change and fire notification
|
2015-12-02 07:20:00 +03:00
|
|
|
nsresult rv = ContentEventHandler::GetFlatTextLengthInRange(
|
2018-02-27 17:30:27 +03:00
|
|
|
NodePosition(mRootContent, 0), NodePosition(aContent, aInfo.mChangeStart),
|
2015-12-02 07:20:00 +03:00
|
|
|
mRootContent, &offset, LINE_BREAK_TYPE_NATIVE);
|
2015-12-02 07:20:00 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return;
|
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
2018-02-27 17:30:27 +03:00
|
|
|
uint32_t newLength = ContentEventHandler::GetNativeTextLength(
|
|
|
|
aContent, aInfo.mChangeStart, aInfo.mChangeStart + aInfo.mReplaceLength);
|
2014-07-31 08:38:01 +04:00
|
|
|
|
|
|
|
uint32_t oldEnd = offset + static_cast<uint32_t>(removedLength);
|
|
|
|
uint32_t newEnd = offset + newLength;
|
2014-03-08 05:20:07 +04:00
|
|
|
|
2016-06-28 10:51:59 +03:00
|
|
|
TextChangeData data(offset, oldEnd, newEnd,
|
|
|
|
IsEditorHandlingEventForComposition(),
|
2015-10-27 01:21:37 +03:00
|
|
|
IsEditorComposing());
|
2014-07-31 08:38:00 +04:00
|
|
|
MaybeNotifyIMEOfTextChange(data);
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::NotifyContentAdded(nsINode* aContainer,
|
2017-09-06 20:47:09 +03:00
|
|
|
nsIContent* aFirstContent,
|
|
|
|
nsIContent* aLastContent) {
|
2017-12-08 01:01:51 +03:00
|
|
|
if (!NeedsTextChangeNotification() ||
|
|
|
|
!nsContentUtils::IsInSameAnonymousTree(mRootContent, aFirstContent)) {
|
2017-04-13 08:32:12 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-09-06 20:47:09 +03:00
|
|
|
MOZ_ASSERT_IF(aFirstContent, aFirstContent->GetParentNode() == aContainer);
|
|
|
|
MOZ_ASSERT_IF(aLastContent, aLastContent->GetParentNode() == aContainer);
|
|
|
|
|
2014-07-31 08:38:00 +04:00
|
|
|
mStartOfRemovingTextRangeCache.Clear();
|
|
|
|
|
2017-06-08 05:24:58 +03:00
|
|
|
// If it's in a document change, nodes are added consecutively. Therefore,
|
|
|
|
// if we cache the first node and the last node, we need to compute the
|
|
|
|
// range once.
|
|
|
|
// FYI: This is not true if the change caused by an operation in the editor.
|
|
|
|
if (IsInDocumentChange()) {
|
|
|
|
// Now, mEndOfAddedTextCache may be invalid if node is added before
|
|
|
|
// the last node in mEndOfAddedTextCache. Clear it.
|
|
|
|
mEndOfAddedTextCache.Clear();
|
|
|
|
if (!HasAddedNodesDuringDocumentChange()) {
|
2017-09-06 20:47:09 +03:00
|
|
|
mFirstAddedContainer = mLastAddedContainer = aContainer;
|
|
|
|
mFirstAddedContent = aFirstContent;
|
|
|
|
mLastAddedContent = aLastContent;
|
2017-06-08 05:24:58 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
|
|
|
("0x%p IMEContentObserver::NotifyContentAdded(), starts to store "
|
|
|
|
"consecutive added nodes",
|
|
|
|
this));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// If first node being added is not next node of the last node,
|
|
|
|
// notify IME of the previous range first, then, restart to cache the
|
|
|
|
// range.
|
2017-09-06 20:47:09 +03:00
|
|
|
if (NS_WARN_IF(!IsNextNodeOfLastAddedNode(aContainer, aFirstContent))) {
|
2017-06-08 05:24:58 +03:00
|
|
|
// Flush the old range first.
|
|
|
|
MaybeNotifyIMEOfAddedTextDuringDocumentChange();
|
2017-09-06 20:47:09 +03:00
|
|
|
mFirstAddedContainer = aContainer;
|
|
|
|
mFirstAddedContent = aFirstContent;
|
2017-06-08 05:24:58 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
|
|
|
("0x%p IMEContentObserver::NotifyContentAdded(), starts to store "
|
|
|
|
"consecutive added nodes",
|
|
|
|
this));
|
|
|
|
}
|
2017-09-06 20:47:09 +03:00
|
|
|
mLastAddedContainer = aContainer;
|
|
|
|
mLastAddedContent = aLastContent;
|
2017-06-08 05:24:58 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
MOZ_ASSERT(!HasAddedNodesDuringDocumentChange(),
|
|
|
|
"The cache should be cleared when document change finished");
|
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
uint32_t offset = 0;
|
2014-07-31 08:38:00 +04:00
|
|
|
nsresult rv = NS_OK;
|
2017-09-06 20:47:09 +03:00
|
|
|
if (!mEndOfAddedTextCache.Match(aContainer,
|
|
|
|
aFirstContent->GetPreviousSibling())) {
|
2014-07-31 08:38:00 +04:00
|
|
|
mEndOfAddedTextCache.Clear();
|
2015-12-02 07:20:00 +03:00
|
|
|
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
|
|
|
NodePosition(mRootContent, 0),
|
2017-09-06 20:47:09 +03:00
|
|
|
NodePositionBefore(aContainer, PointBefore(aContainer, aFirstContent)),
|
2015-12-02 07:20:00 +03:00
|
|
|
mRootContent, &offset, LINE_BREAK_TYPE_NATIVE);
|
2014-07-31 08:38:00 +04:00
|
|
|
if (NS_WARN_IF(NS_FAILED((rv)))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
offset = mEndOfAddedTextCache.mFlatTextLength;
|
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
|
|
|
// get offset at the end of the last added node
|
2014-03-08 05:20:07 +04:00
|
|
|
uint32_t addingLength = 0;
|
2015-12-02 07:20:00 +03:00
|
|
|
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
2017-09-06 20:47:09 +03:00
|
|
|
NodePositionBefore(aContainer, PointBefore(aContainer, aFirstContent)),
|
|
|
|
NodePosition(aContainer, aLastContent), mRootContent, &addingLength,
|
2015-12-02 07:20:00 +03:00
|
|
|
LINE_BREAK_TYPE_NATIVE);
|
2014-07-31 08:38:00 +04:00
|
|
|
if (NS_WARN_IF(NS_FAILED((rv)))) {
|
|
|
|
mEndOfAddedTextCache.Clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If multiple lines are being inserted in an HTML editor, next call of
|
|
|
|
// NotifyContentAdded() is for adding next node. Therefore, caching the text
|
|
|
|
// length can skip to compute the text length before the adding node and
|
|
|
|
// before of it.
|
2017-09-06 20:47:09 +03:00
|
|
|
mEndOfAddedTextCache.Cache(aContainer, aLastContent, offset + addingLength);
|
2014-03-08 05:20:07 +04:00
|
|
|
|
|
|
|
if (!addingLength) {
|
2014-03-08 05:20:07 +04:00
|
|
|
return;
|
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
2014-07-31 08:37:59 +04:00
|
|
|
TextChangeData data(offset, offset, offset + addingLength,
|
2016-06-28 10:51:59 +03:00
|
|
|
IsEditorHandlingEventForComposition(),
|
|
|
|
IsEditorComposing());
|
2014-07-31 08:38:00 +04:00
|
|
|
MaybeNotifyIMEOfTextChange(data);
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
2018-03-01 14:36:58 +03:00
|
|
|
void IMEContentObserver::ContentAppended(nsIContent* aFirstNewContent) {
|
|
|
|
nsIContent* parent = aFirstNewContent->GetParent();
|
|
|
|
MOZ_ASSERT(parent);
|
|
|
|
NotifyContentAdded(parent, aFirstNewContent, parent->GetLastChild());
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
2018-03-01 14:36:58 +03:00
|
|
|
void IMEContentObserver::ContentInserted(nsIContent* aChild) {
|
2017-07-27 16:49:52 +03:00
|
|
|
MOZ_ASSERT(aChild);
|
2018-03-01 14:36:58 +03:00
|
|
|
NotifyContentAdded(aChild->GetParentNode(), aChild, aChild);
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
2018-03-01 14:36:58 +03:00
|
|
|
void IMEContentObserver::ContentRemoved(nsIContent* aChild,
|
2014-03-08 05:20:07 +04:00
|
|
|
nsIContent* aPreviousSibling) {
|
2017-12-08 01:01:51 +03:00
|
|
|
if (!NeedsTextChangeNotification() ||
|
|
|
|
!nsContentUtils::IsInSameAnonymousTree(mRootContent, aChild)) {
|
2017-04-13 08:32:12 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-31 08:38:00 +04:00
|
|
|
mEndOfAddedTextCache.Clear();
|
2017-06-08 05:24:58 +03:00
|
|
|
MaybeNotifyIMEOfAddedTextDuringDocumentChange();
|
2014-07-31 08:38:00 +04:00
|
|
|
|
2018-03-01 14:36:58 +03:00
|
|
|
nsINode* containerNode = aChild->GetParentNode();
|
2017-07-27 16:49:52 +03:00
|
|
|
MOZ_ASSERT(containerNode);
|
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
uint32_t offset = 0;
|
2014-07-31 08:38:00 +04:00
|
|
|
nsresult rv = NS_OK;
|
2017-09-06 20:47:09 +03:00
|
|
|
if (!mStartOfRemovingTextRangeCache.Match(containerNode, aPreviousSibling)) {
|
2015-12-02 07:20:00 +03:00
|
|
|
// At removing a child node of aContainer, we need the line break caused
|
2017-09-06 20:47:09 +03:00
|
|
|
// by open tag of aContainer. Be careful when aPreviousSibling is nullptr.
|
|
|
|
|
2015-12-02 07:20:00 +03:00
|
|
|
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
|
|
|
NodePosition(mRootContent, 0),
|
2017-09-06 20:47:09 +03:00
|
|
|
NodePosition(containerNode, aPreviousSibling), mRootContent, &offset,
|
2015-12-02 07:20:00 +03:00
|
|
|
LINE_BREAK_TYPE_NATIVE);
|
2014-07-31 08:38:00 +04:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
mStartOfRemovingTextRangeCache.Clear();
|
|
|
|
return;
|
|
|
|
}
|
2017-09-06 20:47:09 +03:00
|
|
|
mStartOfRemovingTextRangeCache.Cache(containerNode, aPreviousSibling,
|
2014-07-31 08:38:00 +04:00
|
|
|
offset);
|
|
|
|
} else {
|
|
|
|
offset = mStartOfRemovingTextRangeCache.mFlatTextLength;
|
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
|
|
|
// get offset at the end of the deleted node
|
2014-03-08 05:20:07 +04:00
|
|
|
uint32_t textLength = 0;
|
2018-04-13 01:41:00 +03:00
|
|
|
if (aChild->IsText()) {
|
2015-12-02 07:20:00 +03:00
|
|
|
textLength = ContentEventHandler::GetNativeTextLength(aChild);
|
|
|
|
} else {
|
2015-12-02 07:20:00 +03:00
|
|
|
uint32_t nodeLength = static_cast<int32_t>(aChild->GetChildCount());
|
2015-12-02 07:20:00 +03:00
|
|
|
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
|
|
|
NodePositionBefore(aChild, 0), NodePosition(aChild, nodeLength),
|
2015-12-02 07:20:00 +03:00
|
|
|
mRootContent, &textLength, LINE_BREAK_TYPE_NATIVE, true);
|
2015-12-02 07:20:00 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
mStartOfRemovingTextRangeCache.Clear();
|
|
|
|
return;
|
|
|
|
}
|
2014-07-31 08:38:00 +04:00
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
|
|
|
if (!textLength) {
|
2014-03-08 05:20:07 +04:00
|
|
|
return;
|
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
2015-10-27 01:21:37 +03:00
|
|
|
TextChangeData data(offset, offset + textLength, offset,
|
2016-06-28 10:51:59 +03:00
|
|
|
IsEditorHandlingEventForComposition(),
|
|
|
|
IsEditorComposing());
|
2014-07-31 08:38:00 +04:00
|
|
|
MaybeNotifyIMEOfTextChange(data);
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
2017-06-08 05:24:58 +03:00
|
|
|
void IMEContentObserver::ClearAddedNodesDuringDocumentChange() {
|
2017-09-06 20:47:09 +03:00
|
|
|
mFirstAddedContainer = mLastAddedContainer = nullptr;
|
|
|
|
mFirstAddedContent = mLastAddedContent = nullptr;
|
2017-06-08 05:24:58 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
|
|
|
("0x%p IMEContentObserver::ClearAddedNodesDuringDocumentChange()"
|
|
|
|
", finished storing consecutive nodes",
|
|
|
|
this));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IMEContentObserver::IsNextNodeOfLastAddedNode(nsINode* aParent,
|
2017-09-06 20:47:09 +03:00
|
|
|
nsIContent* aChild) const {
|
2017-06-08 05:24:58 +03:00
|
|
|
MOZ_ASSERT(aParent);
|
2017-09-06 20:47:09 +03:00
|
|
|
MOZ_ASSERT(aChild && aChild->GetParentNode() == aParent);
|
2017-06-08 05:24:58 +03:00
|
|
|
MOZ_ASSERT(mRootContent);
|
|
|
|
MOZ_ASSERT(HasAddedNodesDuringDocumentChange());
|
|
|
|
|
2017-09-06 20:47:09 +03:00
|
|
|
// If the parent node isn't changed, we can check that mLastAddedContent has
|
|
|
|
// aChild as its next sibling.
|
|
|
|
if (aParent == mLastAddedContainer) {
|
|
|
|
if (NS_WARN_IF(mLastAddedContent->GetNextSibling() != aChild)) {
|
2017-06-08 05:24:58 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-09-06 20:47:09 +03:00
|
|
|
// If the parent node is changed, that means that the recorded last added node
|
|
|
|
// shouldn't have a sibling.
|
|
|
|
if (NS_WARN_IF(mLastAddedContent->GetNextSibling())) {
|
2017-06-08 05:24:58 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-09-06 20:47:09 +03:00
|
|
|
// If the node is aParent is a descendant of mLastAddedContainer,
|
|
|
|
// aChild should be the first child in the new container.
|
|
|
|
if (mLastAddedContainer == aParent->GetParent()) {
|
|
|
|
if (NS_WARN_IF(aChild->GetPreviousSibling())) {
|
2017-06-08 05:24:58 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we need to check it even with slow path.
|
|
|
|
nsIContent* nextContentOfLastAddedContent =
|
2017-09-06 20:47:09 +03:00
|
|
|
mLastAddedContent->GetNextNode(mRootContent->GetParentNode());
|
2017-06-08 05:24:58 +03:00
|
|
|
if (NS_WARN_IF(!nextContentOfLastAddedContent)) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-09-06 20:47:09 +03:00
|
|
|
if (NS_WARN_IF(nextContentOfLastAddedContent != aChild)) {
|
2017-06-08 05:24:58 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::MaybeNotifyIMEOfAddedTextDuringDocumentChange() {
|
|
|
|
if (!HasAddedNodesDuringDocumentChange()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
|
|
|
("0x%p "
|
|
|
|
"IMEContentObserver::MaybeNotifyIMEOfAddedTextDuringDocumentChange()"
|
|
|
|
", flushing stored consecutive nodes",
|
|
|
|
this));
|
|
|
|
|
|
|
|
// Notify IME of text change which is caused by added nodes now.
|
|
|
|
|
|
|
|
// First, compute offset of start of first added node from start of the
|
|
|
|
// editor.
|
|
|
|
uint32_t offset;
|
|
|
|
nsresult rv = ContentEventHandler::GetFlatTextLengthInRange(
|
|
|
|
NodePosition(mRootContent, 0),
|
2017-09-06 20:47:09 +03:00
|
|
|
NodePosition(mFirstAddedContainer,
|
|
|
|
PointBefore(mFirstAddedContainer, mFirstAddedContent)),
|
2017-06-08 05:24:58 +03:00
|
|
|
mRootContent, &offset, LINE_BREAK_TYPE_NATIVE);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
ClearAddedNodesDuringDocumentChange();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next, compute the text length of added nodes.
|
|
|
|
uint32_t length;
|
|
|
|
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
2017-09-06 20:47:09 +03:00
|
|
|
NodePosition(mFirstAddedContainer,
|
|
|
|
PointBefore(mFirstAddedContainer, mFirstAddedContent)),
|
|
|
|
NodePosition(mLastAddedContainer, mLastAddedContent), mRootContent,
|
2017-06-08 05:24:58 +03:00
|
|
|
&length, LINE_BREAK_TYPE_NATIVE);
|
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
ClearAddedNodesDuringDocumentChange();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally, try to notify IME of the range.
|
|
|
|
TextChangeData data(offset, offset, offset + length,
|
|
|
|
IsEditorHandlingEventForComposition(),
|
|
|
|
IsEditorComposing());
|
|
|
|
MaybeNotifyIMEOfTextChange(data);
|
|
|
|
ClearAddedNodesDuringDocumentChange();
|
|
|
|
}
|
|
|
|
|
2017-06-08 05:21:28 +03:00
|
|
|
void IMEContentObserver::BeginDocumentUpdate() {
|
2017-06-08 05:24:58 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
|
|
|
("0x%p IMEContentObserver::BeginDocumentUpdate(), "
|
|
|
|
"HasAddedNodesDuringDocumentChange()=%s",
|
|
|
|
this, ToChar(HasAddedNodesDuringDocumentChange())));
|
|
|
|
|
2017-09-12 22:55:01 +03:00
|
|
|
// If we're not in a nested document update, this will return early,
|
|
|
|
// otherwise, it will handle flusing any changes currently pending before
|
|
|
|
// entering a nested document update.
|
|
|
|
MaybeNotifyIMEOfAddedTextDuringDocumentChange();
|
2017-06-08 05:21:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::EndDocumentUpdate() {
|
2017-06-08 05:24:58 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
|
|
|
("0x%p IMEContentObserver::EndDocumentUpdate(), "
|
|
|
|
"HasAddedNodesDuringDocumentChange()=%s",
|
|
|
|
this, ToChar(HasAddedNodesDuringDocumentChange())));
|
|
|
|
|
|
|
|
MaybeNotifyIMEOfAddedTextDuringDocumentChange();
|
2017-06-08 05:21:28 +03:00
|
|
|
}
|
|
|
|
|
2015-09-08 06:54:14 +03:00
|
|
|
void IMEContentObserver::SuppressNotifyingIME() {
|
|
|
|
mSuppressNotifications++;
|
|
|
|
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::SuppressNotifyingIME(), "
|
2015-09-08 06:54:14 +03:00
|
|
|
"mSuppressNotifications=%u",
|
|
|
|
this, mSuppressNotifications));
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::UnsuppressNotifyingIME() {
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::UnsuppressNotifyingIME(), "
|
2015-09-08 06:54:14 +03:00
|
|
|
"mSuppressNotifications=%u",
|
|
|
|
this, mSuppressNotifications));
|
|
|
|
|
|
|
|
if (!mSuppressNotifications || --mSuppressNotifications) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
FlushMergeableNotifications();
|
|
|
|
}
|
|
|
|
|
2018-01-24 08:10:18 +03:00
|
|
|
void IMEContentObserver::OnEditActionHandled() {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::EditAction()", this));
|
2015-09-08 06:54:14 +03:00
|
|
|
|
2014-07-31 08:38:00 +04:00
|
|
|
mEndOfAddedTextCache.Clear();
|
2014-07-31 08:38:00 +04:00
|
|
|
mStartOfRemovingTextRangeCache.Clear();
|
2014-07-31 08:37:59 +04:00
|
|
|
FlushMergeableNotifications();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::BeforeEditAction() {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::BeforeEditAction()", this));
|
2015-09-08 06:54:14 +03:00
|
|
|
|
2014-07-31 08:38:00 +04:00
|
|
|
mEndOfAddedTextCache.Clear();
|
2014-07-31 08:38:00 +04:00
|
|
|
mStartOfRemovingTextRangeCache.Clear();
|
2014-07-31 08:37:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::CancelEditAction() {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::CancelEditAction()", this));
|
2015-09-08 06:54:14 +03:00
|
|
|
|
2014-07-31 08:38:00 +04:00
|
|
|
mEndOfAddedTextCache.Clear();
|
2014-07-31 08:38:00 +04:00
|
|
|
mStartOfRemovingTextRangeCache.Clear();
|
2014-07-31 08:37:59 +04:00
|
|
|
FlushMergeableNotifications();
|
|
|
|
}
|
|
|
|
|
2015-06-17 04:03:57 +03:00
|
|
|
void IMEContentObserver::PostFocusSetNotification() {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::PostFocusSetNotification()", this));
|
2015-09-08 06:54:14 +03:00
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
mNeedsToNotifyIMEOfFocusSet = true;
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:23 +03:00
|
|
|
void IMEContentObserver::PostTextChangeNotification() {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::PostTextChangeNotification("
|
2015-09-16 11:48:23 +03:00
|
|
|
"mTextChangeData=%s)",
|
|
|
|
this, TextChangeDataToString(mTextChangeData).get()));
|
2015-09-08 06:54:14 +03:00
|
|
|
|
2015-07-11 04:53:56 +03:00
|
|
|
MOZ_ASSERT(mTextChangeData.IsValid(),
|
2014-07-31 08:38:00 +04:00
|
|
|
"mTextChangeData must have text change data");
|
2015-09-16 11:48:24 +03:00
|
|
|
mNeedsToNotifyIMEOfTextChange = true;
|
2014-07-31 08:38:00 +04:00
|
|
|
}
|
|
|
|
|
2015-09-14 17:28:43 +03:00
|
|
|
void IMEContentObserver::PostSelectionChangeNotification() {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(
|
|
|
|
sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::PostSelectionChangeNotification(), "
|
2015-09-14 17:28:43 +03:00
|
|
|
"mSelectionData={ mCausedByComposition=%s, mCausedBySelectionEvent=%s }",
|
|
|
|
this, ToChar(mSelectionData.mCausedByComposition),
|
|
|
|
ToChar(mSelectionData.mCausedBySelectionEvent)));
|
2015-09-08 06:54:14 +03:00
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
mNeedsToNotifyIMEOfSelectionChange = true;
|
2014-07-31 08:38:00 +04:00
|
|
|
}
|
|
|
|
|
2015-09-08 06:54:14 +03:00
|
|
|
void IMEContentObserver::MaybeNotifyIMEOfFocusSet() {
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::MaybeNotifyIMEOfFocusSet()", this));
|
2015-09-08 06:54:14 +03:00
|
|
|
|
|
|
|
PostFocusSetNotification();
|
|
|
|
FlushMergeableNotifications();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::MaybeNotifyIMEOfTextChange(
|
|
|
|
const TextChangeDataBase& aTextChangeData) {
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::MaybeNotifyIMEOfTextChange("
|
2015-09-08 06:54:14 +03:00
|
|
|
"aTextChangeData=%s)",
|
|
|
|
this, TextChangeDataToString(aTextChangeData).get()));
|
|
|
|
|
2015-09-16 11:48:23 +03:00
|
|
|
mTextChangeData += aTextChangeData;
|
|
|
|
PostTextChangeNotification();
|
2015-09-08 06:54:14 +03:00
|
|
|
FlushMergeableNotifications();
|
|
|
|
}
|
|
|
|
|
2017-04-13 08:32:12 +03:00
|
|
|
void IMEContentObserver::CancelNotifyingIMEOfTextChange() {
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
|
|
|
("0x%p IMEContentObserver::CancelNotifyingIMEOfTextChange()", this));
|
|
|
|
mTextChangeData.Clear();
|
|
|
|
mNeedsToNotifyIMEOfTextChange = false;
|
|
|
|
}
|
|
|
|
|
2015-09-08 06:54:14 +03:00
|
|
|
void IMEContentObserver::MaybeNotifyIMEOfSelectionChange(
|
2015-10-27 01:21:37 +03:00
|
|
|
bool aCausedByComposition, bool aCausedBySelectionEvent,
|
|
|
|
bool aOccurredDuringComposition) {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(
|
|
|
|
sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::MaybeNotifyIMEOfSelectionChange("
|
2015-10-27 01:21:37 +03:00
|
|
|
"aCausedByComposition=%s, aCausedBySelectionEvent=%s, "
|
|
|
|
"aOccurredDuringComposition)",
|
2015-09-08 06:54:14 +03:00
|
|
|
this, ToChar(aCausedByComposition), ToChar(aCausedBySelectionEvent)));
|
|
|
|
|
2015-09-14 17:28:43 +03:00
|
|
|
mSelectionData.AssignReason(aCausedByComposition, aCausedBySelectionEvent,
|
2015-10-27 01:21:37 +03:00
|
|
|
aOccurredDuringComposition);
|
2015-09-14 17:28:43 +03:00
|
|
|
PostSelectionChangeNotification();
|
2015-09-08 06:54:14 +03:00
|
|
|
FlushMergeableNotifications();
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::MaybeNotifyIMEOfPositionChange() {
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::MaybeNotifyIMEOfPositionChange()", this));
|
2015-09-16 11:48:24 +03:00
|
|
|
// If reflow is caused by ContentEventHandler during PositionChangeEvent
|
|
|
|
// sending NOTIFY_IME_OF_POSITION_CHANGE, we don't need to notify IME of it
|
|
|
|
// again since ContentEventHandler returns the result including this reflow's
|
|
|
|
// result.
|
|
|
|
if (mIsHandlingQueryContentEvent &&
|
|
|
|
mSendingNotification == NOTIFY_IME_OF_POSITION_CHANGE) {
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::MaybeNotifyIMEOfPositionChange(), "
|
2015-09-16 11:48:24 +03:00
|
|
|
"ignored since caused by ContentEventHandler during sending "
|
|
|
|
"NOTIY_IME_OF_POSITION_CHANGE",
|
|
|
|
this));
|
|
|
|
return;
|
|
|
|
}
|
2015-09-08 06:54:14 +03:00
|
|
|
PostPositionChangeNotification();
|
|
|
|
FlushMergeableNotifications();
|
|
|
|
}
|
|
|
|
|
2017-04-13 08:32:12 +03:00
|
|
|
void IMEContentObserver::CancelNotifyingIMEOfPositionChange() {
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
|
|
|
("0x%p IMEContentObserver::CancelNotifyIMEOfPositionChange()", this));
|
|
|
|
mNeedsToNotifyIMEOfPositionChange = false;
|
|
|
|
}
|
|
|
|
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
void IMEContentObserver::MaybeNotifyCompositionEventHandled() {
|
|
|
|
MOZ_LOG(
|
|
|
|
sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::MaybeNotifyCompositionEventHandled()", this));
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
|
|
|
|
PostCompositionEventHandledNotification();
|
|
|
|
FlushMergeableNotifications();
|
|
|
|
}
|
|
|
|
|
2018-10-11 16:06:52 +03:00
|
|
|
bool IMEContentObserver::UpdateSelectionCache(bool aRequireFlush /* = true */) {
|
2015-08-21 19:43:41 +03:00
|
|
|
MOZ_ASSERT(IsSafeToNotifyIME());
|
|
|
|
|
2016-06-28 09:23:12 +03:00
|
|
|
if (WasInitializedWithPlugin()) {
|
2015-08-21 19:43:41 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-09-14 17:28:43 +03:00
|
|
|
mSelectionData.ClearSelectionData();
|
2015-08-21 19:43:41 +03:00
|
|
|
|
|
|
|
// XXX Cannot we cache some information for reducing the cost to compute
|
|
|
|
// selection offset and writing mode?
|
2015-09-10 04:40:05 +03:00
|
|
|
WidgetQueryContentEvent selection(true, eQuerySelectedText, mWidget);
|
2018-10-11 16:06:52 +03:00
|
|
|
selection.mNeedsToFlushLayout = aRequireFlush;
|
2015-08-21 19:43:41 +03:00
|
|
|
ContentEventHandler handler(GetPresContext());
|
|
|
|
handler.OnQuerySelectedText(&selection);
|
2016-03-16 21:20:30 +03:00
|
|
|
if (NS_WARN_IF(!selection.mSucceeded) ||
|
|
|
|
NS_WARN_IF(selection.mReply.mContentsRoot != mRootContent)) {
|
2015-08-21 19:43:41 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-09-08 06:54:14 +03:00
|
|
|
mFocusedWidget = selection.mReply.mFocusedWidget;
|
2015-08-21 19:43:41 +03:00
|
|
|
mSelectionData.mOffset = selection.mReply.mOffset;
|
|
|
|
*mSelectionData.mString = selection.mReply.mString;
|
|
|
|
mSelectionData.SetWritingMode(selection.GetWritingMode());
|
|
|
|
mSelectionData.mReversed = selection.mReply.mReversed;
|
2015-09-14 17:28:43 +03:00
|
|
|
|
|
|
|
// WARNING: Don't modify the reason of selection change here.
|
2015-09-08 06:54:14 +03:00
|
|
|
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::UpdateSelectionCache(), "
|
2015-09-08 06:54:14 +03:00
|
|
|
"mSelectionData=%s",
|
|
|
|
this, SelectionChangeDataToString(mSelectionData).get()));
|
|
|
|
|
2015-08-21 19:43:41 +03:00
|
|
|
return mSelectionData.IsValid();
|
|
|
|
}
|
|
|
|
|
2015-06-17 04:03:57 +03:00
|
|
|
void IMEContentObserver::PostPositionChangeNotification() {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::PostPositionChangeNotification()", this));
|
2015-09-08 06:54:14 +03:00
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
mNeedsToNotifyIMEOfPositionChange = true;
|
2014-07-31 08:38:00 +04:00
|
|
|
}
|
|
|
|
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
void IMEContentObserver::PostCompositionEventHandledNotification() {
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::"
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
"PostCompositionEventHandledNotification()",
|
|
|
|
this));
|
|
|
|
|
|
|
|
mNeedsToNotifyIMEOfCompositionEventHandled = true;
|
|
|
|
}
|
|
|
|
|
2015-06-17 04:03:57 +03:00
|
|
|
bool IMEContentObserver::IsReflowLocked() const {
|
|
|
|
nsPresContext* presContext = GetPresContext();
|
|
|
|
if (NS_WARN_IF(!presContext)) {
|
|
|
|
return false;
|
|
|
|
}
|
2019-04-03 15:40:26 +03:00
|
|
|
PresShell* presShell = presContext->GetPresShell();
|
2015-06-17 04:03:57 +03:00
|
|
|
if (NS_WARN_IF(!presShell)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// During reflow, we shouldn't notify IME because IME may query content
|
|
|
|
// synchronously. Then, it causes ContentEventHandler will try to flush
|
|
|
|
// pending notifications during reflow.
|
|
|
|
return presShell->IsReflowLocked();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IMEContentObserver::IsSafeToNotifyIME() const {
|
2014-08-13 15:25:14 +04:00
|
|
|
// If this is already detached from the widget, this doesn't need to notify
|
|
|
|
// anything.
|
2014-08-19 15:54:08 +04:00
|
|
|
if (!mWidget) {
|
2015-06-17 04:03:57 +03:00
|
|
|
return false;
|
2014-08-19 15:54:08 +04:00
|
|
|
}
|
|
|
|
|
2015-06-04 20:06:10 +03:00
|
|
|
// Don't notify IME of anything if it's not good time to do it.
|
|
|
|
if (mSuppressNotifications) {
|
2015-06-17 04:03:57 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mESM || NS_WARN_IF(!GetPresContext())) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If it's in reflow, we should wait to finish the reflow.
|
|
|
|
// FYI: This should be called again from Reflow() or ReflowInterruptible().
|
|
|
|
if (IsReflowLocked()) {
|
|
|
|
return false;
|
2015-06-04 20:06:10 +03:00
|
|
|
}
|
|
|
|
|
2014-08-19 15:54:08 +04:00
|
|
|
// If we're in handling an edit action, this method will be called later.
|
Bug 1463985 - part 1: Rename EditAction to EditSubAction and related stuff r=m_kato
When we implement InputEvent.inputType, we need to set a stack class to record
which edit action is currently handled. However, currently, we call smaller
jobs as edit action. For example, when user types a character at selecting
some characters, then, EditAction::deleteSelection is performed first, then,
EditAction::insertText is performed. However, for the InputEvent.inputType,
we need inserText information. So, for making new enum EditAction, we need
to rename current EditAction to EditSubAction.
And also this renames related stuff:
EditorBase::mIsInEditAction -> EditorBase::mIsInEditSubAction
EditorBase::IsInEditAction() -> EditorBase::IsInEditSubAction()
EditorBase::mAction -> EditorBase::mTopLevelEditSubAction
TextEditRules::mTheAction -> TextEditRules::mTopLevelEditSubAction
EditorBase::StartOperation() ->
EditorBase::OnStartToHandleTopLevelEditSubAction()
EditorBase::EndOperation() ->
EditorBase::OnEndHandlingTopLevelEditSubAction()
AutoRules -> AutoTopLevelEditSubActionNotifier
RulesInfo -> EditSubActionInfo
MozReview-Commit-ID: cvSkPUjFm1
--HG--
extra : rebase_source : baf527a3e353b7a8ebe9a46be2243b059c500234
2018-05-28 14:12:34 +03:00
|
|
|
if (mEditorBase && mEditorBase->IsInEditSubAction()) {
|
2015-06-17 04:03:57 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::FlushMergeableNotifications() {
|
|
|
|
if (!IsSafeToNotifyIME()) {
|
|
|
|
// So, if this is already called, this should do nothing.
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::FlushMergeableNotifications(), "
|
2015-09-08 06:54:14 +03:00
|
|
|
"FAILED, due to unsafe to notify IME",
|
|
|
|
this));
|
2014-07-31 08:37:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-13 15:25:14 +04:00
|
|
|
// Notifying something may cause nested call of this method. For example,
|
|
|
|
// when somebody notified one of the notifications may dispatch query content
|
|
|
|
// event. Then, it causes flushing layout which may cause another layout
|
|
|
|
// change notification.
|
|
|
|
|
2015-11-10 05:49:05 +03:00
|
|
|
if (mQueuedSender) {
|
2014-08-13 15:25:14 +04:00
|
|
|
// So, if this is already called, this should do nothing.
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::FlushMergeableNotifications(), "
|
2015-09-08 06:54:14 +03:00
|
|
|
"FAILED, due to already flushing pending notifications",
|
|
|
|
this));
|
2014-08-13 15:25:14 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-04-13 08:32:12 +03:00
|
|
|
// If text change notification and/or position change notification becomes
|
|
|
|
// unnecessary, let's cancel them.
|
|
|
|
if (mNeedsToNotifyIMEOfTextChange && !NeedsTextChangeNotification()) {
|
|
|
|
CancelNotifyingIMEOfTextChange();
|
|
|
|
}
|
|
|
|
if (mNeedsToNotifyIMEOfPositionChange && !NeedsPositionChangeNotification()) {
|
|
|
|
CancelNotifyingIMEOfPositionChange();
|
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
if (!NeedsToNotifyIMEOfSomething()) {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::FlushMergeableNotifications(), "
|
2015-09-16 11:48:24 +03:00
|
|
|
"FAILED, due to no pending notifications",
|
|
|
|
this));
|
2015-06-17 04:03:57 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
// NOTE: Reset each pending flag because sending notification may cause
|
|
|
|
// another change.
|
2014-07-31 08:38:00 +04:00
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::FlushMergeableNotifications(), "
|
2015-09-16 11:48:24 +03:00
|
|
|
"creating IMENotificationSender...",
|
|
|
|
this));
|
2014-08-13 15:25:14 +04:00
|
|
|
|
2015-11-10 05:49:05 +03:00
|
|
|
// If contents in selection range is modified, the selection range still
|
2019-01-11 04:47:15 +03:00
|
|
|
// has removed node from the tree. In such case, ContentIterator won't
|
2015-11-10 05:49:05 +03:00
|
|
|
// work well. Therefore, we shouldn't use AddScriptRunnder() here since
|
|
|
|
// it may kick runnable event immediately after DOM tree is changed but
|
|
|
|
// the selection range isn't modified yet.
|
|
|
|
mQueuedSender = new IMENotificationSender(this);
|
2017-06-29 14:46:11 +03:00
|
|
|
mQueuedSender->Dispatch(mDocShell);
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::FlushMergeableNotifications(), "
|
2015-09-08 06:54:14 +03:00
|
|
|
"finished",
|
|
|
|
this));
|
2014-07-31 08:37:59 +04:00
|
|
|
}
|
|
|
|
|
2017-08-03 19:36:58 +03:00
|
|
|
void IMEContentObserver::TryToFlushPendingNotifications(bool aAllowAsync) {
|
2017-06-29 14:46:11 +03:00
|
|
|
if (!mQueuedSender || mSendingNotification != NOTIFY_IME_OF_NOTHING ||
|
2017-08-03 19:36:58 +03:00
|
|
|
(XRE_IsContentProcess() && aAllowAsync)) {
|
2015-11-10 05:49:05 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::TryToFlushPendingNotifications(), "
|
2015-11-10 05:49:05 +03:00
|
|
|
"performing queued IMENotificationSender forcibly",
|
|
|
|
this));
|
2015-11-12 18:56:01 +03:00
|
|
|
RefPtr<IMENotificationSender> queuedSender = mQueuedSender;
|
|
|
|
queuedSender->Run();
|
2015-11-10 05:49:05 +03:00
|
|
|
}
|
|
|
|
|
2015-06-17 04:03:57 +03:00
|
|
|
/******************************************************************************
|
|
|
|
* mozilla::IMEContentObserver::AChangeEvent
|
|
|
|
******************************************************************************/
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
bool IMEContentObserver::AChangeEvent::CanNotifyIME(
|
|
|
|
ChangeEventType aChangeEventType) const {
|
2017-06-29 14:46:11 +03:00
|
|
|
RefPtr<IMEContentObserver> observer = GetObserver();
|
|
|
|
if (NS_WARN_IF(!observer)) {
|
2015-06-17 04:03:57 +03:00
|
|
|
return false;
|
|
|
|
}
|
2017-06-29 14:46:11 +03:00
|
|
|
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
if (aChangeEventType == eChangeEventType_CompositionEventHandled) {
|
2017-06-29 14:46:11 +03:00
|
|
|
return observer->mWidget != nullptr;
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
}
|
2017-06-29 14:46:11 +03:00
|
|
|
State state = observer->GetState();
|
2015-06-17 04:03:57 +03:00
|
|
|
// If it's not initialized, we should do nothing.
|
|
|
|
if (state == eState_NotObserving) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// If setting focus, just check the state.
|
2015-09-16 11:48:24 +03:00
|
|
|
if (aChangeEventType == eChangeEventType_Focus) {
|
2017-06-29 14:46:11 +03:00
|
|
|
return !NS_WARN_IF(observer->mIMEHasFocus);
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
// If we've not notified IME of focus yet, we shouldn't notify anything.
|
2017-06-29 14:46:11 +03:00
|
|
|
if (!observer->mIMEHasFocus) {
|
2015-06-17 04:03:57 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If IME has focus, IMEContentObserver must hold the widget.
|
2017-06-29 14:46:11 +03:00
|
|
|
MOZ_ASSERT(observer->mWidget);
|
2015-06-17 04:03:57 +03:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
bool IMEContentObserver::AChangeEvent::IsSafeToNotifyIME(
|
|
|
|
ChangeEventType aChangeEventType) const {
|
2015-06-17 04:03:57 +03:00
|
|
|
if (NS_WARN_IF(!nsContentUtils::IsSafeToRunScript())) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-06-29 14:46:11 +03:00
|
|
|
|
|
|
|
RefPtr<IMEContentObserver> observer = GetObserver();
|
|
|
|
if (!observer) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
// While we're sending a notification, we shouldn't send another notification
|
|
|
|
// recursively.
|
2017-06-29 14:46:11 +03:00
|
|
|
if (observer->mSendingNotification != NOTIFY_IME_OF_NOTHING) {
|
2015-09-16 11:48:24 +03:00
|
|
|
MOZ_LOG(
|
|
|
|
sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::AChangeEvent::IsSafeToNotifyIME(), "
|
2015-09-16 11:48:24 +03:00
|
|
|
"putting off sending notification due to detecting recursive call, "
|
|
|
|
"mIMEContentObserver={ mSendingNotification=%s }",
|
2017-06-29 14:46:11 +03:00
|
|
|
this, ToChar(observer->mSendingNotification)));
|
2015-09-16 11:48:24 +03:00
|
|
|
return false;
|
|
|
|
}
|
2017-06-29 14:46:11 +03:00
|
|
|
State state = observer->GetState();
|
2015-09-16 11:48:24 +03:00
|
|
|
if (aChangeEventType == eChangeEventType_Focus) {
|
2015-06-17 04:03:57 +03:00
|
|
|
if (NS_WARN_IF(state != eState_Initializing && state != eState_Observing)) {
|
|
|
|
return false;
|
|
|
|
}
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
} else if (aChangeEventType == eChangeEventType_CompositionEventHandled) {
|
|
|
|
// It doesn't need to check the observing status.
|
2015-06-17 04:03:57 +03:00
|
|
|
} else if (state != eState_Observing) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-06-29 14:46:11 +03:00
|
|
|
return observer->IsSafeToNotifyIME();
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2015-06-17 04:03:57 +03:00
|
|
|
/******************************************************************************
|
2015-09-16 11:48:24 +03:00
|
|
|
* mozilla::IMEContentObserver::IMENotificationSender
|
2015-06-17 04:03:57 +03:00
|
|
|
******************************************************************************/
|
2017-06-29 14:46:11 +03:00
|
|
|
|
|
|
|
void IMEContentObserver::IMENotificationSender::Dispatch(
|
|
|
|
nsIDocShell* aDocShell) {
|
|
|
|
if (XRE_IsContentProcess() && aDocShell) {
|
2018-11-20 04:17:53 +03:00
|
|
|
RefPtr<nsPresContext> presContext = aDocShell->GetPresContext();
|
2017-06-29 14:46:11 +03:00
|
|
|
if (presContext) {
|
|
|
|
nsRefreshDriver* refreshDriver = presContext->RefreshDriver();
|
|
|
|
if (refreshDriver) {
|
|
|
|
refreshDriver->AddEarlyRunner(this);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIScriptGlobalObject* globalObject =
|
|
|
|
aDocShell ? aDocShell->GetScriptGlobalObject() : nullptr;
|
|
|
|
if (globalObject) {
|
|
|
|
RefPtr<IMENotificationSender> queuedSender = this;
|
2017-07-26 11:13:35 +03:00
|
|
|
globalObject->Dispatch(TaskCategory::Other, queuedSender.forget());
|
2017-06-29 14:46:11 +03:00
|
|
|
} else {
|
|
|
|
NS_DispatchToCurrentThread(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-17 04:03:57 +03:00
|
|
|
NS_IMETHODIMP
|
2015-09-16 11:48:24 +03:00
|
|
|
IMEContentObserver::IMENotificationSender::Run() {
|
2015-11-10 05:49:05 +03:00
|
|
|
if (NS_WARN_IF(mIsRunning)) {
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Error,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::Run(), FAILED, "
|
2015-11-10 05:49:05 +03:00
|
|
|
"called recursively",
|
|
|
|
this));
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-06-29 14:46:11 +03:00
|
|
|
RefPtr<IMEContentObserver> observer = GetObserver();
|
|
|
|
if (!observer) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-11-10 05:49:05 +03:00
|
|
|
AutoRestore<bool> running(mIsRunning);
|
|
|
|
mIsRunning = true;
|
|
|
|
|
|
|
|
// This instance was already performed forcibly.
|
2017-06-29 14:46:11 +03:00
|
|
|
if (observer->mQueuedSender != this) {
|
2015-11-10 05:49:05 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2015-09-16 11:48:24 +03:00
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
// NOTE: Reset each pending flag because sending notification may cause
|
|
|
|
// another change.
|
|
|
|
|
2017-06-29 14:46:11 +03:00
|
|
|
if (observer->mNeedsToNotifyIMEOfFocusSet) {
|
|
|
|
observer->mNeedsToNotifyIMEOfFocusSet = false;
|
2015-09-16 11:48:24 +03:00
|
|
|
SendFocusSet();
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->mQueuedSender = nullptr;
|
2015-11-10 05:49:04 +03:00
|
|
|
// If it's not safe to notify IME of focus, SendFocusSet() sets
|
|
|
|
// mNeedsToNotifyIMEOfFocusSet true again. For guaranteeing to send the
|
|
|
|
// focus notification later, we should put a new sender into the queue but
|
|
|
|
// this case must be rare. Note that if mIMEContentObserver is already
|
|
|
|
// destroyed, mNeedsToNotifyIMEOfFocusSet is never set true again.
|
2017-06-29 14:46:11 +03:00
|
|
|
if (observer->mNeedsToNotifyIMEOfFocusSet) {
|
|
|
|
MOZ_ASSERT(!observer->mIMEHasFocus);
|
2015-11-10 05:49:04 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::Run(), "
|
2015-11-10 05:49:05 +03:00
|
|
|
"posting IMENotificationSender to current thread",
|
|
|
|
this));
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->mQueuedSender = new IMENotificationSender(observer);
|
|
|
|
observer->mQueuedSender->Dispatch(observer->mDocShell);
|
2015-11-10 05:49:04 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2015-09-16 11:48:24 +03:00
|
|
|
// This is the first notification to IME. So, we don't need to notify
|
|
|
|
// anymore since IME starts to query content after it gets focus.
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->ClearPendingNotifications();
|
2015-09-16 11:48:24 +03:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2017-06-29 14:46:11 +03:00
|
|
|
if (observer->mNeedsToNotifyIMEOfTextChange) {
|
|
|
|
observer->mNeedsToNotifyIMEOfTextChange = false;
|
2015-09-16 11:48:24 +03:00
|
|
|
SendTextChange();
|
2019-09-30 06:59:09 +03:00
|
|
|
// Even if the observer hasn't received selection change, let's try to send
|
|
|
|
// selection change notification to IME because selection start offset may
|
|
|
|
// be changed if the previous contents of selection start are changed. For
|
|
|
|
// example, when previous `<p>` element of another `<p>` element which
|
|
|
|
// contains caret is removed by a DOM mutation, selection change event
|
|
|
|
// won't be fired, but selection start offset should be decreased by the
|
|
|
|
// length of removed `<p>` element.
|
|
|
|
observer->mNeedsToNotifyIMEOfSelectionChange = true;
|
2015-09-16 11:48:24 +03:00
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
// If a text change notification causes another text change again, we should
|
|
|
|
// notify IME of that before sending a selection change notification.
|
2017-06-29 14:46:11 +03:00
|
|
|
if (!observer->mNeedsToNotifyIMEOfTextChange) {
|
2015-09-16 11:48:24 +03:00
|
|
|
// Be aware, PuppetWidget depends on the order of this. A selection change
|
|
|
|
// notification should not be sent before a text change notification because
|
|
|
|
// PuppetWidget shouldn't query new text content every selection change.
|
2019-09-30 06:59:09 +03:00
|
|
|
if (observer->mNeedsToNotifyIMEOfSelectionChange) {
|
|
|
|
observer->mNeedsToNotifyIMEOfSelectionChange = false;
|
|
|
|
SendSelectionChange();
|
|
|
|
}
|
2015-09-16 11:48:24 +03:00
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
// If a text change notification causes another text change again or a
|
|
|
|
// selection change notification causes either a text change or another
|
|
|
|
// selection change, we should notify IME of those before sending a position
|
|
|
|
// change notification.
|
2017-06-29 14:46:11 +03:00
|
|
|
if (!observer->mNeedsToNotifyIMEOfTextChange &&
|
|
|
|
!observer->mNeedsToNotifyIMEOfSelectionChange) {
|
|
|
|
if (observer->mNeedsToNotifyIMEOfPositionChange) {
|
|
|
|
observer->mNeedsToNotifyIMEOfPositionChange = false;
|
2015-09-16 11:48:24 +03:00
|
|
|
SendPositionChange();
|
|
|
|
}
|
2015-09-16 11:48:24 +03:00
|
|
|
}
|
|
|
|
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
// Composition event handled notification should be sent after all the
|
|
|
|
// other notifications because this notifies widget of finishing all pending
|
|
|
|
// events are handled completely.
|
2017-06-29 14:46:11 +03:00
|
|
|
if (!observer->mNeedsToNotifyIMEOfTextChange &&
|
|
|
|
!observer->mNeedsToNotifyIMEOfSelectionChange &&
|
|
|
|
!observer->mNeedsToNotifyIMEOfPositionChange) {
|
|
|
|
if (observer->mNeedsToNotifyIMEOfCompositionEventHandled) {
|
|
|
|
observer->mNeedsToNotifyIMEOfCompositionEventHandled = false;
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
SendCompositionEventHandled();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->mQueuedSender = nullptr;
|
2015-11-10 05:49:04 +03:00
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
// If notifications caused some new change, we should notify them now.
|
2017-06-29 14:46:11 +03:00
|
|
|
if (observer->NeedsToNotifyIMEOfSomething()) {
|
|
|
|
if (observer->GetState() == eState_StoppedObserving) {
|
2016-04-19 12:57:13 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::Run(), "
|
2016-04-19 12:57:13 +03:00
|
|
|
"waiting IMENotificationSender to be reinitialized",
|
|
|
|
this));
|
|
|
|
} else {
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::Run(), "
|
2016-04-19 12:57:13 +03:00
|
|
|
"posting IMENotificationSender to current thread",
|
|
|
|
this));
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->mQueuedSender = new IMENotificationSender(observer);
|
|
|
|
observer->mQueuedSender->Dispatch(observer->mDocShell);
|
2016-04-19 12:57:13 +03:00
|
|
|
}
|
2015-09-16 11:48:24 +03:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::IMENotificationSender::SendFocusSet() {
|
2017-06-29 14:46:11 +03:00
|
|
|
RefPtr<IMEContentObserver> observer = GetObserver();
|
|
|
|
if (!observer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
if (!CanNotifyIME(eChangeEventType_Focus)) {
|
2015-06-17 04:03:57 +03:00
|
|
|
// If IMEContentObserver has already gone, we don't need to notify IME of
|
|
|
|
// focus.
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendFocusSet(), FAILED, due to impossible to notify IME of focus",
|
|
|
|
this));
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->ClearPendingNotifications();
|
2015-09-16 11:48:24 +03:00
|
|
|
return;
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
if (!IsSafeToNotifyIME(eChangeEventType_Focus)) {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendFocusSet(), retrying to send NOTIFY_IME_OF_FOCUS...",
|
|
|
|
this));
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->PostFocusSetNotification();
|
2015-09-16 11:48:24 +03:00
|
|
|
return;
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->mIMEHasFocus = true;
|
2015-08-21 19:43:42 +03:00
|
|
|
// Initialize selection cache with the first selection data.
|
Bug 1530188 - Make nsChildView::GetEditorView() use eQueryContentState without flushing layout r=smaug
`nsChildView::GetEditorView()` is called by `TextInputHandlerBase::GetWindowLevel()`
which is called when Cocoa requests window level of focused widget.
It currently gets widget including focused element (e.g., it may be in a XUL
`<panel>`) with `eQueryTextContent` event. However, it requires only the widget
(i.e., when a XUL `<panel>` has focused element, the widget for the panel).
Therefore, it does not require to flush the layout.
However, on macOS, `ContentEventHandler` always flushes layout even with
`eQueryContentState` which does not require any layout information. Whether
it requires flushing layout or not is considered with
`WidgetQueryContentEvent::mNeedsToFlushLayout` but this is set to false only
when `IMEContentObserver` notifies widget (and IME) of focus set. At this
time, only on macOS, IME caches the layout information, for example, the
character coordinates, but we don't have a way to update it. This is the reason
why we always flush layout on macOS.
Unfortunately, when a menu popup frame is created, widget for the popup is
created synchronously. Then, Cocoa retrieves window level of the widget including
focused element. But this is unsafe to flush the layout. So, we need to stop
flushing layout in this case.
Therefore, this patch moves the `#ifdef` from `TextEvents.h` to
`IMEContentObserver.cpp`, then, makes `nsChildView::GetEditorView()` use
`eQueryContentState` which is the simplest query content event, and finally,
sets `mNeedsToFlushLayout` to `false`.
Differential Revision: https://phabricator.services.mozilla.com/D25912
--HG--
extra : moz-landing-system : lando
2019-04-03 13:27:13 +03:00
|
|
|
#ifdef XP_MACOSX
|
|
|
|
// We need to flush layout only on macOS because character coordinates are
|
|
|
|
// cached by cocoa with this call, but we don't have a way to update them
|
|
|
|
// after that. Therefore, we need the latest layout information right now.
|
|
|
|
observer->UpdateSelectionCache(true);
|
|
|
|
#else
|
2018-10-11 16:06:52 +03:00
|
|
|
// We avoid flushing for focus in the general case.
|
|
|
|
observer->UpdateSelectionCache(false);
|
Bug 1530188 - Make nsChildView::GetEditorView() use eQueryContentState without flushing layout r=smaug
`nsChildView::GetEditorView()` is called by `TextInputHandlerBase::GetWindowLevel()`
which is called when Cocoa requests window level of focused widget.
It currently gets widget including focused element (e.g., it may be in a XUL
`<panel>`) with `eQueryTextContent` event. However, it requires only the widget
(i.e., when a XUL `<panel>` has focused element, the widget for the panel).
Therefore, it does not require to flush the layout.
However, on macOS, `ContentEventHandler` always flushes layout even with
`eQueryContentState` which does not require any layout information. Whether
it requires flushing layout or not is considered with
`WidgetQueryContentEvent::mNeedsToFlushLayout` but this is set to false only
when `IMEContentObserver` notifies widget (and IME) of focus set. At this
time, only on macOS, IME caches the layout information, for example, the
character coordinates, but we don't have a way to update it. This is the reason
why we always flush layout on macOS.
Unfortunately, when a menu popup frame is created, widget for the popup is
created synchronously. Then, Cocoa retrieves window level of the widget including
focused element. But this is unsafe to flush the layout. So, we need to stop
flushing layout in this case.
Therefore, this patch moves the `#ifdef` from `TextEvents.h` to
`IMEContentObserver.cpp`, then, makes `nsChildView::GetEditorView()` use
`eQueryContentState` which is the simplest query content event, and finally,
sets `mNeedsToFlushLayout` to `false`.
Differential Revision: https://phabricator.services.mozilla.com/D25912
--HG--
extra : moz-landing-system : lando
2019-04-03 13:27:13 +03:00
|
|
|
#endif // #ifdef XP_MACOSX #else
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Info,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendFocusSet(), sending NOTIFY_IME_OF_FOCUS...",
|
|
|
|
this));
|
2015-09-08 06:54:14 +03:00
|
|
|
|
2017-06-29 14:46:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(observer->mSendingNotification == NOTIFY_IME_OF_NOTHING);
|
|
|
|
observer->mSendingNotification = NOTIFY_IME_OF_FOCUS;
|
2015-06-27 03:23:31 +03:00
|
|
|
IMEStateManager::NotifyIME(IMENotification(NOTIFY_IME_OF_FOCUS),
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->mWidget);
|
|
|
|
observer->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
2015-09-08 06:54:14 +03:00
|
|
|
|
2017-04-11 15:24:55 +03:00
|
|
|
// IMENotificationRequests referred by ObserveEditableNode() may be different
|
2015-11-10 05:49:04 +03:00
|
|
|
// before or after widget receives NOTIFY_IME_OF_FOCUS. Therefore, we need
|
|
|
|
// to guarantee to call ObserveEditableNode() after sending
|
|
|
|
// NOTIFY_IME_OF_FOCUS.
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->OnIMEReceivedFocus();
|
2015-11-10 05:49:04 +03:00
|
|
|
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendFocusSet(), sent NOTIFY_IME_OF_FOCUS",
|
|
|
|
this));
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
void IMEContentObserver::IMENotificationSender::SendSelectionChange() {
|
2017-06-29 14:46:11 +03:00
|
|
|
RefPtr<IMEContentObserver> observer = GetObserver();
|
|
|
|
if (!observer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
if (!CanNotifyIME(eChangeEventType_Selection)) {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(
|
|
|
|
sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendSelectionChange(), FAILED, due to impossible to notify IME of "
|
|
|
|
"selection change",
|
|
|
|
this));
|
|
|
|
return;
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
if (!IsSafeToNotifyIME(eChangeEventType_Selection)) {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendSelectionChange(), retrying to send "
|
|
|
|
"NOTIFY_IME_OF_SELECTION_CHANGE...",
|
|
|
|
this));
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->PostSelectionChangeNotification();
|
2015-09-16 11:48:24 +03:00
|
|
|
return;
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2017-06-29 14:46:11 +03:00
|
|
|
SelectionChangeData lastSelChangeData = observer->mSelectionData;
|
|
|
|
if (NS_WARN_IF(!observer->UpdateSelectionCache())) {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(
|
|
|
|
sIMECOLog, LogLevel::Error,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendSelectionChange(), FAILED, due to UpdateSelectionCache() failure",
|
|
|
|
this));
|
|
|
|
return;
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2015-06-17 04:03:57 +03:00
|
|
|
// The state may be changed since querying content causes flushing layout.
|
2015-09-16 11:48:24 +03:00
|
|
|
if (!CanNotifyIME(eChangeEventType_Selection)) {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(
|
|
|
|
sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendSelectionChange(), FAILED, due to flushing layout having changed "
|
|
|
|
"something",
|
|
|
|
this));
|
|
|
|
return;
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2015-08-21 19:43:42 +03:00
|
|
|
// If the selection isn't changed actually, we shouldn't notify IME of
|
|
|
|
// selection change.
|
2017-06-29 14:46:11 +03:00
|
|
|
SelectionChangeData& newSelChangeData = observer->mSelectionData;
|
2015-08-21 19:43:42 +03:00
|
|
|
if (lastSelChangeData.IsValid() &&
|
|
|
|
lastSelChangeData.mOffset == newSelChangeData.mOffset &&
|
|
|
|
lastSelChangeData.String() == newSelChangeData.String() &&
|
|
|
|
lastSelChangeData.GetWritingMode() == newSelChangeData.GetWritingMode() &&
|
|
|
|
lastSelChangeData.mReversed == newSelChangeData.mReversed) {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendSelectionChange(), not notifying IME of "
|
|
|
|
"NOTIFY_IME_OF_SELECTION_CHANGE due to not changed actually",
|
|
|
|
this));
|
|
|
|
return;
|
2015-08-21 19:43:42 +03:00
|
|
|
}
|
|
|
|
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Info,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendSelectionChange(), sending NOTIFY_IME_OF_SELECTION_CHANGE... "
|
|
|
|
"newSelChangeData=%s",
|
2015-09-08 06:54:14 +03:00
|
|
|
this, SelectionChangeDataToString(newSelChangeData).get()));
|
|
|
|
|
2015-06-17 04:03:57 +03:00
|
|
|
IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE);
|
2017-06-29 14:46:11 +03:00
|
|
|
notification.SetData(observer->mSelectionData);
|
2015-09-16 11:48:24 +03:00
|
|
|
|
2017-06-29 14:46:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(observer->mSendingNotification == NOTIFY_IME_OF_NOTHING);
|
|
|
|
observer->mSendingNotification = NOTIFY_IME_OF_SELECTION_CHANGE;
|
|
|
|
IMEStateManager::NotifyIME(notification, observer->mWidget);
|
|
|
|
observer->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
2015-09-08 06:54:14 +03:00
|
|
|
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendSelectionChange(), sent NOTIFY_IME_OF_SELECTION_CHANGE",
|
|
|
|
this));
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
void IMEContentObserver::IMENotificationSender::SendTextChange() {
|
2017-06-29 14:46:11 +03:00
|
|
|
RefPtr<IMEContentObserver> observer = GetObserver();
|
|
|
|
if (!observer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
if (!CanNotifyIME(eChangeEventType_Text)) {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(
|
|
|
|
sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendTextChange(), FAILED, due to impossible to notify IME of text "
|
|
|
|
"change",
|
|
|
|
this));
|
|
|
|
return;
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
if (!IsSafeToNotifyIME(eChangeEventType_Text)) {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendTextChange(), retrying to send NOTIFY_IME_OF_TEXT_CHANGE...",
|
|
|
|
this));
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->PostTextChangeNotification();
|
2015-09-16 11:48:24 +03:00
|
|
|
return;
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2017-04-13 08:32:12 +03:00
|
|
|
// If text change notification is unnecessary anymore, just cancel it.
|
2017-06-29 14:46:11 +03:00
|
|
|
if (!observer->NeedsTextChangeNotification()) {
|
2017-04-13 08:32:12 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Warning,
|
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
|
|
|
"SendTextChange(), canceling sending NOTIFY_IME_OF_TEXT_CHANGE",
|
|
|
|
this));
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->CancelNotifyingIMEOfTextChange();
|
2017-04-13 08:32:12 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Info,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendTextChange(), sending NOTIFY_IME_OF_TEXT_CHANGE... "
|
|
|
|
"mIMEContentObserver={ mTextChangeData=%s }",
|
2017-06-29 14:46:11 +03:00
|
|
|
this, TextChangeDataToString(observer->mTextChangeData).get()));
|
2015-09-08 06:54:14 +03:00
|
|
|
|
2015-06-17 04:03:57 +03:00
|
|
|
IMENotification notification(NOTIFY_IME_OF_TEXT_CHANGE);
|
2017-06-29 14:46:11 +03:00
|
|
|
notification.SetData(observer->mTextChangeData);
|
|
|
|
observer->mTextChangeData.Clear();
|
2015-09-16 11:48:24 +03:00
|
|
|
|
2017-06-29 14:46:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(observer->mSendingNotification == NOTIFY_IME_OF_NOTHING);
|
|
|
|
observer->mSendingNotification = NOTIFY_IME_OF_TEXT_CHANGE;
|
|
|
|
IMEStateManager::NotifyIME(notification, observer->mWidget);
|
|
|
|
observer->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
2015-09-08 06:54:14 +03:00
|
|
|
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendTextChange(), sent NOTIFY_IME_OF_TEXT_CHANGE",
|
|
|
|
this));
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
void IMEContentObserver::IMENotificationSender::SendPositionChange() {
|
2017-06-29 14:46:11 +03:00
|
|
|
RefPtr<IMEContentObserver> observer = GetObserver();
|
|
|
|
if (!observer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
if (!CanNotifyIME(eChangeEventType_Position)) {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendPositionChange(), FAILED, due to impossible to notify IME of "
|
|
|
|
"position change",
|
|
|
|
this));
|
|
|
|
return;
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
if (!IsSafeToNotifyIME(eChangeEventType_Position)) {
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendPositionChange(), retrying to send "
|
|
|
|
"NOTIFY_IME_OF_POSITION_CHANGE...",
|
|
|
|
this));
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->PostPositionChangeNotification();
|
2015-09-16 11:48:24 +03:00
|
|
|
return;
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2017-04-13 08:32:12 +03:00
|
|
|
// If position change notification is unnecessary anymore, just cancel it.
|
2017-06-29 14:46:11 +03:00
|
|
|
if (!observer->NeedsPositionChangeNotification()) {
|
2017-04-13 08:32:12 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Warning,
|
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
|
|
|
"SendPositionChange(), canceling sending "
|
|
|
|
"NOTIFY_IME_OF_POSITION_CHANGE",
|
|
|
|
this));
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->CancelNotifyingIMEOfPositionChange();
|
2017-04-13 08:32:12 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-08 06:54:14 +03:00
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Info,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendPositionChange(), sending NOTIFY_IME_OF_POSITION_CHANGE...",
|
|
|
|
this));
|
2015-09-08 06:54:14 +03:00
|
|
|
|
2017-06-29 14:46:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(observer->mSendingNotification == NOTIFY_IME_OF_NOTHING);
|
|
|
|
observer->mSendingNotification = NOTIFY_IME_OF_POSITION_CHANGE;
|
2015-06-27 03:23:31 +03:00
|
|
|
IMEStateManager::NotifyIME(IMENotification(NOTIFY_IME_OF_POSITION_CHANGE),
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->mWidget);
|
|
|
|
observer->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
2015-09-08 06:54:14 +03:00
|
|
|
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
2015-09-16 11:48:24 +03:00
|
|
|
"SendPositionChange(), sent NOTIFY_IME_OF_POSITION_CHANGE",
|
|
|
|
this));
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
void IMEContentObserver::IMENotificationSender::SendCompositionEventHandled() {
|
2017-06-29 14:46:11 +03:00
|
|
|
RefPtr<IMEContentObserver> observer = GetObserver();
|
|
|
|
if (!observer) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
if (!CanNotifyIME(eChangeEventType_CompositionEventHandled)) {
|
|
|
|
MOZ_LOG(
|
|
|
|
sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
"SendCompositionEventHandled(), FAILED, due to impossible to notify "
|
|
|
|
"IME of composition event handled",
|
|
|
|
this));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IsSafeToNotifyIME(eChangeEventType_CompositionEventHandled)) {
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
"SendCompositionEventHandled(), retrying to send "
|
|
|
|
"NOTIFY_IME_OF_POSITION_CHANGE...",
|
|
|
|
this));
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->PostCompositionEventHandledNotification();
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Info,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
"SendCompositionEventHandled(), sending "
|
|
|
|
"NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED...",
|
|
|
|
this));
|
2018-11-30 13:46:48 +03:00
|
|
|
|
2017-06-29 14:46:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(observer->mSendingNotification == NOTIFY_IME_OF_NOTHING);
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
observer->mSendingNotification = NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED;
|
|
|
|
IMEStateManager::NotifyIME(
|
|
|
|
IMENotification(NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED),
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->mWidget);
|
|
|
|
observer->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Debug,
|
2016-07-05 12:58:16 +03:00
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
Bug 1275906 part.2 TextComposition should use IMEContentObserver for sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED if the editor which has the composition is in the active IMEContentObserver r=smaug
For sending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED after the other change notifications which was caused by the user input, we need to use IMEContentObserver::IMENotificationSender because it sends the notifications when it's safe to do it.
This patch makes TextComposition use IMEContentObserver to send the notification. However, if there is no active IMEContentObserver, e.g., composition events are fired on unfocused window, TextComposition sends it by itself (same as current implementation).
If IMEContentObserver stops observing when it has pending NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED, it cannot send the notification (i.e., it is discarded completely in such case). However, in such case, IMEContentObserver sends NOTIFY_IME_OF_BLUR. So, anyway, native IME handler should treat the blur notification as it including NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED.
On the other hand, we're buggy if composition events are fired in non-active window. Even in such case, IMEContentObserver should be created for active editor in each document and it notifies IME of the changes. But this is out of the scope of this bug.
MozReview-Commit-ID: 7Q0ZsJTh4hX
--HG--
extra : rebase_source : 6417f991fa8c0fbe3f25b27bacf4257e5485aecc
2016-06-01 16:14:41 +03:00
|
|
|
"SendCompositionEventHandled(), sent "
|
|
|
|
"NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED",
|
|
|
|
this));
|
|
|
|
}
|
|
|
|
|
2017-06-08 05:21:28 +03:00
|
|
|
/******************************************************************************
|
|
|
|
* mozilla::IMEContentObserver::DocumentObservingHelper
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(IMEContentObserver::DocumentObserver)
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IMEContentObserver::DocumentObserver)
|
|
|
|
// StopObserving() releases mIMEContentObserver and mDocument.
|
|
|
|
tmp->StopObserving();
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IMEContentObserver::DocumentObserver)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIMEContentObserver)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IMEContentObserver::DocumentObserver)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF(IMEContentObserver::DocumentObserver)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE(IMEContentObserver::DocumentObserver)
|
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
void IMEContentObserver::DocumentObserver::Observe(Document* aDocument) {
|
2017-06-08 05:21:28 +03:00
|
|
|
MOZ_ASSERT(aDocument);
|
|
|
|
|
|
|
|
// Guarantee that aDocument won't be destroyed during a call of
|
|
|
|
// StopObserving().
|
2019-01-02 16:05:23 +03:00
|
|
|
RefPtr<Document> newDocument = aDocument;
|
2017-06-08 05:21:28 +03:00
|
|
|
|
|
|
|
StopObserving();
|
|
|
|
|
|
|
|
mDocument = newDocument.forget();
|
|
|
|
mDocument->AddObserver(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::DocumentObserver::StopObserving() {
|
|
|
|
if (!IsObserving()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Grab IMEContentObserver which could be destroyed during method calls.
|
|
|
|
RefPtr<IMEContentObserver> observer = mIMEContentObserver.forget();
|
|
|
|
|
|
|
|
// Stop observing the document first.
|
2019-01-02 16:05:23 +03:00
|
|
|
RefPtr<Document> document = mDocument.forget();
|
2017-06-08 05:21:28 +03:00
|
|
|
document->RemoveObserver(this);
|
|
|
|
|
|
|
|
// Notify IMEContentObserver of ending of document updates if this already
|
|
|
|
// notified it of beginning of document updates.
|
|
|
|
for (; IsUpdating(); --mDocumentUpdating) {
|
|
|
|
// FYI: IsUpdating() returns true until mDocumentUpdating becomes 0.
|
|
|
|
// However, IsObserving() returns false now because mDocument was
|
|
|
|
// already cleared above. Therefore, this method won't be called
|
|
|
|
// recursively.
|
|
|
|
observer->EndDocumentUpdate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IMEContentObserver::DocumentObserver::Destroy() {
|
|
|
|
StopObserving();
|
|
|
|
mIMEContentObserver = nullptr;
|
|
|
|
}
|
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
void IMEContentObserver::DocumentObserver::BeginUpdate(Document* aDocument) {
|
2017-06-08 05:21:28 +03:00
|
|
|
if (NS_WARN_IF(Destroyed()) || NS_WARN_IF(!IsObserving())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mDocumentUpdating++;
|
|
|
|
mIMEContentObserver->BeginDocumentUpdate();
|
|
|
|
}
|
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
void IMEContentObserver::DocumentObserver::EndUpdate(Document* aDocument) {
|
2017-06-08 05:21:28 +03:00
|
|
|
if (NS_WARN_IF(Destroyed()) || NS_WARN_IF(!IsObserving()) ||
|
|
|
|
NS_WARN_IF(!IsUpdating())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mDocumentUpdating--;
|
|
|
|
mIMEContentObserver->EndDocumentUpdate();
|
|
|
|
}
|
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
} // namespace mozilla
|