import from UXP: Issue #2135 - Bug 1066965: Make contentEditable and spellchecking to work in Shadow DOM (010db07b)

This commit is contained in:
2023-03-07 09:49:18 +08:00
parent 9f1361118b
commit df33d59d4e
10 changed files with 60 additions and 30 deletions
+4 -3
View File
@@ -1695,10 +1695,11 @@ Element::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
if (!hadParent) {
uint32_t editableDescendantChange = EditableInclusiveDescendantCount(this);
if (editableDescendantChange != 0) {
// If we are binding a subtree root to the document, we need to update
// the editable descendant count of all the ancestors.
// If we are binding a subtree root to the document, we need to update
// the editable descendant count of all the ancestors. However, we don't
// cross the Shadow DOM boundary (expected behavior is unclear).
nsIContent* parent = GetParent();
while (parent) {
while (parent && parent->IsElement()) {
parent->ChangeEditableDescendantCount(editableDescendantChange);
parent = parent->GetParent();
}
+12
View File
@@ -270,6 +270,18 @@ nsINode* nsINode::GetRootNode(const GetRootNodeOptions& aOptions)
return SubtreeRoot();
}
// TODO: was marked as constant.
nsINode*
nsINode::GetParentOrHostNode()
{
if (mParent) {
return mParent;
}
ShadowRoot* shadowRoot = ShadowRoot::FromNode(this);
return shadowRoot ? shadowRoot->GetHost() : nullptr;
}
nsINode*
nsINode::SubtreeRoot() const
{
+6
View File
@@ -941,6 +941,12 @@ public:
return mParent;
}
/**
* This is similar to above, but in case 'this' is ShadowRoot, we return its
* host element.
*/
nsINode* GetParentOrHostNode();
/**
* Returns the node that is the parent of this node in the flattened
* tree. This differs from the normal parent if the node is filtered
+12 -11
View File
@@ -463,7 +463,7 @@ nsGenericHTMLElement::IntrinsicState() const
uint32_t
nsGenericHTMLElement::EditableInclusiveDescendantCount()
{
bool isEditable = IsInUncomposedDoc() && HasFlag(NODE_IS_EDITABLE) &&
bool isEditable = IsInComposedDoc() && HasFlag(NODE_IS_EDITABLE) &&
GetContentEditableValue() == eTrue;
return EditableDescendantCount() + isEditable;
}
@@ -484,12 +484,14 @@ nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
aDocument->
AddToNameTable(this, GetParsedAttr(nsGkAtoms::name)->GetAtomValue());
}
}
if (HasFlag(NODE_IS_EDITABLE) && GetContentEditableValue() == eTrue) {
nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(aDocument);
if (htmlDocument) {
htmlDocument->ChangeContentEditableCount(this, +1);
}
if (HasFlag(NODE_IS_EDITABLE) && GetContentEditableValue() == eTrue &&
IsInComposedDoc()) {
nsCOMPtr<nsIHTMLDocument> htmlDocument =
do_QueryInterface(GetComposedDoc());
if (htmlDocument) {
htmlDocument->ChangeContentEditableCount(this, +1);
}
}
@@ -514,8 +516,7 @@ nsGenericHTMLElement::UnbindFromTree(bool aDeep, bool aNullParent)
RemoveFromNameTable();
if (GetContentEditableValue() == eTrue) {
//XXXsmaug Fix this for Shadow DOM, bug 1066965.
nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(GetUncomposedDoc());
nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(GetComposedDoc());
if (htmlDocument) {
htmlDocument->ChangeContentEditableCount(this, -1);
}
@@ -2742,8 +2743,7 @@ MakeContentDescendantsEditable(nsIContent *aContent, nsIDocument *aDocument)
void
nsGenericHTMLElement::ChangeEditableState(int32_t aChange)
{
//XXXsmaug Fix this for Shadow DOM, bug 1066965.
nsIDocument* document = GetUncomposedDoc();
nsIDocument* document = GetComposedDoc();
if (!document) {
return;
}
@@ -2756,7 +2756,8 @@ nsGenericHTMLElement::ChangeEditableState(int32_t aChange)
}
nsIContent* parent = GetParent();
while (parent) {
// Don't update across Shadow DOM boundary.
while (parent && parent->IsElement()) {
parent->ChangeEditableDescendantCount(aChange);
parent = parent->GetParent();
}
+1 -1
View File
@@ -683,7 +683,7 @@ nsEditorSpellCheck::UpdateCurrentDictionary(nsIEditorSpellCheckCallback* aCallba
RefPtr<DictionaryFetcher> fetcher =
new DictionaryFetcher(this, aCallback, mDictionaryFetcherGroup);
rootContent->GetLang(fetcher->mRootContentLang);
nsCOMPtr<nsIDocument> doc = rootContent->GetUncomposedDoc();
nsCOMPtr<nsIDocument> doc = rootContent->GetComposedDoc();
NS_ENSURE_STATE(doc);
doc->GetContentLanguage(fetcher->mRootDocContentLang);
+4 -2
View File
@@ -1114,7 +1114,7 @@ EditorEventListener::Focus(WidgetEvent* aFocusEvent)
return NS_OK;
}
nsCOMPtr<nsIDOMEventTarget> target = aFocusEvent->GetDOMEventTarget();
nsCOMPtr<nsIDOMEventTarget> target = aFocusEvent->GetOriginalDOMEventTarget();
nsCOMPtr<nsINode> node = do_QueryInterface(target);
NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
@@ -1126,13 +1126,15 @@ EditorEventListener::Focus(WidgetEvent* aFocusEvent)
}
if (node->IsNodeOfType(nsINode::eCONTENT)) {
nsIContent* content =
node->AsContent()->FindFirstNonChromeOnlyAccessContent();
// XXX If the focus event target is a form control in contenteditable
// element, perhaps, the parent HTML editor should do nothing by this
// handler. However, FindSelectionRoot() returns the root element of the
// contenteditable editor. So, the editableRoot value is invalid for
// the plain text editor, and it will be set to the wrong limiter of
// the selection. However, fortunately, actual bugs are not found yet.
nsCOMPtr<nsIContent> editableRoot = editorBase->FindSelectionRoot(node);
nsCOMPtr<nsIContent> editableRoot = editorBase->FindSelectionRoot(content);
// make sure that the element is really focused in case an earlier
// listener in the chain changed the focus.
+2 -2
View File
@@ -8028,7 +8028,7 @@ HTMLEditRules::ConfirmSelectionInBody()
// check that selNode is inside body
while (temp && !temp->IsHTMLElement(nsGkAtoms::body)) {
temp = temp->GetParentNode();
temp = temp->GetParentOrHostNode();
}
// if we aren't in the body, force the issue
@@ -8047,7 +8047,7 @@ HTMLEditRules::ConfirmSelectionInBody()
// check that selNode is inside body
while (temp && !temp->IsHTMLElement(nsGkAtoms::body)) {
temp = temp->GetParentNode();
temp = temp->GetParentOrHostNode();
}
// if we aren't in the body, force the issue
+8 -3
View File
@@ -382,13 +382,14 @@ HTMLEditor::FindSelectionRoot(nsINode* aNode)
aNode->IsNodeOfType(nsINode::eCONTENT),
"aNode must be content or document node");
nsCOMPtr<nsIDocument> doc = aNode->GetUncomposedDoc();
nsCOMPtr<nsIDocument> doc = aNode->GetComposedDoc();
if (!doc) {
return nullptr;
}
nsCOMPtr<nsIContent> content;
if (doc->HasFlag(NODE_IS_EDITABLE) || !aNode->IsContent()) {
if (aNode->IsInUncomposedDoc() &&
doc->HasFlag(NODE_IS_EDITABLE) || !aNode->IsContent()) {
content = doc->GetRootElement();
return content.forget();
}
@@ -5088,7 +5089,11 @@ HTMLEditor::IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent)
return true;
}
nsCOMPtr<nsIDOMEventTarget> target = aGUIEvent->GetDOMEventTarget();
nsCOMPtr<nsIDOMEventTarget> target = aGUIEvent->GetOriginalDOMEventTarget();
nsCOMPtr<nsIContent> content = do_QueryInterface(target);
if (content) {
target = content->FindFirstNonChromeOnlyAccessContent();
}
NS_ENSURE_TRUE(target, false);
nsCOMPtr<nsIDocument> document = GetDocument();
@@ -1483,8 +1483,9 @@ nsresult mozInlineSpellChecker::DoSpellCheck(mozInlineSpellWordUtil& aWordUtil,
// Now check that we're still looking at a range that's under
// aWordUtil.GetRootNode()
nsINode* rootNode = aWordUtil.GetRootNode();
if (!nsContentUtils::ContentIsDescendantOf(beginNode, rootNode) ||
!nsContentUtils::ContentIsDescendantOf(endNode, rootNode)) {
if (!beginNode->IsInComposedDoc() || !endNode->IsInComposedDoc() ||
!nsContentUtils::ContentIsShadowIncludingDescendantOf(beginNode, rootNode) ||
!nsContentUtils::ContentIsShadowIncludingDescendantOf(endNode, rootNode)) {
// Just bail out and don't try to spell-check this
return NS_OK;
}
+8 -6
View File
@@ -3683,10 +3683,11 @@ CompareToRangeStart(nsINode* aCompareNode, int32_t aCompareOffset,
{
nsINode* start = aRange->GetStartParent();
NS_ENSURE_STATE(aCompareNode && start);
// If the nodes that we're comparing are not in the same document,
// assume that aCompareNode will fall at the end of the ranges.
// If the nodes that we're comparing are not in the same document or in the
// same subtree, assume that aCompareNode will fall at the end of the ranges.
if (aCompareNode->GetComposedDoc() != start->GetComposedDoc() ||
!start->GetComposedDoc()) {
!start->GetComposedDoc() ||
aCompareNode->SubtreeRoot() != start->SubtreeRoot()) {
*aCmp = 1;
} else {
*aCmp = nsContentUtils::ComparePoints(aCompareNode, aCompareOffset,
@@ -3701,10 +3702,11 @@ CompareToRangeEnd(nsINode* aCompareNode, int32_t aCompareOffset,
{
nsINode* end = aRange->GetEndParent();
NS_ENSURE_STATE(aCompareNode && end);
// If the nodes that we're comparing are not in the same document,
// assume that aCompareNode will fall at the end of the ranges.
// If the nodes that we're comparing are not in the same document or in the
// same subtree, assume that aCompareNode will fall at the end of the ranges.
if (aCompareNode->GetComposedDoc() != end->GetComposedDoc() ||
!end->GetComposedDoc()) {
!end->GetComposedDoc() ||
aCompareNode->SubtreeRoot() != end->SubtreeRoot()) {
*aCmp = 1;
} else {
*aCmp = nsContentUtils::ComparePoints(aCompareNode, aCompareOffset,