Bug 805306 Get rid of nsIMEStateManager::OnTextStateBlur() and nsIMEStateManager::OnTextStateFocus() r=smaug

This commit is contained in:
Masayuki Nakano 2012-10-26 09:49:13 +09:00
Родитель 1664ce8a89
Коммит 10ada00346
5 изменённых файлов: 158 добавлений и 110 удалений

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

@ -40,6 +40,41 @@
using namespace mozilla;
using namespace mozilla::widget;
// nsTextStateManager notifies widget of any text and selection changes
// in the currently focused editor
// sTextStateObserver points to the currently active nsTextStateManager
// sTextStateObserver is null if there is no focused editor
class nsTextStateManager MOZ_FINAL : public nsISelectionListener,
public nsStubMutationObserver
{
public:
nsTextStateManager();
NS_DECL_ISUPPORTS
NS_DECL_NSISELECTIONLISTENER
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
nsresult Init(nsIWidget* aWidget,
nsPresContext* aPresContext,
nsINode* aNode,
bool aWantUpdates);
void Destroy(void);
bool IsManaging(nsPresContext* aPresContext, nsIContent* aContent);
nsCOMPtr<nsIWidget> mWidget;
nsCOMPtr<nsISelection> mSel;
nsCOMPtr<nsIContent> mRootContent;
nsCOMPtr<nsINode> mEditableNode;
bool mDestroying;
private:
void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
};
/******************************************************************/
/* nsIMEStateManager */
/******************************************************************/
@ -88,7 +123,7 @@ nsIMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
}
NS_IF_RELEASE(sContent);
sPresContext = nullptr;
OnTextStateBlur(nullptr, nullptr);
DestroyTextStateManager();
return NS_OK;
}
@ -148,6 +183,7 @@ nsIMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
NS_IF_RELEASE(sContent);
sPresContext = nullptr;
DestroyTextStateManager();
return NS_OK;
}
@ -166,7 +202,14 @@ nsIMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
nsIContent* aContent,
InputContextAction aAction)
{
NS_ENSURE_ARG_POINTER(aPresContext);
if (sTextStateObserver &&
!sTextStateObserver->IsManaging(aPresContext, aContent)) {
DestroyTextStateManager();
}
if (!aPresContext) {
return NS_OK;
}
nsCOMPtr<nsIWidget> widget = aPresContext->GetNearestWidget();
if (!widget) {
@ -235,6 +278,9 @@ nsIMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
NS_IF_ADDREF(sContent = aContent);
}
// Don't call CreateTextStateManager() here, it should be called from
// focus event handler of editor.
return NS_OK;
}
@ -288,6 +334,17 @@ nsIMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
SetIMEState(newState, aContent, widget, action);
}
void
nsIMEStateManager::OnFocusInEditor(nsPresContext* aPresContext,
nsIContent* aContent)
{
if (sPresContext != aPresContext || sContent != aContent) {
return;
}
CreateTextStateManager();
}
void
nsIMEStateManager::UpdateIMEState(const IMEState &aNewIMEState,
nsIContent* aContent)
@ -311,9 +368,13 @@ nsIMEStateManager::UpdateIMEState(const IMEState &aNewIMEState,
// commit current composition
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, widget);
DestroyTextStateManager();
InputContextAction action(InputContextAction::CAUSE_UNKNOWN,
InputContextAction::FOCUS_NOT_CHANGED);
SetIMEState(aNewIMEState, aContent, widget, action);
CreateTextStateManager();
}
IMEState
@ -587,41 +648,6 @@ nsIMEStateManager::NotifyIME(NotificationToIME aNotification,
return NotifyIME(aNotification, widget);
}
// nsTextStateManager notifies widget of any text and selection changes
// in the currently focused editor
// sTextStateObserver points to the currently active nsTextStateManager
// sTextStateObserver is null if there is no focused editor
class nsTextStateManager MOZ_FINAL : public nsISelectionListener,
public nsStubMutationObserver
{
public:
nsTextStateManager();
NS_DECL_ISUPPORTS
NS_DECL_NSISELECTIONLISTENER
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
nsresult Init(nsIWidget* aWidget,
nsPresContext* aPresContext,
nsINode* aNode,
bool aWantUpdates);
void Destroy(void);
nsCOMPtr<nsIWidget> mWidget;
nsCOMPtr<nsISelection> mSel;
nsCOMPtr<nsIContent> mRootContent;
nsCOMPtr<nsINode> mEditableNode;
bool mDestroying;
private:
void NotifyContentAdded(nsINode* aContainer, int32_t aStart, int32_t aEnd);
};
nsTextStateManager::nsTextStateManager()
{
mDestroying = false;
@ -712,6 +738,15 @@ nsTextStateManager::Destroy(void)
mWidget = nullptr;
}
bool
nsTextStateManager::IsManaging(nsPresContext* aPresContext,
nsIContent* aContent)
{
return !mDestroying &&
mEditableNode == nsIMEStateManager::GetRootEditableNode(aPresContext,
aContent);
}
NS_IMPL_ISUPPORTS2(nsTextStateManager,
nsIMutationObserver,
nsISelectionListener)
@ -867,7 +902,9 @@ nsTextStateManager::ContentRemoved(nsIDocument* aDocument,
new TextChangeEvent(mWidget, offset, offset + childOffset, offset));
}
static bool IsEditable(nsINode* node) {
bool
nsIMEStateManager::IsEditable(nsINode* node)
{
if (node->IsEditable()) {
return true;
}
@ -878,8 +915,9 @@ static bool IsEditable(nsINode* node) {
return false;
}
static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
nsIContent* aContent)
nsINode*
nsIMEStateManager::GetRootEditableNode(nsPresContext* aPresContext,
nsIContent* aContent)
{
if (aContent) {
nsINode* root = nullptr;
@ -898,68 +936,71 @@ static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
return nullptr;
}
nsresult
nsIMEStateManager::OnTextStateBlur(nsPresContext* aPresContext,
nsIContent* aContent)
void
nsIMEStateManager::DestroyTextStateManager()
{
if (!sTextStateObserver || sTextStateObserver->mDestroying ||
sTextStateObserver->mEditableNode ==
GetRootEditableNode(aPresContext, aContent))
return NS_OK;
if (!sTextStateObserver || sTextStateObserver->mDestroying) {
return;
}
sTextStateObserver->mDestroying = true;
sTextStateObserver->mWidget->OnIMEFocusChange(false);
sTextStateObserver->Destroy();
NS_RELEASE(sTextStateObserver);
return NS_OK;
}
nsresult
nsIMEStateManager::OnTextStateFocus(nsPresContext* aPresContext,
nsIContent* aContent)
void
nsIMEStateManager::CreateTextStateManager()
{
if (sTextStateObserver) return NS_OK;
nsINode *editableNode = GetRootEditableNode(aPresContext, aContent);
if (!editableNode) return NS_OK;
nsIPresShell* shell = aPresContext->GetPresShell();
NS_ENSURE_TRUE(shell, NS_ERROR_NOT_AVAILABLE);
nsIViewManager* vm = shell->GetViewManager();
NS_ENSURE_TRUE(vm, NS_ERROR_NOT_AVAILABLE);
nsCOMPtr<nsIWidget> widget;
nsresult rv = vm->GetRootWidget(getter_AddRefs(widget));
NS_ENSURE_SUCCESS(rv, NS_ERROR_NOT_AVAILABLE);
if (!widget) {
return NS_OK; // Sometimes, there are no widgets.
if (sTextStateObserver) {
NS_WARNING("text state observer has been there already");
MOZ_ASSERT(sTextStateObserver->IsManaging(sPresContext, sContent));
return;
}
rv = widget->OnIMEFocusChange(true);
nsCOMPtr<nsIWidget> widget = sPresContext->GetNearestWidget();
if (!widget) {
return; // Sometimes, there are no widgets.
}
// If it's not text ediable, we don't need to create nsTextStateManager.
switch (widget->GetInputContext().mIMEState.mEnabled) {
case widget::IMEState::ENABLED:
case widget::IMEState::PASSWORD:
break;
default:
return;
}
nsINode *editableNode = GetRootEditableNode(sPresContext, sContent);
if (!editableNode) {
return;
}
nsresult rv = widget->OnIMEFocusChange(true);
if (rv == NS_ERROR_NOT_IMPLEMENTED)
return NS_OK;
NS_ENSURE_SUCCESS(rv, rv);
return;
NS_ENSURE_SUCCESS_VOID(rv);
bool wantUpdates = rv != NS_SUCCESS_IME_NO_UPDATES;
// OnIMEFocusChange may cause focus and sTextStateObserver to change
// In that case return and keep the current sTextStateObserver
NS_ENSURE_TRUE(!sTextStateObserver, NS_OK);
NS_ENSURE_TRUE_VOID(!sTextStateObserver);
sTextStateObserver = new nsTextStateManager();
NS_ENSURE_TRUE(sTextStateObserver, NS_ERROR_OUT_OF_MEMORY);
NS_ENSURE_TRUE_VOID(sTextStateObserver);
NS_ADDREF(sTextStateObserver);
rv = sTextStateObserver->Init(widget, aPresContext,
rv = sTextStateObserver->Init(widget, sPresContext,
editableNode, wantUpdates);
if (NS_FAILED(rv)) {
sTextStateObserver->mDestroying = true;
sTextStateObserver->Destroy();
NS_RELEASE(sTextStateObserver);
widget->OnIMEFocusChange(false);
return rv;
if (NS_SUCCEEDED(rv)) {
return;
}
return NS_OK;
sTextStateObserver->mDestroying = true;
sTextStateObserver->Destroy();
NS_RELEASE(sTextStateObserver);
widget->OnIMEFocusChange(false);
}
nsresult

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

@ -29,6 +29,7 @@ class TextCompositionArray;
class nsIMEStateManager
{
friend class nsTextStateManager;
protected:
typedef mozilla::widget::IMEState IMEState;
typedef mozilla::widget::InputContext InputContext;
@ -42,8 +43,8 @@ public:
nsIContent* aContent);
/**
* OnChangeFocus() should be called when focused content is changed or
* IME enabled state is changed. If focus isn't actually changed and IME
* enabled state isn't changed, this will do nothing.
* IME enabled state is changed. If nobody has focus, set both aPresContext
* and aContent nullptr. E.g., all windows are deactivated.
*/
static nsresult OnChangeFocus(nsPresContext* aPresContext,
nsIContent* aContent,
@ -54,17 +55,6 @@ public:
// They are separate from OnChangeFocus above because this offers finer
// control compared to having the two methods incorporated into OnChangeFocus
// OnTextStateBlur should be called *before* NS_BLUR_CONTENT fires
// aPresContext is the nsPresContext receiving focus (not lost focus)
// aContent is the nsIContent receiving focus (not lost focus)
// aPresContext and/or aContent may be null
static nsresult OnTextStateBlur(nsPresContext* aPresContext,
nsIContent* aContent);
// OnTextStateFocus should be called *after* NS_FOCUS_CONTENT fires
// aPresContext is the nsPresContext receiving focus
// aContent is the nsIContent receiving focus
static nsresult OnTextStateFocus(nsPresContext* aPresContext,
nsIContent* aContent);
// Get the focused editor's selection and root
static nsresult GetFocusSelectionAndRoot(nsISelection** aSel,
nsIContent** aRoot);
@ -84,6 +74,14 @@ public:
nsIContent* aContent,
nsIDOMMouseEvent* aMouseEvent);
// This method is called when editor actually gets focus.
// aContent must be:
// If the editor is for <input> or <textarea>, the element.
// If the editor is for contenteditable, the active editinghost.
// If the editor is for designMode, NULL.
static void OnFocusInEditor(nsPresContext* aPresContext,
nsIContent* aContent);
/**
* All DOM composition events and DOM text events must be dispatched via
* DispatchCompositionEvent() for storing the composition target
@ -118,6 +116,12 @@ protected:
nsIContent* aContent);
static void EnsureTextCompositionArray();
static void CreateTextStateManager();
static void DestroyTextStateManager();
static bool IsEditable(nsINode* node);
static nsINode* GetRootEditableNode(nsPresContext* aPresContext,
nsIContent* aContent);
static nsIContent* sContent;
static nsPresContext* sPresContext;

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

@ -953,10 +953,11 @@ nsFocusManager::WindowHidden(nsIDOMWindow* aWindow)
}
}
nsIMEStateManager::OnTextStateBlur(nullptr, nullptr);
nsPresContext* focusedPresContext =
presShell ? presShell->GetPresContext() : nullptr;
nsIMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
GetFocusMoveActionCause(0));
if (presShell) {
nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nullptr,
GetFocusMoveActionCause(0));
SetCaretVisible(presShell, false, nullptr);
}
@ -1535,14 +1536,10 @@ nsFocusManager::Blur(nsPIDOMWindow* aWindowToClear,
clearFirstBlurEvent = true;
}
// if there is still an active window, adjust the IME state.
// This has to happen before the focus is cleared below, otherwise, the IME
// compositionend event won't get fired at the element being blurred.
nsIMEStateManager::OnTextStateBlur(nullptr, nullptr);
if (mActiveWindow) {
nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nullptr,
GetFocusMoveActionCause(0));
}
nsPresContext* focusedPresContext =
mActiveWindow ? presShell->GetPresContext() : nullptr;
nsIMEStateManager::OnChangeFocus(focusedPresContext, nullptr,
GetFocusMoveActionCause(0));
// now adjust the actual focus, by clearing the fields in the focus manager
// and in the window.
@ -1815,10 +1812,7 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
aContent->GetCurrentDoc(),
aContent, aFlags & FOCUSMETHOD_MASK,
aWindowRaised, isRefocus);
nsIMEStateManager::OnTextStateFocus(presContext, aContent);
} else {
nsIMEStateManager::OnTextStateBlur(presContext, nullptr);
nsIMEStateManager::OnChangeFocus(presContext, nullptr,
GetFocusMoveActionCause(aFlags));
if (!aWindowRaised) {
@ -1843,7 +1837,6 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
}
nsPresContext* presContext = presShell->GetPresContext();
nsIMEStateManager::OnTextStateBlur(presContext, nullptr);
nsIMEStateManager::OnChangeFocus(presContext, nullptr,
GetFocusMoveActionCause(aFlags));

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

@ -314,8 +314,8 @@ nsEditor::PostCreate()
NS_ENSURE_TRUE(ps, NS_ERROR_UNEXPECTED);
nsPresContext* pc = ps->GetPresContext();
nsIMEStateManager::OnTextStateBlur(pc, nullptr);
nsIMEStateManager::OnTextStateFocus(pc, focusedContent);
nsIMEStateManager::OnChangeFocus(pc, focusedContent,
InputContextAction::CAUSE_UNKNOWN);
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(focusedContent);
if (target) {

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

@ -901,6 +901,16 @@ nsEditorEventListener::Focus(nsIDOMEvent* aEvent)
}
mEditor->OnFocus(target);
nsCOMPtr<nsIContent> focusedContent = mEditor->GetFocusedContent();
NS_ENSURE_TRUE(focusedContent, NS_OK);
nsIDocument* currentDoc = focusedContent->GetCurrentDoc();
NS_ENSURE_TRUE(currentDoc, NS_OK);
nsCOMPtr<nsIPresShell> ps = GetPresShell();
NS_ENSURE_TRUE(ps, NS_OK);
nsIMEStateManager::OnFocusInEditor(ps->GetPresContext(),
currentDoc->HasFlag(NODE_IS_EDITABLE) ? nullptr : focusedContent);
return NS_OK;
}