зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1623918 - part 1: Make `nsINode::GetTextEditorRootContent()` handle `TextControlElement` after stopping climbing the DOM tree up r=smaug
It was designed for retrieving associated `TextEditor` and its root content (anonymous `<div>` element) if the node is in native anonymous subtree in a text editor or if the node itself is a `TextControlElement`. Additionally, `TextControlElement` cannot be nested. Therefore, it can stop climbing up the DOM tree when it meets a `TextControlElement`. Then, we can rewrite this without a loop implemented by itself. Instead, it can use `GetClosestNativeAnonymousSubtreeRootParent()` when the node is in native anonymous subtree. Otherwise, it just needs to check whether it's a `TextControlElement` or not. Therefore, we can make it stop using `InclusiveAncestorsOfType`. Finally, it calls `TextControlElement::GetTextEditor()` which is marked as `MOZ_CAN_RUN_SCRIPT`. And I think that it may cause running selection listeners (mutation event listeners won't run because changes occur only in the native anonymous subtree). Therefore, we should mark all callers of it with `MOZ_CAN_RUN_SCRIPT` later. Differential Revision: https://phabricator.services.mozilla.com/D92728
This commit is contained in:
Родитель
fb7e5d1499
Коммит
235177bdeb
|
@ -0,0 +1,16 @@
|
|||
<html>
|
||||
<head>
|
||||
<script>
|
||||
window.addEventListener('load', () => {
|
||||
const anchor = document.getElementById('id_7')
|
||||
anchor.contentEditable = 'true'
|
||||
anchor.spellcheck = false
|
||||
const input = document.createElementNS('http://www.w3.org/1999/xhtml', 'input')
|
||||
anchor.appendChild(input)
|
||||
const selection = self.getSelection()
|
||||
selection.selectAllChildren(input)
|
||||
})
|
||||
</script>
|
||||
</head>
|
||||
<a id='id_7'></a>
|
||||
</html>
|
|
@ -256,5 +256,6 @@ load eventSource_invalid_scheme_worker_shutdown.html
|
|||
load 1291535.html
|
||||
skip-if(!isDebugBuild||xulRuntime.OS!="Linux") load 1611853.html
|
||||
load 1619322.html
|
||||
asserts(0-1) load 1623918.html # May hit an assertion if the <input> element's anonymous tree hasn't been flushed when IMEContentObserver handles focus
|
||||
load 1656925.html
|
||||
skip-if(Android) load 1665792.html # Print preview on android doesn't fly
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "mozilla/PresShell.h"
|
||||
#include "mozilla/ServoBindings.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/TextControlElement.h"
|
||||
#include "mozilla/TextEditor.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/dom/BindContext.h"
|
||||
|
@ -388,25 +389,37 @@ bool nsINode::IsSelected(const uint32_t aStartOffset,
|
|||
return false;
|
||||
}
|
||||
|
||||
nsIContent* nsINode::GetTextEditorRootContent(TextEditor** aTextEditor) {
|
||||
Element* nsINode::GetAnonymousRootElementOfTextEditor(
|
||||
TextEditor** aTextEditor) {
|
||||
if (aTextEditor) {
|
||||
*aTextEditor = nullptr;
|
||||
}
|
||||
for (auto* element : InclusiveAncestorsOfType<nsGenericHTMLElement>()) {
|
||||
RefPtr<TextEditor> textEditor = element->GetTextEditorInternal();
|
||||
if (!textEditor) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!textEditor->AsHTMLEditor(),
|
||||
"If it were an HTML editor, needs to use GetRootElement()");
|
||||
Element* rootElement = textEditor->GetRoot();
|
||||
if (aTextEditor) {
|
||||
textEditor.forget(aTextEditor);
|
||||
}
|
||||
return rootElement;
|
||||
RefPtr<TextControlElement> textControlElement;
|
||||
if (IsInNativeAnonymousSubtree()) {
|
||||
textControlElement = TextControlElement::FromNodeOrNull(
|
||||
GetClosestNativeAnonymousSubtreeRootParent());
|
||||
} else {
|
||||
textControlElement = TextControlElement::FromNode(this);
|
||||
}
|
||||
return nullptr;
|
||||
if (!textControlElement) {
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<TextEditor> textEditor = textControlElement->GetTextEditor();
|
||||
if (!textEditor) {
|
||||
// The found `TextControlElement` may be an input element which is not a
|
||||
// text control element. In this case, such element must not be in a
|
||||
// native anonymous tree of a `TextEditor` so this node is not in any
|
||||
// `TextEditor`.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!textEditor->IsHTMLEditor(),
|
||||
"If it were an HTML editor, needs to use GetRootElement()");
|
||||
Element* rootElement = textEditor->GetRoot();
|
||||
if (aTextEditor) {
|
||||
textEditor.forget(aTextEditor);
|
||||
}
|
||||
return rootElement;
|
||||
}
|
||||
|
||||
nsINode* nsINode::GetRootNode(const GetRootNodeOptions& aOptions) {
|
||||
|
@ -524,8 +537,10 @@ nsIContent* nsINode::GetSelectionRootContent(PresShell* aPresShell) {
|
|||
|
||||
if (AsContent()->HasIndependentSelection()) {
|
||||
// This node should be a descendant of input/textarea editor.
|
||||
nsIContent* content = GetTextEditorRootContent();
|
||||
if (content) return content;
|
||||
Element* anonymousDivElement = GetAnonymousRootElementOfTextEditor();
|
||||
if (anonymousDivElement) {
|
||||
return anonymousDivElement;
|
||||
}
|
||||
}
|
||||
|
||||
nsPresContext* presContext = aPresShell->GetPresContext();
|
||||
|
|
|
@ -1426,11 +1426,16 @@ class nsINode : public mozilla::dom::EventTarget {
|
|||
bool IsSelected(uint32_t aStartOffset, uint32_t aEndOffset) const;
|
||||
|
||||
/**
|
||||
* Get the root content of an editor. So, this node must be a descendant of
|
||||
* an editor. Note that this should be only used for getting input or textarea
|
||||
* editor's root content. This method doesn't support HTML editors.
|
||||
* Get the root element of the text editor associated with this node or the
|
||||
* root element of the text editor of the ancestor 'TextControlElement' if
|
||||
* this is in its native anonymous subtree. I.e., this returns anonymous
|
||||
* `<div>` element of a `TextEditor`. Note that this can be used only for
|
||||
* getting root content of `<input>` or `<textarea>`. I.e., this method
|
||||
* doesn't support HTML editors. Note that this may create a `TextEditor`
|
||||
* instance, and it means that the `TextEditor` may modify its native
|
||||
* anonymous subtree and may run selection listeners.
|
||||
*/
|
||||
nsIContent* GetTextEditorRootContent(
|
||||
MOZ_CAN_RUN_SCRIPT mozilla::dom::Element* GetAnonymousRootElementOfTextEditor(
|
||||
mozilla::TextEditor** aTextEditor = nullptr);
|
||||
|
||||
/**
|
||||
|
@ -1441,7 +1446,8 @@ class nsINode : public mozilla::dom::EventTarget {
|
|||
* node. Be aware that if this node and the computed selection limiter are
|
||||
* not in same subtree, this returns the root content of the closeset subtree.
|
||||
*/
|
||||
nsIContent* GetSelectionRootContent(mozilla::PresShell* aPresShell);
|
||||
MOZ_CAN_RUN_SCRIPT_BOUNDARY nsIContent* GetSelectionRootContent(
|
||||
mozilla::PresShell* aPresShell);
|
||||
|
||||
nsINodeList* ChildNodes();
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче