Bug 1218032 part.4 Notify IMEContentObserver of enough safe timing to notify IME of something r=smaug

This commit is contained in:
Masayuki Nakano 2015-11-10 11:49:05 +09:00
Родитель 0727f7951c
Коммит 8973128bba
8 изменённых файлов: 97 добавлений и 9 удалений

Просмотреть файл

@ -26,6 +26,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=976673
SimpleTest.waitForExplicitFinish();
// In e10s mode, ContentCacheInChild tries to retrieve selected text and
// caret position when IMEContentObserver notifies IME of focus. At this time,
// we hit assertion in nsContentIterator.
SimpleTest.expectAssertions(0, 6);
window.addEventListener("mousedown", function (aEvent) { aEvent.preventDefault(); }, false);
function testSetFocus(aEventType, aCallback)

Просмотреть файл

@ -473,6 +473,14 @@ EventStateManager::OnStopObservingContent(
mIMEContentObserver = nullptr;
}
void
EventStateManager::TryToFlushPendingNotificationsToIME()
{
if (mIMEContentObserver) {
mIMEContentObserver->TryToFlushPendingNotifications();
}
}
nsresult
EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
WidgetEvent* aEvent,

Просмотреть файл

@ -146,6 +146,12 @@ public:
void OnStartToObserveContent(IMEContentObserver* aIMEContentObserver);
void OnStopObservingContent(IMEContentObserver* aIMEContentObserver);
/**
* TryToFlushPendingNotificationsToIME() suggests flushing pending
* notifications to IME to IMEContentObserver.
*/
void TryToFlushPendingNotificationsToIME();
/**
* Register accesskey on the given element. When accesskey is activated then
* the element will be notified via nsIContent::PerformAccesskey() method.

Просмотреть файл

@ -1395,6 +1395,19 @@ IMEContentObserver::FlushMergeableNotifications()
"finished", this));
}
void
IMEContentObserver::TryToFlushPendingNotifications()
{
if (!mQueuedSender || mSendingNotification != NOTIFY_IME_OF_NOTHING) {
return;
}
MOZ_LOG(sIMECOLog, LogLevel::Debug,
("IMECO: 0x%p IMEContentObserver::TryToFlushPendingNotifications(), "
"performing queued IMENotificationSender forcibly", this));
mQueuedSender->Run();
}
/******************************************************************************
* mozilla::IMEContentObserver::AChangeEvent
******************************************************************************/
@ -1461,7 +1474,20 @@ IMEContentObserver::AChangeEvent::IsSafeToNotifyIME(
NS_IMETHODIMP
IMEContentObserver::IMENotificationSender::Run()
{
MOZ_ASSERT(mIMEContentObserver->mQueuedSender);
if (NS_WARN_IF(mIsRunning)) {
MOZ_LOG(sIMECOLog, LogLevel::Error,
("IMECO: 0x%p IMEContentObserver::IMENotificationSender::Run(), FAILED, "
"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;
}
// NOTE: Reset each pending flag because sending notification may cause
// another change.

Просмотреть файл

@ -103,6 +103,12 @@ public:
nsresult GetSelectionAndRoot(nsISelection** aSelection,
nsIContent** aRoot) const;
/**
* TryToFlushPendingNotifications() should be called when pending events
* should be flushed. This tries to run the queued IMENotificationSender.
*/
void TryToFlushPendingNotifications();
private:
~IMEContentObserver() {}
@ -223,6 +229,7 @@ private:
public:
explicit IMENotificationSender(IMEContentObserver* aIMEContentObserver)
: AChangeEvent(aIMEContentObserver)
, mIsRunning(false)
{
}
NS_IMETHOD Run() override;
@ -232,6 +239,8 @@ private:
void SendSelectionChange();
void SendTextChange();
void SendPositionChange();
bool mIsRunning;
};
// mQueuedSender is, it was put into the event queue but not run yet.

Просмотреть файл

@ -515,6 +515,13 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
// editor.
if (newState.mEnabled == IMEState::PLUGIN) {
CreateIMEContentObserver(nullptr);
if (sActiveIMEContentObserver) {
MOZ_LOG(sISMLog, LogLevel::Debug,
("ISM: IMEStateManager::OnChangeFocusInternal(), an "
"IMEContentObserver instance is created for plugin and trying to "
"flush its pending notifications..."));
sActiveIMEContentObserver->TryToFlushPendingNotifications();
}
}
return NS_OK;
@ -684,6 +691,14 @@ IMEStateManager::OnFocusInEditor(nsPresContext* aPresContext,
}
CreateIMEContentObserver(aEditor);
// Let's flush the focus notification now.
if (sActiveIMEContentObserver) {
MOZ_LOG(sISMLog, LogLevel::Debug,
("ISM: IMEStateManager::OnFocusInEditor(), new IMEContentObserver is "
"created, trying to flush pending notifications..."));
sActiveIMEContentObserver->TryToFlushPendingNotifications();
}
}
// static
@ -797,6 +812,9 @@ IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
}
if (createTextStateManager) {
// XXX In this case, it might not be enough safe to notify IME of anything.
// So, don't try to flush pending notifications of IMEContentObserver
// here.
CreateIMEContentObserver(aEditor);
}
}

Просмотреть файл

@ -6988,7 +6988,7 @@ PresShell::HandleEvent(nsIFrame* aFrame,
aFrame = targetContent->GetPrimaryFrame();
if (!aFrame) {
PushCurrentEventInfo(aFrame, targetContent);
nsresult rv = HandleEventInternal(aEvent, aEventStatus);
nsresult rv = HandleEventInternal(aEvent, aEventStatus, true);
PopCurrentEventInfo();
return rv;
}
@ -7645,7 +7645,7 @@ PresShell::HandleEvent(nsIFrame* aFrame,
mCurrentEventFrame = frame;
}
if (GetCurrentEventFrame()) {
rv = HandleEventInternal(aEvent, aEventStatus);
rv = HandleEventInternal(aEvent, aEventStatus, true);
}
#ifdef DEBUG
@ -7658,7 +7658,7 @@ PresShell::HandleEvent(nsIFrame* aFrame,
if (!NS_EVENT_NEEDS_FRAME(aEvent)) {
mCurrentEventFrame = nullptr;
return HandleEventInternal(aEvent, aEventStatus);
return HandleEventInternal(aEvent, aEventStatus, true);
}
else if (aEvent->HasKeyEventMessage()) {
// Keypress events in new blank tabs should not be completely thrown away.
@ -7761,7 +7761,7 @@ PresShell::HandlePositionedEvent(nsIFrame* aTargetFrame,
}
if (GetCurrentEventFrame()) {
rv = HandleEventInternal(aEvent, aEventStatus);
rv = HandleEventInternal(aEvent, aEventStatus, true);
}
#ifdef DEBUG
@ -7787,13 +7787,15 @@ PresShell::HandleEventWithTarget(WidgetEvent* aEvent, nsIFrame* aFrame,
NS_ENSURE_STATE(!aContent || aContent->GetCrossShadowCurrentDoc() == mDocument);
PushCurrentEventInfo(aFrame, aContent);
nsresult rv = HandleEventInternal(aEvent, aStatus);
nsresult rv = HandleEventInternal(aEvent, aStatus, false);
PopCurrentEventInfo();
return rv;
}
nsresult
PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus)
PresShell::HandleEventInternal(WidgetEvent* aEvent,
nsEventStatus* aStatus,
bool aIsHandlingNativeEvent)
{
RefPtr<EventStateManager> manager = mPresContext->EventStateManager();
nsresult rv = NS_OK;
@ -7939,6 +7941,14 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus)
}
}
if (!mIsDestroying && aIsHandlingNativeEvent) {
// Ensure that notifications to IME should be sent before getting next
// native event from the event queue.
// XXX Should we check the event message or event class instead of
// using aIsHandlingNativeEvent?
manager->TryToFlushPendingNotificationsToIME();
}
switch (aEvent->mMessage) {
case eKeyPress:
case eKeyDown:

Просмотреть файл

@ -580,7 +580,7 @@ protected:
mCurrentEventContent = aTarget;
nsresult rv = NS_OK;
if (GetCurrentEventFrame()) {
rv = HandleEventInternal(aEvent, aStatus);
rv = HandleEventInternal(aEvent, aStatus, true);
}
PopCurrentEventInfo();
return rv;
@ -669,8 +669,14 @@ protected:
nsEventStatus* aEventStatus);
void PushCurrentEventInfo(nsIFrame* aFrame, nsIContent* aContent);
void PopCurrentEventInfo();
/**
* @param aIsHandlingNativeEvent true when the caller (perhaps) handles
* an event which is caused by native
* event. Otherwise, false.
*/
nsresult HandleEventInternal(mozilla::WidgetEvent* aEvent,
nsEventStatus* aStatus);
nsEventStatus* aStatus,
bool aIsHandlingNativeEvent);
nsresult HandlePositionedEvent(nsIFrame* aTargetFrame,
mozilla::WidgetGUIEvent* aEvent,
nsEventStatus* aEventStatus);