diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 99120db433..9f579b9c6d 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -1725,10 +1725,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(); } diff --git a/dom/base/nsINode.cpp b/dom/base/nsINode.cpp index 749a3ee4a2..37980db614 100644 --- a/dom/base/nsINode.cpp +++ b/dom/base/nsINode.cpp @@ -273,6 +273,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 { diff --git a/dom/base/nsINode.h b/dom/base/nsINode.h index 1d580540f8..3611a4074d 100644 --- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h @@ -942,6 +942,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 diff --git a/dom/html/nsGenericHTMLElement.cpp b/dom/html/nsGenericHTMLElement.cpp index 0f32d8fb42..da7121a714 100644 --- a/dom/html/nsGenericHTMLElement.cpp +++ b/dom/html/nsGenericHTMLElement.cpp @@ -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 htmlDocument = do_QueryInterface(aDocument); - if (htmlDocument) { - htmlDocument->ChangeContentEditableCount(this, +1); - } + if (HasFlag(NODE_IS_EDITABLE) && GetContentEditableValue() == eTrue && + IsInComposedDoc()) { + nsCOMPtr 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 htmlDocument = do_QueryInterface(GetUncomposedDoc()); + nsCOMPtr htmlDocument = do_QueryInterface(GetComposedDoc()); if (htmlDocument) { htmlDocument->ChangeContentEditableCount(this, -1); } @@ -2774,8 +2775,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; } @@ -2788,7 +2788,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(); } diff --git a/editor/composer/nsEditorSpellCheck.cpp b/editor/composer/nsEditorSpellCheck.cpp index 1413653ac9..a3e41bd160 100644 --- a/editor/composer/nsEditorSpellCheck.cpp +++ b/editor/composer/nsEditorSpellCheck.cpp @@ -682,7 +682,7 @@ nsEditorSpellCheck::UpdateCurrentDictionary(nsIEditorSpellCheckCallback* aCallba RefPtr fetcher = new DictionaryFetcher(this, aCallback, mDictionaryFetcherGroup); rootContent->GetLang(fetcher->mRootContentLang); - nsCOMPtr doc = rootContent->GetUncomposedDoc(); + nsCOMPtr doc = rootContent->GetComposedDoc(); NS_ENSURE_STATE(doc); doc->GetContentLanguage(fetcher->mRootDocContentLang); diff --git a/editor/libeditor/EditorEventListener.cpp b/editor/libeditor/EditorEventListener.cpp index 32f3585288..d809d8d8cd 100644 --- a/editor/libeditor/EditorEventListener.cpp +++ b/editor/libeditor/EditorEventListener.cpp @@ -1114,7 +1114,7 @@ EditorEventListener::Focus(WidgetEvent* aFocusEvent) return NS_OK; } - nsCOMPtr target = aFocusEvent->GetDOMEventTarget(); + nsCOMPtr target = aFocusEvent->GetOriginalDOMEventTarget(); nsCOMPtr 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 editableRoot = editorBase->FindSelectionRoot(node); + nsCOMPtr editableRoot = editorBase->FindSelectionRoot(content); // make sure that the element is really focused in case an earlier // listener in the chain changed the focus. diff --git a/editor/libeditor/HTMLEditRules.cpp b/editor/libeditor/HTMLEditRules.cpp index 850bbe9b5a..a5b284d82f 100644 --- a/editor/libeditor/HTMLEditRules.cpp +++ b/editor/libeditor/HTMLEditRules.cpp @@ -8013,7 +8013,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 @@ -8033,7 +8033,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 diff --git a/editor/libeditor/HTMLEditor.cpp b/editor/libeditor/HTMLEditor.cpp index 130b033bd1..2defc3e12c 100644 --- a/editor/libeditor/HTMLEditor.cpp +++ b/editor/libeditor/HTMLEditor.cpp @@ -381,13 +381,14 @@ HTMLEditor::FindSelectionRoot(nsINode* aNode) aNode->IsNodeOfType(nsINode::eCONTENT), "aNode must be content or document node"); - nsCOMPtr doc = aNode->GetUncomposedDoc(); + nsCOMPtr doc = aNode->GetComposedDoc(); if (!doc) { return nullptr; } nsCOMPtr 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(); } @@ -5135,7 +5136,11 @@ HTMLEditor::IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent) return true; } - nsCOMPtr target = aGUIEvent->GetDOMEventTarget(); + nsCOMPtr target = aGUIEvent->GetOriginalDOMEventTarget(); + nsCOMPtr content = do_QueryInterface(target); + if (content) { + target = content->FindFirstNonChromeOnlyAccessContent(); + } NS_ENSURE_TRUE(target, false); nsCOMPtr document = GetDocument(); diff --git a/extensions/spellcheck/src/mozInlineSpellChecker.cpp b/extensions/spellcheck/src/mozInlineSpellChecker.cpp index 37898c818e..398059fc9b 100644 --- a/extensions/spellcheck/src/mozInlineSpellChecker.cpp +++ b/extensions/spellcheck/src/mozInlineSpellChecker.cpp @@ -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; } diff --git a/layout/generic/nsSelection.cpp b/layout/generic/nsSelection.cpp index f8a231b00c..b9ee20d1fc 100644 --- a/layout/generic/nsSelection.cpp +++ b/layout/generic/nsSelection.cpp @@ -3679,10 +3679,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, @@ -3697,10 +3698,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,