зеркало из https://github.com/mozilla/gecko-dev.git
Bug 805306 Get rid of nsIMEStateManager::OnTextStateBlur() and nsIMEStateManager::OnTextStateFocus() r=smaug
This commit is contained in:
Родитель
1664ce8a89
Коммит
10ada00346
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче