tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit c20c1d810978ac4c7240a88a11fd212396c80f1a
parent c8bb56ecc8e65c3a742bc5efadbe31f18e65a610
Author: Masayuki Nakano <masayuki@d-toybox.com>
Date:   Mon,  1 Dec 2025 23:03:12 +0000

Bug 2001825 - Make `IMEStateManager::OnReFocus()` stop asserting editable state r=m_kato

`Element.focus()` may be called while the element does not have a
primary frame.  Then, its `TextControlState` does not create
`TextEditor` without a bound frame [1] because an element which is
completely invisible (e.g., `display:none`) should not have
`TextEditor`.  Therefore, `GetDesiredIMEState()` of
`nsGenericHTMLFormControlElement` delegates to `nsIContent`'s and return
`IMEEnabled::Disabled`.  Finally, `IMEStateManager::OnReFocus()`
asserts the editable state [2] and may fail.

Fortunately, `TextEditor` will be reinialized after a reframe of the
text control element. Then, `EditorBase` will update IME state to make
it available [3]. So, `IMEStateManager::OnReFocus()` does not need to
assert it at the moment.

1. https://searchfox.org/firefox-main/rev/f6e3ccb5853c46f917578697a488d48c3bc09ac8/dom/html/TextControlState.cpp#1662-1666
2. https://searchfox.org/firefox-main/rev/f6e3ccb5853c46f917578697a488d48c3bc09ac8/dom/events/IMEStateManager.cpp#1312
3. https://searchfox.org/firefox-main/rev/f6e3ccb5853c46f917578697a488d48c3bc09ac8/editor/libeditor/EditorBase.cpp#469-470,475

Differential Revision: https://phabricator.services.mozilla.com/D274385

Diffstat:
Mdom/events/IMEStateManager.cpp | 75++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mdom/html/TextControlState.h | 3+++
2 files changed, 73 insertions(+), 5 deletions(-)

