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"
|
|
|
|
#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"
|
|
|
|
#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";
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
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)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK(mEditor)
|
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)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEditor)
|
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()
|
2014-04-24 04:36:15 +04: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,
|
|
|
|
nsIEditor* aEditor)
|
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();
|
|
|
|
// Clear members which may not be initialized again.
|
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 {
|
|
|
|
if (!InitWithEditor(aPresContext, aContent, aEditor)) {
|
|
|
|
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,
|
|
|
|
nsIEditor* aEditor)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(aEditor);
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-11-05 16:12:44 +03:00
|
|
|
mEditor = aEditor;
|
2015-10-10 04:21:01 +03:00
|
|
|
if (NS_WARN_IF(!mEditor)) {
|
|
|
|
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
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMRange> selDomRange;
|
2014-03-08 05:20:07 +04:00
|
|
|
if (NS_SUCCEEDED(mSelection->GetRangeAt(0, getter_AddRefs(selDomRange)))) {
|
2014-03-08 05:20:07 +04:00
|
|
|
nsRange* selRange = static_cast<nsRange*>(selDomRange.get());
|
2015-10-10 04:21:01 +03:00
|
|
|
if (NS_WARN_IF(!selRange) || NS_WARN_IF(!selRange->GetStartParent())) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-03-08 05:20:07 +04:00
|
|
|
|
|
|
|
mRootContent = selRange->GetStartParent()->
|
|
|
|
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
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2015-10-10 04:21:01 +03:00
|
|
|
mEditor = nullptr;
|
|
|
|
mEditableNode = aContent;
|
|
|
|
mRootContent = aContent;
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
return mDocShell && !mEditor;
|
|
|
|
}
|
|
|
|
|
2015-10-10 04:21:01 +03:00
|
|
|
void
|
|
|
|
IMEContentObserver::Clear()
|
|
|
|
{
|
|
|
|
mEditor = nullptr;
|
|
|
|
mSelection = nullptr;
|
|
|
|
mEditableNode = nullptr;
|
|
|
|
mRootContent = nullptr;
|
|
|
|
mDocShell = 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;
|
2015-10-10 04:21:01 +03:00
|
|
|
if (mEditor) {
|
|
|
|
mEditor->AddEditorObserver(this);
|
|
|
|
}
|
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-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;
|
|
|
|
|
2015-05-26 10:45:26 +03:00
|
|
|
if (mEditor) {
|
|
|
|
mEditor->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-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,
|
|
|
|
nsIEditor* aEditor)
|
|
|
|
{
|
|
|
|
if (!IsObservingContent(aPresContext, aContent)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (GetState() == eState_StoppedObserving) {
|
|
|
|
Init(aWidget, aPresContext, aContent, aEditor);
|
|
|
|
}
|
|
|
|
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.
|
2016-12-20 15:47:31 +03:00
|
|
|
if (NS_WARN_IF(!mEditor)) {
|
2015-10-27 01:21:37 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool isComposing = false;
|
2016-12-20 15:47:31 +03:00
|
|
|
nsresult rv = mEditor->GetComposing(&isComposing);
|
2015-10-27 01:21:37 +03:00
|
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return isComposing;
|
|
|
|
}
|
|
|
|
|
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();
|
|
|
|
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();
|
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,
|
|
|
|
int32_t aStartIndex,
|
|
|
|
int32_t aEndIndex)
|
|
|
|
{
|
2017-04-13 08:32:12 +03:00
|
|
|
if (!NeedsTextChangeNotification()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-31 08:38:00 +04:00
|
|
|
mStartOfRemovingTextRangeCache.Clear();
|
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
uint32_t offset = 0;
|
2014-07-31 08:38:00 +04:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
if (!mEndOfAddedTextCache.Match(aContainer, aStartIndex)) {
|
|
|
|
mEndOfAddedTextCache.Clear();
|
2015-12-02 07:20:00 +03:00
|
|
|
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
|
|
|
NodePosition(mRootContent, 0),
|
2015-12-02 07:20:00 +03:00
|
|
|
NodePositionBefore(aContainer, aStartIndex),
|
|
|
|
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(
|
2015-12-02 07:20:00 +03:00
|
|
|
NodePositionBefore(aContainer, aStartIndex),
|
2015-12-02 07:20:00 +03:00
|
|
|
NodePosition(aContainer, aEndIndex),
|
|
|
|
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.
|
|
|
|
mEndOfAddedTextCache.Cache(aContainer, aEndIndex, 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,
|
|
|
|
nsIContent* aFirstNewContent,
|
|
|
|
int32_t aNewIndexInContainer)
|
|
|
|
{
|
|
|
|
NotifyContentAdded(aContainer, aNewIndexInContainer,
|
|
|
|
aContainer->GetChildCount());
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMEContentObserver::ContentInserted(nsIDocument* aDocument,
|
|
|
|
nsIContent* aContainer,
|
|
|
|
nsIContent* aChild,
|
|
|
|
int32_t aIndexInContainer)
|
|
|
|
{
|
|
|
|
NotifyContentAdded(NODE_FROM(aContainer, aDocument),
|
|
|
|
aIndexInContainer, aIndexInContainer + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMEContentObserver::ContentRemoved(nsIDocument* aDocument,
|
|
|
|
nsIContent* aContainer,
|
|
|
|
nsIContent* aChild,
|
|
|
|
int32_t aIndexInContainer,
|
|
|
|
nsIContent* aPreviousSibling)
|
|
|
|
{
|
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
|
|
|
nsINode* containerNode = NODE_FROM(aContainer, aDocument);
|
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
uint32_t offset = 0;
|
2014-07-31 08:38:00 +04:00
|
|
|
nsresult rv = NS_OK;
|
|
|
|
if (!mStartOfRemovingTextRangeCache.Match(containerNode, aIndexInContainer)) {
|
2015-12-02 07:20:00 +03:00
|
|
|
// At removing a child node of aContainer, we need the line break caused
|
|
|
|
// by open tag of aContainer. Be careful when aIndexInContainer is 0.
|
2015-12-02 07:20:00 +03:00
|
|
|
rv = ContentEventHandler::GetFlatTextLengthInRange(
|
|
|
|
NodePosition(mRootContent, 0),
|
|
|
|
NodePosition(containerNode, aIndexInContainer),
|
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;
|
|
|
|
}
|
|
|
|
mStartOfRemovingTextRangeCache.Cache(containerNode, aIndexInContainer,
|
|
|
|
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
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
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.
|
2014-08-28 18:33:35 +04:00
|
|
|
bool isInEditAction = false;
|
|
|
|
if (mEditor && NS_SUCCEEDED(mEditor->GetIsInEditAction(&isInEditAction)) &&
|
|
|
|
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-03-16 03:11:50 +03:00
|
|
|
nsIScriptGlobalObject* globalObject = mDocShell ?
|
|
|
|
mDocShell->GetScriptGlobalObject() :
|
|
|
|
nullptr;
|
|
|
|
if (globalObject) {
|
|
|
|
RefPtr<IMENotificationSender> queuedSender = mQueuedSender;
|
|
|
|
globalObject->Dispatch(nullptr, TaskCategory::Other, queuedSender.forget());
|
|
|
|
} else {
|
|
|
|
NS_DispatchToCurrentThread(mQueuedSender);
|
|
|
|
}
|
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
|
|
|
|
IMEContentObserver::TryToFlushPendingNotifications()
|
|
|
|
{
|
|
|
|
if (!mQueuedSender || mSendingNotification != NOTIFY_IME_OF_NOTHING) {
|
|
|
|
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
|
|
|
{
|
|
|
|
if (NS_WARN_IF(!mIMEContentObserver)) {
|
|
|
|
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
|
|
|
if (aChangeEventType == eChangeEventType_CompositionEventHandled) {
|
|
|
|
return mIMEContentObserver->mWidget != nullptr;
|
|
|
|
}
|
2015-06-17 04:03:57 +03:00
|
|
|
State state = mIMEContentObserver->GetState();
|
|
|
|
// 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) {
|
2015-06-17 04:03:57 +03:00
|
|
|
return !NS_WARN_IF(mIMEContentObserver->mIMEHasFocus);
|
|
|
|
}
|
|
|
|
// If we've not notified IME of focus yet, we shouldn't notify anything.
|
|
|
|
if (!mIMEContentObserver->mIMEHasFocus) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If IME has focus, IMEContentObserver must hold the widget.
|
|
|
|
MOZ_ASSERT(mIMEContentObserver->mWidget);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2015-09-16 11:48:24 +03:00
|
|
|
// While we're sending a notification, we shouldn't send another notification
|
|
|
|
// recursively.
|
|
|
|
if (mIMEContentObserver->mSendingNotification != NOTIFY_IME_OF_NOTHING) {
|
|
|
|
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 }",
|
|
|
|
this, ToChar(mIMEContentObserver->mSendingNotification)));
|
|
|
|
return false;
|
|
|
|
}
|
2015-06-17 04:03:57 +03:00
|
|
|
State state = mIMEContentObserver->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;
|
|
|
|
}
|
|
|
|
return mIMEContentObserver->IsSafeToNotifyIME();
|
|
|
|
}
|
|
|
|
|
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
|
|
|
******************************************************************************/
|
2015-09-16 11:48:24 +03:00
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
AutoRestore<bool> running(mIsRunning);
|
|
|
|
mIsRunning = true;
|
|
|
|
|
|
|
|
// This instance was already performed forcibly.
|
|
|
|
if (mIMEContentObserver->mQueuedSender != this) {
|
|
|
|
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.
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
if (mIMEContentObserver->mNeedsToNotifyIMEOfFocusSet) {
|
|
|
|
mIMEContentObserver->mNeedsToNotifyIMEOfFocusSet = false;
|
2015-09-16 11:48:24 +03:00
|
|
|
SendFocusSet();
|
2015-11-10 05:49:05 +03:00
|
|
|
mIMEContentObserver->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.
|
|
|
|
if (mIMEContentObserver->mNeedsToNotifyIMEOfFocusSet) {
|
|
|
|
MOZ_ASSERT(!mIMEContentObserver->mIMEHasFocus);
|
|
|
|
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));
|
|
|
|
mIMEContentObserver->mQueuedSender =
|
|
|
|
new IMENotificationSender(mIMEContentObserver);
|
2017-03-16 03:11:50 +03:00
|
|
|
nsIScriptGlobalObject* globalObject =
|
|
|
|
mIMEContentObserver->mDocShell ?
|
|
|
|
mIMEContentObserver->mDocShell->GetScriptGlobalObject() : nullptr;
|
|
|
|
if (globalObject) {
|
|
|
|
RefPtr<IMENotificationSender> queuedSender =
|
|
|
|
mIMEContentObserver->mQueuedSender;
|
|
|
|
globalObject->Dispatch(nullptr, TaskCategory::Other,
|
|
|
|
queuedSender.forget());
|
|
|
|
} else {
|
|
|
|
NS_DispatchToCurrentThread(mIMEContentObserver->mQueuedSender);
|
|
|
|
}
|
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.
|
|
|
|
mIMEContentObserver->ClearPendingNotifications();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
if (mIMEContentObserver->mNeedsToNotifyIMEOfTextChange) {
|
|
|
|
mIMEContentObserver->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.
|
2015-09-16 11:48:24 +03:00
|
|
|
if (!mIMEContentObserver->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.
|
2015-09-16 11:48:24 +03:00
|
|
|
if (mIMEContentObserver->mNeedsToNotifyIMEOfSelectionChange) {
|
|
|
|
mIMEContentObserver->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.
|
2015-09-16 11:48:24 +03:00
|
|
|
if (!mIMEContentObserver->mNeedsToNotifyIMEOfTextChange &&
|
|
|
|
!mIMEContentObserver->mNeedsToNotifyIMEOfSelectionChange) {
|
|
|
|
if (mIMEContentObserver->mNeedsToNotifyIMEOfPositionChange) {
|
|
|
|
mIMEContentObserver->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.
|
|
|
|
if (!mIMEContentObserver->mNeedsToNotifyIMEOfTextChange &&
|
|
|
|
!mIMEContentObserver->mNeedsToNotifyIMEOfSelectionChange &&
|
|
|
|
!mIMEContentObserver->mNeedsToNotifyIMEOfPositionChange) {
|
|
|
|
if (mIMEContentObserver->mNeedsToNotifyIMEOfCompositionEventHandled) {
|
|
|
|
mIMEContentObserver->mNeedsToNotifyIMEOfCompositionEventHandled = false;
|
|
|
|
SendCompositionEventHandled();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-10 05:49:05 +03:00
|
|
|
mIMEContentObserver->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.
|
2015-11-10 05:49:04 +03:00
|
|
|
if (mIMEContentObserver->NeedsToNotifyIMEOfSomething()) {
|
2016-04-19 12:57:13 +03:00
|
|
|
if (mIMEContentObserver->GetState() == eState_StoppedObserving) {
|
|
|
|
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));
|
|
|
|
mIMEContentObserver->mQueuedSender =
|
|
|
|
new IMENotificationSender(mIMEContentObserver);
|
2017-03-16 03:11:50 +03:00
|
|
|
nsIScriptGlobalObject* globalObject =
|
|
|
|
mIMEContentObserver->mDocShell ?
|
|
|
|
mIMEContentObserver->mDocShell->GetScriptGlobalObject() : nullptr;
|
|
|
|
if (globalObject) {
|
|
|
|
RefPtr<IMENotificationSender> queuedSender =
|
|
|
|
mIMEContentObserver->mQueuedSender;
|
|
|
|
globalObject->Dispatch(nullptr, TaskCategory::Other,
|
|
|
|
queuedSender.forget());
|
|
|
|
} else {
|
|
|
|
NS_DispatchToCurrentThread(mIMEContentObserver->mQueuedSender);
|
|
|
|
}
|
2016-04-19 12:57:13 +03:00
|
|
|
}
|
2015-09-16 11:48:24 +03:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IMEContentObserver::IMENotificationSender::SendFocusSet()
|
|
|
|
{
|
|
|
|
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));
|
2015-06-17 04:03:57 +03:00
|
|
|
mIMEContentObserver->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));
|
2015-06-17 04:03:57 +03:00
|
|
|
mIMEContentObserver->PostFocusSetNotification();
|
2015-09-16 11:48:24 +03:00
|
|
|
return;
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2015-06-17 04:03:57 +03:00
|
|
|
mIMEContentObserver->mIMEHasFocus = true;
|
2015-08-21 19:43:42 +03:00
|
|
|
// Initialize selection cache with the first selection data.
|
|
|
|
mIMEContentObserver->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
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mIMEContentObserver->mSendingNotification ==
|
|
|
|
NOTIFY_IME_OF_NOTHING);
|
|
|
|
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_FOCUS;
|
2015-06-27 03:23:31 +03:00
|
|
|
IMEStateManager::NotifyIME(IMENotification(NOTIFY_IME_OF_FOCUS),
|
|
|
|
mIMEContentObserver->mWidget);
|
2015-09-16 11:48:24 +03:00
|
|
|
mIMEContentObserver->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.
|
|
|
|
mIMEContentObserver->OnIMEReceivedFocus();
|
|
|
|
|
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
|
|
|
{
|
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));
|
2015-09-14 17:28:43 +03:00
|
|
|
mIMEContentObserver->PostSelectionChangeNotification();
|
2015-09-16 11:48:24 +03:00
|
|
|
return;
|
2015-06-17 04:03:57 +03:00
|
|
|
}
|
|
|
|
|
2015-08-21 19:43:42 +03:00
|
|
|
SelectionChangeData lastSelChangeData = mIMEContentObserver->mSelectionData;
|
2015-08-21 19:43:41 +03:00
|
|
|
if (NS_WARN_IF(!mIMEContentObserver->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.
|
2016-06-28 10:51:59 +03:00
|
|
|
SelectionChangeData& newSelChangeData = mIMEContentObserver->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);
|
2015-09-14 17:28:43 +03:00
|
|
|
notification.SetData(mIMEContentObserver->mSelectionData);
|
2015-09-16 11:48:24 +03:00
|
|
|
|
|
|
|
MOZ_RELEASE_ASSERT(mIMEContentObserver->mSendingNotification ==
|
|
|
|
NOTIFY_IME_OF_NOTHING);
|
|
|
|
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_SELECTION_CHANGE;
|
2015-06-27 03:23:31 +03:00
|
|
|
IMEStateManager::NotifyIME(notification, mIMEContentObserver->mWidget);
|
2015-09-16 11:48:24 +03:00
|
|
|
mIMEContentObserver->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
|
|
|
{
|
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));
|
2015-09-16 11:48:23 +03:00
|
|
|
mIMEContentObserver->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.
|
|
|
|
if (!mIMEContentObserver->NeedsTextChangeNotification()) {
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Warning,
|
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
|
|
|
"SendTextChange(), canceling sending NOTIFY_IME_OF_TEXT_CHANGE",
|
|
|
|
this));
|
|
|
|
mIMEContentObserver->CancelNotifyingIMEOfTextChange();
|
|
|
|
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 }",
|
2015-09-16 11:48:23 +03:00
|
|
|
this, TextChangeDataToString(mIMEContentObserver->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);
|
2015-09-16 11:48:23 +03:00
|
|
|
notification.SetData(mIMEContentObserver->mTextChangeData);
|
|
|
|
mIMEContentObserver->mTextChangeData.Clear();
|
2015-09-16 11:48:24 +03:00
|
|
|
|
|
|
|
MOZ_RELEASE_ASSERT(mIMEContentObserver->mSendingNotification ==
|
|
|
|
NOTIFY_IME_OF_NOTHING);
|
|
|
|
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_TEXT_CHANGE;
|
2015-06-27 03:23:31 +03:00
|
|
|
IMEStateManager::NotifyIME(notification, mIMEContentObserver->mWidget);
|
2015-09-16 11:48:24 +03:00
|
|
|
mIMEContentObserver->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
|
|
|
{
|
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));
|
2015-06-17 04:03:57 +03:00
|
|
|
mIMEContentObserver->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.
|
|
|
|
if (!mIMEContentObserver->NeedsPositionChangeNotification()) {
|
|
|
|
MOZ_LOG(sIMECOLog, LogLevel::Warning,
|
|
|
|
("0x%p IMEContentObserver::IMENotificationSender::"
|
|
|
|
"SendPositionChange(), canceling sending NOTIFY_IME_OF_POSITION_CHANGE",
|
|
|
|
this));
|
|
|
|
mIMEContentObserver->CancelNotifyingIMEOfPositionChange();
|
|
|
|
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
|
|
|
|
2015-09-16 11:48:24 +03:00
|
|
|
MOZ_RELEASE_ASSERT(mIMEContentObserver->mSendingNotification ==
|
|
|
|
NOTIFY_IME_OF_NOTHING);
|
|
|
|
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_POSITION_CHANGE;
|
2015-06-27 03:23:31 +03:00
|
|
|
IMEStateManager::NotifyIME(IMENotification(NOTIFY_IME_OF_POSITION_CHANGE),
|
|
|
|
mIMEContentObserver->mWidget);
|
2015-09-16 11:48:24 +03:00
|
|
|
mIMEContentObserver->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()
|
|
|
|
{
|
|
|
|
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));
|
|
|
|
mIMEContentObserver->PostCompositionEventHandledNotification();
|
|
|
|
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));
|
|
|
|
|
|
|
|
MOZ_RELEASE_ASSERT(mIMEContentObserver->mSendingNotification ==
|
|
|
|
NOTIFY_IME_OF_NOTHING);
|
|
|
|
mIMEContentObserver->mSendingNotification =
|
|
|
|
NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED;
|
|
|
|
IMEStateManager::NotifyIME(
|
|
|
|
IMENotification(NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED),
|
|
|
|
mIMEContentObserver->mWidget);
|
|
|
|
mIMEContentObserver->mSendingNotification = NOTIFY_IME_OF_NOTHING;
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2014-03-08 05:20:07 +04:00
|
|
|
} // namespace mozilla
|