Bug 1167022 part.2 IMEStateManager::UpdateIMEState() should try to restart to observe focused editor when it's reframed r=smaug+nchen

This commit is contained in:
Masayuki Nakano 2015-05-26 16:45:26 +09:00
parent 2af6616c71
commit f9ae17caea
4 changed files with 75 additions and 21 deletions

View File

@ -105,8 +105,7 @@ IMEContentObserver::Init(nsIWidget* aWidget,
{
MOZ_ASSERT(aEditor, "aEditor must not be null");
bool firstInitialization =
!(mRootContent && !mRootContent->IsInComposedDoc());
bool firstInitialization = GetState() != eState_StoppedObserving;
if (!firstInitialization) {
// If this is now trying to initialize with new contents, all observers
// should be registered again for simpler implementation.
@ -307,16 +306,47 @@ IMEContentObserver::DisconnectFromEventStateManager()
mESM = nullptr;
}
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);
}
bool
IMEContentObserver::IsManaging(nsPresContext* aPresContext,
nsIContent* aContent)
{
return GetState() == eState_Observing &&
IsObservingContent(aPresContext, aContent);
}
IMEContentObserver::State
IMEContentObserver::GetState() const
{
if (!mSelection || !mRootContent || !mEditableNode) {
return false; // failed to initialize.
return eState_NotObserving; // failed to initialize or finalized.
}
if (!mRootContent->IsInComposedDoc()) {
return false; // the focused editor has already been reframed.
// the focused editor has already been reframed.
return eState_StoppedObserving;
}
return eState_Observing;
}
bool
IMEContentObserver::IsObservingContent(nsPresContext* aPresContext,
nsIContent* aContent) const
{
return mEditableNode == IMEStateManager::GetRootEditableNode(aPresContext,
aContent);
}

View File

@ -72,6 +72,17 @@ public:
* storing the instance.
*/
void DisconnectFromEventStateManager();
/**
* MaybeReinitialize() tries to restart to observe the editor's root node.
* This is useful when the editor is reframed and all children are replaced
* with new node instances.
* @return Returns true if the instance is managing the content.
* Otherwise, false.
*/
bool MaybeReinitialize(nsIWidget* aWidget,
nsPresContext* aPresContext,
nsIContent* aContent,
nsIEditor* aEditor);
bool IsManaging(nsPresContext* aPresContext, nsIContent* aContent);
bool IsEditorHandlingEventForComposition() const;
bool KeepAliveDuringDeactive() const
@ -133,6 +144,14 @@ public:
private:
~IMEContentObserver() {}
enum State {
eState_NotObserving,
eState_StoppedObserving,
eState_Observing
};
State GetState() const;
bool IsObservingContent(nsPresContext* aPresContext,
nsIContent* aContent) const;
void MaybeNotifyIMEOfTextChange(const TextChangeData& aTextChangeData);
void MaybeNotifyIMEOfSelectionChange(bool aCausedByComposition);
void MaybeNotifyIMEOfPositionChange();

View File

@ -649,9 +649,23 @@ IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
return;
}
// If the IMEContentObserver instance isn't managing the editor's current
// editable root content, the editor frame might be reframed. We should
// recreate the instance at that time.
// Even if there is active IMEContentObserver, it may not be observing the
// editor with current editable root content due to reframed. In such case,
// We should try to reinitialize the IMEContentObserver.
if (sActiveIMEContentObserver && IsIMEObserverNeeded(aNewIMEState)) {
PR_LOG(sISMLog, PR_LOG_DEBUG,
("ISM: IMEStateManager::UpdateIMEState(), try to reinitialize the "
"active IMEContentObserver"));
if (!sActiveIMEContentObserver->MaybeReinitialize(widget, sPresContext,
aContent, aEditor)) {
PR_LOG(sISMLog, PR_LOG_ERROR,
("ISM: IMEStateManager::UpdateIMEState(), failed to reinitialize the "
"active IMEContentObserver"));
}
}
// If there is no active IMEContentObserver or it isn't observing the
// editor correctly, we should recreate it.
bool createTextStateManager =
(!sActiveIMEContentObserver ||
!sActiveIMEContentObserver->IsManaging(sPresContext, aContent));
@ -1128,18 +1142,9 @@ IMEStateManager::GetRootEditableNode(nsPresContext* aPresContext,
// static
bool
IMEStateManager::IsEditableIMEState(nsIWidget* aWidget)
IMEStateManager::IsIMEObserverNeeded(const IMEState& aState)
{
switch (aWidget->GetInputContext().mIMEState.mEnabled) {
case IMEState::ENABLED:
case IMEState::PASSWORD:
return true;
case IMEState::PLUGIN:
case IMEState::DISABLED:
return false;
default:
MOZ_CRASH("Unknown IME enable state");
}
return aState.IsEditable();
}
// static
@ -1193,8 +1198,8 @@ IMEStateManager::CreateIMEContentObserver(nsIEditor* aEditor)
return; // Sometimes, there are no widgets.
}
// If it's not text ediable, we don't need to create IMEContentObserver.
if (!IsEditableIMEState(widget)) {
// If it's not text editable, we don't need to create IMEContentObserver.
if (!IsIMEObserverNeeded(widget->GetInputContext().mIMEState)) {
MOZ_LOG(sISMLog, PR_LOG_DEBUG,
("ISM: IMEStateManager::CreateIMEContentObserver() doesn't create "
"IMEContentObserver because of non-editable IME state"));

View File

@ -157,7 +157,7 @@ protected:
static bool IsEditable(nsINode* node);
static bool IsEditableIMEState(nsIWidget* aWidget);
static bool IsIMEObserverNeeded(const IMEState& aState);
static nsIContent* sContent;
static nsPresContext* sPresContext;