diff --git a/dom/events/IMEStateManager.cpp b/dom/events/IMEStateManager.cpp @@ -43,6 +43,7 @@ #include "nsIURI.h" #include "nsIURIMutator.h" #include "nsPresContext.h" +#include "nsTextControlFrame.h" #include "nsThreadUtils.h" namespace mozilla { @@ -678,6 +679,14 @@ nsresult IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext, BrowserParent::GetFocused(), sActiveIMEContentObserver.get(), TrueOrFalse(sInstalledMenuKeyboardListener), TrueOrFalse(sIsActive), TrueOrFalse(restoringContextForRemoteContent))); + if (aElement) { + MOZ_LOG(sISMLog, LogLevel::Debug, + (" aElement: %s", ToString(*aElement).c_str())); + } + if (sFocusedElement) { + MOZ_LOG(sISMLog, LogLevel::Debug, + (" sFocusedElement: %s", ToString(*sFocusedElement).c_str())); + } sIsActive = !!aPresContext; if (sPendingFocusedBrowserSwitchingData.isSome()) { @@ -1173,6 +1182,14 @@ void IMEStateManager::OnFocusInEditor(nsPresContext& aPresContext, &aPresContext, TrueOrFalse(CanHandleWith(&aPresContext)), aElement, &aEditorBase, sFocusedPresContext.get(), sFocusedElement.get(), sActiveIMEContentObserver.get())); + if (aElement) { + MOZ_LOG(sISMLog, LogLevel::Debug, + (" aElement: %s", ToString(*aElement).c_str())); + } + if (sFocusedElement) { + MOZ_LOG(sISMLog, LogLevel::Debug, + (" sFocusedElement: %s", ToString(*sFocusedElement).c_str())); + } if (!IsFocusedElement(aPresContext, aElement)) { MOZ_LOG(sISMLog, LogLevel::Debug, @@ -1266,9 +1283,15 @@ void IMEStateManager::OnReFocus(nsPresContext& aPresContext, Element& aElement) { MOZ_LOG(sISMLog, LogLevel::Info, ("OnReFocus(aPresContext=0x%p (available: %s), aElement=0x%p), " - "sActiveIMEContentObserver=0x%p, aElement=0x%p", + "sActiveIMEContentObserver=0x%p, sFocusedElement=0x%p", &aPresContext, TrueOrFalse(CanHandleWith(&aPresContext)), &aElement, sActiveIMEContentObserver.get(), sFocusedElement.get())); + MOZ_LOG(sISMLog, LogLevel::Debug, + (" aElement: %s", ToString(aElement).c_str())); + if (sFocusedElement) { + MOZ_LOG(sISMLog, LogLevel::Debug, + (" sFocusedElement: %s", ToString(*sFocusedElement).c_str())); + } if (NS_WARN_IF(!sTextInputHandlingWidget) || NS_WARN_IF(sTextInputHandlingWidget->Destroyed())) { @@ -1306,10 +1329,44 @@ void IMEStateManager::OnReFocus(nsPresContext& aPresContext, } } - InputContextAction action(InputContextAction::CAUSE_UNKNOWN, - InputContextAction::FOCUS_NOT_CHANGED); - IMEState newState = GetNewIMEState(aPresContext, &aElement); - MOZ_ASSERT(newState.IsEditable()); + const InputContextAction action(InputContextAction::CAUSE_UNKNOWN, + InputContextAction::FOCUS_NOT_CHANGED); + const IMEState newState = GetNewIMEState(aPresContext, &aElement); + // If aElement has not had a primary frame for it, + if (MOZ_UNLIKELY(!newState.IsEditable())) { + if (sActiveIMEContentObserver->EditorIsTextEditor()) { + TextControlElement* const textControlElement = + TextControlElement::FromNode(aElement); + MOZ_ASSERT(textControlElement); + if (textControlElement && + textControlElement->IsSingleLineTextControlOrTextArea()) { + nsTextControlFrame* const boundFrame = + textControlElement->GetTextControlState()->GetBoundFrame(); + MOZ_ASSERT(!boundFrame); + MOZ_LOG( + sISMLog, LogLevel::Warning, + (" OnReFocus(), Temporarily disabling IME for the focused element " + "because probably the TextControlState could not return " + "TextEditor (textControlFrame: %p, textEditor: %p)", + boundFrame, + textControlElement->GetTextControlState()->GetExtantTextEditor())); + } + } else { + HTMLEditor* const htmlEditor = + nsContentUtils::GetHTMLEditor(&aPresContext); +#ifdef DEBUG + MOZ_ASSERT(htmlEditor); + IMEState state; + MOZ_ASSERT(NS_SUCCEEDED(htmlEditor->GetPreferredIMEState(&state))); + MOZ_ASSERT(!state.IsEditable()); +#endif // #ifdef DEBUG + MOZ_LOG(sISMLog, LogLevel::Warning, + (" OnRefocus(), Disabling IME for the focused element, " + "HTMLEditor=%p { IsReadonly()=%s }", + htmlEditor, + htmlEditor ? TrueOrFalse(htmlEditor->IsReadonly()) : "N/A")); + } + } SetIMEState(newState, &aPresContext, &aElement, textInputHandlingWidget, action, sOrigin); } @@ -1406,6 +1463,14 @@ void IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState, TrueOrFalse(sTextInputHandlingWidget && !sTextInputHandlingWidget->Destroyed()), sActiveIMEContentObserver.get(), TrueOrFalse(sIsGettingNewIMEState))); + if (aElement) { + MOZ_LOG(sISMLog, LogLevel::Debug, + (" aElement: %s", ToString(*aElement).c_str())); + } + if (sFocusedElement) { + MOZ_LOG(sISMLog, LogLevel::Debug, + (" sFocusedElement: %s", ToString(*sFocusedElement).c_str())); + } if (sIsGettingNewIMEState) { MOZ_LOG(sISMLog, LogLevel::Debug, diff --git a/dom/html/TextControlState.h b/dom/html/TextControlState.h @@ -225,6 +225,9 @@ class TextControlState final : public SupportsWeakPtr { nsFrameSelection* GetIndependentFrameSelection() const; nsresult BindToFrame(nsTextControlFrame* aFrame); MOZ_CAN_RUN_SCRIPT void UnbindFromFrame(nsTextControlFrame* aFrame); + [[nodiscard]] nsTextControlFrame* GetBoundFrame() const { + return mBoundFrame; + } MOZ_CAN_RUN_SCRIPT nsresult PrepareEditor(const nsAString* aValue = nullptr); void InitializeKeyboardEventListeners();