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"
|
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"
|
|
|
|
#include "nsIAtom.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIDOMDocument.h"
|
|
|
|
#include "nsIDOMRange.h"
|
|
|
|
#include "nsIFrame.h"
|
|
|
|
#include "nsINode.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsISelectionController.h"
|
|
|
|
#include "nsISelectionPrivate.h"
|
|
|
|
#include "nsISupports.h"
|
|
|
|
#include "nsIWidget.h"
|
|
|
|
#include "nsPresContext.h"
|
2017-06-29 14:46:11 +03:00
|
|
|
#include "nsRefreshDriver.h"
|
2014-03-08 05:20:07 +04:00
|
|
|
#include "nsWeakReference.h"
|
2015-05-15 04:18:08 +03:00
|
|
|
#include "WritingModes.h"
|
2014-03-08 05:20:07 +04:00
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
|
|
|
|
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(nsISelectionListener)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIReflowObserver)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIScrollObserver)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
2014-07-31 08:37:59 +04:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIEditorObserver)
|
2014-04-24 04:36:14 +04:00
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISelectionListener)
|
|
|
|
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-03-08 05:20:07 +04:00
|
|
|
{
|
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,
|
2014-11-05 16:12:44 +03:00
|
|
|
nsIContent* aContent,
|
2017-06-20 13:23:44 +03:00
|
|
|
EditorBase* aEditorBase)
|
2014-03-08 05:20:07 +04:00
|
|
|
{
|
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)
|
2015-10-10 04:21:01 +03:00
|
|
|
{
|
2017-06-20 13:23:44 +03:00
|
|
|
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
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
nsIPresShell* presShell = aPresContext->PresShell();
|
|
|
|
|
|
|
|
// get selection and root content
|
|
|
|
nsCOMPtr<nsISelectionController> selCon;
|
|
|
|
if (mEditableNode->IsNodeOfType(nsINode::eCONTENT)) {
|
|
|
|
nsIFrame* frame =
|
|
|
|
static_cast<nsIContent*>(mEditableNode.get())->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
|
|
|
|
selCon = do_QueryInterface(presShell);
|
|
|
|
}
|
2015-10-10 04:21:01 +03:00
|
|
|
|
|
|
|
if (NS_WARN_IF(!selCon)) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
|
|
|
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
|
2014-03-08 05:20:07 +04:00
|
|
|
getter_AddRefs(mSelection));
|
2015-10-10 04:21:01 +03:00
|
|
|
if (NS_WARN_IF(!mSelection)) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
2017-07-21 05:55:46 +03:00
|
|
|
auto selection = static_cast<mozilla::dom::Selection*>(mSelection.get());
|
|
|
|
if (nsRange* selRange = selection->GetRangeAt(0)) {
|
|
|
|
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()->
|
2014-03-08 05:20:07 +04:00
|
|
|
GetSelectionRootContent(presShell);
|
|
|
|
} else {
|
|
|
|
mRootContent = mEditableNode->GetSelectionRootContent(presShell);
|
|
|
|
}
|
|
|
|
if (!mRootContent && mEditableNode->IsNodeOfType(nsINode::eDOCUMENT)) {
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
selCon->GetSelection(nsISelectionController::SELECTION_NORMAL,
|
|
|
|
getter_AddRefs(mSelection));
|
|
|
|
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) {
|
|
|
|
mEditorBase->AddEditorObserver(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()) {
|
|
|
|
// Add selection change listener only when this starts to observe
|
|
|
|
// non-plugin content since we cannot detect selection changes in
|
|
|
|
// plugins.
|
2014-03-08 05:20:07 +04:00
|
|
|
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSelection));
|
2014-03-08 05:20:07 +04:00
|
|
|
NS_ENSURE_TRUE_VOID(selPrivate);
|
|
|
|
nsresult rv = selPrivate->AddSelectionListener(this);
|
|
|
|
NS_ENSURE_SUCCESS_VOID(rv);
|
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.
|
|
|
|
nsIDocument* doc = mRootContent->GetComposedDoc();
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-05-26 10:45:26 +03:00
|
|
|
IMEContentObserver::NotifyIMEOfBlur()
|
2015-05-24 04:11:37 +03:00
|
|
|
{
|
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) {
|
|
|
|
mEditorBase->RemoveEditorObserver(this);
|
2015-05-24 07:40:21 +03:00
|
|
|
}
|
|
|
|
|
2016-06-28 09:23:12 +03:00
|
|
|
if (mSelection) {
|
2014-03-08 05:20:07 +04:00
|
|
|
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSelection));
|
|
|
|
if (selPrivate) {
|
2014-03-08 05:20:07 +04:00
|
|
|
selPrivate->RemoveSelectionListener(this);
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
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
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
nsresult
|
|
|
|
IMEContentObserver::GetSelectionAndRoot(nsISelection** 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;
|
|
|
|
}
|
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
nsresult
|
2014-03-08 05:20:07 +04:00
|
|
|
IMEContentObserver::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
|
|
|
|
nsISelection* aSelection,
|
2014-03-08 05:20:07 +04:00
|
|
|
int16_t aReason)
|
|
|
|
{
|
|
|
|
int32_t count = 0;
|
2014-03-08 05:20:07 +04:00
|
|
|
nsresult rv = aSelection->GetRangeCount(&count);
|
2014-03-08 05:20:07 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (count > 0 && 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,
|
2015-10-27 01:21:37 +03:00
|
|
|
causedBySelectionEvent,
|
|
|
|
duringComposition);
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-17 10:01:30 +03:00
|
|
|
if (!aMouseEvent->IsTrusted() ||
|
2016-03-22 10:47:52 +03:00
|
|
|
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) {
|
|
|
|
charAtPt.mReply.mRect.MoveBy(
|
2015-02-04 23:21:03 +03:00
|
|
|
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());
|
2014-08-29 14:08:43 +04:00
|
|
|
notification.mMouseButtonEventData.mButton = aMouseEvent->button;
|
|
|
|
notification.mMouseButtonEventData.mButtons = aMouseEvent->buttons;
|
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;
|
|
|
|
}
|
|
|
|
|
2014-07-31 08:38:01 +04:00
|
|
|
void
|
|
|
|
IMEContentObserver::CharacterDataWillChange(nsIDocument* aDocument,
|
|
|
|
nsIContent* aContent,
|
|
|
|
CharacterDataChangeInfo* aInfo)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
|
|
|
|
"character data changed for non-text node");
|
|
|
|
MOZ_ASSERT(mPreCharacterDataChangeLength < 0,
|
|
|
|
"CharacterDataChanged() should've reset "
|
|
|
|
"mPreCharacterDataChangeLength");
|
|
|
|
|
2017-04-13 08:32:12 +03:00
|
|
|
if (!NeedsTextChangeNotification()) {
|
|
|
|
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();
|
|
|
|
|
2014-07-31 08:38:01 +04:00
|
|
|
mPreCharacterDataChangeLength =
|
|
|
|
ContentEventHandler::GetNativeTextLength(aContent, aInfo->mChangeStart,
|
|
|
|
aInfo->mChangeEnd);
|
|
|
|
MOZ_ASSERT(mPreCharacterDataChangeLength >=
|
|
|
|
aInfo->mChangeEnd - aInfo->mChangeStart,
|
|
|
|
"The computed length must be same as or larger than XP length");
|
|
|
|
}
|
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
void
|
|
|
|
IMEContentObserver::CharacterDataChanged(nsIDocument* aDocument,
|
|
|
|
nsIContent* aContent,
|
|
|
|
CharacterDataChangeInfo* aInfo)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
|
|
|
|
"character data changed for non-text node");
|
|
|
|
|
2017-04-13 08:32:12 +03:00
|
|
|
if (!NeedsTextChangeNotification()) {
|
|
|
|
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
|
2014-03-08 05:20:07 +04:00
|
|
|
nsresult rv =
|
2015-12-02 07:20:00 +03:00
|
|
|
ContentEventHandler::GetFlatTextLengthInRange(
|
|
|
|
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
|
|
|
|
2014-07-31 08:38:01 +04:00
|
|
|
uint32_t newLength =
|
|
|
|
ContentEventHandler::GetNativeTextLength(aContent, aInfo->mChangeStart,
|
|
|
|
aInfo->mChangeStart +
|
|
|
|
aInfo->mReplaceLength);
|
|
|
|
|
|
|
|
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)
|
2014-03-08 05:20:07 +04:00
|
|
|
{
|
2017-04-13 08:32:12 +03:00
|
|
|
if (!NeedsTextChangeNotification()) {
|
|
|
|
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),
|
2015-12-02 07:20:00 +03:00
|
|
|
mRootContent, &addingLength,
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMEContentObserver::ContentAppended(nsIDocument* aDocument,
|
|
|
|
nsIContent* aContainer,
|
2017-07-27 16:49:52 +03:00
|
|
|
nsIContent* aFirstNewContent)
|
2014-03-08 05:20:07 +04:00
|
|
|
{
|
2017-09-06 20:47:09 +03:00
|
|
|
NotifyContentAdded(NODE_FROM(aContainer, aDocument),
|
|
|
|
aFirstNewContent, aContainer->GetLastChild());
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMEContentObserver::ContentInserted(nsIDocument* aDocument,
|
|
|
|
nsIContent* aContainer,
|
2017-07-27 16:49:52 +03:00
|
|
|
nsIContent* aChild)
|
2014-03-08 05:20:07 +04:00
|
|
|
{
|
2017-07-27 16:49:52 +03:00
|
|
|
MOZ_ASSERT(aChild);
|
2014-03-08 05:20:07 +04:00
|
|
|
NotifyContentAdded(NODE_FROM(aContainer, aDocument),
|
2017-09-06 20:47:09 +03:00
|
|
|
aChild, aChild);
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMEContentObserver::ContentRemoved(nsIDocument* aDocument,
|
|
|
|
nsIContent* aContainer,
|
|
|
|
nsIContent* aChild,
|
|
|
|
nsIContent* aPreviousSibling)
|
|
|
|
{
|
2017-04-13 08:32:12 +03:00
|
|
|
if (!NeedsTextChangeNotification()) {
|
|
|
|
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
|
|
|
|
2014-07-31 08:38:00 +04:00
|
|
|
nsINode* containerNode = NODE_FROM(aContainer, aDocument);
|
|
|
|
|
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),
|
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))) {
|
|
|
|
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;
|
2015-12-02 07:20:00 +03:00
|
|
|
if (aChild->IsNodeOfType(nsINode::eTEXT)) {
|
|
|
|
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(
|
2015-12-02 07:20:00 +03:00
|
|
|
NodePositionBefore(aChild, 0),
|
2015-12-02 07:20:00 +03:00
|
|
|
NodePosition(aChild, nodeLength),
|
|
|
|
mRootContent, &textLength,
|
2015-12-02 07:20:00 +03:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMEContentObserver::AttributeWillChange(nsIDocument* aDocument,
|
|
|
|
dom::Element* aElement,
|
|
|
|
int32_t aNameSpaceID,
|
|
|
|
nsIAtom* aAttribute,
|
2015-07-25 09:05:19 +03:00
|
|
|
int32_t aModType,
|
|
|
|
const nsAttrValue* aNewValue)
|
2014-03-08 05:20:07 +04:00
|
|
|
{
|
2017-04-13 08:32:12 +03:00
|
|
|
if (!NeedsTextChangeNotification()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-12-02 07:20:00 +03:00
|
|
|
mPreAttrChangeLength =
|
2015-12-02 07:20:00 +03:00
|
|
|
ContentEventHandler::GetNativeTextLengthBefore(aElement, mRootContent);
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMEContentObserver::AttributeChanged(nsIDocument* aDocument,
|
|
|
|
dom::Element* aElement,
|
|
|
|
int32_t aNameSpaceID,
|
|
|
|
nsIAtom* aAttribute,
|
2015-07-25 09:01:19 +03:00
|
|
|
int32_t aModType,
|
|
|
|
const nsAttrValue* aOldValue)
|
2014-03-08 05:20:07 +04:00
|
|
|
{
|
2017-04-13 08:32:12 +03:00
|
|
|
if (!NeedsTextChangeNotification()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-31 08:38:00 +04:00
|
|
|
mEndOfAddedTextCache.Clear();
|
2014-07-31 08:38:00 +04:00
|
|
|
mStartOfRemovingTextRangeCache.Clear();
|
2014-07-31 08:38:00 +04:00
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
uint32_t postAttrChangeLength =
|
2015-12-02 07:20:00 +03:00
|
|
|
ContentEventHandler::GetNativeTextLengthBefore(aElement, mRootContent);
|
2014-03-08 05:20:07 +04:00
|
|
|
if (postAttrChangeLength == mPreAttrChangeLength) {
|
|
|
|
return;
|
2014-03-08 05:20:07 +04:00
|
|
|
}
|
2017-06-08 05:24:58 +03:00
|
|
|
// First, compute text range which were added during a document change.
|
|
|
|
MaybeNotifyIMEOfAddedTextDuringDocumentChange();
|
|
|
|
// Then, compute the new text changed caused by this attribute change.
|
2014-03-08 05:20:07 +04:00
|
|
|
uint32_t start;
|
|
|
|
nsresult rv =
|
2015-12-02 07:20:00 +03:00
|
|
|
ContentEventHandler::GetFlatTextLengthInRange(
|
|
|
|
NodePosition(mRootContent, 0),
|
|
|
|
NodePositionBefore(aElement, 0),
|
|
|
|
mRootContent, &start, 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
|
|
|
|
2014-07-31 08:37:59 +04:00
|
|
|
TextChangeData data(start, start + mPreAttrChangeLength,
|
2016-06-28 10:51:59 +03:00
|
|
|
start + postAttrChangeLength,
|
|
|
|
IsEditorHandlingEventForComposition(),
|
2015-10-27 01:21:37 +03:00
|
|
|
IsEditorComposing());
|
2014-07-31 08:38:00 +04:00
|
|
|
MaybeNotifyIMEOfTextChange(data);
|
2014-07-31 08:37:59 +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));
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
nsIContent*
|
|
|
|
IMEContentObserver::GetChildNode(nsINode* aParent, int32_t aOffset)
|
|
|
|
{
|
|
|
|
if (!aParent->HasChildren() || aOffset < 0 ||
|
|
|
|
aOffset >= static_cast<int32_t>(aParent->Length())) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (!aOffset) {
|
|
|
|
return aParent->GetFirstChild();
|
|
|
|
}
|
|
|
|
if (aOffset == static_cast<int32_t>(aParent->Length() - 1)) {
|
|
|
|
return aParent->GetLastChild();
|
|
|
|
}
|
|
|
|
return aParent->GetChildAt(aOffset);
|
|
|
|
}
|
|
|
|
|
|
|
|
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),
|
2017-06-08 05:24:58 +03:00
|
|
|
mRootContent, &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();
|
|
|
|
}
|
|
|
|
|
2014-07-31 08:37:59 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
IMEContentObserver::EditAction()
|
|
|
|
{
|
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();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
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
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
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();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-06-17 04:03:57 +03:00
|
|
|
void
|
2015-06-17 04:03:57 +03:00
|
|
|
IMEContentObserver::PostFocusSetNotification()
|
2015-06-17 04:03:57 +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::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
|
|
|
}
|
|
|
|
|
2014-07-31 08:38:00 +04:00
|
|
|
void
|
2015-09-16 11:48:23 +03:00
|
|
|
IMEContentObserver::PostTextChangeNotification()
|
2014-07-31 08:38:00 +04: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::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
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-09-14 17:28:43 +03:00
|
|
|
IMEContentObserver::PostSelectionChangeNotification()
|
2014-07-31 08:38:00 +04: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::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(
|
|
|
|
bool aCausedByComposition,
|
2015-10-27 01:21:37 +03:00
|
|
|
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,
|
2015-10-27 01:21:37 +03:00
|
|
|
aCausedBySelectionEvent,
|
|
|
|
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()",
|
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
|
|
|
this));
|
|
|
|
|
|
|
|
PostCompositionEventHandledNotification();
|
|
|
|
FlushMergeableNotifications();
|
|
|
|
}
|
|
|
|
|
2015-08-21 19:43:41 +03:00
|
|
|
bool
|
|
|
|
IMEContentObserver::UpdateSelectionCache()
|
|
|
|
{
|
|
|
|
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);
|
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();
|
|
|
|
}
|
|
|
|
|
2014-07-31 08:38:00 +04:00
|
|
|
void
|
2015-06-17 04:03:57 +03:00
|
|
|
IMEContentObserver::PostPositionChangeNotification()
|
2014-07-31 08:38:00 +04: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::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;
|
|
|
|
}
|
|
|
|
nsIPresShell* presShell = presContext->GetPresShell();
|
|
|
|
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-07-31 08:37:59 +04:00
|
|
|
{
|
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.
|
2017-06-20 13:23:44 +03:00
|
|
|
if (mEditorBase && mEditorBase->IsInEditAction()) {
|
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
|
|
|
|
// has removed node from the tree. In such case, nsContentIterator won't
|
|
|
|
// 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
|
|
|
}
|
|
|
|
|
2015-11-10 05:49:05 +03:00
|
|
|
void
|
2017-08-03 19:36:58 +03:00
|
|
|
IMEContentObserver::TryToFlushPendingNotifications(bool aAllowAsync)
|
2015-11-10 05:49:05 +03:00
|
|
|
{
|
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
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
bool
|
2015-09-16 11:48:24 +03:00
|
|
|
IMEContentObserver::AChangeEvent::CanNotifyIME(
|
|
|
|
ChangeEventType aChangeEventType) const
|
2015-06-17 04:03:57 +03:00
|
|
|
{
|
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-06-17 04:03:57 +03:00
|
|
|
bool
|
2015-09-16 11:48:24 +03:00
|
|
|
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) {
|
|
|
|
RefPtr<nsPresContext> presContext;
|
|
|
|
aDocShell->GetPresContext(getter_AddRefs(presContext));
|
|
|
|
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,
|
2017-06-29 14:46:11 +03:00
|
|
|
queuedSender.forget());
|
|
|
|
} 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-06-17 04:03:57 +03:00
|
|
|
{
|
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();
|
|
|
|
}
|
|
|
|
|
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.
|
2017-06-29 14:46:11 +03:00
|
|
|
if (observer->mNeedsToNotifyIMEOfSelectionChange) {
|
|
|
|
observer->mNeedsToNotifyIMEOfSelectionChange = false;
|
2015-09-16 11:48:24 +03:00
|
|
|
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.
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->UpdateSelectionCache();
|
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 ==
|
2015-09-16 11:48:24 +03:00
|
|
|
NOTIFY_IME_OF_NOTHING);
|
2017-06-29 14:46:11 +03:00
|
|
|
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()
|
2015-06-17 04:03:57 +03:00
|
|
|
{
|
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 ==
|
2015-09-16 11:48:24 +03:00
|
|
|
NOTIFY_IME_OF_NOTHING);
|
2017-06-29 14:46:11 +03:00
|
|
|
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()
|
2015-06-17 04:03:57 +03:00
|
|
|
{
|
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 ==
|
2015-09-16 11:48:24 +03:00
|
|
|
NOTIFY_IME_OF_NOTHING);
|
2017-06-29 14:46:11 +03:00
|
|
|
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()
|
2015-06-17 04:03:57 +03:00
|
|
|
{
|
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 ==
|
2015-09-16 11:48:24 +03:00
|
|
|
NOTIFY_IME_OF_NOTHING);
|
2017-06-29 14:46:11 +03:00
|
|
|
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));
|
|
|
|
|
2017-06-29 14:46:11 +03:00
|
|
|
MOZ_RELEASE_ASSERT(observer->mSendingNotification ==
|
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
|
|
|
NOTIFY_IME_OF_NOTHING);
|
2017-06-29 14:46:11 +03:00
|
|
|
observer->mSendingNotification =
|
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
|
|
|
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)
|
|
|
|
|
|
|
|
void
|
|
|
|
IMEContentObserver::DocumentObserver::Observe(nsIDocument* aDocument)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aDocument);
|
|
|
|
|
|
|
|
// Guarantee that aDocument won't be destroyed during a call of
|
|
|
|
// StopObserving().
|
|
|
|
RefPtr<nsIDocument> newDocument = aDocument;
|
|
|
|
|
|
|
|
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.
|
|
|
|
RefPtr<nsIDocument> document = mDocument.forget();
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMEContentObserver::DocumentObserver::BeginUpdate(nsIDocument* aDocument,
|
|
|
|
nsUpdateType aUpdateType)
|
|
|
|
{
|
|
|
|
if (NS_WARN_IF(Destroyed()) || NS_WARN_IF(!IsObserving())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!(aUpdateType & UPDATE_CONTENT_MODEL)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mDocumentUpdating++;
|
|
|
|
mIMEContentObserver->BeginDocumentUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMEContentObserver::DocumentObserver::EndUpdate(nsIDocument* aDocument,
|
|
|
|
nsUpdateType aUpdateType)
|
|
|
|
{
|
|
|
|
if (NS_WARN_IF(Destroyed()) || NS_WARN_IF(!IsObserving()) ||
|
|
|
|
NS_WARN_IF(!IsUpdating())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!(aUpdateType & UPDATE_CONTENT_MODEL)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mDocumentUpdating--;
|
|
|
|
mIMEContentObserver->EndDocumentUpdate();
|
|
|
|
}
|
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
} // namespace mozilla
|