Bug 1022866 - Fix insertion point frame for content distributed to insertion points. r=bz

This commit is contained in:
William Chen 2014-08-04 21:37:25 -07:00
parent f0f0bad187
commit b5232d07d1
11 changed files with 147 additions and 13 deletions

View File

@ -2170,6 +2170,13 @@ public:
*/
static bool IsContentInsertionPoint(const nsIContent* aContent);
/**
* Returns whether the children of the provided content are
* nodes that are distributed to Shadow DOM insertion points.
*/
static bool HasDistributedChildren(nsIContent* aContent);
/**
* Returns whether a given header is forbidden for an XHR or fetch
* request.

View File

@ -152,21 +152,23 @@ nsIContent::FindFirstNonChromeOnlyAccessContent() const
nsIContent*
nsIContent::GetFlattenedTreeParent() const
{
nsIContent* parent = nullptr;
nsIContent* parent = GetParent();
nsTArray<nsIContent*>* destInsertionPoints = GetExistingDestInsertionPoints();
if (destInsertionPoints && !destInsertionPoints->IsEmpty()) {
// This node was distributed into an insertion point. The last node in
// the list of destination insertion insertion points is where this node
// appears in the composed tree (see Shadow DOM spec).
nsIContent* lastInsertionPoint = destInsertionPoints->LastElement();
parent = lastInsertionPoint->GetParent();
if (nsContentUtils::HasDistributedChildren(parent)) {
// This node is distributed to insertion points, thus we
// need to consult the destination insertion points list to
// figure out where this node was inserted in the flattened tree.
// It may be the case that |parent| distributes its children
// but the child does not match any insertion points, thus
// the flattened tree parent is nullptr.
nsTArray<nsIContent*>* destInsertionPoints = GetExistingDestInsertionPoints();
parent = destInsertionPoints && !destInsertionPoints->IsEmpty() ?
destInsertionPoints->LastElement()->GetParent() : nullptr;
} else if (HasFlag(NODE_MAY_BE_IN_BINDING_MNGR)) {
parent = GetXBLInsertionParent();
}
if (!parent) {
parent = GetParent();
nsIContent* insertionParent = GetXBLInsertionParent();
if (insertionParent) {
parent = insertionParent;
}
}
// Shadow roots never shows up in the flattened tree. Return the host

View File

@ -40,6 +40,7 @@
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/HTMLTemplateElement.h"
#include "mozilla/dom/HTMLContentElement.h"
#include "mozilla/dom/HTMLShadowElement.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/TextDecoder.h"
#include "mozilla/dom/TouchEvent.h"
@ -6874,6 +6875,45 @@ nsContentUtils::IsContentInsertionPoint(const nsIContent* aContent)
return false;
}
// static
bool
nsContentUtils::HasDistributedChildren(nsIContent* aContent)
{
if (!aContent) {
return false;
}
if (aContent->GetShadowRoot()) {
// Children of a shadow root host are distributed
// to content insertion points in the shadow root.
return true;
}
ShadowRoot* shadow = ShadowRoot::FromNode(aContent);
if (shadow) {
// Children of a shadow root are distributed to
// the shadow insertion point of the younger shadow root.
return shadow->GetYoungerShadow();
}
HTMLShadowElement* shadowEl = HTMLShadowElement::FromContent(aContent);
if (shadowEl && shadowEl->IsInsertionPoint()) {
// Children of a shadow insertion points are distributed
// to the insertion points in the older shadow root.
return shadow->GetOlderShadow();
}
HTMLContentElement* contentEl = HTMLContentElement::FromContent(aContent);
if (contentEl && contentEl->IsInsertionPoint()) {
// Children of a content insertion point are distributed to the
// content insertion point if the content insertion point does
// not match any nodes (fallback content).
return contentEl->MatchedNodes().IsEmpty();
}
return false;
}
// static
bool
nsContentUtils::IsForbiddenRequestHeader(const nsACString& aHeader)

View File

@ -21,6 +21,8 @@ class HTMLContentElement MOZ_FINAL : public nsGenericHTMLElement
public:
HTMLContentElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLContentElement, content)
// nsISupports
NS_DECL_ISUPPORTS_INHERITED

View File

@ -17,6 +17,8 @@ class HTMLShadowElement MOZ_FINAL : public nsGenericHTMLElement,
public:
HTMLShadowElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo);
NS_IMPL_FROMCONTENT_HTML_WITH_TAG(HTMLShadowElement, shadow)
// nsISupports
NS_DECL_ISUPPORTS_INHERITED

View File

@ -8480,9 +8480,25 @@ nsCSSFrameConstructor::GetInsertionPoint(nsIContent* aContainer,
return ::GetContentInsertionFrameFor(aContainer);
}
if (nsContentUtils::HasDistributedChildren(aContainer)) {
// The container distributes nodes, use the frame of the flattened tree parent.
// It may be the case that the node is distributed but not matched to any
// insertion points, so there is no flattened parent.
nsIContent* flattenedParent = aChildContent->GetFlattenedTreeParent();
return flattenedParent ? ::GetContentInsertionFrameFor(flattenedParent) : nullptr;
}
insertionElement = bindingManager->FindNestedInsertionPoint(aContainer, aChildContent);
}
else {
if (nsContentUtils::HasDistributedChildren(aContainer)) {
// The container distributes nodes to shadow DOM insertion points.
// Return with aMultiple set to true to induce callers to insert children
// individually into the node's flattened tree parent.
*aMultiple = true;
return nullptr;
}
bool multiple;
insertionElement = bindingManager->FindNestedSingleInsertionPoint(aContainer, &multiple);

View File

@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
<div>a b c</div>
</body>
</html>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
</head>
<body>
<div id="host"></div>
<script>
var host = document.getElementById("host");
var root = host.createShadowRoot();
root.innerHTML = 'a <content></content> c';
function tweak() {
var span = document.createElement("span");
span.innerHTML = "b";
// Span should be distributed to insertion point between 'a' and 'c'.
host.appendChild(span);
document.documentElement.removeAttribute("class");
}
window.addEventListener("MozReftestInvalidate", tweak, false);
</script>
</body>
</html>

View File

@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
<div>a</div>
</body>
</html>

View File

@ -0,0 +1,26 @@
<!DOCTYPE html>
<html class="reftest-wait">
<head>
</head>
<body>
<div id="host"></div>
<script>
var host = document.getElementById("host");
var root = host.createShadowRoot();
root.innerHTML = "<span>a</span>";
function tweak() {
var span = document.createElement("span");
span.innerHTML = "b";
// Span should not be visible because it is not distributed to any
// insertion points in the shadow DOM.
host.appendChild(span);
document.documentElement.removeAttribute("class");
}
window.addEventListener("MozReftestInvalidate", tweak, false);
</script>
</body>
</html>

View File

@ -14,3 +14,5 @@ pref(dom.webcomponents.enabled,true) == basic-shadow-element-1.html basic-shadow
pref(dom.webcomponents.enabled,true) == nested-shadow-element-1.html nested-shadow-element-1-ref.html
pref(dom.webcomponents.enabled,true) == update-dist-node-descendants-1.html update-dist-node-descendants-1-ref.html
pref(dom.webcomponents.enabled,true) random-if(B2G&&browserIsRemote) == input-transition-1.html input-transition-1-ref.html # Failure on B2G emulator due to Bug 1018381
pref(dom.webcomponents.enabled,true) == dynamic-insertion-point-distribution-1.html dynamic-insertion-point-distribution-1-ref.html
pref(dom.webcomponents.enabled,true) == dynamic-insertion-point-distribution-2.html dynamic-insertion-point-distribution-2-ref.html