summaryrefslogtreecommitdiffstats
path: root/layout
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2020-04-17 16:02:56 +0200
committerGitHub <noreply@github.com>2020-04-17 16:02:56 +0200
commitd5102d6beafc2a2a0cec3cc3ee5f7ebde31ae7bf (patch)
tree2bfef192cbb748b675ce8308c242a376798e265d /layout
parent5caf99795aa81e1fc145b8e937b1ee8197ed2486 (diff)
parentf35aa3e15fedf3cd4ad163d60ab74a9537ca5c82 (diff)
downloadUXP-d5102d6beafc2a2a0cec3cc3ee5f7ebde31ae7bf.tar
UXP-d5102d6beafc2a2a0cec3cc3ee5f7ebde31ae7bf.tar.gz
UXP-d5102d6beafc2a2a0cec3cc3ee5f7ebde31ae7bf.tar.lz
UXP-d5102d6beafc2a2a0cec3cc3ee5f7ebde31ae7bf.tar.xz
UXP-d5102d6beafc2a2a0cec3cc3ee5f7ebde31ae7bf.zip
Merge pull request #1518 from MoonchildProductions/shadowdom-merge
Incremental shadowdom-merge
Diffstat (limited to 'layout')
-rw-r--r--layout/base/RestyleManager.cpp52
-rw-r--r--layout/base/RestyleManager.h4
-rw-r--r--layout/base/RestyleManagerBase.cpp6
-rw-r--r--layout/base/RestyleManagerHandle.h4
-rw-r--r--layout/base/RestyleManagerHandleInlines.h2
-rw-r--r--layout/base/ServoRestyleManager.cpp18
-rw-r--r--layout/base/ServoRestyleManager.h3
-rw-r--r--layout/base/crashtests/1261351-iframe.html33
-rw-r--r--layout/base/crashtests/1404789-1.html16
-rw-r--r--layout/base/crashtests/1404789-2.html2
-rw-r--r--layout/base/crashtests/1419762.html15
-rw-r--r--layout/base/crashtests/crashtests.list3
-rw-r--r--layout/base/nsCSSFrameConstructor.cpp1576
-rw-r--r--layout/base/nsCSSFrameConstructor.h288
-rw-r--r--layout/base/nsFrameManager.cpp419
-rw-r--r--layout/base/nsFrameManager.h44
-rw-r--r--layout/base/nsFrameManagerBase.h1
-rw-r--r--layout/base/nsFrameTraversal.cpp19
-rw-r--r--layout/base/nsIPresShell.h26
-rw-r--r--layout/base/nsLayoutUtils.cpp126
-rw-r--r--layout/base/nsLayoutUtils.h61
-rw-r--r--layout/base/nsPresShell.cpp72
-rw-r--r--layout/base/nsPresShell.h7
-rw-r--r--layout/forms/nsColorControlFrame.cpp7
-rw-r--r--layout/forms/nsComboboxControlFrame.cpp16
-rw-r--r--layout/forms/nsComboboxControlFrame.h11
-rw-r--r--layout/forms/nsGfxButtonControlFrame.cpp24
-rw-r--r--layout/forms/nsGfxButtonControlFrame.h1
-rw-r--r--layout/forms/nsMeterFrame.cpp9
-rw-r--r--layout/forms/nsNumberControlFrame.cpp33
-rw-r--r--layout/forms/nsNumberControlFrame.h3
-rw-r--r--layout/forms/nsProgressFrame.cpp7
-rw-r--r--layout/forms/nsRangeFrame.cpp8
-rw-r--r--layout/forms/nsTextControlFrame.cpp33
-rw-r--r--layout/generic/DetailsFrame.cpp9
-rw-r--r--layout/generic/DetailsFrame.h6
-rw-r--r--layout/generic/ReflowInput.cpp3
-rw-r--r--layout/generic/Selection.h4
-rw-r--r--layout/generic/crashtests/1381134-2.html45
-rw-r--r--layout/generic/crashtests/1381134.html45
-rw-r--r--layout/generic/crashtests/crashtests.list2
-rw-r--r--layout/generic/nsAbsoluteContainingBlock.cpp21
-rw-r--r--layout/generic/nsBlockFrame.cpp15
-rw-r--r--layout/generic/nsFirstLetterFrame.cpp3
-rw-r--r--layout/generic/nsFrame.cpp61
-rw-r--r--layout/generic/nsHTMLParts.h3
-rw-r--r--layout/generic/nsIAnonymousContentCreator.h17
-rw-r--r--layout/generic/nsIFrame.h24
-rw-r--r--layout/generic/nsIFrameInlines.h13
-rw-r--r--layout/generic/nsImageFrame.cpp14
-rw-r--r--layout/generic/nsPlaceholderFrame.cpp5
-rw-r--r--layout/generic/nsSelection.cpp103
-rw-r--r--layout/generic/nsTextFrame.cpp3
-rw-r--r--layout/inspector/inDOMUtils.cpp42
-rw-r--r--layout/inspector/tests/test_bug522601.xhtml3
-rw-r--r--layout/printing/nsPrintEngine.cpp14
-rw-r--r--layout/reftests/bugs/1066554-1.html20
-rw-r--r--layout/reftests/bugs/reftest.list2
-rw-r--r--layout/reftests/css-display/display-contents-shadow-dom-1-ref.html2
-rw-r--r--layout/reftests/css-display/display-contents-shadow-dom-1.html77
-rw-r--r--layout/reftests/css-grid/reftest.list4
-rw-r--r--layout/reftests/details-summary/reftest.list4
-rw-r--r--layout/reftests/forms/input/number/number-style-inheritance-ref.html6
-rw-r--r--layout/reftests/forms/input/number/number-style-inheritance.html6
-rw-r--r--layout/reftests/forms/input/number/reftest.list3
-rw-r--r--layout/reftests/forms/legend/reftest.list2
-rw-r--r--layout/reftests/forms/legend/shadow-dom.html29
-rw-r--r--layout/reftests/mathml/shadow-dom-1.html8
-rw-r--r--layout/reftests/webcomponents/adjacent-insertion-points-1-ref.html6
-rw-r--r--layout/reftests/webcomponents/adjacent-insertion-points-1.html17
-rw-r--r--layout/reftests/webcomponents/adjacent-insertion-points-2-ref.html6
-rw-r--r--layout/reftests/webcomponents/adjacent-insertion-points-2.html17
-rw-r--r--layout/reftests/webcomponents/basic-insertion-point-1-ref.html8
-rw-r--r--layout/reftests/webcomponents/basic-insertion-point-1.html21
-rw-r--r--layout/reftests/webcomponents/basic-insertion-point-2-ref.html11
-rw-r--r--layout/reftests/webcomponents/basic-insertion-point-2.html24
-rw-r--r--layout/reftests/webcomponents/basic-shadow-1.html2
-rw-r--r--layout/reftests/webcomponents/basic-shadow-2.html2
-rw-r--r--layout/reftests/webcomponents/basic-shadow-3.html2
-rw-r--r--layout/reftests/webcomponents/basic-shadow-4.html2
-rw-r--r--layout/reftests/webcomponents/basic-shadow-element-1-ref.html10
-rw-r--r--layout/reftests/webcomponents/basic-shadow-element-1.html19
-rw-r--r--layout/reftests/webcomponents/basic-slot-1-ref.html11
-rw-r--r--layout/reftests/webcomponents/basic-slot-1.html6
-rw-r--r--layout/reftests/webcomponents/basic-slot-2-ref.html16
-rw-r--r--layout/reftests/webcomponents/basic-slot-2.html7
-rw-r--r--layout/reftests/webcomponents/basic-slot-3-ref.html8
-rw-r--r--layout/reftests/webcomponents/basic-slot-3.html18
-rw-r--r--layout/reftests/webcomponents/basic-slot-4.html20
-rw-r--r--layout/reftests/webcomponents/cross-tree-selection-1.html5
-rw-r--r--layout/reftests/webcomponents/dynamic-insertion-point-distribution-1.html17
-rw-r--r--layout/reftests/webcomponents/dynamic-insertion-point-distribution-2.html17
-rw-r--r--layout/reftests/webcomponents/dynamic-shadow-element-1-ref.html10
-rw-r--r--layout/reftests/webcomponents/dynamic-shadow-element-1.html23
-rw-r--r--layout/reftests/webcomponents/fallback-content-1.html8
-rw-r--r--layout/reftests/webcomponents/input-transition-1.html27
-rw-r--r--layout/reftests/webcomponents/nested-insertion-point-1.html11
-rw-r--r--layout/reftests/webcomponents/nested-shadow-element-1.html29
-rw-r--r--layout/reftests/webcomponents/reframe-shadow-child-1.html16
-rw-r--r--layout/reftests/webcomponents/reframe-shadow-child-2.html15
-rw-r--r--layout/reftests/webcomponents/reftest.list18
-rw-r--r--layout/reftests/webcomponents/remove-append-shadow-host-1.html2
-rw-r--r--layout/reftests/webcomponents/remove-insertion-point-1.html8
-rw-r--r--layout/reftests/webcomponents/style-sharing-across-shadow.html22
-rw-r--r--layout/reftests/webcomponents/style-sharing.html14
-rw-r--r--layout/reftests/webcomponents/update-dist-node-descendants-1.html24
-rw-r--r--layout/style/CSSStyleSheet.cpp20
-rw-r--r--layout/style/CSSStyleSheet.h3
-rw-r--r--layout/style/DocumentStyleRootIterator.cpp41
-rw-r--r--layout/style/DocumentStyleRootIterator.h37
-rw-r--r--layout/style/Loader.cpp10
-rw-r--r--layout/style/ServoStyleSet.cpp2
-rw-r--r--layout/style/ServoStyleSheet.cpp10
-rw-r--r--layout/style/ServoStyleSheet.h3
-rw-r--r--layout/style/StyleRule.cpp20
-rw-r--r--layout/style/StyleSheet.cpp8
-rw-r--r--layout/style/StyleSheet.h23
-rw-r--r--layout/style/StyleSheetInlines.h12
-rw-r--r--layout/style/crashtests/1017798-1.html28
-rw-r--r--layout/style/moz.build2
-rw-r--r--layout/style/nsAnimationManager.cpp2
-rw-r--r--layout/style/nsCSSPseudoClassList.h16
-rw-r--r--layout/style/nsCSSPseudoElements.h9
-rw-r--r--layout/style/nsCSSRules.cpp29
-rw-r--r--layout/style/nsCSSRules.h8
-rw-r--r--layout/style/nsComputedDOMStyle.cpp54
-rw-r--r--layout/style/nsComputedDOMStyle.h6
-rw-r--r--layout/style/nsDOMCSSAttrDeclaration.cpp6
-rw-r--r--layout/style/nsDOMCSSAttrDeclaration.h2
-rw-r--r--layout/style/nsDOMCSSDeclaration.cpp2
-rw-r--r--layout/style/nsICSSDeclaration.h6
-rw-r--r--layout/style/nsStyleSet.cpp2
-rw-r--r--layout/style/nsStyleUtil.cpp1
-rw-r--r--layout/style/nsTransitionManager.cpp4
-rw-r--r--layout/style/res/forms.css2
-rw-r--r--layout/style/res/html.css19
-rw-r--r--layout/style/res/ua.css6
-rw-r--r--layout/style/test/chrome/chrome.ini1
-rw-r--r--layout/style/test/chrome/test_bug1346623.html60
139 files changed, 2211 insertions, 2309 deletions
diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp
index 124b5535e..5c599e1ef 100644
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -146,8 +146,10 @@ RestyleManager::RestyleElement(Element* aElement,
}
if (aMinHint & nsChangeHint_ReconstructFrame) {
- FrameConstructor()->RecreateFramesForContent(aElement, false,
- nsCSSFrameConstructor::REMOVE_FOR_RECONSTRUCTION, nullptr);
+ FrameConstructor()->RecreateFramesForContent(
+ aElement,
+ nsCSSFrameConstructor::InsertionKind::Sync,
+ nsCSSFrameConstructor::REMOVE_FOR_RECONSTRUCTION);
} else if (aPrimaryFrame) {
ComputeAndProcessStyleChange(aPrimaryFrame, aMinHint, aRestyleTracker,
aRestyleHint, aRestyleHintData);
@@ -246,14 +248,14 @@ ElementForStyleContext(nsIContent* aParentContent,
// Forwarded nsIDocumentObserver method, to handle restyling (and
// passing the notification to the frame).
-nsresult
+void
RestyleManager::ContentStateChanged(nsIContent* aContent,
EventStates aStateMask)
{
// XXXbz it would be good if this function only took Elements, but
// we'd have to make ESM guarantee that usefully.
if (!aContent->IsElement()) {
- return NS_OK;
+ return;
}
Element* aElement = aContent->AsElement();
@@ -263,7 +265,6 @@ RestyleManager::ContentStateChanged(nsIContent* aContent,
ContentStateChangedInternal(aElement, aStateMask, &changeHint, &restyleHint);
PostRestyleEvent(aElement, restyleHint, changeHint);
- return NS_OK;
}
// Forwarded nsIMutationObserver method, to handle restyling.
@@ -1062,6 +1063,25 @@ ElementForStyleContext(nsIContent* aParentContent,
return f->GetContent()->AsElement();
}
+ Element* frameElement = aFrame->GetContent()->AsElement();
+ if (frameElement->IsNativeAnonymous() &&
+ nsCSSPseudoElements::PseudoElementIsJSCreatedNAC(aPseudoType)) {
+ // NAC-implemented pseudos use the closest non-NAC element as their
+ // element to inherit from.
+ //
+ // FIXME(heycam): In theory we shouldn't need to limit this only to
+ // JS-created pseudo-implementing NAC, as all pseudo-implementing
+ // should use the closest non-native anonymous ancestor element as
+ // its originating element. But removing that part of the condition
+ // reveals some bugs in style resultion with display:contents and
+ // XBL. See bug 1345809.
+ Element* originatingElement =
+ nsContentUtils::GetClosestNonNativeAnonymousAncestor(frameElement);
+ if (originatingElement) {
+ return originatingElement;
+ }
+ }
+
if (aParentContent) {
return aParentContent->AsElement();
}
@@ -1811,7 +1831,7 @@ ElementRestyler::ConditionallyRestyleUndisplayedNodes(
}
for (UndisplayedNode* undisplayed = aUndisplayed; undisplayed;
- undisplayed = undisplayed->mNext) {
+ undisplayed = undisplayed->getNext()) {
if (!undisplayed->mContent->IsElement()) {
continue;
@@ -2341,6 +2361,16 @@ ElementRestyler::ComputeRestyleResultFromFrame(nsIFrame* aSelf,
return;
}
+ // Each NAC element inherits from the first non-NAC ancestor, so child
+ // NAC may inherit from our parent instead of us. That means we can't
+ // cull traversal if our style context didn't change.
+ if (aSelf->GetContent() && aSelf->GetContent()->IsNativeAnonymous()) {
+ LOG_RESTYLE_CONTINUE("native anonymous content");
+ aRestyleResult = RestyleResult::eContinue;
+ aCanStopWithStyleChange = false;
+ return;
+ }
+
// Style changes might have moved children between the two nsLetterFrames
// (the one matching ::first-letter and the one containing the rest of the
// content). Continue restyling to the children of the nsLetterFrame so
@@ -3442,7 +3472,7 @@ ElementRestyler::RestyleUndisplayedNodes(nsRestyleHint aChildRestyleHint,
if (undisplayed) {
pusher.PushAncestorAndStyleScope(undisplayedParent);
}
- for (; undisplayed; undisplayed = undisplayed->mNext) {
+ for (; undisplayed; undisplayed = undisplayed->getNext()) {
NS_ASSERTION(undisplayedParent ||
undisplayed->mContent ==
mPresContext->Document()->GetRootElement(),
@@ -3459,7 +3489,7 @@ ElementRestyler::RestyleUndisplayedNodes(nsRestyleHint aChildRestyleHint,
// not have a frame and would not otherwise be pushed as an ancestor.
nsIContent* parent = undisplayed->mContent->GetParent();
TreeMatchContext::AutoAncestorPusher insertionPointPusher(mTreeMatchContext);
- if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
+ if (parent && parent->IsActiveChildrenElement()) {
insertionPointPusher.PushAncestorAndStyleScope(parent);
}
@@ -3598,14 +3628,14 @@ ElementRestyler::MustReframeForPseudo(CSSPseudoElementType aPseudoType,
// Check for a ::before pseudo style and the absence of a ::before content,
// but only if aFrame is null or is the first continuation/ib-split.
if ((aFrame && !nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(aFrame)) ||
- nsLayoutUtils::GetBeforeFrameForContent(aGenConParentFrame, aContent)) {
+ nsLayoutUtils::GetBeforeFrame(aContent)) {
return false;
}
} else {
// Similarly for ::after, but check for being the last continuation/
// ib-split.
if ((aFrame && nsLayoutUtils::GetNextContinuationOrIBSplitSibling(aFrame)) ||
- nsLayoutUtils::GetAfterFrameForContent(aGenConParentFrame, aContent)) {
+ nsLayoutUtils::GetAfterFrame(aContent)) {
return false;
}
}
@@ -3685,7 +3715,7 @@ ElementRestyler::RestyleContentChildren(nsIFrame* aParent,
// nsPageFrame that does not have a content.
nsIContent* parent = child->GetContent() ? child->GetContent()->GetParent() : nullptr;
TreeMatchContext::AutoAncestorPusher insertionPointPusher(mTreeMatchContext);
- if (parent && nsContentUtils::IsContentInsertionPoint(parent)) {
+ if (parent && parent->IsActiveChildrenElement()) {
insertionPointPusher.PushAncestorAndStyleScope(parent);
}
diff --git a/layout/base/RestyleManager.h b/layout/base/RestyleManager.h
index e22fe9058..3b60b331a 100644
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -59,8 +59,8 @@ public:
// Forwarded nsIDocumentObserver method, to handle restyling (and
// passing the notification to the frame).
- nsresult ContentStateChanged(nsIContent* aContent,
- EventStates aStateMask);
+ void ContentStateChanged(nsIContent* aContent,
+ EventStates aStateMask);
// Forwarded nsIMutationObserver method, to handle restyling.
void AttributeWillChange(Element* aElement,
diff --git a/layout/base/RestyleManagerBase.cpp b/layout/base/RestyleManagerBase.cpp
index 6ef048a19..1a3cae4bf 100644
--- a/layout/base/RestyleManagerBase.cpp
+++ b/layout/base/RestyleManagerBase.cpp
@@ -1249,8 +1249,10 @@ if (!mDestroyedFrames) {
// We could also have problems with triggering of CSS transitions
// on elements whose frames are reconstructed, since we depend on
// the reconstruction happening synchronously.
- frameConstructor->RecreateFramesForContent(content, false,
- nsCSSFrameConstructor::REMOVE_FOR_RECONSTRUCTION, nullptr);
+ frameConstructor->RecreateFramesForContent(
+ content,
+ nsCSSFrameConstructor::InsertionKind::Sync,
+ nsCSSFrameConstructor::REMOVE_FOR_RECONSTRUCTION);
} else {
NS_ASSERTION(frame, "This shouldn't happen");
diff --git a/layout/base/RestyleManagerHandle.h b/layout/base/RestyleManagerHandle.h
index 8be04d12c..bee1fc6d9 100644
--- a/layout/base/RestyleManagerHandle.h
+++ b/layout/base/RestyleManagerHandle.h
@@ -125,8 +125,8 @@ public:
nsIContent* aChild);
inline void RestyleForAppend(nsIContent* aContainer,
nsIContent* aFirstNewContent);
- inline nsresult ContentStateChanged(nsIContent* aContent,
- EventStates aStateMask);
+ inline void ContentStateChanged(nsIContent* aContent,
+ EventStates aStateMask);
inline void AttributeWillChange(dom::Element* aElement,
int32_t aNameSpaceID,
nsIAtom* aAttribute,
diff --git a/layout/base/RestyleManagerHandleInlines.h b/layout/base/RestyleManagerHandleInlines.h
index cc374edd5..8d6ca9142 100644
--- a/layout/base/RestyleManagerHandleInlines.h
+++ b/layout/base/RestyleManagerHandleInlines.h
@@ -122,7 +122,7 @@ RestyleManagerHandle::Ptr::RestyleForAppend(nsIContent* aContainer,
FORWARD(RestyleForAppend, (aContainer, aFirstNewContent));
}
-nsresult
+void
RestyleManagerHandle::Ptr::ContentStateChanged(nsIContent* aContent,
EventStates aStateMask)
{
diff --git a/layout/base/ServoRestyleManager.cpp b/layout/base/ServoRestyleManager.cpp
index 42ca23bb1..0659ab857 100644
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -277,24 +277,17 @@ ServoRestyleManager::FrameForPseudoElement(const nsIContent* aContent,
nsIAtom* aPseudoTagOrNull)
{
MOZ_ASSERT_IF(aPseudoTagOrNull, aContent->IsElement());
- nsIFrame* primaryFrame = aContent->GetPrimaryFrame();
if (!aPseudoTagOrNull) {
- return primaryFrame;
- }
-
- if (!primaryFrame) {
- return nullptr;
+ return aContent->GetPrimaryFrame();
}
- // NOTE: we probably need to special-case display: contents here. Gecko's
- // RestyleManager passes the primary frame of the parent instead.
if (aPseudoTagOrNull == nsCSSPseudoElements::before) {
- return nsLayoutUtils::GetBeforeFrameForContent(primaryFrame, aContent);
+ return nsLayoutUtils::GetBeforeFrame(aContent);
}
if (aPseudoTagOrNull == nsCSSPseudoElements::after) {
- return nsLayoutUtils::GetAfterFrameForContent(primaryFrame, aContent);
+ return nsLayoutUtils::GetAfterFrame(aContent);
}
MOZ_CRASH("Unkown pseudo-element given to "
@@ -513,12 +506,12 @@ ServoRestyleManager::ContentRemoved(nsINode* aContainer,
NS_WARNING("stylo: ServoRestyleManager::ContentRemoved not implemented");
}
-nsresult
+void
ServoRestyleManager::ContentStateChanged(nsIContent* aContent,
EventStates aChangedBits)
{
if (!aContent->IsElement()) {
- return NS_OK;
+ return;
}
Element* aElement = aContent->AsElement();
@@ -552,7 +545,6 @@ ServoRestyleManager::ContentStateChanged(nsIContent* aContent,
snapshot->AddState(previousState);
PostRestyleEvent(aElement, restyleHint, changeHint);
- return NS_OK;
}
void
diff --git a/layout/base/ServoRestyleManager.h b/layout/base/ServoRestyleManager.h
index 6856171c1..b6bb63d08 100644
--- a/layout/base/ServoRestyleManager.h
+++ b/layout/base/ServoRestyleManager.h
@@ -63,8 +63,7 @@ public:
nsIContent* aChild);
void RestyleForAppend(nsIContent* aContainer,
nsIContent* aFirstNewContent);
- nsresult ContentStateChanged(nsIContent* aContent,
- EventStates aStateMask);
+ void ContentStateChanged(nsIContent* aContent, EventStates aStateMask);
void AttributeWillChange(dom::Element* aElement,
int32_t aNameSpaceID,
nsIAtom* aAttribute,
diff --git a/layout/base/crashtests/1261351-iframe.html b/layout/base/crashtests/1261351-iframe.html
index 82c1e25fa..a0484f332 100644
--- a/layout/base/crashtests/1261351-iframe.html
+++ b/layout/base/crashtests/1261351-iframe.html
@@ -3,23 +3,26 @@
'use strict';
// -sp-context: content
(function () {
- let proto = Object.create(HTMLDivElement.prototype);
- proto.template = `<style></style>`;
- proto.createdCallback = function() {
- let shadow = this.createShadowRoot();
- if (this.template) {
- let te = document.createElement('template');
- te.innerHTML = this.template;
- shadow.appendChild(document.importNode(te.content, true));
- }
- };
+ class UiComponentTest extends HTMLDivElement {
+ constructor() {
+ super();
+ this.template = `<style></style>`;
+ }
- let UiComponentTest = document.registerElement('ui-component-test', {
- prototype: proto,
- });
+ connectedCallback() {
+ let shadow = this.createShadowRoot();
+ if (this.template) {
+ let te = document.createElement('template');
+ te.innerHTML = this.template;
+ shadow.appendChild(document.importNode(te.content, true));
+ }
+ }
+ };
- let uic = new UiComponentTest();
- document.body.appendChild(uic);
+ customElements.define('ui-component-test', UiComponentTest, { extend: 'div'} );
+
+ let uic = new UiComponentTest();
+ document.body.appendChild(uic);
})();
</script>
diff --git a/layout/base/crashtests/1404789-1.html b/layout/base/crashtests/1404789-1.html
new file mode 100644
index 000000000..bd577ae24
--- /dev/null
+++ b/layout/base/crashtests/1404789-1.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<script>
+ // Test for content redistribution outside of the document.
+ // Passes if it doesn't assert.
+ let host = document.createElement('div');
+ host.innerHTML = "<div id='foo'></div>";
+
+ let shadowRoot = host.createShadowRoot();
+ shadowRoot.innerHTML = "<content select='#foo'></content>";
+
+ host.firstElementChild.removeAttribute('id');
+
+ // Move to the document, do the same.
+ document.documentElement.appendChild(host);
+ host.firstElementChild.setAttribute('id', 'foo');
+</script>
diff --git a/layout/base/crashtests/1404789-2.html b/layout/base/crashtests/1404789-2.html
new file mode 100644
index 000000000..667618141
--- /dev/null
+++ b/layout/base/crashtests/1404789-2.html
@@ -0,0 +1,2 @@
+<!doctype html>
+<iframe style="display: none" src="1404789-1.html"></iframe>
diff --git a/layout/base/crashtests/1419762.html b/layout/base/crashtests/1419762.html
new file mode 100644
index 000000000..08a56106d
--- /dev/null
+++ b/layout/base/crashtests/1419762.html
@@ -0,0 +1,15 @@
+<style id='style_1'>
+ :first-child { display: table-column-group; }
+</style>
+<script>
+ try { o1 = document.createElement('isindex') } catch(e) { }
+ try { o2 = document.createElement('input') } catch(e) { }
+ try { o3 = document.createElement('optgroup') } catch(e) { }
+ try { o4 = document.createElement('col') } catch(e) { }
+ try { document.documentElement.appendChild(o1) } catch(e) { }
+ try { o1.appendChild(o2) } catch(e) { }
+ try { o1.appendChild(o3) } catch(e) { }
+ try { document.documentElement.offsetTop; } catch (e) { }
+ try { document.documentElement.appendChild(o4) } catch(e) { }
+ try { document.styleSheets[0].insertRule('optgroup::first-line { list-style-type: japanese-formal; }', 0); } catch(e) { }
+</script>
diff --git a/layout/base/crashtests/crashtests.list b/layout/base/crashtests/crashtests.list
index 6ded4ff3f..9b09d1c84 100644
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -483,3 +483,6 @@ load 1308793.svg
load 1308848-1.html
load 1308848-2.html
asserts(0-1) load 1343606.html # bug 1343948
+load 1404789-1.html
+load 1404789-2.html
+load 1419762.html
diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp
index 37cd3e45e..fc458b5eb 100644
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -43,6 +43,7 @@
#include "nsContainerFrame.h"
#include "nsNameSpaceManager.h"
#include "nsIComboboxControlFrame.h"
+#include "nsComboboxControlFrame.h"
#include "nsIListControlFrame.h"
#include "nsIDOMCharacterData.h"
#include "nsPlaceholderFrame.h"
@@ -691,10 +692,9 @@ nsAbsoluteItems::nsAbsoluteItems(nsContainerFrame* aContainingBlock)
void
nsAbsoluteItems::AddChild(nsIFrame* aChild)
{
- NS_ASSERTION(aChild->PresContext()->FrameManager()->
- GetPlaceholderFrameFor(aChild),
- "Child without placeholder being added to nsAbsoluteItems?");
aChild->AddStateBits(NS_FRAME_OUT_OF_FLOW);
+ NS_ASSERTION(aChild->GetPlaceholderFrame(),
+ "Child without placeholder being added to nsAbsoluteItems?");
nsFrameItems::AddChild(aChild);
}
@@ -1831,11 +1831,7 @@ nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aStat
aPseudoElement == CSSPseudoElementType::after,
"unexpected aPseudoElement");
- // XXXbz is this ever true?
- if (!aParentContent->IsElement()) {
- NS_ERROR("Bogus generated content parent");
- return;
- }
+ MOZ_ASSERT(aParentContent->IsElement());
StyleSetHandle styleSet = mPresShell->StyleSet();
@@ -1863,7 +1859,15 @@ nsCSSFrameConstructor::CreateGeneratedContentItem(nsFrameConstructorState& aStat
nsresult rv = NS_NewXMLElement(getter_AddRefs(container), nodeInfo.forget());
if (NS_FAILED(rv))
return;
+
+ // Cleared when the pseudo is unbound from the tree, so no need to store a
+ // strong reference, nor a destructor.
+ nsIAtom* property = isBefore
+ ? nsGkAtoms::beforePseudoProperty : nsGkAtoms::afterPseudoProperty;
+ aParentContent->SetProperty(property, container.get());
+
container->SetIsNativeAnonymousRoot();
+ container->SetPseudoElementType(aPseudoElement);
// If the parent is in a shadow tree, make sure we don't
// bind with a document because shadow roots and its descendants
@@ -3027,14 +3031,12 @@ nsCSSFrameConstructor::CreatePlaceholderFrameFor(nsIPresShell* aPresShell,
placeholderFrame->Init(aContent, aParentFrame, aPrevInFlow);
- // The placeholder frame has a pointer back to the out-of-flow frame
+ // Associate the placeholder/out-of-flow with each other.
placeholderFrame->SetOutOfFlowFrame(aFrame);
+ aFrame->SetProperty(nsIFrame::PlaceholderFrameProperty(), placeholderFrame);
aFrame->AddStateBits(NS_FRAME_OUT_OF_FLOW);
- // Add mapping from absolutely positioned frame to its placeholder frame
- aPresShell->FrameManager()->RegisterPlaceholderFrame(placeholderFrame);
-
return placeholderFrame;
}
@@ -3075,7 +3077,7 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState,
// The drop-down list's frame is created explicitly. The combobox frame shares its content
// with the drop-down list.
nsFrameState flags = NS_BLOCK_FLOAT_MGR;
- nsContainerFrame* comboboxFrame =
+ nsComboboxControlFrame* comboboxFrame =
NS_NewComboboxControlFrame(mPresShell, styleContext, flags);
// Save the history state so we don't restore during construction
@@ -3090,10 +3092,6 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState,
aState.AddChild(comboboxFrame, aFrameItems, content, styleContext,
aParentFrame);
- nsIComboboxControlFrame* comboBox = do_QueryFrame(comboboxFrame);
- NS_ASSERTION(comboBox, "NS_NewComboboxControlFrame returned frame that "
- "doesn't implement nsIComboboxControlFrame");
-
// Resolve pseudo element style for the dropdown list
RefPtr<nsStyleContext> listStyle;
listStyle = mPresShell->StyleSet()->
@@ -3108,7 +3106,7 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState,
listControlFrame->SetComboboxFrame(comboboxFrame);
}
// Notify combobox that it should use the listbox as it's popup
- comboBox->SetDropDown(listFrame);
+ comboboxFrame->SetDropDown(listFrame);
NS_ASSERTION(!listFrame->IsAbsPosContainingBlock(),
"Ended up with positioned dropdown list somehow.");
@@ -3129,10 +3127,29 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState,
// Create display and button frames from the combobox's anonymous content.
// The anonymous content is appended to existing anonymous content for this
// element (the scrollbars).
-
nsFrameItems childItems;
- CreateAnonymousFrames(aState, content, comboboxFrame,
- aItem.mPendingBinding, childItems);
+
+ // nsComboboxControlFrame needs special frame creation behavior for its first
+ // piece of anonymous content, which means that we can't take the normal
+ // ProcessChildren path.
+ AutoTArray<nsIAnonymousContentCreator::ContentInfo, 2> newAnonymousItems;
+ DebugOnly<nsresult> rv = GetAnonymousContent(content, comboboxFrame, newAnonymousItems);
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
+ MOZ_ASSERT(newAnonymousItems.Length() == 2);
+
+ // Manually create a frame for the special NAC.
+ MOZ_ASSERT(newAnonymousItems[0].mContent == comboboxFrame->GetDisplayNode());
+ newAnonymousItems.RemoveElementAt(0);
+ nsIFrame* customFrame = comboboxFrame->CreateFrameForDisplayNode();
+ MOZ_ASSERT(customFrame);
+ customFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
+ childItems.AddChild(customFrame);
+
+ // The other piece of NAC can take the normal path.
+ FrameConstructionItemList fcItems;
+ AddFCItemsForAnonymousContent(aState, comboboxFrame, newAnonymousItems,
+ fcItems);
+ ConstructFramesFromItemList(aState, fcItems, comboboxFrame, childItems);
comboboxFrame->SetInitialChildList(kPrincipalList, childItems);
@@ -3172,7 +3189,7 @@ nsCSSFrameConstructor::ConstructSelectFrame(nsFrameConstructorState& aState,
* But the select tag should really be fixed to use GFX scrollbars that can
* be create with BuildScrollFrame.
*/
-nsresult
+void
nsCSSFrameConstructor::InitializeSelectFrame(nsFrameConstructorState& aState,
nsContainerFrame* scrollFrame,
nsContainerFrame* scrolledFrame,
@@ -3218,7 +3235,6 @@ nsCSSFrameConstructor::InitializeSelectFrame(nsFrameConstructorState& aState,
// Set the scrolled frame's initial child lists
scrolledFrame->SetInitialChildList(kPrincipalList, childItems);
- return NS_OK;
}
nsIFrame*
@@ -3805,7 +3821,7 @@ nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aIt
// AutoDisplayContentsAncestorPusher above.)
TreeMatchContext::AutoAncestorPusher
insertionPointPusher(aState.mTreeMatchContext);
- if (adcp.IsEmpty() && parent && nsContentUtils::IsContentInsertionPoint(parent)) {
+ if (adcp.IsEmpty() && parent && parent->IsActiveChildrenElement()) {
if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
insertionPointPusher.PushAncestorAndStyleScope(parent);
} else {
@@ -4094,70 +4110,6 @@ nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aIt
}
}
-// after the node has been constructed and initialized create any
-// anonymous content a node needs.
-nsresult
-nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState,
- nsIContent* aParent,
- nsContainerFrame* aParentFrame,
- PendingBinding* aPendingBinding,
- nsFrameItems& aChildItems)
-{
- AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> newAnonymousItems;
- nsresult rv = GetAnonymousContent(aParent, aParentFrame, newAnonymousItems);
- NS_ENSURE_SUCCESS(rv, rv);
-
- uint32_t count = newAnonymousItems.Length();
- if (count == 0) {
- return NS_OK;
- }
-
- nsFrameConstructorState::PendingBindingAutoPusher pusher(aState,
- aPendingBinding);
- TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
- if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
- ancestorPusher.PushAncestorAndStyleScope(aParent->AsElement());
- } else {
- ancestorPusher.PushStyleScope(aParent->AsElement());
- }
-
- nsIAnonymousContentCreator* creator = do_QueryFrame(aParentFrame);
- NS_ASSERTION(creator,
- "How can that happen if we have nodes to construct frames for?");
-
- InsertionPoint insertion(aParentFrame, aParent);
- for (uint32_t i=0; i < count; i++) {
- nsIContent* content = newAnonymousItems[i].mContent;
- NS_ASSERTION(content, "null anonymous content?");
- NS_ASSERTION(!newAnonymousItems[i].mStyleContext, "Unexpected style context");
- NS_ASSERTION(newAnonymousItems[i].mChildren.IsEmpty(),
- "This method is not currently used with frames that implement "
- "nsIAnonymousContentCreator::CreateAnonymousContent to "
- "output a list where the items have their own children");
-
- nsIFrame* newFrame = creator->CreateFrameFor(content);
- if (newFrame) {
- NS_ASSERTION(content->GetPrimaryFrame(),
- "Content must have a primary frame now");
- newFrame->AddStateBits(NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT);
- aChildItems.AddChild(newFrame);
- } else {
- FrameConstructionItemList items;
- {
- // Skip parent display based style-fixup during our
- // AddFrameConstructionItems() call:
- TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper
- parentDisplayBasedStyleFixupSkipper(aState.mTreeMatchContext);
-
- AddFrameConstructionItems(aState, content, true, insertion, items);
- }
- ConstructFramesFromItemList(aState, items, aParentFrame, aChildItems);
- }
- }
-
- return NS_OK;
-}
-
static void
SetFlagsOnSubtree(nsIContent *aNode, uintptr_t aFlagsToSet)
{
@@ -4209,6 +4161,13 @@ ConnectAnonymousTreeDescendants(nsIContent* aParent,
}
}
+void SetNativeAnonymousBitOnDescendants(nsIContent *aRoot)
+{
+ for (nsIContent* curr = aRoot; curr; curr = curr->GetNextNode(aRoot)) {
+ curr->SetFlags(NODE_IS_NATIVE_ANONYMOUS);
+ }
+}
+
nsresult
nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
nsIFrame* aParentFrame,
@@ -4230,16 +4189,32 @@ nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
nsIContent* content = aContent[i].mContent;
NS_ASSERTION(content, "null anonymous content?");
- // least-surprise CSS binding until we do the SVG specified
- // cascading rules for <svg:use> - bug 265894
- if (aParentFrame->GetType() == nsGkAtoms::svgUseFrame) {
+ ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
+
+ nsIAtom* parentFrameType = aParentFrame->GetType();
+ if (parentFrameType == nsGkAtoms::svgUseFrame) {
+ // least-surprise CSS binding until we do the SVG specified
+ // cascading rules for <svg:use> - bug 265894
content->SetFlags(NODE_IS_ANONYMOUS_ROOT);
} else {
content->SetIsNativeAnonymousRoot();
+ // Don't mark descendants of the custom content container
+ // as native anonymous. When canvas custom content is initially
+ // created and appended to the custom content container, in
+ // nsIDocument::InsertAnonymousContent, it is not considered native
+ // anonymous content. But if we end up reframing the root element,
+ // we will re-create the nsCanvasFrame, and we would end up in here,
+ // marking it as NAC. Existing uses of canvas custom content would
+ // break if it becomes NAC (since each element starts inheriting
+ // styles from its closest non-NAC ancestor, rather than from its
+ // parent).
+ if (!(parentFrameType == nsGkAtoms::canvasFrame &&
+ content == static_cast<nsCanvasFrame*>(aParentFrame)
+ ->GetCustomContentContainer())) {
+ SetNativeAnonymousBitOnDescendants(content);
+ }
}
- ConnectAnonymousTreeDescendants(content, aContent[i].mChildren);
-
bool anonContentIsEditable = content->HasFlag(NODE_IS_EDITABLE);
// If the parent is in a shadow tree, make sure we don't
@@ -4264,11 +4239,9 @@ nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
}
if (ServoStyleSet* styleSet = mPresShell->StyleSet()->GetAsServo()) {
- // Eagerly compute styles for the anonymous content tree, but only do so
- // if the content doesn't have an explicit style context (if it does, we
- // don't need the normal computed values).
+ // Eagerly compute styles for the anonymous content tree.
for (auto& info : aContent) {
- if (!info.mStyleContext) {
+ if (info.mContent->IsElement()) {
styleSet->StyleNewSubtree(info.mContent);
}
}
@@ -4574,11 +4547,25 @@ nsCSSFrameConstructor::BeginBuildingScrollFrame(nsFrameConstructorState& aState,
// if there are any anonymous children for the scroll frame, create
// frames for them.
- // Pass a null pending binding: we don't care how constructors for any of
- // this anonymous content order with anything else. It's never been
- // consistent anyway.
- CreateAnonymousFrames(aState, aContent, gfxScrollFrame, nullptr,
- anonymousItems);
+ //
+ // We can't take the normal ProcessChildren path, because the NAC needs to
+ // be parented to the scrollframe, and everything else needs to be parented
+ // to the scrolledframe.
+ AutoTArray<nsIAnonymousContentCreator::ContentInfo, 4> scrollNAC;
+ DebugOnly<nsresult> rv = GetAnonymousContent(aContent, gfxScrollFrame, scrollNAC);
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
+ if (scrollNAC.Length() > 0) {
+ TreeMatchContext::AutoAncestorPusher ancestorPusher(aState.mTreeMatchContext);
+ if (aState.mTreeMatchContext.mAncestorFilter.HasFilter()) {
+ ancestorPusher.PushAncestorAndStyleScope(aContent->AsElement());
+ } else {
+ ancestorPusher.PushStyleScope(aContent->AsElement());
+ }
+
+ FrameConstructionItemList items;
+ AddFCItemsForAnonymousContent(aState, gfxScrollFrame, scrollNAC, items);
+ ConstructFramesFromItemList(aState, items, gfxScrollFrame, anonymousItems);
+ }
aNewFrame = gfxScrollFrame;
@@ -5033,22 +5020,46 @@ nsCSSFrameConstructor::ResolveStyleContext(const InsertionPoint& aInsertion,
already_AddRefed<nsStyleContext>
nsCSSFrameConstructor::ResolveStyleContext(nsStyleContext* aParentStyleContext,
nsIContent* aContent,
- nsFrameConstructorState* aState)
+ nsFrameConstructorState* aState,
+ Element* aOriginatingElementOrNull)
{
StyleSetHandle styleSet = mPresShell->StyleSet();
aContent->OwnerDoc()->FlushPendingLinkUpdates();
RefPtr<nsStyleContext> result;
if (aContent->IsElement()) {
- if (aState) {
- result = styleSet->ResolveStyleFor(aContent->AsElement(),
- aParentStyleContext,
- aState->mTreeMatchContext);
+ auto pseudoType = aContent->AsElement()->GetPseudoElementType();
+ if (pseudoType == CSSPseudoElementType::NotPseudo) {
+ MOZ_ASSERT(!aOriginatingElementOrNull);
+ if (aState) {
+ result = styleSet->ResolveStyleFor(aContent->AsElement(),
+ aParentStyleContext,
+ aState->mTreeMatchContext);
+ } else {
+ result = styleSet->ResolveStyleFor(aContent->AsElement(),
+ aParentStyleContext);
+ }
} else {
- result = styleSet->ResolveStyleFor(aContent->AsElement(),
- aParentStyleContext);
+ MOZ_ASSERT(aContent->IsInNativeAnonymousSubtree());
+ if (!aOriginatingElementOrNull) {
+ // For pseudo-implementing NAC created by JS using the ChromeOnly
+ // document.createElement(..., { pseudo: ... }) API, we find the
+ // originating element by lookup the tree until we find a non-NAC
+ // ancestor. (These are the correct semantics for C++-generated pseudo-
+ // implementing NAC as well, but for those cases we already have a
+ // correct originating element passed in.)
+ MOZ_ASSERT(nsCSSPseudoElements::PseudoElementIsJSCreatedNAC(pseudoType));
+ aOriginatingElementOrNull =
+ nsContentUtils::GetClosestNonNativeAnonymousAncestor(aContent->AsElement());
+ }
+ MOZ_ASSERT(aOriginatingElementOrNull);
+ result = styleSet->ResolvePseudoElementStyle(aOriginatingElementOrNull,
+ pseudoType,
+ aParentStyleContext,
+ aContent->AsElement());
}
} else {
+ MOZ_ASSERT(!aOriginatingElementOrNull);
NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT),
"shouldn't waste time creating style contexts for "
"comments and processing instructions");
@@ -6065,9 +6076,10 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
static void
AddGenConPseudoToFrame(nsIFrame* aOwnerFrame, nsIContent* aContent)
{
- NS_ASSERTION(nsLayoutUtils::IsFirstContinuationOrIBSplitSibling(aOwnerFrame),
- "property should only be set on first continuation/ib-sibling");
+ // FIXME(emilio): Remove this property, and use the frame of the generated
+ // content itself to tear the content down? It should be quite simpler.
+ aOwnerFrame = nsLayoutUtils::FirstContinuationOrIBSplitSibling(aOwnerFrame);
nsIFrame::ContentArray* value =
aOwnerFrame->GetProperty(nsIFrame::GenConProperty());
if (!value) {
@@ -6198,16 +6210,16 @@ IsRootBoxFrame(nsIFrame *aFrame)
return (aFrame->GetType() == nsGkAtoms::rootFrame);
}
-nsresult
+void
nsCSSFrameConstructor::ReconstructDocElementHierarchy()
{
Element* rootElement = mDocument->GetRootElement();
if (!rootElement) {
/* nothing to do */
- return NS_OK;
+ return;
}
- return RecreateFramesForContent(rootElement, false, REMOVE_FOR_RECONSTRUCTION,
- nullptr);
+ RecreateFramesForContent(rootElement, InsertionKind::Sync,
+ REMOVE_FOR_RECONSTRUCTION);
}
nsContainerFrame*
@@ -6312,129 +6324,24 @@ nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame)
}
/**
- * This function will check whether aContainer has :after generated content.
- * If so, appending to it should actually insert. The return value is the
- * parent to use for newly-appended content. *aAfterFrame points to the :after
- * frame before which appended content should go, if there is one.
- */
-static nsContainerFrame*
-AdjustAppendParentForAfterContent(nsFrameManager* aFrameManager,
- nsIContent* aContainer,
- nsContainerFrame* aParentFrame,
- nsIContent* aChild,
- nsIFrame** aAfterFrame)
-{
- // If the parent frame has any pseudo-elements or aContainer is a
- // display:contents node then we need to walk through the child
- // frames to find the first one that is either a ::after frame for an
- // ancestor of aChild or a frame that is for a node later in the
- // document than aChild and return that in aAfterFrame.
- if (aParentFrame->GetGenConPseudos() ||
- nsLayoutUtils::HasPseudoStyle(aContainer, aParentFrame->StyleContext(),
- CSSPseudoElementType::after,
- aParentFrame->PresContext()) ||
- aFrameManager->GetDisplayContentsStyleFor(aContainer)) {
- nsIFrame* afterFrame = nullptr;
- nsContainerFrame* parent =
- static_cast<nsContainerFrame*>(aParentFrame->LastContinuation());
- bool done = false;
- while (!done && parent) {
- // Ensure that all normal flow children are on the principal child list.
- parent->DrainSelfOverflowList();
-
- nsIFrame* child = parent->GetChildList(nsIFrame::kPrincipalList).LastChild();
- if (child && child->IsPseudoFrame(aContainer) &&
- !child->IsGeneratedContentFrame()) {
- // Drill down into non-generated pseudo frames of aContainer.
- nsContainerFrame* childAsContainer = do_QueryFrame(child);
- if (childAsContainer) {
- parent = nsLayoutUtils::LastContinuationWithChild(childAsContainer);
- continue;
- }
- }
-
- for (; child; child = child->GetPrevSibling()) {
- nsIContent* c = child->GetContent();
- if (child->IsGeneratedContentFrame()) {
- nsIContent* p = c->GetParent();
- if (c->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter) {
- if (!nsContentUtils::ContentIsDescendantOf(aChild, p) &&
- p != aContainer &&
- nsContentUtils::PositionIsBefore(p, aChild)) {
- // ::after generated content for content earlier in the doc and not
- // for an ancestor. "p != aContainer" may seem redundant but it
- // checks if the ::after belongs to the XBL insertion point we're
- // inserting aChild into (in which case ContentIsDescendantOf is
- // false even though p == aContainer).
- // See layout/reftests/bugs/482592-1a.xhtml for an example of that.
- done = true;
- break;
- }
- } else if (nsContentUtils::PositionIsBefore(p, aChild)) {
- // Non-::after generated content for content earlier in the doc.
- done = true;
- break;
- }
- } else if (nsContentUtils::PositionIsBefore(c, aChild)) {
- // Content is before aChild.
- done = true;
- break;
- }
- afterFrame = child;
- }
-
- parent = static_cast<nsContainerFrame*>(parent->GetPrevContinuation());
- }
- if (afterFrame) {
- *aAfterFrame = afterFrame;
- return afterFrame->GetParent();
- }
- }
-
- *aAfterFrame = nullptr;
-
- if (IsFramePartOfIBSplit(aParentFrame)) {
- // We might be in a situation where the last part of the {ib} split was
- // empty. Since we have no ::after pseudo-element, we do in fact want to be
- // appending to that last part, so advance to it if needed. Note that here
- // aParentFrame is the result of a GetLastIBSplitSibling call, so must be
- // either the last or next to last ib-split sibling.
- nsContainerFrame* trailingInline = GetIBSplitSibling(aParentFrame);
- if (trailingInline) {
- aParentFrame = trailingInline;
- }
-
- // Always make sure to look at the last continuation of the frame
- // for the {ib} case, even if that continuation is empty. We
- // don't do this for the non-ib-split-frame case, since in the
- // other cases appending to the last nonempty continuation is fine
- // and in fact not doing that can confuse code that doesn't know
- // to pull kids from continuations other than its next one.
- aParentFrame =
- static_cast<nsContainerFrame*>(aParentFrame->LastContinuation());
- }
-
- return aParentFrame;
-}
-
-/**
* This function will get the previous sibling to use for an append operation.
- * it takes a parent frame (must not be null) and its :after frame (may be
- * null).
+ *
+ * It takes a parent frame (must not be null) and the next insertion sibling, if
+ * the parent content is display: contents or has ::after content (may be null).
*/
static nsIFrame*
-FindAppendPrevSibling(nsIFrame* aParentFrame, nsIFrame* aAfterFrame)
+FindAppendPrevSibling(nsIFrame* aParentFrame, nsIFrame* aNextSibling)
{
- if (aAfterFrame) {
- NS_ASSERTION(aAfterFrame->GetParent() == aParentFrame, "Wrong parent");
- NS_ASSERTION(aAfterFrame->GetPrevSibling() ||
- aParentFrame->PrincipalChildList().FirstChild() == aAfterFrame,
- ":after frame must be on the principal child list here");
- return aAfterFrame->GetPrevSibling();
- }
-
aParentFrame->DrainSelfOverflowList();
+ if (aNextSibling) {
+ MOZ_ASSERT(aNextSibling->GetParent() == aParentFrame, "Wrong parent");
+ MOZ_ASSERT(aNextSibling->GetPrevSibling() ||
+ aParentFrame->PrincipalChildList().FirstChild() == aNextSibling,
+ "next sibling must be on the principal child list here");
+ return aNextSibling->GetPrevSibling();
+ }
+
return aParentFrame->GetChildList(kPrincipalList).LastChild();
}
@@ -6457,7 +6364,7 @@ GetInsertNextSibling(nsIFrame* aParentFrame, nsIFrame* aPrevSibling)
* appending flowed frames to a parent's principal child list. It handles the
* case where the parent is the trailing inline of an {ib} split.
*/
-nsresult
+void
nsCSSFrameConstructor::AppendFramesToParent(nsFrameConstructorState& aState,
nsContainerFrame* aParentFrame,
nsFrameItems& aFrameList,
@@ -6542,13 +6449,11 @@ nsCSSFrameConstructor::AppendFramesToParent(nsFrameConstructorState& aStat
return AppendFramesToParent(aState, aParentFrame->GetParent(), ibSiblings,
aParentFrame, true);
}
-
- return NS_OK;
+ return;
}
// Insert the frames after our aPrevSibling
InsertFrames(aParentFrame, kPrincipalList, aPrevSibling, aFrameList);
- return NS_OK;
}
#define UNSET_DISPLAY static_cast<StyleDisplay>(255)
@@ -6650,111 +6555,147 @@ nsCSSFrameConstructor::IsValidSibling(nsIFrame* aSibling,
return true;
}
+// FIXME(emilio): If we ever kill IsValidSibling() we can simplify this quite a
+// bit (no need to pass aTargetContent or aTargetContentDisplay, and the
+// adjust() calls can be responsibility of the caller).
+template<nsCSSFrameConstructor::SiblingDirection aDirection>
nsIFrame*
-nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent* aContent,
- nsIContent* aTargetContent,
- StyleDisplay& aTargetContentDisplay,
- nsContainerFrame* aParentFrame,
- bool aPrevSibling)
-{
- nsIFrame* sibling = aContent->GetPrimaryFrame();
- if (!sibling && GetDisplayContentsStyleFor(aContent)) {
- // A display:contents node - check if it has a ::before / ::after frame...
- sibling = aPrevSibling ?
- nsLayoutUtils::GetAfterFrameForContent(aParentFrame, aContent) :
- nsLayoutUtils::GetBeforeFrameForContent(aParentFrame, aContent);
- if (!sibling) {
- // ... then recurse into children ...
- const bool forward = !aPrevSibling;
- FlattenedChildIterator iter(aContent, forward);
- sibling = aPrevSibling ?
- FindPreviousSibling(iter, aTargetContent, aTargetContentDisplay, aParentFrame) :
- FindNextSibling(iter, aTargetContent, aTargetContentDisplay, aParentFrame);
- }
- if (!sibling) {
- // ... then ::after / ::before on the opposite end.
- sibling = aPrevSibling ?
- nsLayoutUtils::GetBeforeFrameForContent(aParentFrame, aContent) :
- nsLayoutUtils::GetAfterFrameForContent(aParentFrame, aContent);
- }
- if (!sibling) {
- return nullptr;
+nsCSSFrameConstructor::FindSiblingInternal(
+ FlattenedChildIterator aIter,
+ nsIContent* aTargetContent,
+ StyleDisplay& aTargetContentDisplay)
+{
+ auto adjust = [&](nsIFrame* aPotentialSiblingFrame) -> nsIFrame* {
+ return AdjustSiblingFrame(
+ aPotentialSiblingFrame, aTargetContent, aTargetContentDisplay,
+ aDirection);
+ };
+
+ auto nextDomSibling = [](FlattenedChildIterator& aIter) -> nsIContent* {
+ return aDirection == SiblingDirection::Forward
+ ? aIter.GetNextChild() : aIter.GetPreviousChild();
+ };
+
+ auto getNearPseudo = [](const nsIContent* aContent) -> nsIFrame* {
+ return aDirection == SiblingDirection::Forward
+ ? nsLayoutUtils::GetBeforeFrame(aContent)
+ : nsLayoutUtils::GetAfterFrame(aContent);
+ };
+
+ auto getFarPseudo = [](const nsIContent* aContent) -> nsIFrame* {
+ return aDirection == SiblingDirection::Forward
+ ? nsLayoutUtils::GetAfterFrame(aContent)
+ : nsLayoutUtils::GetBeforeFrame(aContent);
+ };
+
+ while (nsIContent* sibling = nextDomSibling(aIter)) {
+ if (nsIFrame* primaryFrame = sibling->GetPrimaryFrame()) {
+ // XXX the GetContent() == sibling check is needed due to bug 135040.
+ // Remove it once that's fixed.
+ if (primaryFrame->GetContent() == sibling) {
+ if (nsIFrame* frame = adjust(primaryFrame)) {
+ return frame;
+ }
+ }
+ }
+
+ if (GetDisplayContentsStyleFor(sibling)) {
+ if (nsIFrame* frame = adjust(getNearPseudo(sibling))) {
+ return frame;
+ }
+
+ const bool startFromBeginning = aDirection == SiblingDirection::Forward;
+ FlattenedChildIterator iter(sibling, startFromBeginning);
+ nsIFrame* sibling = FindSiblingInternal<aDirection>(
+ iter, aTargetContent, aTargetContentDisplay);
+ if (sibling) {
+ return sibling;
+ }
}
- } else if (!sibling || sibling->GetContent() != aContent) {
- // XXX the GetContent() != aContent check is needed due to bug 135040.
- // Remove it once that's fixed.
- return nullptr;
}
- // If the frame is out-of-flow, GetPrimaryFrame() will have returned the
- // out-of-flow frame; we want the placeholder.
- if (sibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
- nsIFrame* placeholderFrame = GetPlaceholderFrameFor(sibling);
- NS_ASSERTION(placeholderFrame, "no placeholder for out-of-flow frame");
- sibling = placeholderFrame;
+ return adjust(getFarPseudo(aIter.Parent()));
+}
+
+nsIFrame*
+nsCSSFrameConstructor::AdjustSiblingFrame(
+ nsIFrame* aSibling,
+ nsIContent* aTargetContent,
+ mozilla::StyleDisplay& aTargetContentDisplay,
+ SiblingDirection aDirection)
+{
+ if (!aSibling) {
+ return nullptr;
}
- // The frame we have now should never be a continuation
- NS_ASSERTION(!sibling->GetPrevContinuation(), "How did that happen?");
+ if (aSibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
+ aSibling = aSibling->GetPlaceholderFrame();
+ MOZ_ASSERT(aSibling);
+ }
- if (aPrevSibling) {
- // The frame may be a ib-split frame (a split inline frame that
- // contains a block). Get the last part of that split.
- if (IsFramePartOfIBSplit(sibling)) {
- sibling = GetLastIBSplitSibling(sibling, true);
+ MOZ_ASSERT(!aSibling->GetPrevContinuation(), "How?");
+ if (aDirection == SiblingDirection::Backward) {
+ // The frame may be a ib-split frame (a split inline frame that contains a
+ // block). Get the last part of that split.
+ if (IsFramePartOfIBSplit(aSibling)) {
+ aSibling = GetLastIBSplitSibling(aSibling, true);
}
// The frame may have a continuation. If so, we want the last
// non-overflow-container continuation as our previous sibling.
- sibling = sibling->GetTailContinuation();
+ aSibling = aSibling->GetTailContinuation();
}
- if (aTargetContent &&
- !IsValidSibling(sibling, aTargetContent, aTargetContentDisplay)) {
- sibling = nullptr;
+ if (!IsValidSibling(aSibling, aTargetContent, aTargetContentDisplay)) {
+ return nullptr;
}
- return sibling;
+ return aSibling;
}
nsIFrame*
-nsCSSFrameConstructor::FindPreviousSibling(FlattenedChildIterator aIter,
- nsIContent* aTargetContent,
- StyleDisplay& aTargetContentDisplay,
- nsContainerFrame* aParentFrame)
+nsCSSFrameConstructor::FindPreviousSibling(const FlattenedChildIterator& aIter,
+ StyleDisplay& aTargetContentDisplay)
{
- // Note: not all content objects are associated with a frame (e.g., if it's
- // `display: none') so keep looking until we find a previous frame.
- while (nsIContent* sibling = aIter.GetPreviousChild()) {
- MOZ_ASSERT(sibling != aTargetContent);
- nsIFrame* prevSibling =
- FindFrameForContentSibling(sibling, aTargetContent, aTargetContentDisplay,
- aParentFrame, true);
- if (prevSibling) {
- // Found a previous sibling, we're done!
- return prevSibling;
- }
- }
+ return FindSibling<SiblingDirection::Backward>(aIter, aTargetContentDisplay);
+}
- return nullptr;
+nsIFrame*
+nsCSSFrameConstructor::FindNextSibling(const FlattenedChildIterator& aIter,
+ StyleDisplay& aTargetContentDisplay)
+{
+ return FindSibling<SiblingDirection::Forward>(aIter, aTargetContentDisplay);
}
+template<nsCSSFrameConstructor::SiblingDirection aDirection>
nsIFrame*
-nsCSSFrameConstructor::FindNextSibling(FlattenedChildIterator aIter,
- nsIContent* aTargetContent,
- StyleDisplay& aTargetContentDisplay,
- nsContainerFrame* aParentFrame)
+nsCSSFrameConstructor::FindSibling(const FlattenedChildIterator& aIter,
+ StyleDisplay& aTargetContentDisplay)
{
- while (nsIContent* sibling = aIter.GetNextChild()) {
- MOZ_ASSERT(sibling != aTargetContent);
- nsIFrame* nextSibling =
- FindFrameForContentSibling(sibling, aTargetContent, aTargetContentDisplay,
- aParentFrame, false);
+ nsIContent* targetContent = aIter.Get();
+ nsIFrame* sibling =
+ FindSiblingInternal<aDirection>(aIter, targetContent, aTargetContentDisplay);
+ if (sibling) {
+ return sibling;
+ }
+
+ // Our siblings (if any) do not have a frame to guide us. The frame for the
+ // target content should be inserted whereever a frame for the container would
+ // be inserted. This is needed when inserting into display: contents nodes.
+ const nsIContent* current = aIter.Parent();
+ while (GetDisplayContentsStyleFor(current)) {
+ const nsIContent* parent = current->GetFlattenedTreeParent();
+ MOZ_ASSERT(parent, "No display: contents on the root");
- if (nextSibling) {
- // We found a next sibling, we're done!
- return nextSibling;
+ FlattenedChildIterator iter(parent);
+ iter.Seek(current);
+ sibling = FindSiblingInternal<aDirection>(
+ iter, targetContent, aTargetContentDisplay);
+ if (sibling) {
+ return sibling;
}
+
+ current = parent;
}
return nullptr;
@@ -6820,8 +6761,7 @@ nsCSSFrameConstructor::GetInsertionPrevSibling(InsertionPoint* aInsertion,
// Note that FindPreviousSibling is passed the iterator by value, so that
// the later usage of the iterator starts from the same place.
StyleDisplay childDisplay = UNSET_DISPLAY;
- nsIFrame* prevSibling =
- FindPreviousSibling(iter, iter.Get(), childDisplay, aInsertion->mParentFrame);
+ nsIFrame* prevSibling = FindPreviousSibling(iter, childDisplay);
// Now, find the geometric parent so that we can handle
// continuations properly. Use the prev sibling if we have it;
@@ -6834,48 +6774,20 @@ nsCSSFrameConstructor::GetInsertionPrevSibling(InsertionPoint* aInsertion,
iter.Seek(aEndSkipChild);
iter.GetPreviousChild();
}
- nsIFrame* nextSibling =
- FindNextSibling(iter, iter.Get(), childDisplay, aInsertion->mParentFrame);
- if (GetDisplayContentsStyleFor(aInsertion->mContainer)) {
- if (!nextSibling) {
- // Our siblings (if any) does not have a frame to guide us.
- // The frame for aChild should be inserted whereever a frame for
- // the container would be inserted. This is needed when inserting
- // into nested display:contents nodes.
- nsIContent* child = aInsertion->mContainer;
- nsIContent* parent = child->GetParent();
- aInsertion->mParentFrame =
- ::GetAdjustedParentFrame(aInsertion->mParentFrame,
- aInsertion->mParentFrame->GetType(),
- parent);
- InsertionPoint fakeInsertion(aInsertion->mParentFrame, parent);
- nsIFrame* result = GetInsertionPrevSibling(&fakeInsertion, child, aIsAppend,
- aIsRangeInsertSafe, nullptr, nullptr);
- MOZ_ASSERT(aInsertion->mParentFrame->GetContent() ==
- fakeInsertion.mParentFrame->GetContent());
- // fakeInsertion.mParentFrame may now be a continuation of the frame
- // we started with in the ctor above.
- aInsertion->mParentFrame = fakeInsertion.mParentFrame;
- return result;
- }
-
- prevSibling = nextSibling->GetPrevSibling();
- }
-
- if (nextSibling) {
+ if (nsIFrame* nextSibling = FindNextSibling(iter, childDisplay)) {
aInsertion->mParentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
} else {
// No previous or next sibling, so treat this like an appended frame.
*aIsAppend = true;
if (IsFramePartOfIBSplit(aInsertion->mParentFrame)) {
// Since we're appending, we'll walk to the last anonymous frame
- // that was created for the broken inline frame. But don't walk
- // to the trailing inline if it's empty; stop at the block.
+ // that was created for the broken inline frame. We can walk to the
+ // trailing inline, since we know this is a real append, and not an
+ // insert (that would've been handled by `FindNextSibling`).
aInsertion->mParentFrame =
- GetLastIBSplitSibling(aInsertion->mParentFrame, false);
+ GetLastIBSplitSibling(aInsertion->mParentFrame, true);
}
- // Get continuation that parents the last child. This MUST be done
- // before the AdjustAppendParentForAfterContent call.
+ // Get continuation that parents the last child.
aInsertion->mParentFrame =
nsLayoutUtils::LastContinuationWithChild(aInsertion->mParentFrame);
// Deal with fieldsets
@@ -6883,12 +6795,7 @@ nsCSSFrameConstructor::GetInsertionPrevSibling(InsertionPoint* aInsertion,
::GetAdjustedParentFrame(aInsertion->mParentFrame,
aInsertion->mParentFrame->GetType(),
aChild);
- nsIFrame* appendAfterFrame;
- aInsertion->mParentFrame =
- ::AdjustAppendParentForAfterContent(this, aInsertion->mContainer,
- aInsertion->mParentFrame,
- aChild, &appendAfterFrame);
- prevSibling = ::FindAppendPrevSibling(aInsertion->mParentFrame, appendAfterFrame);
+ prevSibling = ::FindAppendPrevSibling(aInsertion->mParentFrame, nullptr);
}
}
@@ -7004,7 +6911,8 @@ nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aParentContent,
}
NS_ASSERTION(!aContent->GetPrimaryFrame(),
"Text node has a frame and NS_CREATE_FRAME_IF_NON_WHITESPACE");
- ContentInserted(aParentContent, aContent, nullptr, false);
+ const bool allowLazyConstruction = true;
+ ContentInserted(aParentContent, aContent, nullptr, allowLazyConstruction);
}
// For inserts aChild should be valid, for appends it should be null.
@@ -7014,11 +6922,8 @@ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
nsIContent* aContainer,
nsIContent* aChild)
{
- // XXXmats no lazy frames for display:contents direct descendants yet
- // (Mozilla bug 979782).
if (mPresShell->GetPresContext()->IsChrome() || !aContainer ||
- aContainer->IsInNativeAnonymousSubtree() || aContainer->IsXULElement() ||
- GetDisplayContentsStyleFor(aContainer)) {
+ aContainer->IsInNativeAnonymousSubtree() || aContainer->IsXULElement()) {
return false;
}
@@ -7054,8 +6959,7 @@ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
// hit a node with a leaf frame.
//
// Also, it's fine if one of the nodes without primary frame is a display:
- // contents node except if it's the direct ancestor of the children we're
- // recreating frames for.
+ // contents node.
bool noPrimaryFrame = false;
bool needsFrameBitSet = false;
#endif
@@ -7287,8 +7191,9 @@ nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
cur = cur->GetNextSibling()) {
if (IsSpecialFramesetChild(cur)) {
// Just reframe the parent, since framesets are weird like that.
- RecreateFramesForContent(aParentFrame->GetContent(), false,
- REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(aParentFrame->GetContent(),
+ InsertionKind::Sync,
+ REMOVE_FOR_RECONSTRUCTION);
return true;
}
}
@@ -7296,7 +7201,7 @@ nsCSSFrameConstructor::MaybeRecreateForFrameset(nsIFrame* aParentFrame,
return false;
}
-nsresult
+void
nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
nsIContent* aFirstNewContent,
bool aAllowLazyConstruction)
@@ -7339,8 +7244,8 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
if (tag == nsGkAtoms::treechildren ||
tag == nsGkAtoms::treeitem ||
tag == nsGkAtoms::treerow)
- return NS_OK;
+ return;
}
#endif // MOZ_XUL
@@ -7353,21 +7258,21 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
//XXXsmaug This is super unefficient!
nsIContent* bindingParent = aContainer->GetBindingParent();
LAYOUT_PHASE_TEMP_EXIT();
- nsresult rv = RecreateFramesForContent(bindingParent, false,
- REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(bindingParent, InsertionKind::Sync,
+ REMOVE_FOR_RECONSTRUCTION);
LAYOUT_PHASE_TEMP_REENTER();
- return rv;
+ return;
}
// See comment in ContentRangeInserted for why this is necessary.
if (!GetContentInsertionFrameFor(aContainer) &&
!aContainer->IsActiveChildrenElement()) {
- return NS_OK;
+ return;
}
if (aAllowLazyConstruction &&
MaybeConstructLazily(CONTENTAPPEND, aContainer, aFirstNewContent)) {
- return NS_OK;
+ return;
}
LAYOUT_PHASE_TEMP_EXIT();
@@ -7377,13 +7282,13 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
nsContainerFrame*& parentFrame = insertion.mParentFrame;
LAYOUT_PHASE_TEMP_REENTER();
if (!parentFrame) {
- return NS_OK;
+ return;
}
LAYOUT_PHASE_TEMP_EXIT();
if (MaybeRecreateForFrameset(parentFrame, aFirstNewContent, nullptr)) {
LAYOUT_PHASE_TEMP_REENTER();
- return NS_OK;
+ return;
}
LAYOUT_PHASE_TEMP_REENTER();
@@ -7391,21 +7296,22 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
// Nothing to do here; we shouldn't be constructing kids of leaves
// Clear lazy bits so we don't try to construct again.
ClearLazyBits(aFirstNewContent, nullptr);
- return NS_OK;
+ return;
}
if (parentFrame->IsFrameOfType(nsIFrame::eMathML)) {
LAYOUT_PHASE_TEMP_EXIT();
- nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false,
- REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(parentFrame->GetContent(),
+ InsertionKind::Sync,
+ REMOVE_FOR_RECONSTRUCTION);
LAYOUT_PHASE_TEMP_REENTER();
- return rv;
+ return;
}
// If the frame we are manipulating is a ib-split frame (that is, one
// that's been created as a result of a block-in-inline situation) then we
// need to append to the last ib-split sibling, not to the frame itself.
- bool parentIBSplit = IsFramePartOfIBSplit(parentFrame);
+ const bool parentIBSplit = IsFramePartOfIBSplit(parentFrame);
if (parentIBSplit) {
#ifdef DEBUG
if (gNoisyContentUpdates) {
@@ -7431,38 +7337,79 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
parentFrame->GetType() != nsGkAtoms::detailsFrame,
"Parent frame should not be fieldset or details!");
- // Deal with possible :after generated content on the parent
- nsIFrame* parentAfterFrame;
- parentFrame =
- ::AdjustAppendParentForAfterContent(this, insertion.mContainer, parentFrame,
- aFirstNewContent, &parentAfterFrame);
+ // Deal with possible :after generated content on the parent, or display:
+ // contents.
+ nsIFrame* nextSibling = nullptr;
+ if (GetDisplayContentsStyleFor(insertion.mContainer) ||
+ nsLayoutUtils::GetAfterFrame(insertion.mContainer)) {
+ FlattenedChildIterator iter(insertion.mContainer);
+ iter.Seek(insertion.mContainer->GetLastChild());
+ StyleDisplay unused = UNSET_DISPLAY;
+ nextSibling = FindNextSibling(iter, unused);
+ }
- // Create some new frames
- nsFrameConstructorState state(mPresShell,
- GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
- GetAbsoluteContainingBlock(parentFrame, ABS_POS),
- GetFloatContainingBlock(parentFrame));
- state.mTreeMatchContext.InitAncestors(aContainer->AsElement());
+ if (nextSibling) {
+ parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
+ } else if (parentIBSplit) {
+ // We might be in a situation where the last part of the {ib} split was
+ // empty. Since we have no ::after pseudo-element, we do in fact want to be
+ // appending to that last part, so advance to it if needed. Note that here
+ // aParentFrame is the result of a GetLastIBSplitSibling call, so must be
+ // either the last or next to last ib-split sibling.
+ if (nsContainerFrame* trailingInline = GetIBSplitSibling(parentFrame)) {
+ parentFrame = trailingInline;
+ }
- // See if the containing block has :first-letter style applied.
- bool haveFirstLetterStyle = false, haveFirstLineStyle = false;
- nsContainerFrame* containingBlock = state.mFloatedItems.containingBlock;
- if (containingBlock) {
- haveFirstLetterStyle = HasFirstLetterStyle(containingBlock);
- haveFirstLineStyle =
- ShouldHaveFirstLineStyle(containingBlock->GetContent(),
- containingBlock->StyleContext());
+ // Always make sure to look at the last continuation of the frame
+ // for the {ib} case, even if that continuation is empty. We
+ // don't do this for the non-ib-split-frame case, since in the
+ // other cases appending to the last nonempty continuation is fine
+ // and in fact not doing that can confuse code that doesn't know
+ // to pull kids from continuations other than its next one.
+ parentFrame =
+ static_cast<nsContainerFrame*>(parentFrame->LastContinuation());
}
+ nsContainerFrame* containingBlock = GetFloatContainingBlock(parentFrame);
+
+ // See if the containing block has :first-letter style applied.
+ const bool haveFirstLetterStyle =
+ containingBlock && HasFirstLetterStyle(containingBlock);
+
+ const bool haveFirstLineStyle =
+ containingBlock &&
+ ShouldHaveFirstLineStyle(containingBlock->GetContent(),
+ containingBlock->StyleContext());
+
if (haveFirstLetterStyle) {
+ nsWeakFrame wf(nextSibling);
// Before we get going, remove the current letter frames
- RemoveLetterFrames(state.mPresShell, containingBlock);
+ RemoveLetterFrames(mPresShell, containingBlock);
+
+ // Reget nextSibling, since we may have killed it.
+ if (nextSibling && !wf) {
+ FlattenedChildIterator iter(insertion.mContainer);
+ iter.Seek(insertion.mContainer->GetLastChild());
+ StyleDisplay unused = UNSET_DISPLAY;
+ nextSibling = FindNextSibling(iter, unused);
+ if (nextSibling) {
+ parentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
+ containingBlock = GetFloatContainingBlock(parentFrame);
+ }
+ }
}
+ // Create some new frames
+ nsFrameConstructorState state(mPresShell,
+ GetAbsoluteContainingBlock(parentFrame, FIXED_POS),
+ GetAbsoluteContainingBlock(parentFrame, ABS_POS),
+ containingBlock);
+ state.mTreeMatchContext.InitAncestors(aContainer->AsElement());
+
nsIAtom* frameType = parentFrame->GetType();
FlattenedChildIterator iter(aContainer);
- bool haveNoXBLChildren = (!iter.XBLInvolved() || !iter.GetNextChild());
+ const bool haveNoXBLChildren = !iter.XBLInvolved() || !iter.GetNextChild();
FrameConstructionItemList items;
if (aFirstNewContent->GetPreviousSibling() &&
GetParentType(frameType) == eTypeBlock &&
@@ -7487,7 +7434,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
AddFrameConstructionItems(state, child, false, insertion, items);
}
- nsIFrame* prevSibling = ::FindAppendPrevSibling(parentFrame, parentAfterFrame);
+ nsIFrame* prevSibling = ::FindAppendPrevSibling(parentFrame, nextSibling);
// Perform special check for diddling around with the frames in
// a ib-split inline frame.
@@ -7497,7 +7444,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
if (WipeContainingBlock(state, containingBlock, parentFrame, items,
true, prevSibling)) {
LAYOUT_PHASE_TEMP_REENTER();
- return NS_OK;
+ return;
}
LAYOUT_PHASE_TEMP_REENTER();
@@ -7510,8 +7457,11 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
!prevSibling->IsInlineOutside() ||
prevSibling->GetType() == nsGkAtoms::brFrame);
// :after content can't be <br> so no need to check it
- items.SetLineBoundaryAtEnd(!parentAfterFrame ||
- !parentAfterFrame->IsInlineOutside());
+ //
+ // FIXME(emilio): A display: contents sibling could! Write a test-case and
+ // fix.
+ items.SetLineBoundaryAtEnd(
+ !nextSibling || !nextSibling->IsInlineOutside());
}
// To suppress whitespace-only text frames, we have to verify that
// our container's DOM child list matches its flattened tree child list.
@@ -7584,7 +7534,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
}
#endif
- return NS_OK;
+ return;
}
#ifdef MOZ_XUL
@@ -7627,17 +7577,17 @@ bool NotifyListBoxBody(nsPresContext* aPresContext,
}
#endif // MOZ_XUL
-nsresult
+void
nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
nsIContent* aChild,
nsILayoutHistoryState* aFrameState,
bool aAllowLazyConstruction)
{
- return ContentRangeInserted(aContainer,
- aChild,
- aChild->GetNextSibling(),
- aFrameState,
- aAllowLazyConstruction);
+ ContentRangeInserted(aContainer,
+ aChild,
+ aChild->GetNextSibling(),
+ aFrameState,
+ aAllowLazyConstruction);
}
// ContentRangeInserted handles creating frames for a range of nodes that
@@ -7658,7 +7608,7 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
// in the caption list, while skipping any nodes in the range being inserted
// (because when we treat the caption frames the other nodes have had their
// frames constructed but not yet inserted into the frame tree).
-nsresult
+void
nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
nsIContent* aStartChild,
nsIContent* aEndChild,
@@ -7715,7 +7665,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
// The insert case in NotifyListBoxBody
// doesn't use "old next sibling".
aStartChild, nullptr, nullptr, CONTENT_INSERTED)) {
- return NS_OK;
+ return;
}
} else {
// We don't handle a range insert to a listbox parent, issue single
@@ -7724,7 +7674,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
aAllowLazyConstruction);
LAYOUT_PHASE_TEMP_REENTER();
- return NS_OK;
+ return;
}
}
#endif // MOZ_XUL
@@ -7739,7 +7689,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
if (aStartChild != docElement) {
// Not the root element; just bail out
- return NS_OK;
+ return;
}
NS_PRECONDITION(nullptr == mRootElementFrame,
@@ -7776,7 +7726,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
}
#endif
- return NS_OK;
+ return;
}
if (aContainer->HasFlag(NODE_IS_IN_SHADOW_TREE) &&
@@ -7789,10 +7739,10 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
//XXXsmaug This is super unefficient!
nsIContent* bindingParent = aContainer->GetBindingParent();
LAYOUT_PHASE_TEMP_EXIT();
- nsresult rv = RecreateFramesForContent(bindingParent, false,
- REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(bindingParent, InsertionKind::Sync,
+ REMOVE_FOR_RECONSTRUCTION);
LAYOUT_PHASE_TEMP_REENTER();
- return rv;
+ return;
}
// Put 'parentFrame' inside a scope so we don't confuse it with
@@ -7803,7 +7753,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
// a parent. While its uncommon to change the structure of the default content itself, a label,
// for example, can be reframed by having its value attribute set or removed.
if (!parentFrame && !aContainer->IsActiveChildrenElement()) {
- return NS_OK;
+ return;
}
// Otherwise, we've got parent content. Find its frame.
@@ -7812,7 +7762,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
if (aAllowLazyConstruction &&
MaybeConstructLazily(CONTENTINSERT, aContainer, aStartChild)) {
- return NS_OK;
+ return;
}
}
@@ -7832,7 +7782,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
}
if (!insertion.mParentFrame) {
- return NS_OK;
+ return;
}
bool isAppend, isRangeInsertSafe;
@@ -7846,16 +7796,14 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
aAllowLazyConstruction);
LAYOUT_PHASE_TEMP_REENTER();
- return NS_OK;
+ return;
}
- nsIContent* container = insertion.mParentFrame->GetContent();
-
nsIAtom* frameType = insertion.mParentFrame->GetType();
LAYOUT_PHASE_TEMP_EXIT();
if (MaybeRecreateForFrameset(insertion.mParentFrame, aStartChild, aEndChild)) {
LAYOUT_PHASE_TEMP_REENTER();
- return NS_OK;
+ return;
}
LAYOUT_PHASE_TEMP_REENTER();
@@ -7872,10 +7820,11 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
// and if so, proceed. But we'd have to extend nsFieldSetFrame
// to locate this legend in the inserted frames and extract it.
LAYOUT_PHASE_TEMP_EXIT();
- nsresult rv = RecreateFramesForContent(insertion.mParentFrame->GetContent(), false,
- REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(insertion.mParentFrame->GetContent(),
+ InsertionKind::Sync,
+ REMOVE_FOR_RECONSTRUCTION);
LAYOUT_PHASE_TEMP_REENTER();
- return rv;
+ return;
}
// We should only get here with details when doing a single insertion because
@@ -7887,26 +7836,27 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
// expensive to recreate the entire details frame, but it's the simplest way
// to handle the insertion.
LAYOUT_PHASE_TEMP_EXIT();
- nsresult rv =
- RecreateFramesForContent(insertion.mParentFrame->GetContent(), false,
- REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(insertion.mParentFrame->GetContent(),
+ InsertionKind::Sync,
+ REMOVE_FOR_RECONSTRUCTION);
LAYOUT_PHASE_TEMP_REENTER();
- return rv;
+ return;
}
// Don't construct kids of leaves
if (insertion.mParentFrame->IsLeaf()) {
// Clear lazy bits so we don't try to construct again.
ClearLazyBits(aStartChild, aEndChild);
- return NS_OK;
+ return;
}
if (insertion.mParentFrame->IsFrameOfType(nsIFrame::eMathML)) {
LAYOUT_PHASE_TEMP_EXIT();
- nsresult rv = RecreateFramesForContent(insertion.mParentFrame->GetContent(), false,
- REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(insertion.mParentFrame->GetContent(),
+ InsertionKind::Sync,
+ REMOVE_FOR_RECONSTRUCTION);
LAYOUT_PHASE_TEMP_REENTER();
- return rv;
+ return;
}
nsFrameConstructorState state(mPresShell,
@@ -7956,7 +7906,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
// the placeholder frame.
if (insertion.mParentFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
nsPlaceholderFrame* placeholderFrame =
- GetPlaceholderFrameFor(insertion.mParentFrame);
+ insertion.mParentFrame->GetPlaceholderFrame();
NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?");
insertion.mParentFrame = placeholderFrame->GetParent();
} else {
@@ -7983,30 +7933,13 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
IssueSingleInsertNofications(aContainer, aStartChild, aEndChild,
aAllowLazyConstruction);
LAYOUT_PHASE_TEMP_REENTER();
- return NS_OK;
+ return;
}
- container = insertion.mParentFrame->GetContent();
frameType = insertion.mParentFrame->GetType();
}
}
- if (!prevSibling) {
- // We're inserting the new frames as the first child. See if the
- // parent has a :before pseudo-element
- nsIFrame* firstChild = insertion.mParentFrame->PrincipalChildList().FirstChild();
-
- if (firstChild &&
- nsLayoutUtils::IsGeneratedContentFor(container, firstChild,
- nsCSSPseudoElements::before)) {
- // Insert the new frames after the last continuation of the :before
- prevSibling = firstChild->GetTailContinuation();
- insertion.mParentFrame = prevSibling->GetParent()->GetContentInsertionFrame();
- // Don't change isAppend here; we'll can call AppendFrames as needed, and
- // the change to our prevSibling doesn't affect that.
- }
- }
-
FrameConstructionItemList items;
ParentType parentType = GetParentType(frameType);
FlattenedChildIterator iter(aContainer);
@@ -8051,7 +7984,7 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
if (WipeContainingBlock(state, containingBlock, insertion.mParentFrame, items,
isAppend, prevSibling)) {
LAYOUT_PHASE_TEMP_REENTER();
- return NS_OK;
+ return;
}
LAYOUT_PHASE_TEMP_REENTER();
@@ -8075,65 +8008,11 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
}
}
- // If the parent of our current prevSibling is different from the frame we'll
- // actually use as the parent, then the calculated insertion point is now
- // invalid and as it is unknown where to insert correctly we append instead
- // (bug 341858).
- // This can affect our prevSibling and isAppend, but should not have any
- // effect on the WipeContainingBlock above, since this should only happen
- // when neither parent is a ib-split frame and should not affect whitespace
- // handling inside table-related frames (and in fact, can only happen when
- // one of the parents is a table wrapper and one is an inner table or when the
- // parent is a fieldset or fieldset content frame). So it won't affect the
- // {ib} or XUL box cases in WipeContainingBlock(), and the table pseudo
- // handling will only be affected by us maybe thinking we're not inserting
- // at the beginning, whereas we really are. That would have made us reframe
- // unnecessarily, but that's ok.
- // XXXbz we should push our frame construction item code up higher, so we
- // know what our items are by the time we start figuring out previous
- // siblings
- if (prevSibling && frameItems.NotEmpty() &&
- frameItems.FirstChild()->GetParent() != prevSibling->GetParent()) {
-#ifdef DEBUG
- nsIFrame* frame1 = frameItems.FirstChild()->GetParent();
- nsIFrame* frame2 = prevSibling->GetParent();
- NS_ASSERTION(!IsFramePartOfIBSplit(frame1) &&
- !IsFramePartOfIBSplit(frame2),
- "Neither should be ib-split");
- NS_ASSERTION((frame1->GetType() == nsGkAtoms::tableFrame &&
- frame2->GetType() == nsGkAtoms::tableWrapperFrame) ||
- (frame1->GetType() == nsGkAtoms::tableWrapperFrame &&
- frame2->GetType() == nsGkAtoms::tableFrame) ||
- frame1->GetType() == nsGkAtoms::fieldSetFrame ||
- (frame1->GetParent() &&
- frame1->GetParent()->GetType() == nsGkAtoms::fieldSetFrame),
- "Unexpected frame types");
-#endif
- isAppend = true;
- nsIFrame* appendAfterFrame;
- insertion.mParentFrame =
- ::AdjustAppendParentForAfterContent(this, container,
- frameItems.FirstChild()->GetParent(),
- aStartChild, &appendAfterFrame);
- prevSibling = ::FindAppendPrevSibling(insertion.mParentFrame, appendAfterFrame);
- }
-
- if (haveFirstLineStyle && insertion.mParentFrame == containingBlock) {
+ if (haveFirstLineStyle && insertion.mParentFrame == containingBlock && isAppend) {
// It's possible that the new frame goes into a first-line
// frame. Look at it and see...
- if (isAppend) {
- // Use append logic when appending
- AppendFirstLineFrames(state, containingBlock->GetContent(),
- containingBlock, frameItems);
- }
- else {
- // Use more complicated insert logic when inserting
- // XXXbz this method is a no-op, so it's easy for the args being passed
- // here to make no sense without anyone noticing... If it ever stops
- // being a no-op, vet them carefully!
- InsertFirstLineFrames(state, container, containingBlock, &insertion.mParentFrame,
- prevSibling, frameItems);
- }
+ AppendFirstLineFrames(state, containingBlock->GetContent(),
+ containingBlock, frameItems);
}
// We might have captions; put them into the caption list of the
@@ -8216,32 +8095,35 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
#endif
#ifdef ACCESSIBILITY
- nsAccessibilityService* accService = nsIPresShell::AccService();
- if (accService) {
+ if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
accService->ContentRangeInserted(mPresShell, aContainer,
aStartChild, aEndChild);
}
#endif
- return NS_OK;
+ return;
}
-nsresult
-nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
- nsIContent* aChild,
- nsIContent* aOldNextSibling,
- RemoveFlags aFlags,
- bool* aDidReconstruct,
- nsIContent** aDestroyedFramesFor)
-{
+void
+nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
+ nsIContent* aChild,
+ nsIContent* aOldNextSibling,
+ RemoveFlags aFlags,
+ bool* aDidReconstruct)
+{
+ MOZ_ASSERT(aChild);
+ MOZ_ASSERT(aDidReconstruct);
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
NS_PRECONDITION(mUpdateCount != 0,
"Should be in an update while destroying frames");
*aDidReconstruct = false;
- if (aDestroyedFramesFor) {
- *aDestroyedFramesFor = aChild;
- }
+
+ // Only recreate sync if we're already in frame construction, that is,
+ // recreate async for XBL DOM changes, and normal content removals.
+ const InsertionKind insertionKind = (aFlags == REMOVE_FOR_RECONSTRUCTION)
+ ? InsertionKind::Sync
+ : InsertionKind::Async;
nsPresContext* presContext = mPresShell->GetPresContext();
MOZ_ASSERT(presContext, "Our presShell should have a valid presContext");
@@ -8274,7 +8156,6 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
}
#endif
- nsresult rv = NS_OK;
nsIFrame* childFrame = aChild->GetPrimaryFrame();
if (!childFrame || childFrame->GetContent() != aChild) {
// XXXbz the GetContent() != aChild check is needed due to bug 135040.
@@ -8284,37 +8165,33 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
MOZ_ASSERT(!childFrame || !GetDisplayContentsStyleFor(aChild),
"display:contents nodes shouldn't have a frame");
if (!childFrame && GetDisplayContentsStyleFor(aChild)) {
- nsIFrame* ancestorFrame = nullptr;
- nsIContent* ancestor = aContainer;
- for (; ancestor; ancestor = ancestor->GetParent()) {
- ancestorFrame = ancestor->GetPrimaryFrame();
- if (ancestorFrame) {
- break;
- }
+ nsIContent* ancestor = aChild->GetFlattenedTreeParent();
+ MOZ_ASSERT(ancestor, "display: contents on the root?");
+ while (!ancestor->GetPrimaryFrame()) {
+ ancestor = ancestor->GetFlattenedTreeParent();
+ MOZ_ASSERT(ancestor, "we can't have a display: contents subtree root!");
}
- if (ancestorFrame) {
- nsIFrame* contentInsertion = ancestorFrame->GetContentInsertionFrame();
- if (ancestorFrame->GetGenConPseudos() ||
- (contentInsertion && contentInsertion->GetGenConPseudos())) {
- *aDidReconstruct = true;
- LAYOUT_PHASE_TEMP_EXIT();
- // XXXmats Can we recreate frames only for the ::after/::before content?
- // XXX Perhaps even only those that belong to the aChild sub-tree?
- RecreateFramesForContent(ancestor, false, aFlags, aDestroyedFramesFor);
- LAYOUT_PHASE_TEMP_REENTER();
- return NS_OK;
- }
+
+ nsIFrame* ancestorFrame = ancestor->GetPrimaryFrame();
+ if (ancestorFrame->GetProperty(nsIFrame::GenConProperty())) {
+ *aDidReconstruct = true;
+
+ // XXXmats Can we recreate frames only for the ::after/::before content?
+ // XXX Perhaps even only those that belong to the aChild sub-tree?
+ LAYOUT_PHASE_TEMP_EXIT();
+ RecreateFramesForContent(ancestor, insertionKind, aFlags);
+ LAYOUT_PHASE_TEMP_REENTER();
+ return;
}
FlattenedChildIterator iter(aChild);
for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
if (c->GetPrimaryFrame() || GetDisplayContentsStyleFor(c)) {
LAYOUT_PHASE_TEMP_EXIT();
- rv = ContentRemoved(aChild, c, nullptr, aFlags, aDidReconstruct, aDestroyedFramesFor);
+ ContentRemoved(aChild, c, nullptr, aFlags, aDidReconstruct);
LAYOUT_PHASE_TEMP_REENTER();
- NS_ENSURE_SUCCESS(rv, rv);
if (aFlags != REMOVE_DESTROY_FRAMES && *aDidReconstruct) {
- return rv;
+ return;
}
}
}
@@ -8327,7 +8204,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
if (aFlags == REMOVE_DESTROY_FRAMES) {
CaptureStateForFramesOf(aChild, mTempFrameTreeState);
}
- return NS_OK;
+ return;
}
#endif // MOZ_XUL
@@ -8365,10 +8242,9 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
nsIContent* bindingParent = aContainer->GetBindingParent();
*aDidReconstruct = true;
LAYOUT_PHASE_TEMP_EXIT();
- nsresult rv = RecreateFramesForContent(bindingParent, false,
- aFlags, aDestroyedFramesFor);
+ RecreateFramesForContent(bindingParent, insertionKind, aFlags);
LAYOUT_PHASE_TEMP_REENTER();
- return rv;
+ return;
}
if (aFlags == REMOVE_DESTROY_FRAMES) {
@@ -8380,15 +8256,11 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
// See whether we need to remove more than just childFrame
LAYOUT_PHASE_TEMP_EXIT();
- nsIContent* container;
- if (MaybeRecreateContainerForFrameRemoval(childFrame, aFlags, &rv, &container)) {
- LAYOUT_PHASE_TEMP_REENTER();
- MOZ_ASSERT(container);
+ if (MaybeRecreateContainerForFrameRemoval(
+ childFrame, insertionKind, aFlags)) {
*aDidReconstruct = true;
- if (aDestroyedFramesFor) {
- *aDestroyedFramesFor = container;
- }
- return rv;
+ LAYOUT_PHASE_TEMP_REENTER();
+ return;
}
LAYOUT_PHASE_TEMP_REENTER();
@@ -8401,10 +8273,10 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
// Just reframe the parent, since framesets are weird like that.
*aDidReconstruct = true;
LAYOUT_PHASE_TEMP_EXIT();
- nsresult rv = RecreateFramesForContent(parentFrame->GetContent(), false,
- aFlags, aDestroyedFramesFor);
+ RecreateFramesForContent(parentFrame->GetContent(), insertionKind,
+ aFlags);
LAYOUT_PHASE_TEMP_REENTER();
- return rv;
+ return;
}
// If we're a child of MathML, then we should reframe the MathML content.
@@ -8415,10 +8287,9 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
if (possibleMathMLAncestor->IsFrameOfType(nsIFrame::eMathML)) {
*aDidReconstruct = true;
LAYOUT_PHASE_TEMP_EXIT();
- nsresult rv = RecreateFramesForContent(possibleMathMLAncestor->GetContent(),
- false, aFlags, aDestroyedFramesFor);
+ RecreateFramesForContent(parentFrame->GetContent(), insertionKind, aFlags);
LAYOUT_PHASE_TEMP_REENTER();
- return rv;
+ return;
}
// Undo XUL wrapping if it's no longer needed.
@@ -8432,15 +8303,14 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
!AnyKidsNeedBlockParent(childFrame->GetNextSibling())) {
*aDidReconstruct = true;
LAYOUT_PHASE_TEMP_EXIT();
- nsresult rv = RecreateFramesForContent(grandparentFrame->GetContent(), true,
- aFlags, aDestroyedFramesFor);
+ RecreateFramesForContent(grandparentFrame->GetContent(), insertionKind,
+ aFlags);
LAYOUT_PHASE_TEMP_REENTER();
- return rv;
+ return;
}
#ifdef ACCESSIBILITY
- nsAccessibilityService* accService = nsIPresShell::AccService();
- if (accService) {
+ if (nsAccessibilityService* accService = nsIPresShell::AccService()) {
accService->ContentRemoved(mPresShell, aChild);
}
#endif
@@ -8449,7 +8319,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
// :first-letter style applies.
nsIFrame* inflowChild = childFrame;
if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
- inflowChild = GetPlaceholderFrameFor(childFrame);
+ inflowChild = childFrame->GetPlaceholderFrame();
NS_ASSERTION(inflowChild, "No placeholder for out-of-flow?");
}
nsContainerFrame* containingBlock =
@@ -8479,7 +8349,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
// XXXbz the GetContent() != aChild check is needed due to bug 135040.
// Remove it once that's fixed.
ClearUndisplayedContentIn(aChild, aContainer);
- return NS_OK;
+ return;
}
parentFrame = childFrame->GetParent();
parentType = parentFrame->GetType();
@@ -8505,7 +8375,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
// Notify the parent frame that it should delete the frame
if (childFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
- childFrame = GetPlaceholderFrameFor(childFrame);
+ childFrame = childFrame->GetPlaceholderFrame();
NS_ASSERTION(childFrame, "Missing placeholder frame for out of flow.");
parentFrame = childFrame->GetParent();
}
@@ -8543,6 +8413,9 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
// and hence it's adjacent to a block end.
// If aOldNextSibling is null, then the text node before the node being
// removed is the last node, and we don't need to worry about it.
+ //
+ // FIXME(emilio): This should probably use the lazy frame construction
+ // bits if possible instead of reframing it in place.
if (aOldNextSibling) {
nsIContent* prevSibling = aOldNextSibling->GetPreviousSibling();
if (prevSibling && prevSibling->GetPreviousSibling()) {
@@ -8569,7 +8442,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
#endif
}
- return rv;
+ return;
}
/**
@@ -8631,12 +8504,11 @@ nsCSSFrameConstructor::EnsureFrameForTextNode(nsGenericDOMDataNode* aContent)
return aContent->GetPrimaryFrame();
}
-nsresult
+void
nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent,
CharacterDataChangeInfo* aInfo)
{
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
- nsresult rv = NS_OK;
if ((aContent->HasFlag(NS_CREATE_FRAME_IF_NON_WHITESPACE) &&
!aContent->TextIsOnlyWhitespace()) ||
@@ -8648,10 +8520,10 @@ nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent,
"Bit should never be set on generated content");
#endif
LAYOUT_PHASE_TEMP_EXIT();
- nsresult rv = RecreateFramesForContent(aContent, false,
- REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(aContent, InsertionKind::Sync,
+ REMOVE_FOR_RECONSTRUCTION);
LAYOUT_PHASE_TEMP_REENTER();
- return rv;
+ return;
}
// Find the child frame
@@ -8699,8 +8571,6 @@ nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent,
RecoverLetterFrames(block);
}
}
-
- return rv;
}
void
@@ -9149,7 +9019,7 @@ nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame)
// are within fixed frames, because that would cause duplicates on the new
// page - bug 389619)
for (nsIFrame* fixed = firstFixed; fixed; fixed = fixed->GetNextSibling()) {
- nsIFrame* prevPlaceholder = GetPlaceholderFrameFor(fixed);
+ nsIFrame* prevPlaceholder = fixed->GetPlaceholderFrame();
if (prevPlaceholder &&
nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame, prevPlaceholder)) {
// We want to use the same style as the primary style frame for
@@ -9314,7 +9184,8 @@ nsCSSFrameConstructor::MaybeRecreateFramesForElement(Element* aElement)
}
}
- RecreateFramesForContent(aElement, false, REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(aElement, InsertionKind::Sync,
+ REMOVE_FOR_RECONSTRUCTION);
return nullptr;
}
@@ -9357,19 +9228,16 @@ FindPreviousNonWhitespaceSibling(nsIFrame* aFrame)
}
bool
-nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
- RemoveFlags aFlags,
- nsresult* aResult,
- nsIContent** aDestroyedFramesFor)
+nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(
+ nsIFrame* aFrame,
+ InsertionKind aInsertionKind,
+ RemoveFlags aFlags)
{
NS_PRECONDITION(aFrame, "Must have a frame");
NS_PRECONDITION(aFrame->GetParent(), "Frame shouldn't be root");
- NS_PRECONDITION(aResult, "Null out param?");
NS_PRECONDITION(aFrame == aFrame->FirstContinuation(),
"aFrame not the result of GetPrimaryFrame()?");
- *aDestroyedFramesFor = nullptr;
-
if (IsFramePartOfIBSplit(aFrame)) {
// The removal functions can't handle removal of an {ib} split directly; we
// need to rebuild the containing block.
@@ -9382,44 +9250,44 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
}
#endif
- *aResult = ReframeContainingBlock(aFrame, aFlags, aDestroyedFramesFor);
+ ReframeContainingBlock(aFrame, aInsertionKind, aFlags);
return true;
}
nsContainerFrame* insertionFrame = aFrame->GetContentInsertionFrame();
if (insertionFrame && insertionFrame->GetType() == nsGkAtoms::legendFrame &&
aFrame->GetParent()->GetType() == nsGkAtoms::fieldSetFrame) {
- // When we remove the legend for a fieldset, we should reframe
- // the fieldset to ensure another legend is used, if there is one
- *aResult = RecreateFramesForContent(aFrame->GetParent()->GetContent(), false,
- aFlags, aDestroyedFramesFor);
+ RecreateFramesForContent(aFrame->GetParent()->GetContent(), aInsertionKind,
+ aFlags);
return true;
}
- if (insertionFrame &&
- aFrame->GetParent()->GetType() == nsGkAtoms::detailsFrame) {
+ nsIFrame* inFlowFrame =
+ (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ?
+ aFrame->GetPlaceholderFrame() : aFrame;
+ MOZ_ASSERT(inFlowFrame, "How did that happen?");
+ MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(),
+ "placeholder for primary frame has previous continuations?");
+ nsIFrame* parent = inFlowFrame->GetParent();
+
+ if (parent && parent->GetType() == nsGkAtoms::detailsFrame) {
HTMLSummaryElement* summary =
- HTMLSummaryElement::FromContent(insertionFrame->GetContent());
+ HTMLSummaryElement::FromContent(aFrame->GetContent());
+ DetailsFrame* detailsFrame = static_cast<DetailsFrame*>(parent);
- if (summary && summary->IsMainSummary()) {
+ // Unlike adding summary element cases, we need to check children of the
+ // parent details frame since at this moment the summary element has been
+ // already removed from the parent details element's child list.
+ if (summary && detailsFrame->HasMainSummaryFrame(aFrame)) {
// When removing a summary, we should reframe the parent details frame to
// ensure that another summary is used or the default summary is
// generated.
- *aResult = RecreateFramesForContent(aFrame->GetParent()->GetContent(),
- false, REMOVE_FOR_RECONSTRUCTION,
- aDestroyedFramesFor);
+ RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags);
return true;
}
}
// Now check for possibly needing to reconstruct due to a pseudo parent
- nsIFrame* inFlowFrame =
- (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) ?
- GetPlaceholderFrameFor(aFrame) : aFrame;
- MOZ_ASSERT(inFlowFrame, "How did that happen?");
- MOZ_ASSERT(inFlowFrame == inFlowFrame->FirstContinuation(),
- "placeholder for primary frame has previous continuations?");
- nsIFrame* parent = inFlowFrame->GetParent();
// For the case of ruby pseudo parent, effectively, only pseudo rb/rt frame
// need to be checked here, since all other types of parent will be catched
// by "Check ruby containers" section below.
@@ -9437,10 +9305,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
// Similar if we're a table-caption.
(inFlowFrame->IsTableCaption() &&
parent->GetChildList(nsIFrame::kCaptionList).FirstChild() == inFlowFrame)) {
- // We're the first or last frame in the pseudo. Need to reframe.
- // Good enough to recreate frames for |parent|'s content
- *aResult = RecreateFramesForContent(parent->GetContent(), true, aFlags,
- aDestroyedFramesFor);
+ RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags);
return true;
}
}
@@ -9469,8 +9334,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
#endif
// Good enough to recreate frames for aFrame's parent's content; even if
// aFrame's parent is a pseudo, that'll be the right content node.
- *aResult = RecreateFramesForContent(parent->GetContent(), true, aFlags,
- aDestroyedFramesFor);
+ RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags);
return true;
}
}
@@ -9486,8 +9350,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
// frames may be constructed or destroyed accordingly.
// 2. The type of the first child of a ruby frame determines
// whether a pseudo ruby base container should exist.
- *aResult = RecreateFramesForContent(parent->GetContent(), true, aFlags,
- aDestroyedFramesFor);
+ RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags);
return true;
}
@@ -9510,8 +9373,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
}
#endif // DEBUG
// Recreate frames for the flex container (the removed frame's parent)
- *aResult = RecreateFramesForContent(parent->GetContent(), true, aFlags,
- aDestroyedFramesFor);
+ RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags);
return true;
}
@@ -9529,8 +9391,8 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
}
#endif // DEBUG
// Recreate frames for the flex container (the removed frame's grandparent)
- *aResult = RecreateFramesForContent(parent->GetParent()->GetContent(), true,
- aFlags, aDestroyedFramesFor);
+ RecreateFramesForContent(parent->GetParent()->GetContent(), aInsertionKind,
+ aFlags);
return true;
}
@@ -9538,7 +9400,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
if (aFrame->GetType() == nsGkAtoms::popupSetFrame) {
nsIRootBox* rootBox = nsIRootBox::GetRootBox(mPresShell);
if (rootBox && rootBox->GetPopupSetFrame() == aFrame) {
- *aResult = ReconstructDocElementHierarchy();
+ ReconstructDocElementHierarchy();
return true;
}
}
@@ -9550,8 +9412,7 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
!inFlowFrame->GetNextSibling() &&
((parent->GetPrevContinuation() && !parent->GetPrevInFlow()) ||
(parent->GetNextContinuation() && !parent->GetNextInFlow()))) {
- *aResult = RecreateFramesForContent(parent->GetContent(), true, aFlags,
- aDestroyedFramesFor);
+ RecreateFramesForContent(parent->GetContent(), aInsertionKind, aFlags);
return true;
}
@@ -9587,24 +9448,26 @@ nsCSSFrameConstructor::MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
}
#endif
- *aResult = ReframeContainingBlock(parent, aFlags, aDestroyedFramesFor);
+ ReframeContainingBlock(parent, aInsertionKind, aFlags);
return true;
}
-nsresult
-nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
- bool aAsyncInsert,
- RemoveFlags aFlags,
- nsIContent** aDestroyedFramesFor)
+void
+nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
+ InsertionKind aInsertionKind,
+ RemoveFlags aFlags)
{
- NS_PRECONDITION(!aAsyncInsert || aContent->IsElement(),
- "Can only insert elements async");
+ MOZ_ASSERT(aInsertionKind != InsertionKind::Async || aContent->IsElement());
+ MOZ_ASSERT(aContent);
+
// If there is no document, we don't want to recreate frames for it. (You
// shouldn't generally be giving this method content without a document
// anyway).
// Rebuilding the frame tree can have bad effects, especially if it's the
// frame tree for chrome (see bug 157322).
- NS_ENSURE_TRUE(aContent->GetComposedDoc(), NS_ERROR_FAILURE);
+ if (NS_WARN_IF(!aContent->GetComposedDoc())) {
+ return;
+ }
// Is the frame ib-split? If so, we need to reframe the containing
// block *here*, rather than trying to remove and re-insert the
@@ -9630,8 +9493,8 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
if (frame) {
nsIFrame* nonGeneratedAncestor = nsLayoutUtils::GetNonGeneratedAncestor(frame);
if (nonGeneratedAncestor->GetContent() != aContent) {
- return RecreateFramesForContent(nonGeneratedAncestor->GetContent(), aAsyncInsert,
- aFlags, aDestroyedFramesFor);
+ return RecreateFramesForContent(nonGeneratedAncestor->GetContent(),
+ aInsertionKind, aFlags);
}
if (frame->GetStateBits() & NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT) {
@@ -9651,8 +9514,8 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
if (ancestor->GetType() != nsGkAtoms::svgUseFrame) {
NS_ASSERTION(aContent->IsInNativeAnonymousSubtree(),
"Why is NS_FRAME_ANONYMOUSCONTENTCREATOR_CONTENT set?");
- return RecreateFramesForContent(ancestor->GetContent(), aAsyncInsert,
- aFlags, aDestroyedFramesFor);
+ return RecreateFramesForContent(ancestor->GetContent(), aInsertionKind,
+ aFlags);
}
}
@@ -9663,20 +9526,13 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
// with native anonymous content from the editor.
if (parent && parent->IsLeaf() && parentContent &&
parentContent != aContent) {
- return RecreateFramesForContent(parentContent, aAsyncInsert, aFlags,
- aDestroyedFramesFor);
+ return RecreateFramesForContent(parentContent, aInsertionKind, aFlags);
}
}
- nsresult rv = NS_OK;
- nsIContent* container;
- if (frame && MaybeRecreateContainerForFrameRemoval(frame, aFlags, &rv,
- &container)) {
- MOZ_ASSERT(container);
- if (aDestroyedFramesFor) {
- *aDestroyedFramesFor = container;
- }
- return rv;
+ if (frame &&
+ MaybeRecreateContainerForFrameRemoval(frame, aInsertionKind, aFlags)) {
+ return;
}
nsINode* containerNode = aContent->GetParentNode();
@@ -9688,47 +9544,44 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent,
// Need the nsIContent parent, which might be null here, since we need to
// pass it to ContentInserted and ContentRemoved.
+ //
+ // FIXME(emilio): Do we need a strong ref here?
nsCOMPtr<nsIContent> container = aContent->GetParent();
// Remove the frames associated with the content object.
bool didReconstruct;
nsIContent* nextSibling = aContent->IsRootOfAnonymousSubtree() ?
nullptr : aContent->GetNextSibling();
- const bool reconstruct = aFlags != REMOVE_DESTROY_FRAMES;
- RemoveFlags flags = reconstruct ? REMOVE_FOR_RECONSTRUCTION : aFlags;
- rv = ContentRemoved(container, aContent, nextSibling, flags,
- &didReconstruct, aDestroyedFramesFor);
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (reconstruct && !didReconstruct) {
- // Now, recreate the frames associated with this content object. If
- // ContentRemoved triggered reconstruction, then we don't need to do this
- // because the frames will already have been built.
- if (aAsyncInsert) {
+ ContentRemoved(container, aContent, nextSibling, aFlags, &didReconstruct);
+ if (!didReconstruct) {
+ if (aInsertionKind == InsertionKind::Async) {
// XXXmats doesn't frame state need to be restored in this case too?
- RestyleManager()->PostRestyleEvent(
- aContent->AsElement(), nsRestyleHint(0), nsChangeHint_ReconstructFrame);
+ RestyleManager()->PostRestyleEvent(aContent->AsElement(),
+ nsRestyleHint(0),
+ nsChangeHint_ReconstructFrame);
} else {
- rv = ContentInserted(container, aContent, mTempFrameTreeState, false);
+ // Now, recreate the frames associated with this content object. If
+ // ContentRemoved triggered reconstruction, then we don't need to do this
+ // because the frames will already have been built.
+ ContentInserted(container, aContent, mTempFrameTreeState, false);
}
}
}
-
- return rv;
}
void
-nsCSSFrameConstructor::DestroyFramesFor(nsIContent* aContent,
- nsIContent** aDestroyedFramesFor)
+nsCSSFrameConstructor::DestroyFramesFor(nsIContent* aContent,
+ bool* aDidReconstruct)
{
MOZ_ASSERT(aContent && aContent->GetParentNode());
- bool didReconstruct;
nsIContent* nextSibling =
aContent->IsRootOfAnonymousSubtree() ? nullptr : aContent->GetNextSibling();
- ContentRemoved(aContent->GetParent(), aContent, nextSibling,
- REMOVE_DESTROY_FRAMES, &didReconstruct, aDestroyedFramesFor);
+ ContentRemoved(aContent->GetParent(),
+ aContent,
+ nextSibling,
+ REMOVE_DESTROY_FRAMES,
+ aDidReconstruct);
}
//////////////////////////////////////////////////////////////////////
@@ -10660,13 +10513,6 @@ nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
{
for (uint32_t i = 0; i < aAnonymousItems.Length(); ++i) {
nsIContent* content = aAnonymousItems[i].mContent;
-#ifdef DEBUG
- nsIAnonymousContentCreator* creator = do_QueryFrame(aFrame);
- NS_ASSERTION(!creator || !creator->CreateFrameFor(content),
- "If you need to use CreateFrameFor, you need to call "
- "CreateAnonymousFrames manually and not follow the standard "
- "ProcessChildren() codepath for this frame");
-#endif
// Gecko-styled nodes should have no pending restyle flags.
MOZ_ASSERT_IF(!content->IsStyledByServo(),
!content->IsElement() ||
@@ -10684,24 +10530,111 @@ nsCSSFrameConstructor::AddFCItemsForAnonymousContent(
RefPtr<nsStyleContext> styleContext;
TreeMatchContext::AutoParentDisplayBasedStyleFixupSkipper
parentDisplayBasedStyleFixupSkipper(aState.mTreeMatchContext);
- if (aAnonymousItems[i].mStyleContext) {
- // If we have an explicit style context, that means that the anonymous
- // content creator had its own plan for the style, and doesn't need the
- // computed style obtained by cascading this content as a normal node.
- // This happens when a native anonymous node is used to implement a
- // pseudo-element. Allowing Servo to traverse these nodes would be wasted
- // work, so assert that we didn't do that.
- MOZ_ASSERT_IF(content->IsStyledByServo(), !content->HasServoData());
- styleContext = aAnonymousItems[i].mStyleContext.forget();
- } else {
- // If we don't have an explicit style context, that means we need the
- // ordinary computed values. Make sure we eagerly cascaded them when the
- // anonymous nodes were created.
- MOZ_ASSERT_IF(content->IsStyledByServo() && content->IsElement(),
- content->HasServoData());
- styleContext = ResolveStyleContext(aFrame, content, &aState);
+
+ // Make sure we eagerly performed the servo cascade when the anonymous
+ // nodes were created.
+ MOZ_ASSERT_IF(content->IsStyledByServo() && content->IsElement(),
+ content->AsElement()->HasServoData());
+
+ // Determine whether this NAC is pseudo-implementing.
+ nsIAtom* pseudo = nullptr;
+ if (content->IsElement()) {
+ auto pseudoType = content->AsElement()->GetPseudoElementType();
+ if (pseudoType != CSSPseudoElementType::NotPseudo) {
+ pseudo = nsCSSPseudoElements::GetPseudoAtom(pseudoType);
+ }
+ }
+
+ // Determine the appropriate parent style for this NAC, and if the NAC
+ // implements a pseudo-element, the appropriate originating element
+ // (that is to say, the element to the left of the ::pseudo-element in
+ // the selector). This is all rather tricky, and merits some discussion.
+ //
+ // First, it's important to note that author stylesheets generally do not
+ // apply to elements in native-anonymous subtrees. The exceptions to
+ // this are web-exposed pseudo-elements, where authors can style the
+ // pseudo-implementing NAC if the originating element is not itself in a NAC
+ // subtree.
+ //
+ // For this reason, it's very important that we avoid using a style parent
+ // that is inside a NAC subtree together with an originating element that
+ // is not inside a NAC subtree, since that would allow authors to
+ // explicitly inherit styles from internal elements, potentially making
+ // the NAC hierarchy observable. To ensure this, and generally simplify
+ // things, we always set the originating element to the style parent.
+ //
+ // As a consequence of the above, all web-exposed pseudo-elements (which,
+ // by definition, must have a content-accessible originating element) must
+ // also inherit style from that same content-accessible element. To avoid
+ // unintuitive behavior differences between NAC elements that do and don't
+ // correspond to web-exposed pseudo-elements, we follow this protocol for
+ // all NAC, pseudo-implementing or not.
+ //
+ // However, things get tricky with the <video> element, where we have a
+ // bunch of XBL-generated anonymous content descending from a native-
+ // anonymous XULElement. The XBL elements inherit style from their
+ // flattened tree parent, because that's how XBL works. But then we need
+ // to figure out what to do when one of those anonymous XBL elements
+ // (like an <input> element) generates its own (possibly pseudo-element-
+ // implementing) NAC.
+ //
+ // In this case, we inherit style from the XBL-generated NAC-creating
+ // element, rather than the <video> element. There are a number of good
+ // reasons for this. First, inheriting from the great-grandparent while
+ // the parent inherits from the grandparent would be bizarre at best.
+ // Second, exposing pseudo-elements from elements within our particular
+ // XBL implementation would allow content styles to (un)intentionally
+ // alter the video controls, which would be very bad. Third, our UA
+ // stylesheets have selectors like:
+ //
+ // input[type=range][orient=horizontal]::-moz-range-track
+ //
+ // and we need to make sure that the originating element is the <input>,
+ // not the <video>, because that's where the |orient| attribute lives.
+ //
+ // The upshot of all of this is that, to find the style parent (and
+ // originating element, if applicable), we walk up our parent chain to the
+ // first element that is not itself NAC (distinct from whether it happens
+ // to be in a NAC subtree).
+ //
+ // The one exception to all of this is scrollbar content, which we parent
+ // directly to the scrollframe. This is because the special-snowflake
+ // construction of scroll frames doesn't result in the placeholder frame
+ // being constructed until later, which means that GetInFlowParent() doesn't
+ // work right in the case of out-of-flow scrollframes.
+ //
+ // To implement all this, we need to pass the correct parent style context
+ // here because SetPrimaryFrame() may not have been called on the content
+ // yet and thus ResolveStyleContext can't find it otherwise.
+ //
+ // We don't need to worry about display:contents here, because such
+ // elements don't get a frame and thus can't generate NAC. But we do need
+ // to worry about anonymous boxes, which CorrectStyleParentFrame handles
+ // for us.
+ nsIFrame* inheritFrame = aFrame;
+ if (!content->IsNativeScrollbarContent()) {
+ while (inheritFrame->GetContent()->IsNativeAnonymous()) {
+ inheritFrame = inheritFrame->GetInFlowParent();
+ }
}
+ nsIFrame* styleParentFrame =
+ nsFrame::CorrectStyleParentFrame(inheritFrame, pseudo);
+ // The only way we can not have a style parent now is if inheritFrame is the
+ // canvas frame and we're the NAC parent for all the things added via
+ // nsIDocument::InsertAnonymousContent.
+ MOZ_ASSERT_IF(!styleParentFrame,
+ inheritFrame->GetType() == nsGkAtoms::canvasFrame);
+ // And that anonymous div has no pseudo.
+ MOZ_ASSERT_IF(!styleParentFrame, !pseudo);
+
+ Element* originating =
+ pseudo ? styleParentFrame->GetContent()->AsElement() : nullptr;
+ nsStyleContext* parentStyle =
+ styleParentFrame ? styleParentFrame->StyleContext() : nullptr;
+ styleContext =
+ ResolveStyleContext(parentStyle, content, &aState, originating);
+
nsTArray<nsIAnonymousContentCreator::ContentInfo>* anonChildren = nullptr;
if (!aAnonymousItems[i].mChildren.IsEmpty()) {
anonChildren = &aAnonymousItems[i].mChildren;
@@ -11028,151 +10961,6 @@ nsCSSFrameConstructor::AppendFirstLineFrames(
lineFrame, aFrameItems);
}
-// Special routine to handle inserting a new frame into a block
-// frame's child list. Takes care of placing the new frame into the
-// right place when first-line style is present.
-nsresult
-nsCSSFrameConstructor::InsertFirstLineFrames(
- nsFrameConstructorState& aState,
- nsIContent* aContent,
- nsIFrame* aBlockFrame,
- nsContainerFrame** aParentFrame,
- nsIFrame* aPrevSibling,
- nsFrameItems& aFrameItems)
-{
- nsresult rv = NS_OK;
- // XXXbz If you make this method actually do something, check to
- // make sure that the caller is passing what you expect. In
- // particular, which content is aContent? And audit the rest of
- // this code too; it makes bogus assumptions and may not build.
-#if 0
- nsIFrame* parentFrame = *aParentFrame;
- nsIFrame* newFrame = aFrameItems.childList;
- bool isInline = IsInlineOutside(newFrame);
-
- if (!aPrevSibling) {
- // Insertion will become the first frame. Two cases: we either
- // already have a first-line frame or we don't.
- nsIFrame* firstBlockKid = aBlockFrame->PrincipalChildList().FirstChild();
- if (firstBlockKid->GetType() == nsGkAtoms::lineFrame) {
- // We already have a first-line frame
- nsIFrame* lineFrame = firstBlockKid;
-
- if (isInline) {
- // Easy case: the new inline frame will go into the lineFrame.
- ReparentFrame(this, lineFrame, newFrame);
- InsertFrames(lineFrame, kPrincipalList, nullptr, newFrame);
-
- // Since the frame is going into the lineFrame, don't let it
- // go into the block too.
- aFrameItems.childList = nullptr;
- aFrameItems.lastChild = nullptr;
- }
- else {
- // Harder case: We are about to insert a block level element
- // before the first-line frame.
- // XXX need a method to steal away frames from the line-frame
- }
- }
- else {
- // We do not have a first-line frame
- if (isInline) {
- // We now need a first-line frame to contain the inline frame.
- nsIFrame* lineFrame = NS_NewFirstLineFrame(firstLineStyle);
-
- if (NS_SUCCEEDED(rv)) {
- // Lookup first-line style context
- nsStyleContext* parentStyle =
- nsFrame::CorrectStyleParentFrame(aBlockFrame,
- nsCSSPseudoElements::firstLine)->
- StyleContext();
- RefPtr<nsStyleContext> firstLineStyle =
- GetFirstLineStyle(aContent, parentStyle);
-
- // Initialize the line frame
- InitAndRestoreFrame(aState, aContent, aBlockFrame, lineFrame);
-
- // Make sure the caller inserts the lineFrame into the
- // blocks list of children.
- aFrameItems.childList = lineFrame;
- aFrameItems.lastChild = lineFrame;
-
- // Give the inline frames to the lineFrame <b>after</b>
- // reparenting them
- NS_ASSERTION(lineFrame->StyleContext() == firstLineStyle,
- "Bogus style context on line frame");
- ReparentFrame(aPresContext, lineFrame, newFrame);
- lineFrame->SetInitialChildList(kPrincipalList, newFrame);
- }
- }
- else {
- // Easy case: the regular insertion logic can insert the new
- // frame because it's a block frame.
- }
- }
- }
- else {
- // Insertion will not be the first frame.
- nsIFrame* prevSiblingParent = aPrevSibling->GetParent();
- if (prevSiblingParent == aBlockFrame) {
- // Easy case: The prev-siblings parent is the block
- // frame. Therefore the prev-sibling is not currently in a
- // line-frame. Therefore the new frame which is going after it,
- // regardless of type, is not going into a line-frame.
- }
- else {
- // If the prevSiblingParent is not the block-frame then it must
- // be a line-frame (if it were a letter-frame, that logic would
- // already have adjusted the prev-sibling to be the
- // letter-frame).
- if (isInline) {
- // Easy case: the insertion can go where the caller thinks it
- // should go (which is into prevSiblingParent).
- }
- else {
- // Block elements don't end up in line-frames, therefore
- // change the insertion point to aBlockFrame. However, there
- // might be more inline elements following aPrevSibling that
- // need to be pulled out of the line-frame and become children
- // of the block.
- nsIFrame* nextSibling = aPrevSibling->GetNextSibling();
- nsIFrame* nextLineFrame = prevSiblingParent->GetNextInFlow();
- if (nextSibling || nextLineFrame) {
- // Oy. We have work to do. Create a list of the new frames
- // that are going into the block by stripping them away from
- // the line-frame(s).
- if (nextSibling) {
- nsLineFrame* lineFrame = (nsLineFrame*) prevSiblingParent;
- nsFrameList tail = lineFrame->StealFramesAfter(aPrevSibling);
- // XXX do something with 'tail'
- }
-
- nsLineFrame* nextLineFrame = (nsLineFrame*) lineFrame;
- for (;;) {
- nextLineFrame = nextLineFrame->GetNextInFlow();
- if (!nextLineFrame) {
- break;
- }
- nsIFrame* kids = nextLineFrame->PrincipalChildList().FirstChild();
- }
- }
- else {
- // We got lucky: aPrevSibling was the last inline frame in
- // the line-frame.
- ReparentFrame(this, aBlockFrame, newFrame);
- InsertFrames(aBlockFrame, kPrincipalList,
- prevSiblingParent, newFrame);
- aFrameItems.childList = nullptr;
- aFrameItems.lastChild = nullptr;
- }
- }
- }
- }
-
-#endif
- return rv;
-}
-
//----------------------------------------------------------------------
// First-letter support
@@ -11494,7 +11282,7 @@ FindFirstLetterFrame(nsIFrame* aFrame, nsIFrame::ChildListID aListID)
return nullptr;
}
-nsresult
+void
nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
nsIPresShell* aPresShell,
nsIFrame* aBlockFrame)
@@ -11506,7 +11294,7 @@ nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
floatFrame =
::FindFirstLetterFrame(aBlockFrame, nsIFrame::kPushedFloatsList);
if (!floatFrame) {
- return NS_OK;
+ return;
}
}
@@ -11514,19 +11302,19 @@ nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
// destroyed when we destroy the letter frame).
nsIFrame* textFrame = floatFrame->PrincipalChildList().FirstChild();
if (!textFrame) {
- return NS_OK;
+ return;
}
// Discover the placeholder frame for the letter frame
- nsPlaceholderFrame* placeholderFrame = GetPlaceholderFrameFor(floatFrame);
+ nsPlaceholderFrame* placeholderFrame = floatFrame->GetPlaceholderFrame();
if (!placeholderFrame) {
// Somethings really wrong
- return NS_OK;
+ return;
}
nsContainerFrame* parentFrame = placeholderFrame->GetParent();
if (!parentFrame) {
// Somethings really wrong
- return NS_OK;
+ return;
}
// Create a new text frame with the right style context that maps
@@ -11535,7 +11323,7 @@ nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
nsStyleContext* parentSC = parentFrame->StyleContext();
nsIContent* textContent = textFrame->GetContent();
if (!textContent) {
- return NS_OK;
+ return;
}
RefPtr<nsStyleContext> newSC = aPresShell->StyleSet()->
ResolveStyleForText(textContent, parentSC);
@@ -11580,11 +11368,9 @@ nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames(
if (offsetsNeedFixing) {
prevSibling->RemoveStateBits(TEXT_OFFSETS_NEED_FIXING);
}
-
- return NS_OK;
}
-nsresult
+void
nsCSSFrameConstructor::RemoveFirstLetterFrames(nsIPresShell* aPresShell,
nsContainerFrame* aFrame,
nsContainerFrame* aBlockFrame,
@@ -11657,11 +11443,9 @@ nsCSSFrameConstructor::RemoveFirstLetterFrames(nsIPresShell* aPresShell,
prevSibling = kid;
kid = kid->GetNextSibling();
}
-
- return NS_OK;
}
-nsresult
+void
nsCSSFrameConstructor::RemoveLetterFrames(nsIPresShell* aPresShell,
nsContainerFrame* aBlockFrame)
{
@@ -11670,20 +11454,16 @@ nsCSSFrameConstructor::RemoveLetterFrames(nsIPresShell* aPresShell,
nsContainerFrame* continuation = aBlockFrame;
bool stopLooking = false;
- nsresult rv;
do {
- rv = RemoveFloatingFirstLetterFrames(aPresShell, continuation);
- if (NS_SUCCEEDED(rv)) {
- rv = RemoveFirstLetterFrames(aPresShell,
- continuation, aBlockFrame, &stopLooking);
- }
+ RemoveFloatingFirstLetterFrames(aPresShell, continuation);
+ RemoveFirstLetterFrames(aPresShell, continuation, aBlockFrame,
+ &stopLooking);
if (stopLooking) {
break;
}
continuation =
static_cast<nsContainerFrame*>(continuation->GetNextContinuation());
} while (continuation);
- return rv;
}
// Fixup the letter frame situation for the given block
@@ -11726,7 +11506,7 @@ nsCSSFrameConstructor::RecoverLetterFrames(nsContainerFrame* aBlockFrame)
// listbox Widget Routines
-nsresult
+void
nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame,
nsIFrame* aPrevFrame,
nsIContent* aChild,
@@ -11734,8 +11514,6 @@ nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame,
bool aIsAppend)
{
#ifdef MOZ_XUL
- nsresult rv = NS_OK;
-
// Construct a new frame
if (nullptr != aParentFrame) {
nsFrameItems frameItems;
@@ -11756,7 +11534,7 @@ nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame,
if (StyleDisplay::None == display->mDisplay) {
*aNewFrame = nullptr;
- return NS_OK;
+ return;
}
BeginUpdate();
@@ -11775,9 +11553,9 @@ nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame,
if (newFrame) {
// Notify the parent frame
if (aIsAppend)
- rv = ((nsListBoxBodyFrame*)aParentFrame)->ListBoxAppendFrames(frameItems);
+ ((nsListBoxBodyFrame*)aParentFrame)->ListBoxAppendFrames(frameItems);
else
- rv = ((nsListBoxBodyFrame*)aParentFrame)->ListBoxInsertFrames(aPrevFrame, frameItems);
+ ((nsListBoxBodyFrame*)aParentFrame)->ListBoxInsertFrames(aPrevFrame, frameItems);
}
EndUpdate();
@@ -11792,10 +11570,6 @@ nsCSSFrameConstructor::CreateListBoxContent(nsContainerFrame* aParentFrame,
}
#endif
}
-
- return rv;
-#else
- return NS_ERROR_FAILURE;
#endif
}
@@ -12218,8 +11992,8 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
if (aFrame->IsXULBoxFrame() &&
!(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
aItems.AnyItemsNeedBlockParent()) {
- RecreateFramesForContent(aFrame->GetContent(), true,
- REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async,
+ REMOVE_FOR_RECONSTRUCTION);
return true;
}
@@ -12238,8 +12012,8 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
const bool isWebkitBox = IsFlexContainerForLegacyBox(aFrame, frameType);
if (aPrevSibling && IsAnonymousFlexOrGridItem(aPrevSibling) &&
iter.item().NeedsAnonFlexOrGridItem(aState, isWebkitBox)) {
- RecreateFramesForContent(aFrame->GetContent(), true,
- REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async,
+ REMOVE_FOR_RECONSTRUCTION);
return true;
}
@@ -12250,8 +12024,9 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
iter.SetToEnd();
iter.Prev();
if (iter.item().NeedsAnonFlexOrGridItem(aState, isWebkitBox)) {
- RecreateFramesForContent(aFrame->GetContent(), true,
- REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(aFrame->GetContent(),
+ InsertionKind::Async,
+ REMOVE_FOR_RECONSTRUCTION);
return true;
}
}
@@ -12281,8 +12056,9 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
isWebkitBox)) {
// We hit something that _doesn't_ need an anonymous flex item!
// Rebuild the flex container to bust it out.
- RecreateFramesForContent(containerFrame->GetContent(), true,
- REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(containerFrame->GetContent(),
+ InsertionKind::Async,
+ REMOVE_FOR_RECONSTRUCTION);
return true;
}
@@ -12306,8 +12082,8 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
// We want to optimize it better, and avoid reframing as much as
// possible. But given the cases above, and the fact that a ruby
// usually won't be very large, it should be fine to reframe it.
- RecreateFramesForContent(aFrame->GetContent(), true,
- REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async,
+ REMOVE_FOR_RECONSTRUCTION);
return true;
}
@@ -12473,8 +12249,8 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
if (!aItems.AllWantParentType(parentType)) {
// Reframing aFrame->GetContent() is good enough, since the content of
// table pseudo-frames is the ancestor content.
- RecreateFramesForContent(aFrame->GetContent(), true,
- REMOVE_FOR_RECONSTRUCTION, nullptr);
+ RecreateFramesForContent(aFrame->GetContent(), InsertionKind::Async,
+ REMOVE_FOR_RECONSTRUCTION);
return true;
}
}
@@ -12562,15 +12338,15 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
static_cast<void*>(blockContent));
}
#endif
- RecreateFramesForContent(blockContent, true, REMOVE_FOR_RECONSTRUCTION,
- nullptr);
+ RecreateFramesForContent(blockContent, InsertionKind::Async,
+ REMOVE_FOR_RECONSTRUCTION);
return true;
}
-nsresult
-nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame,
- RemoveFlags aFlags,
- nsIContent** aDestroyedFramesFor)
+void
+nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame,
+ InsertionKind aInsertionKind,
+ RemoveFlags aFlags)
{
#ifdef DEBUG
@@ -12590,7 +12366,7 @@ nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame,
// don't ReframeContainingBlock, this will result in a crash
// if we remove a tree that's in reflow - see bug 121368 for testcase
NS_ERROR("Atemptted to nsCSSFrameConstructor::ReframeContainingBlock during a Reflow!!!");
- return NS_OK;
+ return;
}
// Get the first "normal" ancestor of the target frame.
@@ -12606,23 +12382,25 @@ nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame,
// so GetFloatContainingBlock(aFrame) has been removed
// And get the containingBlock's content
- nsCOMPtr<nsIContent> blockContent = containingBlock->GetContent();
- if (blockContent) {
+ if (nsIContent* blockContent = containingBlock->GetContent()) {
#ifdef DEBUG
if (gNoisyContentUpdates) {
printf(" ==> blockContent=%p\n", static_cast<void*>(blockContent));
}
#endif
- return RecreateFramesForContent(blockContent, true, aFlags, aDestroyedFramesFor);
+ RecreateFramesForContent(blockContent->AsElement(), aInsertionKind,
+ REMOVE_FOR_RECONSTRUCTION);
+ return;
}
}
// If we get here, we're screwed!
- return RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
- true, aFlags, nullptr);
+ RecreateFramesForContent(mPresShell->GetDocument()->GetRootElement(),
+ aInsertionKind,
+ REMOVE_FOR_RECONSTRUCTION);
}
-nsresult
+void
nsCSSFrameConstructor::GenerateChildFrames(nsContainerFrame* aFrame)
{
{
@@ -12656,8 +12434,6 @@ nsCSSFrameConstructor::GenerateChildFrames(nsContainerFrame* aFrame)
// call XBL constructors after the frames are created
mPresShell->GetDocument()->BindingManager()->ProcessAttachedQueue();
-
- return NS_OK;
}
//////////////////////////////////////////////////////////
diff --git a/layout/base/nsCSSFrameConstructor.h b/layout/base/nsCSSFrameConstructor.h
index 7d1b8d42f..0de00a90c 100644
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -48,7 +48,7 @@ class FlattenedChildIterator;
} // namespace dom
} // namespace mozilla
-class nsCSSFrameConstructor : public nsFrameManager
+class nsCSSFrameConstructor final : public nsFrameManager
{
public:
typedef mozilla::CSSPseudoElementType CSSPseudoElementType;
@@ -60,7 +60,7 @@ public:
nsCSSFrameConstructor(nsIDocument* aDocument, nsIPresShell* aPresShell);
~nsCSSFrameConstructor(void) {
- NS_ASSERTION(mUpdateCount == 0, "Dying in the middle of our own update?");
+ MOZ_ASSERT(mUpdateCount == 0, "Dying in the middle of our own update?");
}
// get the alternate text for a content node
@@ -78,7 +78,7 @@ public:
nsIFrame* ConstructRootFrame();
- nsresult ReconstructDocElementHierarchy();
+ void ReconstructDocElementHierarchy();
// Create frames for content nodes that are marked as needing frames. This
// should be called before ProcessPendingRestyles.
@@ -97,8 +97,8 @@ private:
// aChild is the child being inserted for inserts, and the first
// child being appended for appends.
bool MaybeConstructLazily(Operation aOperation,
- nsIContent* aContainer,
- nsIContent* aChild);
+ nsIContent* aContainer,
+ nsIContent* aChild);
// Issues a single ContentInserted for each child of aContainer in the range
// [aStartChild, aEndChild).
@@ -152,8 +152,8 @@ private:
// Returns true if parent was recreated due to frameset child, false otherwise.
bool MaybeRecreateForFrameset(nsIFrame* aParentFrame,
- nsIContent* aStartChild,
- nsIContent* aEndChild);
+ nsIContent* aStartChild,
+ nsIContent* aEndChild);
public:
/**
@@ -202,16 +202,16 @@ public:
// If aAllowLazyConstruction is true then frame construction of the new
// children can be done lazily.
- nsresult ContentAppended(nsIContent* aContainer,
- nsIContent* aFirstNewContent,
- bool aAllowLazyConstruction);
+ void ContentAppended(nsIContent* aContainer,
+ nsIContent* aFirstNewContent,
+ bool aAllowLazyConstruction);
// If aAllowLazyConstruction is true then frame construction of the new child
// can be done lazily.
- nsresult ContentInserted(nsIContent* aContainer,
- nsIContent* aChild,
- nsILayoutHistoryState* aFrameState,
- bool aAllowLazyConstruction);
+ void ContentInserted(nsIContent* aContainer,
+ nsIContent* aChild,
+ nsILayoutHistoryState* aFrameState,
+ bool aAllowLazyConstruction);
// Like ContentInserted but handles inserting the children of aContainer in
// the range [aStartChild, aEndChild). aStartChild must be non-null.
@@ -219,12 +219,17 @@ public:
// aStartChild. If aAllowLazyConstruction is true then frame construction of
// the new children can be done lazily. It is only allowed to be true when
// inserting a single node.
- nsresult ContentRangeInserted(nsIContent* aContainer,
- nsIContent* aStartChild,
- nsIContent* aEndChild,
- nsILayoutHistoryState* aFrameState,
- bool aAllowLazyConstruction);
+ void ContentRangeInserted(nsIContent* aContainer,
+ nsIContent* aStartChild,
+ nsIContent* aEndChild,
+ nsILayoutHistoryState* aFrameState,
+ bool aAllowLazyConstruction);
+public:
+ // FIXME(emilio): How important is it to keep the frame tree state around for
+ // REMOVE_DESTROY_FRAMES?
+ //
+ // Seems like otherwise we could just remove it.
enum RemoveFlags {
REMOVE_CONTENT, REMOVE_FOR_RECONSTRUCTION, REMOVE_DESTROY_FRAMES };
/**
@@ -243,15 +248,14 @@ public:
* only when aFlags == REMOVE_DESTROY_FRAMES, otherwise it will only be
* captured if we reconstructed frames for an ancestor.
*/
- nsresult ContentRemoved(nsIContent* aContainer,
- nsIContent* aChild,
- nsIContent* aOldNextSibling,
- RemoveFlags aFlags,
- bool* aDidReconstruct,
- nsIContent** aDestroyedFramesFor = nullptr);
+ void ContentRemoved(nsIContent* aContainer,
+ nsIContent* aChild,
+ nsIContent* aOldNextSibling,
+ RemoveFlags aFlags,
+ bool* aDidReconstruct);
- nsresult CharacterDataChanged(nsIContent* aContent,
- CharacterDataChangeInfo* aInfo);
+ void CharacterDataChanged(nsIContent* aContent,
+ CharacterDataChangeInfo* aInfo);
// If aContent is a text node that has been optimized away due to being
// whitespace next to a block boundary (or for some other reason), stop
@@ -260,8 +264,8 @@ public:
// Returns the frame for aContent if there is one.
nsIFrame* EnsureFrameForTextNode(nsGenericDOMDataNode* aContent);
- // generate the child frames and process bindings
- nsresult GenerateChildFrames(nsContainerFrame* aFrame);
+ // Generate the child frames and process bindings
+ void GenerateChildFrames(nsContainerFrame* aFrame);
// Should be called when a frame is going to be destroyed and
// WillDestroyFrameTree hasn't been called yet.
@@ -280,14 +284,10 @@ public:
/**
* Destroy the frames for aContent. Note that this may destroy frames
- * for an ancestor instead - aDestroyedFramesFor contains the content node
- * where frames were actually destroyed (which should be used in the
- * ContentInserted call to recreate frames). The frame tree state
- * is captured before the frames are destroyed and can be retrieved using
- * GetLastCapturedLayoutHistoryState().
+ * for an ancestor instead - aDidReconstruct contains whether a reconstruct
+ * was posted for any ancestor.
*/
- void DestroyFramesFor(nsIContent* aContent,
- nsIContent** aDestroyedFramesFor);
+ void DestroyFramesFor(nsIContent* aContent, bool* aDidReconstruct);
// Request to create a continuing frame. This method never returns null.
nsIFrame* CreateContinuingFrame(nsPresContext* aPresContext,
@@ -303,11 +303,11 @@ public:
*/
InsertionPoint GetInsertionPoint(nsIContent* aContainer, nsIContent* aChild);
- nsresult CreateListBoxContent(nsContainerFrame* aParentFrame,
- nsIFrame* aPrevFrame,
- nsIContent* aChild,
- nsIFrame** aResult,
- bool aIsAppend);
+ void CreateListBoxContent(nsContainerFrame* aParentFrame,
+ nsIFrame* aPrevFrame,
+ nsIContent* aChild,
+ nsIFrame** aResult,
+ bool aIsAppend);
// GetInitialContainingBlock() is deprecated in favor of GetRootElementFrame();
// nsIFrame* GetInitialContainingBlock() { return mRootElementFrame; }
@@ -322,15 +322,6 @@ public:
nsContainerFrame* GetDocElementContainingBlock()
{ return mDocElementContainingBlock; }
- /**
- * Return the layout history state that was captured in the last
- * ContentRemoved / RecreateFramesForContent call.
- */
- nsILayoutHistoryState* GetLastCapturedLayoutHistoryState()
- {
- return mTempFrameTreeState;
- }
-
private:
struct FrameConstructionItem;
class FrameConstructionItemList;
@@ -364,7 +355,8 @@ private:
already_AddRefed<nsStyleContext>
ResolveStyleContext(nsStyleContext* aParentStyleContext,
nsIContent* aContent,
- nsFrameConstructorState* aState);
+ nsFrameConstructorState* aState,
+ Element* aOriginatingElementOrNull = nullptr);
// Add the frame construction items for the given aContent and aParentFrame
// to the list. This might add more than one item in some rare cases.
@@ -418,14 +410,14 @@ private:
* @param [out] aNewContent the content node we create
* @param [out] aNewFrame the new frame we create
*/
- nsresult CreateAttributeContent(nsIContent* aParentContent,
- nsIFrame* aParentFrame,
- int32_t aAttrNamespace,
- nsIAtom* aAttrName,
- nsStyleContext* aStyleContext,
- nsCOMArray<nsIContent>& aGeneratedContent,
- nsIContent** aNewContent,
- nsIFrame** aNewFrame);
+ void CreateAttributeContent(nsIContent* aParentContent,
+ nsIFrame* aParentFrame,
+ int32_t aAttrNamespace,
+ nsIAtom* aAttrName,
+ nsStyleContext* aStyleContext,
+ nsCOMArray<nsIContent>& aGeneratedContent,
+ nsIContent** aNewContent,
+ nsIFrame** aNewFrame);
/**
* Create a text node containing the given string. If aText is non-null
@@ -463,11 +455,11 @@ private:
// aParentFrame. aPrevSibling must be the frame after which aFrameList is to
// be placed on aParentFrame's principal child list. It may be null if
// aFrameList is being added at the beginning of the child list.
- nsresult AppendFramesToParent(nsFrameConstructorState& aState,
- nsContainerFrame* aParentFrame,
- nsFrameItems& aFrameList,
- nsIFrame* aPrevSibling,
- bool aIsRecursiveCall = false);
+ void AppendFramesToParent(nsFrameConstructorState& aState,
+ nsContainerFrame* aParentFrame,
+ nsFrameItems& aFrameList,
+ nsIFrame* aPrevSibling,
+ bool aIsRecursiveCall = false);
// BEGIN TABLE SECTION
/**
@@ -1440,12 +1432,6 @@ private:
nsFrameItems& aFrameItems);
static bool AtLineBoundary(FCItemIterator& aIter);
- nsresult CreateAnonymousFrames(nsFrameConstructorState& aState,
- nsIContent* aParent,
- nsContainerFrame* aParentFrame,
- PendingBinding* aPendingBinding,
- nsFrameItems& aChildItems);
-
nsresult GetAnonymousContent(nsIContent* aParent,
nsIFrame* aParentFrame,
nsTArray<nsIAnonymousContentCreator::ContentInfo>& aAnonContent);
@@ -1697,7 +1683,7 @@ private:
// InitializeSelectFrame puts scrollFrame in aFrameItems if aBuildCombobox is false
// aBuildCombobox indicates if we are building a combobox that has a dropdown
// popup widget or not.
- nsresult
+ void
InitializeSelectFrame(nsFrameConstructorState& aState,
nsContainerFrame* aScrollFrame,
nsContainerFrame* aScrolledFrame,
@@ -1718,34 +1704,36 @@ private:
nsStyleContext* MaybeRecreateFramesForElement(Element* aElement);
/**
+ * Whether insertion should be done synchronously or asynchronously.
+ *
+ * Generally, insertion is synchronous if we're reconstructing something from
+ * frame construction/reconstruction, and async if we're removing stuff, like
+ * from ContentRemoved.
+ */
+ enum class InsertionKind
+ {
+ Sync,
+ Async,
+ };
+
+ /**
* Recreate frames for aContent.
* @param aContent the content to recreate frames for
- * @param aAsyncInsert if true then a restyle event will be posted to handle
- * the required ContentInserted call instead of doing it immediately.
* @param aFlags normally you want to pass REMOVE_FOR_RECONSTRUCTION here
- * @param aDestroyedFramesFor if non-null, it will contain the content that
- * was actually reframed - it may be different than aContent.
*/
- nsresult
- RecreateFramesForContent(nsIContent* aContent,
- bool aAsyncInsert,
- RemoveFlags aFlags,
- nsIContent** aDestroyedFramesFor);
+ void RecreateFramesForContent(nsIContent* aContent,
+ InsertionKind aInsertionKind,
+ RemoveFlags aFlags);
// If removal of aFrame from the frame tree requires reconstruction of some
// containing block (either of aFrame or of its parent) due to {ib} splits or
// table pseudo-frames, recreate the relevant frame subtree. The return value
- // indicates whether this happened. If this method returns true, *aResult is
- // the return value of ReframeContainingBlock or RecreateFramesForContent. If
- // this method returns false, the value of *aResult is not affected. aFrame
- // and aResult must not be null. aFrame must be the result of a
+ // indicates whether this happened. aFrame must be the result of a
// GetPrimaryFrame() call on a content node (which means its parent is also
- // not null). If this method returns true, aDestroyedFramesFor contains the
- // content that was reframed.
- bool MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
- RemoveFlags aFlags,
- nsresult* aResult,
- nsIContent** aDestroyedFramesFor);
+ // not null).
+ bool MaybeRecreateContainerForFrameRemoval(nsIFrame* aFrame,
+ InsertionKind aInsertionKind,
+ RemoveFlags aFlags);
nsIFrame* CreateContinuingOuterTableFrame(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
@@ -1869,9 +1857,9 @@ private:
bool aIsAppend,
nsIFrame* aPrevSibling);
- nsresult ReframeContainingBlock(nsIFrame* aFrame,
- RemoveFlags aFlags,
- nsIContent** aReframeContent);
+ void ReframeContainingBlock(nsIFrame* aFrame,
+ InsertionKind aInsertionKind,
+ RemoveFlags aFlags);
//----------------------------------------
@@ -1925,18 +1913,18 @@ private:
void RecoverLetterFrames(nsContainerFrame* aBlockFrame);
//
- nsresult RemoveLetterFrames(nsIPresShell* aPresShell,
- nsContainerFrame* aBlockFrame);
+ void RemoveLetterFrames(nsIPresShell* aPresShell,
+ nsContainerFrame* aBlockFrame);
// Recursive helper for RemoveLetterFrames
- nsresult RemoveFirstLetterFrames(nsIPresShell* aPresShell,
- nsContainerFrame* aFrame,
- nsContainerFrame* aBlockFrame,
- bool* aStopLooking);
+ void RemoveFirstLetterFrames(nsIPresShell* aPresShell,
+ nsContainerFrame* aFrame,
+ nsContainerFrame* aBlockFrame,
+ bool* aStopLooking);
// Special remove method for those pesky floating first-letter frames
- nsresult RemoveFloatingFirstLetterFrames(nsIPresShell* aPresShell,
- nsIFrame* aBlockFrame);
+ void RemoveFloatingFirstLetterFrames(nsIPresShell* aPresShell,
+ nsIFrame* aBlockFrame);
// Capture state for the frame tree rooted at the frame associated with the
// content object, aContent
@@ -1967,71 +1955,53 @@ private:
nsContainerFrame* aBlockFrame,
nsFrameItems& aFrameItems);
- nsresult InsertFirstLineFrames(nsFrameConstructorState& aState,
- nsIContent* aContent,
- nsIFrame* aBlockFrame,
- nsContainerFrame** aParentFrame,
- nsIFrame* aPrevSibling,
- nsFrameItems& aFrameItems);
+ // The direction in which we should look for siblings.
+ enum class SiblingDirection
+ {
+ Forward,
+ Backward,
+ };
/**
- * Find the right frame to use for aContent when looking for sibling
- * frames for aTargetContent. If aPrevSibling is true, this
- * will look for last continuations, etc, as necessary. This calls
- * IsValidSibling as needed; if that returns false it returns null.
+ * Find the frame for the content immediately next to the one aIter points to,
+ * in the direction SiblingDirection indicates, following continuations if
+ * necessary.
*
- * @param aContent the content to search for frames
- * @param aTargetContent the content we're finding a sibling frame for
- * @param aTargetContentDisplay the CSS display enum for aTargetContent if
- * already known, UNSET_DISPLAY otherwise. It will be filled in
- * if needed.
- * @param aParentFrame the nearest ancestor frame, used internally for
- * finding ::after / ::before frames
- * @param aPrevSibling true if we're searching in reverse DOM order
- */
- nsIFrame* FindFrameForContentSibling(nsIContent* aContent,
- nsIContent* aTargetContent,
- mozilla::StyleDisplay& aTargetContentDisplay,
- nsContainerFrame* aParentFrame,
- bool aPrevSibling);
-
- /**
- * Find the frame for the content immediately preceding the one aIter
- * points to, following continuations if necessary. aIter is passed by
- * value on purpose, so as not to modify the caller's iterator.
+ * aIter is passed by const reference on purpose, so as not to modify the
+ * caller's iterator.
*
* @param aIter should be positioned such that aIter.GetPreviousChild()
* is the first content to search for frames
- * @param aTargetContent the content we're finding a sibling frame for
- * @param aTargetContentDisplay the CSS display enum for aTargetContent if
- * already known, UNSET_DISPLAY otherwise. It will be filled in
- * if needed.
- * @param aParentFrame the nearest ancestor frame, used inernally for
- * finding ::after / ::before frames
- */
- nsIFrame* FindPreviousSibling(mozilla::dom::FlattenedChildIterator aIter,
- nsIContent* aTargetContent,
- mozilla::StyleDisplay& aTargetContentDisplay,
- nsContainerFrame* aParentFrame);
-
- /**
- * Find the frame for the content node immediately following the one aIter
- * points to, following continuations if necessary. aIter is passed by value
- * on purpose, so as not to modify the caller's iterator.
- *
- * @param aIter should be positioned such that aIter.GetNextChild()
- * is the first content to search for frames
- * @param aTargetContent the content we're finding a sibling frame for
- * @param aTargetContentDisplay the CSS display enum for aTargetContent if
- * already known, UNSET_DISPLAY otherwise. It will be filled in
- * if needed.
- * @param aParentFrame the nearest ancestor frame, used inernally for
- * finding ::after / ::before frames
+ * @param aTargetContentDisplay the CSS display enum for the content aIter
+ * points to if already known, UNSET_DISPLAY otherwise. It will be
+ * filled in if needed.
*/
- nsIFrame* FindNextSibling(mozilla::dom::FlattenedChildIterator aIter,
- nsIContent* aTargetContent,
- mozilla::StyleDisplay& aTargetContentDisplay,
- nsContainerFrame* aParentFrame);
+ template<SiblingDirection>
+ nsIFrame* FindSibling(const mozilla::dom::FlattenedChildIterator& aIter,
+ mozilla::StyleDisplay& aTargetContentDisplay);
+
+ // Helper for the implementation of FindSibling.
+ template<SiblingDirection>
+ nsIFrame* FindSiblingInternal(
+ mozilla::dom::FlattenedChildIterator,
+ nsIContent* aTargetContent,
+ mozilla::StyleDisplay& aTargetContentDisplay);
+
+ // An alias of FindSibling<SiblingDirection::Forward>.
+ nsIFrame* FindNextSibling(const mozilla::dom::FlattenedChildIterator& aIter,
+ mozilla::StyleDisplay& aTargetContentDisplay);
+ // An alias of FindSibling<SiblingDirection::Backwards>.
+ nsIFrame* FindPreviousSibling(const mozilla::dom::FlattenedChildIterator& aIter,
+ mozilla::StyleDisplay& aTargetContentDisplay);
+
+ // Given a potential first-continuation sibling frame for aTargetContent,
+ // verify that it is an actual valid sibling for it, and return the
+ // appropriate continuation the new frame for aTargetContent should be
+ // inserted next to.
+ nsIFrame* AdjustSiblingFrame(nsIFrame* aSibling,
+ nsIContent* aTargetContent,
+ mozilla::StyleDisplay& aTargetContentDisplay,
+ SiblingDirection aDirection);
// Find the right previous sibling for an insertion. This also updates the
// parent frame to point to the correct continuation of the parent frame to
diff --git a/layout/base/nsFrameManager.cpp b/layout/base/nsFrameManager.cpp
index 97b022da8..be8cd7147 100644
--- a/layout/base/nsFrameManager.cpp
+++ b/layout/base/nsFrameManager.cpp
@@ -38,47 +38,17 @@
#include "nsIStatefulFrame.h"
#include "nsContainerFrame.h"
- #ifdef DEBUG
- //#define DEBUG_UNDISPLAYED_MAP
- //#define DEBUG_DISPLAY_CONTENTS_MAP
- #else
- #undef DEBUG_UNDISPLAYED_MAP
- #undef DEBUG_DISPLAY_CONTENTS_MAP
- #endif
+// #define DEBUG_UNDISPLAYED_MAP
+// #define DEBUG_DISPLAY_CONTENTS_MAP
using namespace mozilla;
using namespace mozilla::dom;
//----------------------------------------------------------------------
-struct PlaceholderMapEntry : public PLDHashEntryHdr {
- // key (the out of flow frame) can be obtained through placeholder frame
- nsPlaceholderFrame *placeholderFrame;
-};
-
-static bool
-PlaceholderMapMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
-{
- const PlaceholderMapEntry *entry =
- static_cast<const PlaceholderMapEntry*>(hdr);
- NS_ASSERTION(entry->placeholderFrame->GetOutOfFlowFrame() !=
- (void*)0xdddddddd,
- "Dead placeholder in placeholder map");
- return entry->placeholderFrame->GetOutOfFlowFrame() == key;
-}
-
-static const PLDHashTableOps PlaceholderMapOps = {
- PLDHashTable::HashVoidPtrKeyStub,
- PlaceholderMapMatchEntry,
- PLDHashTable::MoveEntryStub,
- PLDHashTable::ClearEntryStub,
- nullptr
-};
-
nsFrameManagerBase::nsFrameManagerBase()
: mPresShell(nullptr)
, mRootFrame(nullptr)
- , mPlaceholderMap(&PlaceholderMapOps, sizeof(PlaceholderMapEntry))
, mUndisplayedMap(nullptr)
, mDisplayContentsMap(nullptr)
, mIsDestroyingFrames(false)
@@ -87,40 +57,49 @@ nsFrameManagerBase::nsFrameManagerBase()
//----------------------------------------------------------------------
-// XXXldb This seems too complicated for what I think it's doing, and it
-// should also be using PLDHashTable rather than plhash to use less memory.
+/**
+ * The undisplayed map is a class that maps a parent content node to the
+ * undisplayed content children, and their style contexts.
+ *
+ * The linked list of nodes holds strong references to the style contexts and
+ * the content.
+ */
+class nsFrameManagerBase::UndisplayedMap :
+ private nsClassHashtable<nsPtrHashKey<nsIContent>,
+ LinkedList<UndisplayedNode>>
+{
+ typedef nsClassHashtable<nsPtrHashKey<nsIContent>, LinkedList<UndisplayedNode>> base_type;
-class nsFrameManagerBase::UndisplayedMap {
public:
- explicit UndisplayedMap(uint32_t aNumBuckets = 16);
- ~UndisplayedMap(void);
+ UndisplayedMap();
+ ~UndisplayedMap();
UndisplayedNode* GetFirstNode(nsIContent* aParentContent);
- nsresult AddNodeFor(nsIContent* aParentContent,
- nsIContent* aChild, nsStyleContext* aStyle);
+ void AddNodeFor(nsIContent* aParentContent,
+ nsIContent* aChild,
+ nsStyleContext* aStyle);
- void RemoveNodeFor(nsIContent* aParentContent,
- UndisplayedNode* aNode);
+ void RemoveNodeFor(nsIContent* aParentContent, UndisplayedNode* aNode);
void RemoveNodesFor(nsIContent* aParentContent);
- UndisplayedNode* UnlinkNodesFor(nsIContent* aParentContent);
+
+ nsAutoPtr<LinkedList<UndisplayedNode>>
+ UnlinkNodesFor(nsIContent* aParentContent);
// Removes all entries from the hash table
- void Clear(void);
+ void Clear();
protected:
+ LinkedList<UndisplayedNode>* GetListFor(nsIContent* aParentContent);
+ LinkedList<UndisplayedNode>* GetOrCreateListFor(nsIContent* aParentContent);
+ void AppendNodeFor(UndisplayedNode* aNode, nsIContent* aParentContent);
/**
- * Gets the entry for the provided parent content. If the content
- * is a <xbl:children> element, |**aParentContent| is set to
- * the parent of the children element.
+ * Get the applicable parent for the map lookup. This is almost always the
+ * provided argument, except if it's a <xbl:children> element, in which case
+ * it's the parent of the children element.
*/
- PLHashEntry** GetEntryFor(nsIContent** aParentContent);
- void AppendNodeFor(UndisplayedNode* aNode,
- nsIContent* aParentContent);
-
- PLHashTable* mTable;
- PLHashEntry** mLastLookup;
+ nsIContent* GetApplicableParent(nsIContent* aParent);
};
//----------------------------------------------------------------------
@@ -138,14 +117,10 @@ nsFrameManager::Destroy()
// Destroy the frame hierarchy.
mPresShell->SetIgnoreFrameDestruction(true);
- // Unregister all placeholders before tearing down the frame tree
- nsFrameManager::ClearPlaceholderFrameMap();
-
if (mRootFrame) {
mRootFrame->Destroy();
mRootFrame = nullptr;
}
-
delete mUndisplayedMap;
mUndisplayedMap = nullptr;
delete mDisplayContentsMap;
@@ -156,58 +131,9 @@ nsFrameManager::Destroy()
//----------------------------------------------------------------------
-// Placeholder frame functions
-nsPlaceholderFrame*
-nsFrameManager::GetPlaceholderFrameFor(const nsIFrame* aFrame)
-{
- NS_PRECONDITION(aFrame, "null param unexpected");
-
- auto entry = static_cast<PlaceholderMapEntry*>
- (const_cast<PLDHashTable*>(&mPlaceholderMap)->Search(aFrame));
- if (entry) {
- return entry->placeholderFrame;
- }
-
- return nullptr;
-}
-
-void
-nsFrameManager::RegisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame)
-{
- MOZ_ASSERT(aPlaceholderFrame, "null param unexpected");
- MOZ_ASSERT(nsGkAtoms::placeholderFrame == aPlaceholderFrame->GetType(),
- "unexpected frame type");
- auto entry = static_cast<PlaceholderMapEntry*>
- (mPlaceholderMap.Add(aPlaceholderFrame->GetOutOfFlowFrame()));
- MOZ_ASSERT(!entry->placeholderFrame,
- "Registering a placeholder for a frame that already has a placeholder!");
- entry->placeholderFrame = aPlaceholderFrame;
-}
-
-void
-nsFrameManager::UnregisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame)
-{
- NS_PRECONDITION(aPlaceholderFrame, "null param unexpected");
- NS_PRECONDITION(nsGkAtoms::placeholderFrame == aPlaceholderFrame->GetType(),
- "unexpected frame type");
-
- mPlaceholderMap.Remove(aPlaceholderFrame->GetOutOfFlowFrame());
-}
-
-void
-nsFrameManager::ClearPlaceholderFrameMap()
-{
- for (auto iter = mPlaceholderMap.Iter(); !iter.Done(); iter.Next()) {
- auto entry = static_cast<PlaceholderMapEntry*>(iter.Get());
- entry->placeholderFrame->SetOutOfFlowFrame(nullptr);
- }
- mPlaceholderMap.Clear();
-}
-
-//----------------------------------------------------------------------
-
/* static */ nsStyleContext*
-nsFrameManager::GetStyleContextInMap(UndisplayedMap* aMap, nsIContent* aContent)
+nsFrameManager::GetStyleContextInMap(UndisplayedMap* aMap,
+ const nsIContent* aContent)
{
if (!aContent) {
return nullptr;
@@ -215,7 +141,7 @@ nsFrameManager::GetStyleContextInMap(UndisplayedMap* aMap, nsIContent* aContent)
nsIContent* parent = aContent->GetParentElementCrossingShadowRoot();
MOZ_ASSERT(parent || !aContent->GetParent(), "no non-elements");
for (UndisplayedNode* node = aMap->GetFirstNode(parent);
- node; node = node->mNext) {
+ node; node = node->getNext()) {
if (node->mContent == aContent)
return node->mStyle;
}
@@ -241,16 +167,16 @@ nsFrameManager::SetStyleContextInMap(UndisplayedMap* aMap,
nsIContent* aContent,
nsStyleContext* aStyleContext)
{
- NS_PRECONDITION(!aStyleContext->GetPseudo(),
- "Should only have actual elements here");
+ MOZ_ASSERT(!aStyleContext->GetPseudo(),
+ "Should only have actual elements here");
#if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_BOX_CONTENTS_MAP)
static int i = 0;
printf("SetStyleContextInMap(%d): p=%p \n", i++, (void *)aContent);
#endif
- NS_ASSERTION(!GetStyleContextInMap(aMap, aContent),
- "Already have an entry for aContent");
+ MOZ_ASSERT(!GetStyleContextInMap(aMap, aContent),
+ "Already have an entry for aContent");
nsIContent* parent = aContent->GetParentElementCrossingShadowRoot();
MOZ_ASSERT(parent || !aContent->GetParent(), "no non-elements");
@@ -287,7 +213,7 @@ nsFrameManager::ChangeStyleContextInMap(UndisplayedMap* aMap,
#endif
for (UndisplayedNode* node = aMap->GetFirstNode(aContent->GetParent());
- node; node = node->mNext) {
+ node; node = node->getNext()) {
if (node->mContent == aContent) {
node->mStyle = aStyleContext;
return;
@@ -306,25 +232,25 @@ nsFrameManager::ClearUndisplayedContentIn(nsIContent* aContent,
printf("ClearUndisplayedContent(%d): content=%p parent=%p --> ", i++, (void *)aContent, (void*)aParentContent);
#endif
- if (mUndisplayedMap) {
- UndisplayedNode* node = mUndisplayedMap->GetFirstNode(aParentContent);
- while (node) {
- if (node->mContent == aContent) {
- mUndisplayedMap->RemoveNodeFor(aParentContent, node);
+ if (!mUndisplayedMap) {
+ return;
+ }
+
+ for (UndisplayedNode* node = mUndisplayedMap->GetFirstNode(aParentContent);
+ node; node = node->getNext()) {
+ if (node->mContent == aContent) {
+ mUndisplayedMap->RemoveNodeFor(aParentContent, node);
#ifdef DEBUG_UNDISPLAYED_MAP
- printf( "REMOVED!\n");
+ printf( "REMOVED!\n");
#endif
-#ifdef DEBUG
- // make sure that there are no more entries for the same content
- nsStyleContext *context = GetUndisplayedContent(aContent);
- NS_ASSERTION(context == nullptr, "Found more undisplayed content data after removal");
-#endif
- return;
- }
- node = node->mNext;
+ // make sure that there are no more entries for the same content
+ MOZ_ASSERT(!GetUndisplayedContent(aContent),
+ "Found more undisplayed content data after removal");
+ return;
}
}
+
#ifdef DEBUG_UNDISPLAYED_MAP
printf( "not found.\n");
#endif
@@ -380,26 +306,25 @@ nsFrameManager::ClearDisplayContentsIn(nsIContent* aContent,
static int i = 0;
printf("ClearDisplayContents(%d): content=%p parent=%p --> ", i++, (void *)aContent, (void*)aParentContent);
#endif
-
- if (mDisplayContentsMap) {
- UndisplayedNode* node = mDisplayContentsMap->GetFirstNode(aParentContent);
- while (node) {
- if (node->mContent == aContent) {
- mDisplayContentsMap->RemoveNodeFor(aParentContent, node);
+
+ if (!mDisplayContentsMap) {
+ return;
+ }
+
+ for (UndisplayedNode* node = mDisplayContentsMap->GetFirstNode(aParentContent);
+ node; node = node->getNext()) {
+ if (node->mContent == aContent) {
+ mDisplayContentsMap->RemoveNodeFor(aParentContent, node);
#ifdef DEBUG_DISPLAY_CONTENTS_MAP
- printf( "REMOVED!\n");
-#endif
-#ifdef DEBUG
- // make sure that there are no more entries for the same content
- nsStyleContext* context = GetDisplayContentsStyleFor(aContent);
- NS_ASSERTION(context == nullptr, "Found more entries for aContent after removal");
+ printf( "REMOVED!\n");
#endif
- ClearAllDisplayContentsIn(aContent);
- ClearAllUndisplayedContentIn(aContent);
- return;
- }
- node = node->mNext;
+ // make sure that there are no more entries for the same content
+ MOZ_ASSERT(!GetDisplayContentsStyleFor(aContent),
+ "Found more entries for aContent after removal");
+ ClearAllDisplayContentsIn(aContent);
+ ClearAllUndisplayedContentIn(aContent);
+ return;
}
}
#ifdef DEBUG_DISPLAY_CONTENTS_MAP
@@ -416,14 +341,14 @@ nsFrameManager::ClearAllDisplayContentsIn(nsIContent* aParentContent)
#endif
if (mDisplayContentsMap) {
- UndisplayedNode* cur = mDisplayContentsMap->UnlinkNodesFor(aParentContent);
- while (cur) {
- UndisplayedNode* next = cur->mNext;
- cur->mNext = nullptr;
- ClearAllDisplayContentsIn(cur->mContent);
- ClearAllUndisplayedContentIn(cur->mContent);
- delete cur;
- cur = next;
+ nsAutoPtr<LinkedList<UndisplayedNode>> list =
+ mDisplayContentsMap->UnlinkNodesFor(aParentContent);
+ if (list) {
+ while (UndisplayedNode* node = list->popFirst()) {
+ ClearAllDisplayContentsIn(node->mContent);
+ ClearAllUndisplayedContentIn(node->mContent);
+ delete node;
+ }
}
}
@@ -495,7 +420,7 @@ nsFrameManager::RemoveFrame(ChildListID aListID,
aOldFrame->GetType() == nsGkAtoms::textFrame,
"Must remove first continuation.");
NS_ASSERTION(!(aOldFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW &&
- GetPlaceholderFrameFor(aOldFrame)),
+ aOldFrame->GetPlaceholderFrame()),
"Must call RemoveFrame on placeholder for out-of-flows.");
nsContainerFrame* parentFrame = aOldFrame->GetParent();
if (parentFrame->IsAbsoluteContainer() &&
@@ -654,182 +579,132 @@ nsFrameManager::RestoreFrameState(nsIFrame* aFrame,
//----------------------------------------------------------------------
-static PLHashNumber
-HashKey(void* key)
-{
- return NS_PTR_TO_INT32(key);
-}
-
-static int
-CompareKeys(void* key1, void* key2)
-{
- return key1 == key2;
-}
-
-//----------------------------------------------------------------------
-
-nsFrameManagerBase::UndisplayedMap::UndisplayedMap(uint32_t aNumBuckets)
+nsFrameManagerBase::UndisplayedMap::UndisplayedMap()
{
MOZ_COUNT_CTOR(nsFrameManagerBase::UndisplayedMap);
- mTable = PL_NewHashTable(aNumBuckets, (PLHashFunction)HashKey,
- (PLHashComparator)CompareKeys,
- (PLHashComparator)nullptr,
- nullptr, nullptr);
- mLastLookup = nullptr;
}
nsFrameManagerBase::UndisplayedMap::~UndisplayedMap(void)
{
MOZ_COUNT_DTOR(nsFrameManagerBase::UndisplayedMap);
Clear();
- PL_HashTableDestroy(mTable);
}
-PLHashEntry**
-nsFrameManagerBase::UndisplayedMap::GetEntryFor(nsIContent** aParentContent)
+void
+nsFrameManagerBase::UndisplayedMap::Clear()
{
- nsIContent* parentContent = *aParentContent;
-
- if (mLastLookup && (parentContent == (*mLastLookup)->key)) {
- return mLastLookup;
+ for (auto iter = Iter(); !iter.Done(); iter.Next()) {
+ auto* list = iter.UserData();
+ while (auto* node = list->popFirst()) {
+ delete node;
+ }
+ iter.Remove();
}
+}
+nsIContent*
+nsFrameManagerBase::UndisplayedMap::GetApplicableParent(nsIContent* aParent)
+{
// In the case of XBL default content, <xbl:children> elements do not get a
// frame causing a mismatch between the content tree and the frame tree.
// |GetEntryFor| is sometimes called with the content tree parent (which may
// be a <xbl:children> element) but the parent in the frame tree would be the
// insertion parent (parent of the <xbl:children> element). Here the children
// elements are normalized to the insertion parent to correct for the mismatch.
- if (parentContent && nsContentUtils::IsContentInsertionPoint(parentContent)) {
- parentContent = parentContent->GetParent();
- // Change the caller's pointer for the parent content to be the insertion parent.
- *aParentContent = parentContent;
+ if (aParent && aParent->IsActiveChildrenElement()) {
+ return aParent->GetParent();
}
- PLHashNumber hashCode = NS_PTR_TO_INT32(parentContent);
- PLHashEntry** entry = PL_HashTableRawLookup(mTable, hashCode, parentContent);
- if (*entry) {
- mLastLookup = entry;
- }
- return entry;
+ return aParent;
}
-UndisplayedNode*
-nsFrameManagerBase::UndisplayedMap::GetFirstNode(nsIContent* aParentContent)
+LinkedList<UndisplayedNode>*
+nsFrameManagerBase::UndisplayedMap::GetListFor(nsIContent* aParent)
{
- PLHashEntry** entry = GetEntryFor(&aParentContent);
- if (*entry) {
- return (UndisplayedNode*)((*entry)->value);
+ aParent = GetApplicableParent(aParent);
+
+ LinkedList<UndisplayedNode>* list;
+ if (Get(aParent, &list)) {
+ return list;
}
+
return nullptr;
}
+LinkedList<UndisplayedNode>*
+nsFrameManagerBase::UndisplayedMap::GetOrCreateListFor(nsIContent* aParent)
+{
+ aParent = GetApplicableParent(aParent);
+ return LookupOrAdd(aParent);
+}
+
+
+UndisplayedNode*
+nsFrameManagerBase::UndisplayedMap::GetFirstNode(nsIContent* aParentContent)
+{
+ auto* list = GetListFor(aParentContent);
+ return list ? list->getFirst() : nullptr;
+}
+
void
nsFrameManagerBase::UndisplayedMap::AppendNodeFor(UndisplayedNode* aNode,
nsIContent* aParentContent)
{
- PLHashEntry** entry = GetEntryFor(&aParentContent);
- if (*entry) {
- UndisplayedNode* node = (UndisplayedNode*)((*entry)->value);
- while (node->mNext) {
- if (node->mContent == aNode->mContent) {
- // We actually need to check this in optimized builds because
- // there are some callers that do this. See bug 118014, bug
- // 136704, etc.
- NS_NOTREACHED("node in map twice");
- delete aNode;
- return;
- }
- node = node->mNext;
- }
- node->mNext = aNode;
- }
- else {
- PLHashNumber hashCode = NS_PTR_TO_INT32(aParentContent);
- PL_HashTableRawAdd(mTable, entry, hashCode, aParentContent, aNode);
- mLastLookup = nullptr; // hashtable may have shifted bucket out from under us
+ LinkedList<UndisplayedNode>* list = GetOrCreateListFor(aParentContent);
+
+#ifdef DEBUG
+ for (UndisplayedNode* node = list->getFirst(); node; node = node->getNext()) {
+ // NOTE: In the original code there was a work around for this case, I want
+ // to check it still happens before hacking around it the same way.
+ MOZ_ASSERT(node->mContent != aNode->mContent,
+ "Duplicated content in undisplayed list!");
}
+#endif
+
+ list->insertBack(aNode);
}
-nsresult
+void
nsFrameManagerBase::UndisplayedMap::AddNodeFor(nsIContent* aParentContent,
- nsIContent* aChild,
+ nsIContent* aChild,
nsStyleContext* aStyle)
{
UndisplayedNode* node = new UndisplayedNode(aChild, aStyle);
-
AppendNodeFor(node, aParentContent);
- return NS_OK;
}
void
nsFrameManagerBase::UndisplayedMap::RemoveNodeFor(nsIContent* aParentContent,
UndisplayedNode* aNode)
{
- PLHashEntry** entry = GetEntryFor(&aParentContent);
- NS_ASSERTION(*entry, "content not in map");
- if (*entry) {
- if ((UndisplayedNode*)((*entry)->value) == aNode) { // first node
- if (aNode->mNext) {
- (*entry)->value = aNode->mNext;
- aNode->mNext = nullptr;
- }
- else {
- PL_HashTableRawRemove(mTable, entry, *entry);
- mLastLookup = nullptr; // hashtable may have shifted bucket out from under us
- }
- }
- else {
- UndisplayedNode* node = (UndisplayedNode*)((*entry)->value);
- while (node->mNext) {
- if (node->mNext == aNode) {
- node->mNext = aNode->mNext;
- aNode->mNext = nullptr;
- break;
- }
- node = node->mNext;
- }
- }
- }
+#ifdef DEBUG
+ auto list = GetListFor(aParentContent);
+ MOZ_ASSERT(list, "content not in map");
+ aNode->removeFrom(*list);
+#else
+ aNode->remove();
+#endif
delete aNode;
}
-UndisplayedNode*
+nsAutoPtr<LinkedList<UndisplayedNode>>
nsFrameManagerBase::UndisplayedMap::UnlinkNodesFor(nsIContent* aParentContent)
{
- PLHashEntry** entry = GetEntryFor(&aParentContent);
- NS_ASSERTION(entry, "content not in map");
- if (*entry) {
- UndisplayedNode* node = (UndisplayedNode*)((*entry)->value);
- NS_ASSERTION(node, "null node for non-null entry in UndisplayedMap");
- PL_HashTableRawRemove(mTable, entry, *entry);
- mLastLookup = nullptr; // hashtable may have shifted bucket out from under us
- return node;
- }
- return nullptr;
+ nsAutoPtr<LinkedList<UndisplayedNode>> list;
+ RemoveAndForget(GetApplicableParent(aParentContent), list);
+ return list;
}
void
nsFrameManagerBase::UndisplayedMap::RemoveNodesFor(nsIContent* aParentContent)
{
- delete UnlinkNodesFor(aParentContent);
-}
-
-static int
-RemoveUndisplayedEntry(PLHashEntry* he, int i, void* arg)
-{
- UndisplayedNode* node = (UndisplayedNode*)(he->value);
- delete node;
- // Remove and free this entry and continue enumerating
- return HT_ENUMERATE_REMOVE | HT_ENUMERATE_NEXT;
-}
-
-void
-nsFrameManagerBase::UndisplayedMap::Clear(void)
-{
- mLastLookup = nullptr;
- PL_HashTableEnumerateEntries(mTable, RemoveUndisplayedEntry, 0);
+ nsAutoPtr<LinkedList<UndisplayedNode>> list = UnlinkNodesFor(aParentContent);
+ if (list) {
+ while (auto* node = list->popFirst()) {
+ delete node;
+ }
+ }
}
uint32_t nsFrameManagerBase::sGlobalGenerationNumber;
diff --git a/layout/base/nsFrameManager.h b/layout/base/nsFrameManager.h
index 1b9148314..ae7477d3d 100644
--- a/layout/base/nsFrameManager.h
+++ b/layout/base/nsFrameManager.h
@@ -33,40 +33,25 @@ namespace mozilla {
* Node in a linked list, containing the style for an element that
* does not have a frame but whose parent does have a frame.
*/
-struct UndisplayedNode {
+struct UndisplayedNode : public LinkedListElement<UndisplayedNode>
+{
UndisplayedNode(nsIContent* aContent, nsStyleContext* aStyle)
- : mContent(aContent),
- mStyle(aStyle),
- mNext(nullptr)
+ : mContent(aContent)
+ , mStyle(aStyle)
{
MOZ_COUNT_CTOR(mozilla::UndisplayedNode);
}
- ~UndisplayedNode()
- {
- MOZ_COUNT_DTOR(mozilla::UndisplayedNode);
-
- // Delete mNext iteratively to avoid blowing up the stack (bug 460461).
- UndisplayedNode* cur = mNext;
- while (cur) {
- UndisplayedNode* next = cur->mNext;
- cur->mNext = nullptr;
- delete cur;
- cur = next;
- }
- }
+ ~UndisplayedNode() { MOZ_COUNT_DTOR(mozilla::UndisplayedNode); }
- nsCOMPtr<nsIContent> mContent;
- RefPtr<nsStyleContext> mStyle;
- UndisplayedNode* mNext;
+ nsCOMPtr<nsIContent> mContent;
+ RefPtr<nsStyleContext> mStyle;
};
} // namespace mozilla
/**
- * Frame manager interface. The frame manager serves two purposes:
- * <li>provides a service for mapping from content to frame and from
- * out-of-flow frame to placeholder frame.
+ * Frame manager interface. The frame manager serves one purpose:
* <li>handles structural modifications to the frame model. If the frame model
* lock can be acquired, then the changes are processed immediately; otherwise,
* they're queued and processed later.
@@ -94,15 +79,8 @@ public:
*/
void Destroy();
- // Placeholder frame functions
- nsPlaceholderFrame* GetPlaceholderFrameFor(const nsIFrame* aFrame);
- void RegisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame);
- void UnregisterPlaceholderFrame(nsPlaceholderFrame* aPlaceholderFrame);
-
- void ClearPlaceholderFrameMap();
-
// Mapping undisplayed content
- nsStyleContext* GetUndisplayedContent(nsIContent* aContent)
+ nsStyleContext* GetUndisplayedContent(const nsIContent* aContent)
{
if (!mUndisplayedMap) {
return nullptr;
@@ -127,7 +105,7 @@ public:
/**
* Return the registered display:contents style context for aContent, if any.
*/
- nsStyleContext* GetDisplayContentsStyleFor(nsIContent* aContent)
+ nsStyleContext* GetDisplayContentsStyleFor(const nsIContent* aContent)
{
if (!mDisplayContentsMap) {
return nullptr;
@@ -207,7 +185,7 @@ public:
nsILayoutHistoryState* aState);
protected:
static nsStyleContext* GetStyleContextInMap(UndisplayedMap* aMap,
- nsIContent* aContent);
+ const nsIContent* aContent);
static mozilla::UndisplayedNode*
GetAllUndisplayedNodesInMapFor(UndisplayedMap* aMap,
nsIContent* aParentContent);
diff --git a/layout/base/nsFrameManagerBase.h b/layout/base/nsFrameManagerBase.h
index 757dce7e5..bb192b64f 100644
--- a/layout/base/nsFrameManagerBase.h
+++ b/layout/base/nsFrameManagerBase.h
@@ -53,7 +53,6 @@ protected:
// weak link, because the pres shell owns us
nsIPresShell* MOZ_NON_OWNING_REF mPresShell;
nsIFrame* mRootFrame;
- PLDHashTable mPlaceholderMap;
UndisplayedMap* mUndisplayedMap;
UndisplayedMap* mDisplayContentsMap;
bool mIsDestroyingFrames; // The frame manager is destroying some frame(s).
diff --git a/layout/base/nsFrameTraversal.cpp b/layout/base/nsFrameTraversal.cpp
index 40fb5ff30..76dd40af1 100644
--- a/layout/base/nsFrameTraversal.cpp
+++ b/layout/base/nsFrameTraversal.cpp
@@ -82,6 +82,10 @@ protected:
virtual nsIFrame* GetNextSiblingInner(nsIFrame* aFrame);
virtual nsIFrame* GetPrevSiblingInner(nsIFrame* aFrame);
+ /**
+ * Return the placeholder frame for aFrame if it has one, otherwise return
+ * aFrame itself.
+ */
nsIFrame* GetPlaceholderFrame(nsIFrame* aFrame);
bool IsPopupFrame(nsIFrame* aFrame);
@@ -486,18 +490,11 @@ nsFrameIterator::GetPrevSiblingInner(nsIFrame* aFrame) {
nsIFrame*
nsFrameIterator::GetPlaceholderFrame(nsIFrame* aFrame)
{
- nsIFrame* result = aFrame;
- nsIPresShell *presShell = mPresContext->GetPresShell();
- if (presShell) {
- nsIFrame* placeholder = presShell->GetPlaceholderFrameFor(aFrame);
- if (placeholder)
- result = placeholder;
+ if (MOZ_LIKELY(!aFrame || !aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW))) {
+ return aFrame;
}
-
- if (result != aFrame)
- result = GetPlaceholderFrame(result);
-
- return result;
+ nsIFrame* placeholder = aFrame->GetPlaceholderFrame();
+ return placeholder ? placeholder : aFrame;
}
bool
diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h
index 865f5534c..5f83b9c15 100644
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -486,12 +486,6 @@ public:
virtual nsCanvasFrame* GetCanvasFrame() const = 0;
/**
- * Gets the placeholder frame associated with the specified frame. This is
- * a helper frame that forwards the request to the frame manager.
- */
- virtual nsIFrame* GetPlaceholderFrameFor(nsIFrame* aFrame) const = 0;
-
- /**
* Tell the pres shell that a frame needs to be marked dirty and needs
* Reflow. It's OK if this is an ancestor of the frame needing reflow as
* long as the ancestor chain between them doesn't cross a reflow root.
@@ -545,20 +539,12 @@ public:
virtual void NotifyCounterStylesAreDirty() = 0;
/**
- * Destroy the frames for aContent. Note that this may destroy frames
- * for an ancestor instead - aDestroyedFramesFor contains the content node
- * where frames were actually destroyed (which should be used in the
- * CreateFramesFor call). The frame tree state will be captured before
- * the frames are destroyed in the frame constructor.
- */
- virtual void DestroyFramesFor(nsIContent* aContent,
- nsIContent** aDestroyedFramesFor) = 0;
- /**
- * Create new frames for aContent. It will use the last captured layout
- * history state captured in the frame constructor to restore the state
- * in the new frame tree.
+ * Destroy the frames for aElement, and reconstruct them asynchronously if
+ * needed.
+ *
+ * Note that this may destroy frames for an ancestor instead.
*/
- virtual void CreateFramesFor(nsIContent* aContent) = 0;
+ virtual void DestroyFramesForAndRestyle(mozilla::dom::Element* aElement) = 0;
/**
* Recreates the frames for a node
@@ -977,7 +963,7 @@ public:
/**
* Reconstruct frames for all elements in the document
*/
- virtual nsresult ReconstructFrames() = 0;
+ virtual void ReconstructFrames() = 0;
/**
* Notify that a content node's state has changed
diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp
index 21d20c69f..7496a4946 100644
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1486,90 +1486,38 @@ nsLayoutUtils::GetChildListNameFor(nsIFrame* aChildFrame)
return id;
}
-/*static*/ nsIFrame*
-nsLayoutUtils::GetBeforeFrameForContent(nsIFrame* aFrame,
- const nsIContent* aContent)
-{
- // We need to call GetGenConPseudos() on the first continuation/ib-split.
- // Find it, for symmetry with GetAfterFrameForContent.
- nsContainerFrame* genConParentFrame =
- FirstContinuationOrIBSplitSibling(aFrame)->GetContentInsertionFrame();
- if (!genConParentFrame) {
- return nullptr;
- }
- nsTArray<nsIContent*>* prop = genConParentFrame->GetGenConPseudos();
- if (prop) {
- const nsTArray<nsIContent*>& pseudos(*prop);
- for (uint32_t i = 0; i < pseudos.Length(); ++i) {
- if (pseudos[i]->GetParent() == aContent &&
- pseudos[i]->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore) {
- return pseudos[i]->GetPrimaryFrame();
- }
- }
- }
- // If the first child frame is a pseudo-frame, then try that.
- // Note that the frame we create for the generated content is also a
- // pseudo-frame and so don't drill down in that case.
- nsIFrame* childFrame = genConParentFrame->PrincipalChildList().FirstChild();
- if (childFrame &&
- childFrame->IsPseudoFrame(aContent) &&
- !childFrame->IsGeneratedContentFrame()) {
- return GetBeforeFrameForContent(childFrame, aContent);
- }
- return nullptr;
+static Element*
+GetPseudo(const nsIContent* aContent, nsIAtom* aPseudoProperty)
+{
+ MOZ_ASSERT(aPseudoProperty == nsGkAtoms::beforePseudoProperty ||
+ aPseudoProperty == nsGkAtoms::afterPseudoProperty);
+ return static_cast<Element*>(aContent->GetProperty(aPseudoProperty));
}
-/*static*/ nsIFrame*
-nsLayoutUtils::GetBeforeFrame(nsIFrame* aFrame)
+/*static*/ Element*
+nsLayoutUtils::GetBeforePseudo(const nsIContent* aContent)
{
- return GetBeforeFrameForContent(aFrame, aFrame->GetContent());
+ return GetPseudo(aContent, nsGkAtoms::beforePseudoProperty);
}
/*static*/ nsIFrame*
-nsLayoutUtils::GetAfterFrameForContent(nsIFrame* aFrame,
- const nsIContent* aContent)
-{
- // We need to call GetGenConPseudos() on the first continuation,
- // but callers are likely to pass the last.
- nsContainerFrame* genConParentFrame =
- FirstContinuationOrIBSplitSibling(aFrame)->GetContentInsertionFrame();
- if (!genConParentFrame) {
- return nullptr;
- }
- nsTArray<nsIContent*>* prop = genConParentFrame->GetGenConPseudos();
- if (prop) {
- const nsTArray<nsIContent*>& pseudos(*prop);
- for (uint32_t i = 0; i < pseudos.Length(); ++i) {
- if (pseudos[i]->GetParent() == aContent &&
- pseudos[i]->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter) {
- return pseudos[i]->GetPrimaryFrame();
- }
- }
- }
- // If the last child frame is a pseudo-frame, then try that.
- // Note that the frame we create for the generated content is also a
- // pseudo-frame and so don't drill down in that case.
- genConParentFrame = aFrame->GetContentInsertionFrame();
- if (!genConParentFrame) {
- return nullptr;
- }
- nsIFrame* lastParentContinuation =
- LastContinuationWithChild(static_cast<nsContainerFrame*>(
- LastContinuationOrIBSplitSibling(genConParentFrame)));
- nsIFrame* childFrame =
- lastParentContinuation->GetChildList(nsIFrame::kPrincipalList).LastChild();
- if (childFrame &&
- childFrame->IsPseudoFrame(aContent) &&
- !childFrame->IsGeneratedContentFrame()) {
- return GetAfterFrameForContent(childFrame->FirstContinuation(), aContent);
- }
- return nullptr;
+nsLayoutUtils::GetBeforeFrame(const nsIContent* aContent)
+{
+ Element* pseudo = GetBeforePseudo(aContent);
+ return pseudo ? pseudo->GetPrimaryFrame() : nullptr;
+}
+
+/*static*/ Element*
+nsLayoutUtils::GetAfterPseudo(const nsIContent* aContent)
+{
+ return GetPseudo(aContent, nsGkAtoms::afterPseudoProperty);
}
/*static*/ nsIFrame*
-nsLayoutUtils::GetAfterFrame(nsIFrame* aFrame)
+nsLayoutUtils::GetAfterFrame(const nsIContent* aContent)
{
- return GetAfterFrameForContent(aFrame, aFrame->GetContent());
+ Element* pseudo = GetAfterPseudo(aContent);
+ return pseudo ? pseudo->GetPrimaryFrame() : nullptr;
}
// static
@@ -1640,33 +1588,6 @@ nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) {
}
// static
-bool
-nsLayoutUtils::IsGeneratedContentFor(nsIContent* aContent,
- nsIFrame* aFrame,
- nsIAtom* aPseudoElement)
-{
- NS_PRECONDITION(aFrame, "Must have a frame");
- NS_PRECONDITION(aPseudoElement, "Must have a pseudo name");
-
- if (!aFrame->IsGeneratedContentFrame()) {
- return false;
- }
- nsIFrame* parent = aFrame->GetParent();
- NS_ASSERTION(parent, "Generated content can't be root frame");
- if (parent->IsGeneratedContentFrame()) {
- // Not the root of the generated content
- return false;
- }
-
- if (aContent && parent->GetContent() != aContent) {
- return false;
- }
-
- return (aFrame->GetContent()->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore) ==
- (aPseudoElement == nsCSSPseudoElements::before);
-}
-
-// static
nsIFrame*
nsLayoutUtils::GetCrossDocParentFrame(const nsIFrame* aFrame,
nsPoint* aExtraOffset)
@@ -4400,8 +4321,7 @@ nsLayoutUtils::GetParentOrPlaceholderFor(nsIFrame* aFrame)
{
if ((aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
&& !aFrame->GetPrevInFlow()) {
- return aFrame->PresContext()->PresShell()->FrameManager()->
- GetPlaceholderFrameFor(aFrame);
+ return aFrame->GetProperty(nsIFrame::PlaceholderFrameProperty());
}
return aFrame->GetParent();
}
diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h
index bba1f3265..36a43e46b 100644
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -276,50 +276,26 @@ public:
static mozilla::layout::FrameChildListID GetChildListNameFor(nsIFrame* aChildFrame);
/**
- * GetBeforeFrameForContent returns the ::before frame for aContent, if
- * one exists. This is typically O(1). The frame passed in must be
- * the first-in-flow.
- *
- * @param aGenConParentFrame an ancestor of the ::before frame
- * @param aContent the content whose ::before is wanted
- * @return the ::before frame or nullptr if there isn't one
+ * Returns the ::before pseudo-element for aContent, if any.
*/
- static nsIFrame* GetBeforeFrameForContent(nsIFrame* aGenConParentFrame,
- const nsIContent* aContent);
+ static mozilla::dom::Element* GetBeforePseudo(const nsIContent* aContent);
/**
- * GetBeforeFrame returns the outermost ::before frame of the given frame, if
- * one exists. This is typically O(1). The frame passed in must be
- * the first-in-flow.
- *
- * @param aFrame the frame whose ::before is wanted
- * @return the :before frame or nullptr if there isn't one
+ * Returns the frame corresponding to the ::before pseudo-element for
+ * aContent, if any.
*/
- static nsIFrame* GetBeforeFrame(nsIFrame* aFrame);
+ static nsIFrame* GetBeforeFrame(const nsIContent* aContent);
/**
- * GetAfterFrameForContent returns the ::after frame for aContent, if one
- * exists. This will walk the in-flow chain of aGenConParentFrame to the
- * last-in-flow if needed. This function is typically O(N) in the number
- * of child frames, following in-flows, etc.
- *
- * @param aGenConParentFrame an ancestor of the ::after frame
- * @param aContent the content whose ::after is wanted
- * @return the ::after frame or nullptr if there isn't one
+ * Returns the ::after pseudo-element for aContent, if any.
*/
- static nsIFrame* GetAfterFrameForContent(nsIFrame* aGenConParentFrame,
- const nsIContent* aContent);
+ static mozilla::dom::Element* GetAfterPseudo(const nsIContent* aContent);
/**
- * GetAfterFrame returns the outermost ::after frame of the given frame, if one
- * exists. This will walk the in-flow chain to the last-in-flow if
- * needed. This function is typically O(N) in the number of child
- * frames, following in-flows, etc.
- *
- * @param aFrame the frame whose ::after is wanted
- * @return the :after frame or nullptr if there isn't one
+ * Returns the frame corresponding to the ::after pseudo-element for aContent,
+ * if any.
*/
- static nsIFrame* GetAfterFrame(nsIFrame* aFrame);
+ static nsIFrame* GetAfterFrame(const nsIContent* aContent);
/**
* Given a frame, search up the frame tree until we find an
@@ -377,23 +353,6 @@ public:
*/
static nsIFrame* GetRealPrimaryFrameFor(const nsIContent* aContent);
- /**
- * IsGeneratedContentFor returns true if aFrame is the outermost
- * frame for generated content of type aPseudoElement for aContent.
- * aFrame *might not* have the aPseudoElement pseudo-style! For example
- * it might be a table wrapper frame and the inner table frame might
- * have the pseudo-style.
- *
- * @param aContent the content node we're looking at. If this is
- * null, then we just assume that aFrame has the right content
- * pointer.
- * @param aFrame the frame we're looking at
- * @param aPseudoElement the pseudo type we're interested in
- * @return whether aFrame is the generated aPseudoElement frame for aContent
- */
- static bool IsGeneratedContentFor(nsIContent* aContent, nsIFrame* aFrame,
- nsIAtom* aPseudoElement);
-
#ifdef DEBUG
// TODO: remove, see bug 598468.
static bool gPreventAssertInCompareTreePosition;
diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp
index 264b52b18..bd5125637 100644
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -2828,10 +2828,9 @@ PresShell::CancelAllPendingReflows()
}
void
-PresShell::DestroyFramesFor(nsIContent* aContent,
- nsIContent** aDestroyedFramesFor)
+PresShell::DestroyFramesForAndRestyle(Element* aElement)
{
- MOZ_ASSERT(aContent);
+ MOZ_ASSERT(aElement);
NS_ENSURE_TRUE_VOID(mPresContext);
if (!mDidInitialize) {
return;
@@ -2843,43 +2842,20 @@ PresShell::DestroyFramesFor(nsIContent* aContent,
++mChangeNestCount;
nsCSSFrameConstructor* fc = FrameConstructor();
+ bool didReconstruct;
fc->BeginUpdate();
- fc->DestroyFramesFor(aContent, aDestroyedFramesFor);
+ fc->DestroyFramesFor(aElement, &didReconstruct);
fc->EndUpdate();
- --mChangeNestCount;
-}
+ auto changeHint = didReconstruct
+ ? nsChangeHint(0)
+ : nsChangeHint_ReconstructFrame;
-void
-PresShell::CreateFramesFor(nsIContent* aContent)
-{
- NS_ENSURE_TRUE_VOID(mPresContext);
- if (!mDidInitialize) {
- // Nothing to do here. In fact, if we proceed and aContent is the
- // root we will crash.
- return;
- }
-
- // Don't call RecreateFramesForContent since that is not exported and we want
- // to keep the number of entrypoints down.
-
- NS_ASSERTION(mViewManager, "Should have view manager");
- MOZ_ASSERT(aContent);
-
- // Have to make sure that the content notifications are flushed before we
- // start messing with the frame model; otherwise we can get content doubling.
- mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
-
- nsAutoScriptBlocker scriptBlocker;
-
- // Mark ourselves as not safe to flush while we're doing frame construction.
- ++mChangeNestCount;
-
- nsCSSFrameConstructor* fc = FrameConstructor();
- nsILayoutHistoryState* layoutState = fc->GetLastCapturedLayoutHistoryState();
- fc->BeginUpdate();
- fc->ContentInserted(aContent->GetParent(), aContent, layoutState, false);
- fc->EndUpdate();
+ // NOTE(emilio): eRestyle_Subtree is needed to force also a full subtree
+ // restyle for the content (in Stylo, where the existence of frames != the
+ // existence of styles).
+ mPresContext->RestyleManager()->PostRestyleEvent(
+ aElement, eRestyle_Subtree, changeHint);
--mChangeNestCount;
}
@@ -4444,14 +4420,14 @@ PresShell::NotifyCounterStylesAreDirty()
mFrameConstructor->EndUpdate();
}
-nsresult
-PresShell::ReconstructFrames(void)
+void
+PresShell::ReconstructFrames()
{
NS_PRECONDITION(!mFrameConstructor->GetRootFrame() || mDidInitialize,
"Must not have root frame before initial reflow");
if (!mDidInitialize || mIsDestroying) {
// Nothing to do here
- return NS_OK;
+ return;
}
nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
@@ -4461,16 +4437,14 @@ PresShell::ReconstructFrames(void)
mDocument->FlushPendingNotifications(Flush_ContentAndNotify);
if (mIsDestroying) {
- return NS_OK;
+ return;
}
nsAutoCauseReflowNotifier crNotifier(this);
mFrameConstructor->BeginUpdate();
- nsresult rv = mFrameConstructor->ReconstructDocElementHierarchy();
+ mFrameConstructor->ReconstructDocElementHierarchy();
VERIFY_STYLE_TREE;
mFrameConstructor->EndUpdate();
-
- return rv;
}
void
@@ -4598,12 +4572,6 @@ PresShell::StyleRuleRemoved(StyleSheet* aStyleSheet)
RecordStyleSheetChange(aStyleSheet);
}
-nsIFrame*
-PresShell::GetPlaceholderFrameFor(nsIFrame* aFrame) const
-{
- return mFrameConstructor->GetPlaceholderFrameFor(aFrame);
-}
-
nsresult
PresShell::RenderDocument(const nsRect& aRect, uint32_t aFlags,
nscolor aBackgroundColor,
@@ -4755,9 +4723,11 @@ PresShell::ClipListToRange(nsDisplayListBuilder *aBuilder,
frame->GetOffsets(frameStartOffset, frameEndOffset);
int32_t hilightStart =
- atStart ? std::max(aRange->StartOffset(), frameStartOffset) : frameStartOffset;
+ atStart ? std::max(static_cast<int32_t>(aRange->StartOffset()),
+ frameStartOffset) : frameStartOffset;
int32_t hilightEnd =
- atEnd ? std::min(aRange->EndOffset(), frameEndOffset) : frameEndOffset;
+ atEnd ? std::min(static_cast<int32_t>(aRange->EndOffset()),
+ frameEndOffset) : frameEndOffset;
if (hilightStart < hilightEnd) {
// determine the location of the start and end edges of the range.
nsPoint startPoint, endPoint;
diff --git a/layout/base/nsPresShell.h b/layout/base/nsPresShell.h
index f20370d73..628e613c8 100644
--- a/layout/base/nsPresShell.h
+++ b/layout/base/nsPresShell.h
@@ -130,7 +130,6 @@ public:
virtual nsIPageSequenceFrame* GetPageSequenceFrame() const override;
virtual nsCanvasFrame* GetCanvasFrame() const override;
- virtual nsIFrame* GetPlaceholderFrameFor(nsIFrame* aFrame) const override;
virtual void FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
nsFrameState aBitToAdd,
ReflowRootHandling aRootHandling =
@@ -140,9 +139,7 @@ public:
virtual bool IsSafeToFlush() const override;
virtual void FlushPendingNotifications(mozFlushType aType) override;
virtual void FlushPendingNotifications(mozilla::ChangesToFlush aType) override;
- virtual void DestroyFramesFor(nsIContent* aContent,
- nsIContent** aDestroyedFramesFor) override;
- virtual void CreateFramesFor(nsIContent* aContent) override;
+ virtual void DestroyFramesForAndRestyle(mozilla::dom::Element* aElement) override;
/**
* Recreates the frames for a node
@@ -200,7 +197,7 @@ public:
virtual void NotifyCounterStylesAreDirty() override;
- virtual nsresult ReconstructFrames(void) override;
+ virtual void ReconstructFrames(void) override;
virtual void Freeze() override;
virtual void Thaw() override;
virtual void FireOrClearDelayedEvents(bool aFireEvents) override;
diff --git a/layout/forms/nsColorControlFrame.cpp b/layout/forms/nsColorControlFrame.cpp
index e0bae43a9..63aee814a 100644
--- a/layout/forms/nsColorControlFrame.cpp
+++ b/layout/forms/nsColorControlFrame.cpp
@@ -67,6 +67,7 @@ nsColorControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
{
nsCOMPtr<nsIDocument> doc = mContent->GetComposedDoc();
mColorContent = doc->CreateHTMLElement(nsGkAtoms::div);
+ mColorContent->SetPseudoElementType(CSSPseudoElementType::mozColorSwatch);
// Mark the element to be native anonymous before setting any attributes.
mColorContent->SetIsNativeAnonymousRoot();
@@ -74,11 +75,7 @@ nsColorControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
nsresult rv = UpdateColor();
NS_ENSURE_SUCCESS(rv, rv);
- CSSPseudoElementType pseudoType = CSSPseudoElementType::mozColorSwatch;
- RefPtr<nsStyleContext> newStyleContext = PresContext()->StyleSet()->
- ResolvePseudoElementStyle(mContent->AsElement(), pseudoType,
- StyleContext(), mColorContent->AsElement());
- if (!aElements.AppendElement(ContentInfo(mColorContent, newStyleContext))) {
+ if (!aElements.AppendElement(mColorContent)) {
return NS_ERROR_OUT_OF_MEMORY;
}
diff --git a/layout/forms/nsComboboxControlFrame.cpp b/layout/forms/nsComboboxControlFrame.cpp
index 78185616f..98a91b9f5 100644
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -115,7 +115,7 @@ NS_IMPL_ISUPPORTS(nsComboButtonListener,
// static class data member for Bug 32920
nsComboboxControlFrame* nsComboboxControlFrame::sFocused = nullptr;
-nsContainerFrame*
+nsComboboxControlFrame*
NS_NewComboboxControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, nsFrameState aStateFlags)
{
nsComboboxControlFrame* it = new (aPresShell) nsComboboxControlFrame(aContext);
@@ -249,6 +249,7 @@ nsComboboxControlFrame::~nsComboboxControlFrame()
//--------------------------------------------------------------
NS_QUERYFRAME_HEAD(nsComboboxControlFrame)
+ NS_QUERYFRAME_ENTRY(nsComboboxControlFrame)
NS_QUERYFRAME_ENTRY(nsIComboboxControlFrame)
NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
@@ -1350,16 +1351,9 @@ nsComboboxDisplayFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
}
nsIFrame*
-nsComboboxControlFrame::CreateFrameFor(nsIContent* aContent)
+nsComboboxControlFrame::CreateFrameForDisplayNode()
{
- NS_PRECONDITION(nullptr != aContent, "null ptr");
-
- NS_ASSERTION(mDisplayContent, "mDisplayContent can't be null!");
-
- if (mDisplayContent != aContent) {
- // We only handle the frames for mDisplayContent here
- return nullptr;
- }
+ MOZ_ASSERT(mDisplayContent);
// Get PresShell
nsIPresShell *shell = PresContext()->PresShell();
@@ -1384,7 +1378,7 @@ nsComboboxControlFrame::CreateFrameFor(nsIContent* aContent)
nsIFrame* textFrame = NS_NewTextFrame(shell, textStyleContext);
// initialize the text frame
- textFrame->Init(aContent, mDisplayFrame, nullptr);
+ textFrame->Init(mDisplayContent, mDisplayFrame, nullptr);
mDisplayContent->SetPrimaryFrame(textFrame);
nsFrameList textList(textFrame, textFrame);
diff --git a/layout/forms/nsComboboxControlFrame.h b/layout/forms/nsComboboxControlFrame.h
index 22849e8d1..de713576f 100644
--- a/layout/forms/nsComboboxControlFrame.h
+++ b/layout/forms/nsComboboxControlFrame.h
@@ -54,9 +54,10 @@ class nsComboboxControlFrame final : public nsBlockFrame,
typedef mozilla::gfx::DrawTarget DrawTarget;
public:
- friend nsContainerFrame* NS_NewComboboxControlFrame(nsIPresShell* aPresShell,
- nsStyleContext* aContext,
- nsFrameState aFlags);
+ NS_DECL_QUERYFRAME_TARGET(nsComboboxControlFrame)
+ friend nsComboboxControlFrame* NS_NewComboboxControlFrame(nsIPresShell* aPresShell,
+ nsStyleContext* aContext,
+ nsFrameState aFlags);
friend class nsComboboxDisplayFrame;
explicit nsComboboxControlFrame(nsStyleContext* aContext);
@@ -69,7 +70,9 @@ public:
virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter) override;
- virtual nsIFrame* CreateFrameFor(nsIContent* aContent) override;
+
+ nsIContent* GetDisplayNode() { return mDisplayContent; }
+ nsIFrame* CreateFrameForDisplayNode();
#ifdef ACCESSIBILITY
virtual mozilla::a11y::AccType AccessibleType() override;
diff --git a/layout/forms/nsGfxButtonControlFrame.cpp b/layout/forms/nsGfxButtonControlFrame.cpp
index 393145e0b..df729c1aa 100644
--- a/layout/forms/nsGfxButtonControlFrame.cpp
+++ b/layout/forms/nsGfxButtonControlFrame.cpp
@@ -77,30 +77,6 @@ nsGfxButtonControlFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElemen
}
}
-// Create the text content used as label for the button.
-// The frame will be generated by the frame constructor.
-nsIFrame*
-nsGfxButtonControlFrame::CreateFrameFor(nsIContent* aContent)
-{
- nsIFrame * newFrame = nullptr;
-
- if (aContent == mTextContent) {
- nsContainerFrame* parentFrame = do_QueryFrame(mFrames.FirstChild());
-
- nsPresContext* presContext = PresContext();
- RefPtr<nsStyleContext> textStyleContext;
- textStyleContext = presContext->StyleSet()->
- ResolveStyleForText(mTextContent, mStyleContext);
-
- newFrame = NS_NewTextFrame(presContext->PresShell(), textStyleContext);
- // initialize the text frame
- newFrame->Init(mTextContent, parentFrame, nullptr);
- mTextContent->SetPrimaryFrame(newFrame);
- }
-
- return newFrame;
-}
-
NS_QUERYFRAME_HEAD(nsGfxButtonControlFrame)
NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
NS_QUERYFRAME_TAIL_INHERITING(nsHTMLButtonControlFrame)
diff --git a/layout/forms/nsGfxButtonControlFrame.h b/layout/forms/nsGfxButtonControlFrame.h
index d91fe3695..07072fdb5 100644
--- a/layout/forms/nsGfxButtonControlFrame.h
+++ b/layout/forms/nsGfxButtonControlFrame.h
@@ -42,7 +42,6 @@ public:
virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter) override;
- virtual nsIFrame* CreateFrameFor(nsIContent* aContent) override;
virtual nsresult AttributeChanged(int32_t aNameSpaceID,
nsIAtom* aAttribute,
diff --git a/layout/forms/nsMeterFrame.cpp b/layout/forms/nsMeterFrame.cpp
index 1f3bd8022..6ef362820 100644
--- a/layout/forms/nsMeterFrame.cpp
+++ b/layout/forms/nsMeterFrame.cpp
@@ -75,14 +75,9 @@ nsMeterFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
mBarDiv = doc->CreateHTMLElement(nsGkAtoms::div);
// Associate ::-moz-meter-bar pseudo-element to the anonymous child.
- CSSPseudoElementType pseudoType = CSSPseudoElementType::mozMeterBar;
- RefPtr<nsStyleContext> newStyleContext = PresContext()->StyleSet()->
- ResolvePseudoElementStyle(mContent->AsElement(), pseudoType,
- StyleContext(), mBarDiv->AsElement());
+ mBarDiv->SetPseudoElementType(CSSPseudoElementType::mozMeterBar);
- if (!aElements.AppendElement(ContentInfo(mBarDiv, newStyleContext))) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
+ aElements.AppendElement(mBarDiv);
return NS_OK;
}
diff --git a/layout/forms/nsNumberControlFrame.cpp b/layout/forms/nsNumberControlFrame.cpp
index 9724109cb..64e3df0fe 100644
--- a/layout/forms/nsNumberControlFrame.cpp
+++ b/layout/forms/nsNumberControlFrame.cpp
@@ -325,27 +325,15 @@ nsresult
nsNumberControlFrame::MakeAnonymousElement(Element** aResult,
nsTArray<ContentInfo>& aElements,
nsIAtom* aTagName,
- CSSPseudoElementType aPseudoType,
- nsStyleContext* aParentContext)
+ CSSPseudoElementType aPseudoType)
{
// Get the NodeInfoManager and tag necessary to create the anonymous divs.
nsCOMPtr<nsIDocument> doc = mContent->GetComposedDoc();
RefPtr<Element> resultElement = doc->CreateHTMLElement(aTagName);
+ resultElement->SetPseudoElementType(aPseudoType);
- // If we legitimately fail this assertion and need to allow
- // non-pseudo-element anonymous children, then we'll need to add a branch
- // that calls ResolveStyleFor((*aResult)->AsElement(), aParentContext)") to
- // set newStyleContext.
- NS_ASSERTION(aPseudoType != CSSPseudoElementType::NotPseudo,
- "Expecting anonymous children to all be pseudo-elements");
// Associate the pseudo-element with the anonymous child
- RefPtr<nsStyleContext> newStyleContext =
- PresContext()->StyleSet()->ResolvePseudoElementStyle(mContent->AsElement(),
- aPseudoType,
- aParentContext,
- resultElement);
-
- if (!aElements.AppendElement(ContentInfo(resultElement, newStyleContext))) {
+ if (!aElements.AppendElement(resultElement)) {
return NS_ERROR_OUT_OF_MEMORY;
}
@@ -382,8 +370,7 @@ nsNumberControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
rv = MakeAnonymousElement(getter_AddRefs(mOuterWrapper),
aElements,
nsGkAtoms::div,
- CSSPseudoElementType::mozNumberWrapper,
- mStyleContext);
+ CSSPseudoElementType::mozNumberWrapper);
NS_ENSURE_SUCCESS(rv, rv);
ContentInfo& outerWrapperCI = aElements.LastElement();
@@ -392,8 +379,7 @@ nsNumberControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
rv = MakeAnonymousElement(getter_AddRefs(mTextField),
outerWrapperCI.mChildren,
nsGkAtoms::input,
- CSSPseudoElementType::mozNumberText,
- outerWrapperCI.mStyleContext);
+ CSSPseudoElementType::mozNumberText);
NS_ENSURE_SUCCESS(rv, rv);
mTextField->SetAttr(kNameSpaceID_None, nsGkAtoms::type,
@@ -442,8 +428,7 @@ nsNumberControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
rv = MakeAnonymousElement(getter_AddRefs(mSpinBox),
outerWrapperCI.mChildren,
nsGkAtoms::div,
- CSSPseudoElementType::mozNumberSpinBox,
- outerWrapperCI.mStyleContext);
+ CSSPseudoElementType::mozNumberSpinBox);
NS_ENSURE_SUCCESS(rv, rv);
ContentInfo& spinBoxCI = outerWrapperCI.mChildren.LastElement();
@@ -452,16 +437,14 @@ nsNumberControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
rv = MakeAnonymousElement(getter_AddRefs(mSpinUp),
spinBoxCI.mChildren,
nsGkAtoms::div,
- CSSPseudoElementType::mozNumberSpinUp,
- spinBoxCI.mStyleContext);
+ CSSPseudoElementType::mozNumberSpinUp);
NS_ENSURE_SUCCESS(rv, rv);
// Create the ::-moz-number-spin-down pseudo-element:
rv = MakeAnonymousElement(getter_AddRefs(mSpinDown),
spinBoxCI.mChildren,
nsGkAtoms::div,
- CSSPseudoElementType::mozNumberSpinDown,
- spinBoxCI.mStyleContext);
+ CSSPseudoElementType::mozNumberSpinDown);
return rv;
}
diff --git a/layout/forms/nsNumberControlFrame.h b/layout/forms/nsNumberControlFrame.h
index 47e32ad65..5396e7170 100644
--- a/layout/forms/nsNumberControlFrame.h
+++ b/layout/forms/nsNumberControlFrame.h
@@ -170,8 +170,7 @@ private:
nsresult MakeAnonymousElement(Element** aResult,
nsTArray<ContentInfo>& aElements,
nsIAtom* aTagName,
- CSSPseudoElementType aPseudoType,
- nsStyleContext* aParentContext);
+ CSSPseudoElementType aPseudoType);
class SyncDisabledStateEvent;
friend class SyncDisabledStateEvent;
diff --git a/layout/forms/nsProgressFrame.cpp b/layout/forms/nsProgressFrame.cpp
index 2445defd3..6d6db7a1f 100644
--- a/layout/forms/nsProgressFrame.cpp
+++ b/layout/forms/nsProgressFrame.cpp
@@ -72,12 +72,9 @@ nsProgressFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
mBarDiv = doc->CreateHTMLElement(nsGkAtoms::div);
// Associate ::-moz-progress-bar pseudo-element to the anonymous child.
- CSSPseudoElementType pseudoType = CSSPseudoElementType::mozProgressBar;
- RefPtr<nsStyleContext> newStyleContext = PresContext()->StyleSet()->
- ResolvePseudoElementStyle(mContent->AsElement(), pseudoType,
- StyleContext(), mBarDiv->AsElement());
+ mBarDiv->SetPseudoElementType(CSSPseudoElementType::mozProgressBar);
- if (!aElements.AppendElement(ContentInfo(mBarDiv, newStyleContext))) {
+ if (!aElements.AppendElement(mBarDiv)) {
return NS_ERROR_OUT_OF_MEMORY;
}
diff --git a/layout/forms/nsRangeFrame.cpp b/layout/forms/nsRangeFrame.cpp
index 7590da066..99faa6043 100644
--- a/layout/forms/nsRangeFrame.cpp
+++ b/layout/forms/nsRangeFrame.cpp
@@ -119,13 +119,9 @@ nsRangeFrame::MakeAnonymousDiv(Element** aResult,
RefPtr<Element> resultElement = doc->CreateHTMLElement(nsGkAtoms::div);
// Associate the pseudo-element with the anonymous child.
- RefPtr<nsStyleContext> newStyleContext =
- PresContext()->StyleSet()->ResolvePseudoElementStyle(mContent->AsElement(),
- aPseudoType,
- StyleContext(),
- resultElement);
+ resultElement->SetPseudoElementType(aPseudoType);
- if (!aElements.AppendElement(ContentInfo(resultElement, newStyleContext))) {
+ if (!aElements.AppendElement(resultElement)) {
return NS_ERROR_OUT_OF_MEMORY;
}
diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp
index f8fdf3420..b34e132e6 100644
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -352,32 +352,12 @@ nsTextControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
// Create the placeholder anonymous content if needed.
if (mUsePlaceholder) {
- nsIContent* placeholderNode = txtCtrl->CreatePlaceholderNode();
+ Element* placeholderNode = txtCtrl->CreatePlaceholderNode();
NS_ENSURE_TRUE(placeholderNode, NS_ERROR_OUT_OF_MEMORY);
// Associate ::placeholder pseudo-element with the placeholder node.
- CSSPseudoElementType pseudoType = CSSPseudoElementType::placeholder;
-
- // If this is a text input inside a number input then we want to use the
- // main number input as the source of style for the placeholder frame.
- nsIFrame* mainInputFrame = this;
- if (StyleContext()->GetPseudoType() == CSSPseudoElementType::mozNumberText) {
- do {
- mainInputFrame = mainInputFrame->GetParent();
- } while (mainInputFrame &&
- mainInputFrame->GetType() != nsGkAtoms::numberControlFrame);
- MOZ_ASSERT(mainInputFrame);
- }
-
- RefPtr<nsStyleContext> placeholderStyleContext =
- PresContext()->StyleSet()->ResolvePseudoElementStyle(
- mainInputFrame->GetContent()->AsElement(), pseudoType, StyleContext(),
- placeholderNode->AsElement());
-
- if (!aElements.AppendElement(ContentInfo(placeholderNode,
- placeholderStyleContext))) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
+ placeholderNode->SetPseudoElementType(CSSPseudoElementType::placeholder);
+ aElements.AppendElement(placeholderNode);
if (!IsSingleLineTextControl()) {
// For textareas, UpdateValueDisplay doesn't initialize the visibility
@@ -778,7 +758,12 @@ nsTextControlFrame::SetSelectionInternal(nsIDOMNode *aStartNode,
// we have access to the node.
nsCOMPtr<nsINode> start = do_QueryInterface(aStartNode);
nsCOMPtr<nsINode> end = do_QueryInterface(aEndNode);
- nsresult rv = range->Set(start, aStartOffset, end, aEndOffset);
+ // XXXbz nsRange::SetStartAndEnd takes int32_t (and ranges generally work on
+ // int32_t), but we're passing uint32_t. The good news is that at this point
+ // our endpoints should really be within our length, so not really that big.
+ // And if they _are_ that big, SetStartAndEnd() will simply error out, which
+ // is not too bad for a case we don't expect to happen.
+ nsresult rv = range->SetStartAndEnd(start, aStartOffset, end, aEndOffset);
NS_ENSURE_SUCCESS(rv, rv);
// Get the selection, clear it and add the new range to it!
diff --git a/layout/generic/DetailsFrame.cpp b/layout/generic/DetailsFrame.cpp
index 1d28bbe96..389a476cb 100644
--- a/layout/generic/DetailsFrame.cpp
+++ b/layout/generic/DetailsFrame.cpp
@@ -129,3 +129,12 @@ DetailsFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
aElements.AppendElement(mDefaultSummary);
}
}
+
+bool
+DetailsFrame::HasMainSummaryFrame(nsIFrame* aSummaryFrame)
+{
+ nsIFrame* firstChild =
+ nsPlaceholderFrame::GetRealFrameFor(mFrames.FirstChild());
+
+ return aSummaryFrame == firstChild;
+}
diff --git a/layout/generic/DetailsFrame.h b/layout/generic/DetailsFrame.h
index 1eb4ea87b..4ae177f16 100644
--- a/layout/generic/DetailsFrame.h
+++ b/layout/generic/DetailsFrame.h
@@ -54,6 +54,12 @@ public:
void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter) override;
+ // Returns true if |aSummaryFrame| is the main summary (i.e. the first child
+ // of this details frame).
+ // This function is used when the summary element is removed from the parent
+ // details element since at that moment the summary element has been already
+ // removed from the details element children.
+ bool HasMainSummaryFrame(nsIFrame* aSummaryFrame);
private:
nsCOMPtr<nsIContent> mDefaultSummary;
diff --git a/layout/generic/ReflowInput.cpp b/layout/generic/ReflowInput.cpp
index 78eca8c6c..9f7b4368c 100644
--- a/layout/generic/ReflowInput.cpp
+++ b/layout/generic/ReflowInput.cpp
@@ -1564,8 +1564,7 @@ ReflowInput::InitAbsoluteConstraints(nsPresContext* aPresContext,
// have been if it had been in the flow
nsHypotheticalPosition hypotheticalPos;
if ((iStartIsAuto && iEndIsAuto) || (bStartIsAuto && bEndIsAuto)) {
- nsIFrame* placeholderFrame =
- aPresContext->PresShell()->GetPlaceholderFrameFor(mFrame);
+ nsPlaceholderFrame* placeholderFrame = mFrame->GetPlaceholderFrame();
NS_ASSERTION(placeholderFrame, "no placeholder frame");
if (placeholderFrame->HasAnyStateBits(
diff --git a/layout/generic/Selection.h b/layout/generic/Selection.h
index 5414d15c1..cc696a7c7 100644
--- a/layout/generic/Selection.h
+++ b/layout/generic/Selection.h
@@ -31,6 +31,9 @@ class nsHTMLCopyEncoder;
namespace mozilla {
class ErrorResult;
struct AutoPrepareFocusRange;
+namespace dom {
+class DocGroup;
+} // namespace dom
} // namespace mozilla
struct RangeData
@@ -73,6 +76,7 @@ public:
nsresult EndBatchChangesInternal(int16_t aReason = nsISelectionListener::NO_REASON);
nsIDocument* GetParentObject() const;
+ DocGroup* GetDocGroup() const;
// utility methods for scrolling the selection into view
nsPresContext* GetPresContext() const;
diff --git a/layout/generic/crashtests/1381134-2.html b/layout/generic/crashtests/1381134-2.html
new file mode 100644
index 000000000..d3ac73507
--- /dev/null
+++ b/layout/generic/crashtests/1381134-2.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+addEventListener("DOMContentLoaded", () => {
+ [d1, d2] = document.getElementsByTagName("div");
+ [s1, s2] = document.getElementsByTagName("span")
+ d3 = document.createElement("div")
+ d4 = document.createElement("div")
+ d4.setAttribute("class", "grid")
+ d3.appendChild(d4)
+ d1.appendChild(document.createElement("span"))
+ setTimeout(() => {
+ d2.removeChild(s2)
+ setTimeout(() => {
+ d2.insertBefore(d3, s1)
+ }, 100)
+ }, 100)
+})
+</script>
+<style>
+.columns {
+ columns: 3;
+}
+.grid {
+ border:5px solid;
+ counter-reset: item;
+}
+.grid * { display:block; }
+span { display:contents; }
+span::before { content: counter(item) ":before"; }
+span::after { content: counter(item) ":after"; }
+</style>
+</head>
+<body>
+<div class=columns>
+<div class=grid>
+<c></c>
+<span><c></c></span>
+<span><c></c></span>
+</div>
+</div>
+</body>
+</html>
diff --git a/layout/generic/crashtests/1381134.html b/layout/generic/crashtests/1381134.html
new file mode 100644
index 000000000..a45fa04ec
--- /dev/null
+++ b/layout/generic/crashtests/1381134.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+addEventListener("DOMContentLoaded", () => {
+ [d1, d2] = document.getElementsByTagName("div");
+ [s1, s2] = document.getElementsByTagName("span")
+ d3 = document.createElement("div")
+ d4 = document.createElement("div")
+ d4.setAttribute("class", "grid")
+ d3.appendChild(d4)
+ d1.appendChild(document.createElement("span"))
+ setTimeout(() => {
+ d2.removeChild(s2)
+ setTimeout(() => {
+ d2.insertBefore(d3, s1)
+ }, 100)
+ }, 100)
+})
+</script>
+<style>
+.columns {
+ columns: 3;
+}
+.grid {
+ display: grid;
+ border:5px solid;
+ counter-reset: item;
+}
+span { display:contents; }
+span::before { content: counter(item) ":before"; }
+span::after { content: counter(item) ":after"; }
+</style>
+</head>
+<body>
+<div class=columns>
+<div class=grid>
+<c></c>
+<span><c></c></span>
+<span><c></c></span>
+</div>
+</div>
+</body>
+</html>
diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list
index a3c0d62c6..1a597e51c 100644
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -642,3 +642,5 @@ load 1278461-1.html
load 1278461-2.html
load 1304441.html
load 1316649.html
+load 1381134.html
+load 1381134-2.html
diff --git a/layout/generic/nsAbsoluteContainingBlock.cpp b/layout/generic/nsAbsoluteContainingBlock.cpp
index e3c847d01..a92a2062d 100644
--- a/layout/generic/nsAbsoluteContainingBlock.cpp
+++ b/layout/generic/nsAbsoluteContainingBlock.cpp
@@ -338,17 +338,9 @@ nsAbsoluteContainingBlock::DoMarkFramesDirty(bool aMarkAllDirty)
// Given an out-of-flow frame, this method returns the parent frame of
// its placeholder frame, if that parent is a nsContainerFrame.
static nsContainerFrame*
-GetPlaceholderContainer(nsPresContext* aPresContext,
- nsIFrame* aPositionedFrame)
+GetPlaceholderContainer(nsIFrame* aPositionedFrame)
{
- MOZ_ASSERT(aPositionedFrame, "need non-null frame");
- MOZ_ASSERT(aPositionedFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW),
- "expecting abspos frame");
- MOZ_ASSERT(aPresContext && aPresContext == aPositionedFrame->PresContext(),
- "need non-null pres context which matches our frame");
-
- nsIFrame* placeholder =
- aPresContext->PresShell()->GetPlaceholderFrameFor(aPositionedFrame);
+ nsIFrame* placeholder = aPositionedFrame->GetPlaceholderFrame();
if (!placeholder) {
return nullptr;
@@ -557,8 +549,7 @@ nsAbsoluteContainingBlock::ResolveSizeDependentOffsets(
aOffsets->IEnd(outerWM) - aMargin.IStartEnd(outerWM) -
aKidSize.ISize(outerWM);
} else if (aKidReflowInput.mFlags.mIOffsetsNeedCSSAlign) {
- placeholderContainer = GetPlaceholderContainer(aPresContext,
- aKidReflowInput.mFrame);
+ placeholderContainer = GetPlaceholderContainer(aKidReflowInput.mFrame);
nscoord offset = OffsetToAlignedStaticPos(aKidReflowInput, aKidSize,
logicalCBSizeOuterWM,
placeholderContainer,
@@ -579,8 +570,7 @@ nsAbsoluteContainingBlock::ResolveSizeDependentOffsets(
aKidSize.BSize(outerWM);
} else if (aKidReflowInput.mFlags.mBOffsetsNeedCSSAlign) {
if (!placeholderContainer) {
- placeholderContainer = GetPlaceholderContainer(aPresContext,
- aKidReflowInput.mFrame);
+ placeholderContainer = GetPlaceholderContainer(aKidReflowInput.mFrame);
}
nscoord offset = OffsetToAlignedStaticPos(aKidReflowInput, aKidSize,
logicalCBSizeOuterWM,
@@ -655,8 +645,7 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
// due to the multiple coordinate spaces in play, we use a convenience flag
// to simply have the child's ReflowInput give it a static position at its
// abs.pos. CB origin, and then we'll align & offset it from there.
- nsIFrame* placeholder =
- aPresContext->PresShell()->GetPlaceholderFrameFor(aKidFrame);
+ nsIFrame* placeholder = aKidFrame->GetPlaceholderFrame();
if (placeholder && placeholder->GetParent() == aDelegatingFrame) {
rsFlags |= ReflowInput::STATIC_POS_IS_CB_ORIGIN;
}
diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp
index a37bfc06b..8fec6cd6a 100644
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -4336,8 +4336,7 @@ CheckPlaceholderInLine(nsIFrame* aBlock, nsLineBox* aLine, nsFloatCache* aFC)
"float in a line should never be a continuation");
NS_ASSERTION(!(aFC->mFloat->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT),
"float in a line should never be a pushed float");
- nsIFrame* ph = aBlock->PresContext()->FrameManager()->
- GetPlaceholderFrameFor(aFC->mFloat->FirstInFlow());
+ nsIFrame* ph = aFC->mFloat->FirstInFlow()->GetPlaceholderFrame();
for (nsIFrame* f = ph; f; f = f->GetParent()) {
if (f->GetParent() == aBlock)
return aLine->Contains(f);
@@ -4939,9 +4938,8 @@ nsBlockFrame::DrainSelfPushedFloats()
if (f->GetPrevContinuation()) {
// FIXME
} else {
- nsPlaceholderFrame *placeholder =
- presContext->FrameManager()->GetPlaceholderFrameFor(f);
- nsIFrame *floatOriginalParent = presContext->PresShell()->
+ nsPlaceholderFrame* placeholder = f->GetPlaceholderFrame();
+ nsIFrame* floatOriginalParent = presContext->PresShell()->
FrameConstructor()->GetFloatContainingBlock(placeholder);
if (floatOriginalParent != this) {
// This is a first continuation that was pushed from one of our
@@ -5565,7 +5563,7 @@ FindChildContaining(nsBlockFrame* aFrame, nsIFrame* aFindFrame)
return nullptr;
if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW))
break;
- aFindFrame = aFrame->PresContext()->FrameManager()->GetPlaceholderFrameFor(child);
+ aFindFrame = child->GetPlaceholderFrame();
}
return child;
@@ -6847,9 +6845,8 @@ nsBlockFrame::ChildIsDirty(nsIFrame* aChild)
AddStateBits(NS_BLOCK_LOOK_FOR_DIRTY_FRAMES);
} else {
NS_ASSERTION(aChild->IsFloating(), "should be a float");
- nsIFrame *thisFC = FirstContinuation();
- nsIFrame *placeholderPath =
- PresContext()->FrameManager()->GetPlaceholderFrameFor(aChild);
+ nsIFrame* thisFC = FirstContinuation();
+ nsIFrame* placeholderPath = aChild->GetPlaceholderFrame();
// SVG code sometimes sends FrameNeedsReflow notifications during
// frame destruction, leading to null placeholders, but we're safe
// ignoring those.
diff --git a/layout/generic/nsFirstLetterFrame.cpp b/layout/generic/nsFirstLetterFrame.cpp
index 980e1e9be..5f561c759 100644
--- a/layout/generic/nsFirstLetterFrame.cpp
+++ b/layout/generic/nsFirstLetterFrame.cpp
@@ -320,8 +320,7 @@ nsFirstLetterFrame::CreateContinuationForFloatingParent(nsPresContext* aPresCont
*aContinuation = nullptr;
nsIPresShell* presShell = aPresContext->PresShell();
- nsPlaceholderFrame* placeholderFrame =
- presShell->FrameManager()->GetPlaceholderFrameFor(this);
+ nsPlaceholderFrame* placeholderFrame = GetPlaceholderFrame();
nsContainerFrame* parent = placeholderFrame->GetParent();
nsIFrame* continuation = presShell->FrameConstructor()->
diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp
index 0d0c7108c..ea29c6945 100644
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -633,8 +633,7 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
nsIPresShell *shell = presContext->GetPresShell();
if (mState & NS_FRAME_OUT_OF_FLOW) {
- nsPlaceholderFrame* placeholder =
- shell->FrameManager()->GetPlaceholderFrameFor(this);
+ nsPlaceholderFrame* placeholder = GetPlaceholderFrame();
NS_ASSERTION(!placeholder || (aDestructRoot != this),
"Don't call Destroy() on OOFs, call Destroy() on the placeholder.");
NS_ASSERTION(!placeholder ||
@@ -642,7 +641,6 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
"Placeholder relationship should have been torn down already; "
"this might mean we have a stray placeholder in the tree.");
if (placeholder) {
- shell->FrameManager()->UnregisterPlaceholderFrame(placeholder);
placeholder->SetOutOfFlowFrame(nullptr);
}
}
@@ -8073,9 +8071,8 @@ int32_t
nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainingBlock)
{
NS_ASSERTION(aFrame, "null aFrame");
- nsFrameManager* frameManager = aFrame->PresContext()->FrameManager();
- nsIFrame *blockFrame = aFrame;
- nsIFrame *thisBlock;
+ nsIFrame* blockFrame = aFrame;
+ nsIFrame* thisBlock;
nsAutoLineIterator it;
nsresult result = NS_ERROR_FAILURE;
while (NS_FAILED(result) && blockFrame)
@@ -8088,7 +8085,7 @@ nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainin
// abspos continuations don't have placeholders, get the fif
thisBlock = thisBlock->FirstInFlow();
}
- thisBlock = frameManager->GetPlaceholderFrameFor(thisBlock);
+ thisBlock = thisBlock->GetPlaceholderFrame();
if (!thisBlock)
return -1;
}
@@ -8918,6 +8915,8 @@ GetIBSplitSiblingForAnonymousBlock(const nsIFrame* aFrame)
*
* Also skip anonymous scrolled-content parents; inherit directly from the
* outer scroll frame.
+ *
+ * Also skip NAC parents if the child frame is NAC.
*/
static nsIFrame*
GetCorrectedParent(const nsIFrame* aFrame)
@@ -8943,6 +8942,32 @@ GetCorrectedParent(const nsIFrame* aFrame)
if (pseudo == nsCSSAnonBoxes::tableWrapper) {
pseudo = aFrame->PrincipalChildList().FirstChild()->StyleContext()->GetPseudo();
}
+
+ // Prevent NAC from inheriting NAC. This partially duplicates the logic
+ // implemented in nsCSSFrameConstructor::AddFCItemsForAnonymousContent, and is
+ // necessary so that restyle inherits style contexts in the same way as the
+ // initial styling performed in frame construction.
+ //
+ // It would be nice to put it in CorrectStyleParentFrame and therefore share
+ // it, but that would lose the information of whether the _child_ is NAC,
+ // since CorrectStyleParentFrame only knows about the prospective _parent_.
+ // This duplication and complexity will go away when we fully switch to the
+ // Servo style system, where all this can be handled much more naturally.
+ //
+ // We need to take special care not to disrupt the style inheritance of frames
+ // whose content is NAC but who implement a pseudo (like an anonymous
+ // box, or a non-NAC-backed pseudo like ::first-line) that does not match the
+ // one that the NAC implements, if any.
+ nsIContent* content = aFrame->GetContent();
+ Element* element =
+ content && content->IsElement() ? content->AsElement() : nullptr;
+ if (element && element->IsNativeAnonymous() && !element->IsNativeScrollbarContent() &&
+ element->GetPseudoElementType() == aFrame->StyleContext()->GetPseudoType()) {
+ while (parent->GetContent() && parent->GetContent()->IsNativeAnonymous()) {
+ parent = parent->GetInFlowParent();
+ }
+ }
+
return nsFrame::CorrectStyleParentFrame(parent, pseudo);
}
@@ -9012,7 +9037,9 @@ nsStyleContext*
nsFrame::DoGetParentStyleContext(nsIFrame** aProviderFrame) const
{
*aProviderFrame = nullptr;
- nsFrameManager* fm = PresContext()->FrameManager();
+
+ // Handle display:contents and the root frame, when there's no parent frame
+ // to inherit from.
if (MOZ_LIKELY(mContent)) {
nsIContent* parentContent = mContent->GetFlattenedTreeParent();
if (MOZ_LIKELY(parentContent)) {
@@ -9026,6 +9053,7 @@ nsFrame::DoGetParentStyleContext(nsIFrame** aProviderFrame) const
/* if next is true then it's really a request for the table frame's
parent context, see nsTable[Outer]Frame::GetParentStyleContext. */
pseudo == nsCSSAnonBoxes::tableWrapper) {
+ nsFrameManager* fm = PresContext()->FrameManager();
nsStyleContext* sc = fm->GetDisplayContentsStyleFor(parentContent);
if (MOZ_UNLIKELY(sc)) {
return sc;
@@ -9062,7 +9090,7 @@ nsFrame::DoGetParentStyleContext(nsIFrame** aProviderFrame) const
// We're an out-of-flow frame. For out-of-flow frames, we must
// resolve underneath the placeholder's parent. The placeholder is
// reached from the first-in-flow.
- nsIFrame* placeholder = fm->GetPlaceholderFrameFor(FirstInFlow());
+ nsIFrame* placeholder = FirstInFlow()->GetPlaceholderFrame();
if (!placeholder) {
NS_NOTREACHED("no placeholder frame for out-of-flow frame");
*aProviderFrame = GetCorrectedParent(this);
@@ -9977,19 +10005,16 @@ nsIFrame::IsPseudoStackingContextFromStyle() {
Element*
nsIFrame::GetPseudoElement(CSSPseudoElementType aType)
{
- nsIFrame* frame = nullptr;
+ if (!mContent) {
+ return nullptr;
+ }
if (aType == CSSPseudoElementType::before) {
- frame = nsLayoutUtils::GetBeforeFrame(this);
- } else if (aType == CSSPseudoElementType::after) {
- frame = nsLayoutUtils::GetAfterFrame(this);
+ return nsLayoutUtils::GetBeforePseudo(mContent);
}
- if (frame) {
- nsIContent* content = frame->GetContent();
- if (content->IsElement()) {
- return content->AsElement();
- }
+ if (aType == CSSPseudoElementType::after) {
+ return nsLayoutUtils::GetAfterPseudo(mContent);
}
return nullptr;
diff --git a/layout/generic/nsHTMLParts.h b/layout/generic/nsHTMLParts.h
index 89a7a6edd..243c432b2 100644
--- a/layout/generic/nsHTMLParts.h
+++ b/layout/generic/nsHTMLParts.h
@@ -11,6 +11,7 @@
#include "nscore.h"
#include "nsISupports.h"
#include "nsIFrame.h"
+class nsComboboxControlFrame;
class nsIAtom;
class nsNodeInfoManager;
class nsIContent;
@@ -161,7 +162,7 @@ nsIFrame*
NS_NewNativeSelectControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
nsContainerFrame*
NS_NewListControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
-nsContainerFrame*
+nsComboboxControlFrame*
NS_NewComboboxControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, nsFrameState aFlags);
nsIFrame*
NS_NewProgressFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
diff --git a/layout/generic/nsIAnonymousContentCreator.h b/layout/generic/nsIAnonymousContentCreator.h
index e7d4399b6..5167178b8 100644
--- a/layout/generic/nsIAnonymousContentCreator.h
+++ b/layout/generic/nsIAnonymousContentCreator.h
@@ -34,12 +34,7 @@ public:
mContent(aContent)
{}
- ContentInfo(nsIContent* aContent, nsStyleContext* aStyleContext) :
- mContent(aContent), mStyleContext(aStyleContext)
- {}
-
nsIContent* mContent;
- RefPtr<nsStyleContext> mStyleContext;
nsTArray<ContentInfo> mChildren;
};
@@ -66,18 +61,12 @@ public:
* Appends "native" anonymous children created by CreateAnonymousContent()
* to the given content list depending on the filter.
*
- * @see nsIContent::GetChildren for set of values used for filter.
+ * @see nsIContent::GetChildren for set of values used for filter. Currently,
+ * eSkipPlaceholderContent is the only flag that any implementation of
+ * this method heeds.
*/
virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter) = 0;
-
- /**
- * Implementations can override this method to create special frames for the
- * anonymous content returned from CreateAnonymousContent.
- * By default this method returns nullptr, which means the default frame
- * is created.
- */
- virtual nsIFrame* CreateFrameFor(nsIContent* aContent) { return nullptr; }
};
#endif
diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h
index 93eb95099..e22dd690a 100644
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -82,6 +82,7 @@ class nsLineList_iterator;
class nsAbsoluteContainingBlock;
class nsIContent;
class nsContainerFrame;
+class nsPlaceholderFrame;
struct nsPeekOffsetStruct;
struct nsPoint;
@@ -721,6 +722,23 @@ public:
* Accessor functions for geometric parent.
*/
nsContainerFrame* GetParent() const { return mParent; }
+
+ /**
+ * Gets the parent of a frame, using the parent of the placeholder for
+ * out-of-flow frames.
+ */
+ inline nsContainerFrame* GetInFlowParent();
+
+ /**
+ * Return the placeholder for this frame (which must be out-of-flow).
+ * @note this will only return non-null if |this| is the first-in-flow
+ * although we don't assert that here for legacy reasons.
+ */
+ inline nsPlaceholderFrame* GetPlaceholderFrame() const {
+ MOZ_ASSERT(HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
+ return GetProperty(PlaceholderFrameProperty());
+ }
+
/**
* Set this frame's parent to aParent.
* If the frame may have moved into or out of a scrollframe's
@@ -1040,6 +1058,8 @@ public:
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BidiDataProperty, mozilla::FrameBidiData)
+ NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(PlaceholderFrameProperty, nsPlaceholderFrame)
+
mozilla::FrameBidiData GetBidiData()
{
return GetProperty(BidiDataProperty());
@@ -1055,10 +1075,6 @@ public:
return GetBidiData().embeddingLevel;
}
- nsTArray<nsIContent*>* GetGenConPseudos() {
- return GetProperty(GenConProperty());
- }
-
/**
* Return the distance between the border edge of the frame and the
* margin edge of the frame. Like GetRect(), returns the dimensions
diff --git a/layout/generic/nsIFrameInlines.h b/layout/generic/nsIFrameInlines.h
index eb9a7202a..a3da7ebca 100644
--- a/layout/generic/nsIFrameInlines.h
+++ b/layout/generic/nsIFrameInlines.h
@@ -8,8 +8,10 @@
#define nsIFrameInlines_h___
#include "nsContainerFrame.h"
+#include "nsPlaceholderFrame.h"
#include "nsStyleStructInlines.h"
#include "nsCSSAnonBoxes.h"
+#include "nsFrameManager.h"
bool
nsIFrame::IsFlexItem() const
@@ -160,4 +162,15 @@ nsIFrame::BaselineBOffset(mozilla::WritingMode aWM,
return SynthesizeBaselineBOffsetFromBorderBox(aWM, aBaselineGroup);
}
+nsContainerFrame*
+nsIFrame::GetInFlowParent()
+{
+ if (GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
+ nsIFrame* ph = FirstContinuation()->GetProperty(nsIFrame::PlaceholderFrameProperty());
+ return ph->GetParent();
+ }
+
+ return GetParent();
+}
+
#endif
diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp
index c64520f2e..ee35ecad8 100644
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1836,7 +1836,7 @@ nsImageFrame::ShouldDisplaySelection()
int32_t thisOffset = parentContent->IndexOf(mContent);
nsCOMPtr<nsIDOMNode> parentNode = do_QueryInterface(parentContent);
nsCOMPtr<nsIDOMNode> rangeNode;
- int32_t rangeOffset;
+ uint32_t rangeOffset;
nsCOMPtr<nsIDOMRange> range;
selection->GetRangeAt(0,getter_AddRefs(range));
if (range)
@@ -1844,12 +1844,16 @@ nsImageFrame::ShouldDisplaySelection()
range->GetStartContainer(getter_AddRefs(rangeNode));
range->GetStartOffset(&rangeOffset);
- if (parentNode && rangeNode && (rangeNode == parentNode) && rangeOffset == thisOffset)
- {
+ if (parentNode && rangeNode && rangeNode == parentNode &&
+ static_cast<int32_t>(rangeOffset) == thisOffset) {
range->GetEndContainer(getter_AddRefs(rangeNode));
range->GetEndOffset(&rangeOffset);
- if ((rangeNode == parentNode) && (rangeOffset == (thisOffset +1))) //+1 since that would mean this whole content is selected only
- return false; //do not allow nsFrame do draw any further selection
+ // +1 since that would mean this whole content is selected only
+ if (rangeNode == parentNode &&
+ static_cast<int32_t>(rangeOffset) == thisOffset + 1) {
+ // Do not allow nsFrame do draw any further selection
+ return false;
+ }
}
}
}
diff --git a/layout/generic/nsPlaceholderFrame.cpp b/layout/generic/nsPlaceholderFrame.cpp
index bd380a2d9..62370a06a 100644
--- a/layout/generic/nsPlaceholderFrame.cpp
+++ b/layout/generic/nsPlaceholderFrame.cpp
@@ -156,16 +156,15 @@ nsPlaceholderFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
nsIFrame* oof = mOutOfFlowFrame;
if (oof) {
- // Unregister out-of-flow frame
- nsFrameManager* fm = PresContext()->GetPresShell()->FrameManager();
- fm->UnregisterPlaceholderFrame(this);
mOutOfFlowFrame = nullptr;
+ oof->DeleteProperty(nsIFrame::PlaceholderFrameProperty());
// If aDestructRoot is not an ancestor of the out-of-flow frame,
// then call RemoveFrame on it here.
// Also destroy it here if it's a popup frame. (Bug 96291)
if ((GetStateBits() & PLACEHOLDER_FOR_POPUP) ||
!nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, oof)) {
ChildListID listId = nsLayoutUtils::GetChildListNameFor(oof);
+ nsFrameManager* fm = PresContext()->GetPresShell()->FrameManager();
fm->RemoveFrame(listId, oof);
}
// else oof will be destroyed by its parent
diff --git a/layout/generic/nsSelection.cpp b/layout/generic/nsSelection.cpp
index 5ccb2d8bf..919ab0815 100644
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -1788,8 +1788,7 @@ nsFrameSelection::TakeFocus(nsIContent* aNewFocus,
RefPtr<nsRange> newRange = new nsRange(aNewFocus);
- newRange->SetStart(aNewFocus, aContentOffset);
- newRange->SetEnd(aNewFocus, aContentOffset);
+ newRange->CollapseTo(aNewFocus, aContentOffset);
mDomSelections[index]->AddRange(newRange);
mBatching = batching;
mChangesDuringBatching = changes;
@@ -3352,10 +3351,11 @@ nsFrameSelection::CreateAndAddRange(nsINode *aParentNode, int32_t aOffset)
RefPtr<nsRange> range = new nsRange(aParentNode);
// Set range around child at given offset
- nsresult result = range->SetStart(aParentNode, aOffset);
- if (NS_FAILED(result)) return result;
- result = range->SetEnd(aParentNode, aOffset+1);
- if (NS_FAILED(result)) return result;
+ nsresult rv = range->SetStartAndEnd(aParentNode, aOffset,
+ aParentNode, aOffset + 1);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
if (!mDomSelections[index])
@@ -3521,6 +3521,18 @@ Selection::GetParentObject() const
return nullptr;
}
+DocGroup*
+Selection::GetDocGroup() const
+{
+ nsIPresShell* shell = GetPresShell();
+ if (!shell) {
+ return nullptr;
+ }
+
+ nsIDocument* doc = shell->GetDocument();
+ return doc ? doc->GetDocGroup() : nullptr;
+}
+
NS_IMPL_CYCLE_COLLECTION_CLASS(Selection)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Selection)
@@ -3780,13 +3792,12 @@ Selection::SubtractRange(RangeData* aRange, nsRange* aSubtract,
// We need to add a new RangeData to the output, running from
// the end of aSubtract to the end of range
RefPtr<nsRange> postOverlap = new nsRange(aSubtract->GetEndParent());
-
- rv =
- postOverlap->SetStart(aSubtract->GetEndParent(), aSubtract->EndOffset());
- NS_ENSURE_SUCCESS(rv, rv);
- rv =
- postOverlap->SetEnd(range->GetEndParent(), range->EndOffset());
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = postOverlap->SetStartAndEnd(
+ aSubtract->GetEndParent(), aSubtract->EndOffset(),
+ range->GetEndParent(), range->EndOffset());
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
if (!postOverlap->Collapsed()) {
if (!aOutput->InsertElementAt(0, RangeData(postOverlap)))
return NS_ERROR_OUT_OF_MEMORY;
@@ -3799,12 +3810,12 @@ Selection::SubtractRange(RangeData* aRange, nsRange* aSubtract,
// the start of the range to the start of aSubtract
RefPtr<nsRange> preOverlap = new nsRange(range->GetStartParent());
- nsresult rv =
- preOverlap->SetStart(range->GetStartParent(), range->StartOffset());
- NS_ENSURE_SUCCESS(rv, rv);
- rv =
- preOverlap->SetEnd(aSubtract->GetStartParent(), aSubtract->StartOffset());
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = preOverlap->SetStartAndEnd(
+ range->GetStartParent(), range->StartOffset(),
+ aSubtract->GetStartParent(), aSubtract->StartOffset());
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
if (!preOverlap->Collapsed()) {
if (!aOutput->InsertElementAt(0, RangeData(preOverlap)))
@@ -4120,13 +4131,15 @@ Selection::GetType(int16_t* aType)
static inline bool
RangeMatchesBeginPoint(nsRange* aRange, nsINode* aNode, int32_t aOffset)
{
- return aRange->GetStartParent() == aNode && aRange->StartOffset() == aOffset;
+ return aRange->GetStartParent() == aNode &&
+ static_cast<int32_t>(aRange->StartOffset()) == aOffset;
}
static inline bool
RangeMatchesEndPoint(nsRange* aRange, nsINode* aNode, int32_t aOffset)
{
- return aRange->GetEndParent() == aNode && aRange->EndOffset() == aOffset;
+ return aRange->GetEndParent() == aNode &&
+ static_cast<int32_t>(aRange->EndOffset()) == aOffset;
}
// Selection::EqualsRangeAtPoint
@@ -5186,12 +5199,7 @@ Selection::Collapse(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
}
RefPtr<nsRange> range = new nsRange(parentNode);
- result = range->SetEnd(parentNode, aOffset);
- if (NS_FAILED(result)) {
- aRv.Throw(result);
- return;
- }
- result = range->SetStart(parentNode, aOffset);
+ result = range->CollapseTo(parentNode, aOffset);
if (NS_FAILED(result)) {
aRv.Throw(result);
return;
@@ -5579,11 +5587,8 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
return;
}
SetDirection(eDirNext);
- res = difRange->SetEnd(range->GetEndParent(), range->EndOffset());
- nsresult tmp = difRange->SetStart(focusNode, focusOffset);
- if (NS_FAILED(tmp)) {
- res = tmp;
- }
+ res = difRange->SetStartAndEnd(focusNode, focusOffset,
+ range->GetEndParent(), range->EndOffset());
if (NS_FAILED(res)) {
aRv.Throw(res);
return;
@@ -5611,11 +5616,8 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
}
else if (result3 <= 0 && result2 >= 0) {//a,2,1 or a2,1 or a,21 or a21
//deselect from 2 to 1
- res = difRange->SetEnd(focusNode, focusOffset);
- difRange->SetStart(aParentNode, aOffset, aRv);
- if (aRv.Failed()) {
- return;
- }
+ res = difRange->SetStartAndEnd(&aParentNode, aOffset,
+ focusNode, focusOffset);
if (NS_FAILED(res)) {
aRv.Throw(res);
return;
@@ -5678,11 +5680,8 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
}
else if (result2 <= 0 && result3 >= 0) {//1,2,a or 12,a or 1,2a or 12a
//deselect from 1 to 2
- difRange->SetEnd(aParentNode, aOffset, aRv);
- res = difRange->SetStart(focusNode, focusOffset);
- if (aRv.Failed()) {
- return;
- }
+ res = difRange->SetStartAndEnd(focusNode, focusOffset,
+ &aParentNode, aOffset);
if (NS_FAILED(res)) {
aRv.Throw(res);
return;
@@ -5713,15 +5712,9 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
}
//deselect from a to 1
if (focusNode != anchorNode || focusOffset!= anchorOffset) {//if collapsed diff dont do anything
- res = difRange->SetStart(anchorNode, anchorOffset);
- nsresult tmp = difRange->SetEnd(focusNode, focusOffset);
- if (NS_FAILED(tmp)) {
- res = tmp;
- }
- tmp = SetAnchorFocusToRange(range);
- if (NS_FAILED(tmp)) {
- res = tmp;
- }
+ res = difRange->SetStartAndEnd(anchorNode, anchorOffset,
+ focusNode, focusOffset);
+ nsresult tmp = SetAnchorFocusToRange(range);
if (NS_FAILED(res)) {
aRv.Throw(res);
return;
@@ -5746,11 +5739,9 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
return;
}
SetDirection(eDirPrevious);
- res = difRange->SetEnd(focusNode, focusOffset);
- nsresult tmp = difRange->SetStart(range->GetStartParent(), range->StartOffset());
- if (NS_FAILED(tmp)) {
- res = tmp;
- }
+ res = difRange->SetStartAndEnd(
+ range->GetStartParent(), range->StartOffset(),
+ focusNode, focusOffset);
if (NS_FAILED(res)) {
aRv.Throw(res);
return;
diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp
index 59ef020ce..6875f33e8 100644
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -1383,8 +1383,7 @@ BuildTextRuns(DrawTarget* aDrawTarget, nsTextFrame* aForFrame,
nsIFrame* lineContainerChild = aForFrame;
if (!aLineContainer) {
if (aForFrame->IsFloatingFirstLetterChild()) {
- lineContainerChild = aForFrame->PresContext()->PresShell()->
- GetPlaceholderFrameFor(aForFrame->GetParent());
+ lineContainerChild = aForFrame->GetParent()->GetPlaceholderFrame();
}
aLineContainer = FindLineContainer(lineContainerChild);
} else {
diff --git a/layout/inspector/inDOMUtils.cpp b/layout/inspector/inDOMUtils.cpp
index e212e20df..58afc5f76 100644
--- a/layout/inspector/inDOMUtils.cpp
+++ b/layout/inspector/inDOMUtils.cpp
@@ -48,7 +48,8 @@
#include "nsCSSProps.h"
#include "nsCSSValue.h"
#include "nsColor.h"
-#include "nsStyleSet.h"
+#include "mozilla/StyleSetHandle.h"
+#include "mozilla/StyleSetHandleInlines.h"
#include "nsStyleUtil.h"
#include "nsQueryObject.h"
@@ -77,7 +78,7 @@ inDOMUtils::GetAllStyleSheets(nsIDOMDocument *aDocument, uint32_t *aLength,
{
NS_ENSURE_ARG_POINTER(aDocument);
- nsTArray<RefPtr<CSSStyleSheet>> sheets;
+ nsTArray<RefPtr<StyleSheet>> sheets;
nsCOMPtr<nsIDocument> document = do_QueryInterface(aDocument);
MOZ_ASSERT(document);
@@ -85,15 +86,8 @@ inDOMUtils::GetAllStyleSheets(nsIDOMDocument *aDocument, uint32_t *aLength,
// Get the agent, then user and finally xbl sheets in the style set.
nsIPresShell* presShell = document->GetShell();
- if (presShell && presShell->StyleSet()->IsServo()) {
- // XXXheycam ServoStyleSets don't have the ability to expose their
- // sheets in a script-accessible way yet.
- NS_ERROR("stylo: ServoStyleSets cannot expose their sheets to script yet");
- return NS_ERROR_FAILURE;
- }
-
if (presShell) {
- nsStyleSet* styleSet = presShell->StyleSet()->AsGecko();
+ StyleSetHandle styleSet = presShell->StyleSet();
SheetType sheetType = SheetType::Agent;
for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i));
@@ -102,24 +96,26 @@ inDOMUtils::GetAllStyleSheets(nsIDOMDocument *aDocument, uint32_t *aLength,
for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i));
}
- AutoTArray<CSSStyleSheet*, 32> xblSheetArray;
- styleSet->AppendAllXBLStyleSheets(xblSheetArray);
-
- // The XBL stylesheet array will quite often be full of duplicates. Cope:
- nsTHashtable<nsPtrHashKey<CSSStyleSheet>> sheetSet;
- for (CSSStyleSheet* sheet : xblSheetArray) {
- if (!sheetSet.Contains(sheet)) {
- sheetSet.PutEntry(sheet);
- sheets.AppendElement(sheet);
+ if (styleSet->IsGecko()) {
+ AutoTArray<CSSStyleSheet*, 32> xblSheetArray;
+ styleSet->AsGecko()->AppendAllXBLStyleSheets(xblSheetArray);
+
+ // The XBL stylesheet array will quite often be full of duplicates. Cope:
+ nsTHashtable<nsPtrHashKey<CSSStyleSheet>> sheetSet;
+ for (CSSStyleSheet* sheet : xblSheetArray) {
+ if (!sheetSet.Contains(sheet)) {
+ sheetSet.PutEntry(sheet);
+ sheets.AppendElement(sheet);
+ }
}
+ } else {
+ NS_WARNING("stylo: XBL style sheets not supported yet");
}
}
// Get the document sheets.
- for (int32_t i = 0; i < document->GetNumberOfStyleSheets(); i++) {
- // XXXheycam ServoStyleSets don't have the ability to expose their
- // sheets in a script-accessible way yet.
- sheets.AppendElement(document->GetStyleSheetAt(i)->AsGecko());
+ for (size_t i = 0; i < document->SheetCount(); i++) {
+ sheets.AppendElement(document->SheetAt(i));
}
nsISupports** ret = static_cast<nsISupports**>(moz_xmalloc(sheets.Length() *
diff --git a/layout/inspector/tests/test_bug522601.xhtml b/layout/inspector/tests/test_bug522601.xhtml
index 7c5a9e79c..c49f2fa83 100644
--- a/layout/inspector/tests/test_bug522601.xhtml
+++ b/layout/inspector/tests/test_bug522601.xhtml
@@ -237,6 +237,8 @@ addLoadEvent(function() {
testFunc(walkerAnon, "previousNode", $("display"), "step back to root (anon)");
testFunc(walkerAnon, "previousNode", null, "step back past root (anon)");
+ //XXXsmaug update this test for Shadow DOM v1! bug 1421539
+ /*if (Element.prototype.createShadowRoot) {
var shadowdiv = document.querySelector('#test-shadow');
var shadowRoot = shadowdiv.createShadowRoot();
var h = document.createElement("header");
@@ -266,6 +268,7 @@ addLoadEvent(function() {
SimpleTest.finish();
});
+ }*/
]]>
</script>
diff --git a/layout/printing/nsPrintEngine.cpp b/layout/printing/nsPrintEngine.cpp
index f2db53250..0c455f563 100644
--- a/layout/printing/nsPrintEngine.cpp
+++ b/layout/printing/nsPrintEngine.cpp
@@ -2449,13 +2449,17 @@ CloneRangeToSelection(nsRange* aRange, nsIDocument* aDoc,
NS_ENSURE_TRUE_VOID(newStart && newEnd);
nsCOMPtr<nsINode> newStartNode = do_QueryInterface(newStart);
- NS_ENSURE_TRUE_VOID(newStartNode);
+ nsCOMPtr<nsINode> newEndNode = do_QueryInterface(newEnd);
+ if (NS_WARN_IF(!newStartNode) || NS_WARN_IF(!newEndNode)) {
+ return;
+ }
RefPtr<nsRange> range = new nsRange(newStartNode);
- nsresult rv = range->SetStart(newStartNode, startOffset);
- NS_ENSURE_SUCCESS_VOID(rv);
- rv = range->SetEnd(newEnd, endOffset);
- NS_ENSURE_SUCCESS_VOID(rv);
+ nsresult rv =
+ range->SetStartAndEnd(newStartNode, startOffset, newEndNode, endOffset);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return;
+ }
aSelection->AddRange(range);
}
diff --git a/layout/reftests/bugs/1066554-1.html b/layout/reftests/bugs/1066554-1.html
index bb0a97f96..f4df207a1 100644
--- a/layout/reftests/bugs/1066554-1.html
+++ b/layout/reftests/bugs/1066554-1.html
@@ -7,15 +7,17 @@
<script>
function insertShadowSVG() {
var x = document.getElementById("x");
- x.createShadowRoot();
- x.shadowRoot.innerHTML =
- '<svg width="50px" height="10px"> \
- <switch> \
- <foreignObject width="50px" height="50px"> \
- <div style="width: 100px; height: 10px; background: red;"></div> \
- </foreignObject> \
- </switch> \
- </svg>';
+ if (x.createShadowRoot) {
+ x.createShadowRoot();
+ x.shadowRoot.innerHTML =
+ '<svg width="50px" height="10px"> \
+ <switch> \
+ <foreignObject width="50px" height="50px"> \
+ <div style="width: 100px; height: 10px; background: red;"></div> \
+ </foreignObject> \
+ </switch> \
+ </svg>';
+ }
document.documentElement.removeAttribute("class");
}
window.addEventListener("MozReftestInvalidate", insertShadowSVG, false);
diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list
index d6f58a9c2..84d7f188f 100644
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1851,7 +1851,7 @@ test-pref(layout.css.grid.enabled,true) == 1053035-1-grid.html 1053035-1-ref.htm
== 1062108-1.html 1062108-1-ref.html
== 1062792-1.html 1062792-1-ref.html
== 1062963-floatmanager-reflow.html 1062963-floatmanager-reflow-ref.html
-test-pref(dom.webcomponents.enabled,true) == 1066554-1.html 1066554-1-ref.html
+test-pref(dom.webcomponents.enabled,true) fails-if(stylo||styloVsGecko) == 1066554-1.html 1066554-1-ref.html
== 1069716-1.html 1069716-1-ref.html
== 1078262-1.html about:blank
test-pref(layout.testing.overlay-scrollbars.always-visible,false) == 1081072-1.html 1081072-1-ref.html
diff --git a/layout/reftests/css-display/display-contents-shadow-dom-1-ref.html b/layout/reftests/css-display/display-contents-shadow-dom-1-ref.html
index f57822901..6e6dad233 100644
--- a/layout/reftests/css-display/display-contents-shadow-dom-1-ref.html
+++ b/layout/reftests/css-display/display-contents-shadow-dom-1-ref.html
@@ -45,8 +45,6 @@ span { color:blue; }
<span style="color:green">R</span>
<div></div>
<b style="color:green">V</b>
- <b style="color:green">W</b>
- <b style="color:green">X</b>
<!-- <b style="color:green">Y</b> -->
</body>
</html>
diff --git a/layout/reftests/css-display/display-contents-shadow-dom-1.html b/layout/reftests/css-display/display-contents-shadow-dom-1.html
index f5e49a192..6c0f297f9 100644
--- a/layout/reftests/css-display/display-contents-shadow-dom-1.html
+++ b/layout/reftests/css-display/display-contents-shadow-dom-1.html
@@ -51,8 +51,6 @@ div.after::after {content: " Y";}
<div id="hostT" class="c">T</div>
<div id="hostU"><span class="c">U</span></div>
<div id="hostV" class="c" style="color:red"><b class="c" style="color:inherit">V</b></div>
- <div id="hostW" class="c" style="color:red"><b class="c" style="color:inherit">W</b></div>
- <span id="hostX" style="color:red"><b class="c" style="color:inherit">X</b></span>
<!-- TODO(bug 1021572?) <div id="hostY" class="c" style="color:red"><b>Y</b></div> -->
<script>
@@ -76,38 +74,40 @@ div.after::after {content: " Y";}
return e;
}
- document.body.offsetHeight;
-
- shadow("host1").innerHTML = '<content></content> c';
- shadow("host2").innerHTML = 'a <content style="display:contents"></content> c';
- shadow("host3").innerHTML = 'a <content style="display:contents"></content>';
- shadow("host4").innerHTML = '<content style="display:contents"></content>';
- shadow("host5").innerHTML = 'a <content style="display:contents"></content>';
- shadow("host6").innerHTML = '<z style="color:blue; display:contents"><content></content></z> c';
- shadow("host7").innerHTML = 'a <content style="display:contents"></content> c';
- shadow("host8").innerHTML = 'a <z style="color:blue; display:contents"><content style="display:contents"></z></content>';
- shadow("host9").innerHTML = '<content style="display:contents"></content>';
- shadow("hostA").innerHTML = 'a <content style="display:contents"></content>';
- shadow("hostB").innerHTML = 'a <content select=".c"></content> <content select=".b"></content> B';
- shadow("hostC").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B';
- shadow("hostD").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B <content select=".b"></content>';
- shadow("hostE").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B';
- shadow("hostF").innerHTML = '<content select=".c"></content> <content select=".b"></content> B';
- shadow("hostG").innerHTML = '<content select=".b"></content>';
- shadow("hostH").innerHTML = '<content select=".b"></content>';
- shadow("hostI").innerHTML = 'A<content select=".b"></content>';
- shadow("hostJ").innerHTML = 'A<content select=".b"></content>';
- shadow("hostK").innerHTML = '<content select=".b"></content>';
- shadow("hostL").innerHTML = '<content select=".b"></content>';
- shadow("hostM").innerHTML = '<content select="b"></content><content select="i"></content>';
- shadow("hostN").innerHTML = '<content select="b"></content><content select="i"></content>';
- shadow("hostO").innerHTML = '<content select="b"></content><content select="i"></content>';
- shadow("hostP").innerHTML = '<content select="b"></content><content select="i"></content>';
- shadow("hostQ").innerHTML = '<content select="b"></content><content select="i"></content>';
- shadow("hostR").innerHTML = '<content select="span"></content>';
- shadow("hostW").innerHTML = '<z style="color:red"><content select="b"></content></z>';
- shadow("hostX").innerHTML = '<z style="color:red"><content select="b"></content></z>';
- // TODO(bug 1021572?) shadow("hostY").innerHTML = '<content select="b"><style scoped>:scope{color:green}</style></content>';
+ function run() {
+ document.body.offsetHeight;
+
+ shadow("host1").innerHTML = '<content></content> c';
+ shadow("host2").innerHTML = 'a <content style="display:contents"></content> c';
+ shadow("host3").innerHTML = 'a <content style="display:contents"></content>';
+ shadow("host4").innerHTML = '<content style="display:contents"></content>';
+ shadow("host5").innerHTML = 'a <content style="display:contents"></content>';
+ shadow("host6").innerHTML = '<z style="color:blue; display:contents"><content></content></z> c';
+ shadow("host7").innerHTML = 'a <content style="display:contents"></content> c';
+ shadow("host8").innerHTML = 'a <z style="color:blue; display:contents"><content style="display:contents"></z></content>';
+ shadow("host9").innerHTML = '<content style="display:contents"></content>';
+ shadow("hostA").innerHTML = 'a <content style="display:contents"></content>';
+ shadow("hostB").innerHTML = 'a <content select=".c"></content> <content select=".b"></content> B';
+ shadow("hostC").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B';
+ shadow("hostD").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B <content select=".b"></content>';
+ shadow("hostE").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B';
+ shadow("hostF").innerHTML = '<content select=".c"></content> <content select=".b"></content> B';
+ shadow("hostG").innerHTML = '<content select=".b"></content>';
+ shadow("hostH").innerHTML = '<content select=".b"></content>';
+ shadow("hostI").innerHTML = 'A<content select=".b"></content>';
+ shadow("hostJ").innerHTML = 'A<content select=".b"></content>';
+ shadow("hostK").innerHTML = '<content select=".b"></content>';
+ shadow("hostL").innerHTML = '<content select=".b"></content>';
+ shadow("hostM").innerHTML = '<content select="b"></content><content select="i"></content>';
+ shadow("hostN").innerHTML = '<content select="b"></content><content select="i"></content>';
+ shadow("hostO").innerHTML = '<content select="b"></content><content select="i"></content>';
+ shadow("hostP").innerHTML = '<content select="b"></content><content select="i"></content>';
+ shadow("hostQ").innerHTML = '<content select="b"></content><content select="i"></content>';
+ shadow("hostR").innerHTML = '<content select="span"></content>';
+ shadow("hostW").innerHTML = '<z style="color:red"><content select="b"></content></z>';
+ shadow("hostX").innerHTML = '<z style="color:red"><content select="b"></content></z>';
+ // TODO(bug 1021572?) shadow("hostY").innerHTML = '<content select="b"><style scoped>:scope{color:green}</style></content>';
+ }
function tweak() {
document.body.offsetHeight;
@@ -222,15 +222,18 @@ div.after::after {content: " Y";}
shadow("hostT");
shadow("hostU");
shadow("hostV").innerHTML = '<z style="color:green"><content select="b"></content></z>';
- shadow("hostW").innerHTML = '<z style="color:green"><content select="b"></content></z>';
- shadow("hostX").innerHTML = '<z style="color:green"><content select="b"></content></z>';
document.body.offsetHeight;
document.documentElement.removeAttribute("class");
},0);
}
- window.addEventListener("MozReftestInvalidate", tweak, false);
+ if (document.body.createShadowRoot) {
+ run();
+ window.addEventListener("MozReftestInvalidate", tweak, false);
+ } else {
+ document.documentElement.removeAttribute("class");
+ }
</script>
</body>
</html>
diff --git a/layout/reftests/css-grid/reftest.list b/layout/reftests/css-grid/reftest.list
index 7c5e6be51..35e3140a8 100644
--- a/layout/reftests/css-grid/reftest.list
+++ b/layout/reftests/css-grid/reftest.list
@@ -248,10 +248,10 @@ asserts(0-10) == grid-fragmentation-015.html grid-fragmentation-015-ref.html # b
== grid-fragmentation-dyn5-019.html grid-fragmentation-019-ref.html
== grid-fragmentation-dyn1-020.html grid-fragmentation-020-ref.html
== grid-fragmentation-dyn2-020.html grid-fragmentation-020-ref.html
-!= grid-fragmentation-dyn1-021.html grid-fragmentation-021-ref.html # bug 1251799
+== grid-fragmentation-dyn1-021.html grid-fragmentation-021-ref.html
== grid-fragmentation-dyn2-021.html grid-fragmentation-021-ref.html
== grid-fragmentation-dyn3-021.html grid-fragmentation-021-ref.html
-asserts(1-10) == grid-fragmentation-dyn4-021.html grid-fragmentation-021-ref.html # assertion related to bug 1251799 ?
+== grid-fragmentation-dyn4-021.html grid-fragmentation-021-ref.html
== grid-fragmentation-dyn5-021.html grid-fragmentation-021-ref.html
== grid-fragmentation-dyn2-022.html grid-fragmentation-007-ref.html
== grid-fragmentation-dyn1-023.html grid-fragmentation-023-ref.html
diff --git a/layout/reftests/details-summary/reftest.list b/layout/reftests/details-summary/reftest.list
index e96581ad4..a972cf498 100644
--- a/layout/reftests/details-summary/reftest.list
+++ b/layout/reftests/details-summary/reftest.list
@@ -101,3 +101,7 @@ fuzzy(1,1) == mouse-click-twice-float-details.html float-details.html # Bug 1316
== details-before.html single-summary.html
== open-details-after.html open-single-summary.html
== open-details-before.html open-single-summary.html
+
+# Move summary element
+== move-float-summary-to-different-details.html move-float-summary-to-different-details-ref.html
+== move-position-absolute-summary-to-different-details.html move-position-absolute-summary-to-different-details-ref.html
diff --git a/layout/reftests/forms/input/number/number-style-inheritance-ref.html b/layout/reftests/forms/input/number/number-style-inheritance-ref.html
new file mode 100644
index 000000000..00c8dba43
--- /dev/null
+++ b/layout/reftests/forms/input/number/number-style-inheritance-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <input type="text" style="width: 100px; text-decoration: underline;" value="1234">
+ </body>
+</html>
diff --git a/layout/reftests/forms/input/number/number-style-inheritance.html b/layout/reftests/forms/input/number/number-style-inheritance.html
new file mode 100644
index 000000000..b21ff1f1c
--- /dev/null
+++ b/layout/reftests/forms/input/number/number-style-inheritance.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+ <body>
+ <input type="number" style="width: 100px; -moz-appearance: textfield; text-decoration: underline;" value="1234">
+ </body>
+</html>
diff --git a/layout/reftests/forms/input/number/reftest.list b/layout/reftests/forms/input/number/reftest.list
index ecf05ce15..bd07e274c 100644
--- a/layout/reftests/forms/input/number/reftest.list
+++ b/layout/reftests/forms/input/number/reftest.list
@@ -52,3 +52,6 @@ fuzzy-if(skiaContent,2,5) needs-focus == focus-handling.html focus-handling-ref.
fuzzy(128,4) == number-reframe-anon-text-field.html number-reframe-anon-text-field-ref.html
== pseudo-classes.html about:blank
+
+# Style inheritance:
+== number-style-inheritance.html number-style-inheritance-ref.html
diff --git a/layout/reftests/forms/legend/reftest.list b/layout/reftests/forms/legend/reftest.list
index 879835a59..03e25eb20 100644
--- a/layout/reftests/forms/legend/reftest.list
+++ b/layout/reftests/forms/legend/reftest.list
@@ -1,3 +1,3 @@
== legend.html legend-ref.html
-fuzzy-if(skiaContent,1,7) pref(dom.webcomponents.enabled,true) == shadow-dom.html shadow-dom-ref.html
+#bug 1418002 fuzzy-if(skiaContent,1,7) pref(dom.webcomponents.enabled,true) == shadow-dom.html shadow-dom-ref.html
== 1273433.html 1273433-ref.html
diff --git a/layout/reftests/forms/legend/shadow-dom.html b/layout/reftests/forms/legend/shadow-dom.html
index ad7babcf7..0f0a53665 100644
--- a/layout/reftests/forms/legend/shadow-dom.html
+++ b/layout/reftests/forms/legend/shadow-dom.html
@@ -48,17 +48,19 @@ div.after::after {content: " Y";}
return e;
}
- document.body.offsetHeight;
+ function run() {
+ document.body.offsetHeight;
- shadow("host1").innerHTML = '<content></content> c';
- shadow("host2").innerHTML = 'a <content></content> c';
- shadow("host3").innerHTML = 'a <content></content>';
- shadow("host4").innerHTML = '<content></content>';
- shadow("host5").innerHTML = 'a <content></content>';
- shadow("host6").innerHTML = '<z style="color:blue; display:contents"><content></content></z> c';
- shadow("host7").innerHTML = 'a <content select=".c"></content> <content select=".b"></content> B';
- shadow("host8").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B';
- shadow("host9").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B <content select=".b"></content>';
+ shadow("host1").innerHTML = '<content></content> c';
+ shadow("host2").innerHTML = 'a <content></content> c';
+ shadow("host3").innerHTML = 'a <content></content>';
+ shadow("host4").innerHTML = '<content></content>';
+ shadow("host5").innerHTML = 'a <content></content>';
+ shadow("host6").innerHTML = '<z style="color:blue; display:contents"><content></content></z> c';
+ shadow("host7").innerHTML = 'a <content select=".c"></content> <content select=".b"></content> B';
+ shadow("host8").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B';
+ shadow("host9").innerHTML = 'A <content select=".c"></content> <content select=".b"></content> B <content select=".b"></content>';
+ }
function tweak() {
document.body.offsetHeight;
@@ -105,7 +107,12 @@ div.after::after {content: " Y";}
},0);
}
- window.addEventListener("MozReftestInvalidate", tweak, false);
+ if (document.body.createShadowRoot) {
+ run();
+ window.addEventListener("MozReftestInvalidate", tweak, false);
+ } else {
+ document.documentElement.removeAttribute("class");
+ }
</script>
</body>
</html>
diff --git a/layout/reftests/mathml/shadow-dom-1.html b/layout/reftests/mathml/shadow-dom-1.html
index 547253a3c..bbf27069f 100644
--- a/layout/reftests/mathml/shadow-dom-1.html
+++ b/layout/reftests/mathml/shadow-dom-1.html
@@ -7,9 +7,11 @@
<script>
function insertShadowMathML() {
var x = document.getElementById("x");
- x.createShadowRoot();
- x.shadowRoot.innerHTML =
- '<math><msup><mi>X</mi><mi>X</mi></msup></math>';
+ if (x.createShadowRoot) {
+ x.createShadowRoot();
+ x.shadowRoot.innerHTML =
+ '<math><msup><mi>X</mi><mi>X</mi></msup></math>';
+ }
document.documentElement.removeAttribute("class");
}
window.addEventListener("MozReftestInvalidate", insertShadowMathML, false);
diff --git a/layout/reftests/webcomponents/adjacent-insertion-points-1-ref.html b/layout/reftests/webcomponents/adjacent-insertion-points-1-ref.html
deleted file mode 100644
index 2c1f4e341..000000000
--- a/layout/reftests/webcomponents/adjacent-insertion-points-1-ref.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body>
-<div><span>Hello</span><span>World</span></div>
-</body>
-</html>
diff --git a/layout/reftests/webcomponents/adjacent-insertion-points-1.html b/layout/reftests/webcomponents/adjacent-insertion-points-1.html
deleted file mode 100644
index a8c6f983d..000000000
--- a/layout/reftests/webcomponents/adjacent-insertion-points-1.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <script>
- function tweak() {
- var oldShadowRoot = document.getElementById('outer').createShadowRoot();
- oldShadowRoot.innerHTML = 'World';
-
- var youngShadowRoot = document.getElementById('outer').createShadowRoot();
- youngShadowRoot.innerHTML = 'Hello<content></content><shadow></shadow>';
- }
- </script>
-</head>
-<body onload="tweak()">
-<div id="outer"></div>
-</body>
-</html>
diff --git a/layout/reftests/webcomponents/adjacent-insertion-points-2-ref.html b/layout/reftests/webcomponents/adjacent-insertion-points-2-ref.html
deleted file mode 100644
index 2c1f4e341..000000000
--- a/layout/reftests/webcomponents/adjacent-insertion-points-2-ref.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body>
-<div><span>Hello</span><span>World</span></div>
-</body>
-</html>
diff --git a/layout/reftests/webcomponents/adjacent-insertion-points-2.html b/layout/reftests/webcomponents/adjacent-insertion-points-2.html
deleted file mode 100644
index f90cb206b..000000000
--- a/layout/reftests/webcomponents/adjacent-insertion-points-2.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <script>
- function tweak() {
- var oldShadowRoot = document.getElementById('outer').createShadowRoot();
- oldShadowRoot.innerHTML = 'Hello';
-
- var youngShadowRoot = document.getElementById('outer').createShadowRoot();
- youngShadowRoot.innerHTML = '<shadow></shadow><content></content>World';
- }
- </script>
-</head>
-<body onload="tweak()">
-<div id="outer"></div>
-</body>
-</html>
diff --git a/layout/reftests/webcomponents/basic-insertion-point-1-ref.html b/layout/reftests/webcomponents/basic-insertion-point-1-ref.html
deleted file mode 100644
index 16f6afb28..000000000
--- a/layout/reftests/webcomponents/basic-insertion-point-1-ref.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body>
-<div>
- <div style="border: 10px solid green">Hello</div>
-</div>
-</body>
-</html>
diff --git a/layout/reftests/webcomponents/basic-insertion-point-1.html b/layout/reftests/webcomponents/basic-insertion-point-1.html
deleted file mode 100644
index 727175ef3..000000000
--- a/layout/reftests/webcomponents/basic-insertion-point-1.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <script>
- function tweak() {
- // div with style "border: 10px solid green"
- var shadowDiv = document.createElement("div");
- shadowDiv.style.border = "10px solid green";
-
- var insertionPoint = document.createElement("content");
- shadowDiv.appendChild(insertionPoint);
-
- var shadowRoot = document.getElementById('outer').createShadowRoot();
- shadowRoot.appendChild(shadowDiv);
- }
- </script>
-</head>
-<body onload="tweak()">
-<div id="outer">Hello</div>
-</body>
-</html>
diff --git a/layout/reftests/webcomponents/basic-insertion-point-2-ref.html b/layout/reftests/webcomponents/basic-insertion-point-2-ref.html
deleted file mode 100644
index 5e9213775..000000000
--- a/layout/reftests/webcomponents/basic-insertion-point-2-ref.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body>
-<div>
- <div style="border: 10px solid green">
- <span style="background-color: purple">Hello</span>
- <span style="background-color: orange">World</span>
- </div>
-</div>
-</body>
-</html>
diff --git a/layout/reftests/webcomponents/basic-insertion-point-2.html b/layout/reftests/webcomponents/basic-insertion-point-2.html
deleted file mode 100644
index 595edb471..000000000
--- a/layout/reftests/webcomponents/basic-insertion-point-2.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <script>
- function tweak() {
- // div with style "border: 10px solid green"
- var shadowDiv = document.createElement("div");
- shadowDiv.style.border = "10px solid green";
-
- var insertionPoint = document.createElement("content");
- shadowDiv.appendChild(insertionPoint);
-
- var shadowRoot = document.getElementById('outer').createShadowRoot();
- shadowRoot.appendChild(shadowDiv);
- }
- </script>
-</head>
-<body onload="tweak()">
-<div id="outer">
- <span style="background-color: purple">Hello</span>
- <span style="background-color: orange">World</span>
-</div>
-</body>
-</html>
diff --git a/layout/reftests/webcomponents/basic-shadow-1.html b/layout/reftests/webcomponents/basic-shadow-1.html
index 944a594d2..8949dfc6d 100644
--- a/layout/reftests/webcomponents/basic-shadow-1.html
+++ b/layout/reftests/webcomponents/basic-shadow-1.html
@@ -9,7 +9,7 @@
shadowDiv.style.height = "100px";
shadowDiv.style.backgroundColor = "green";
- var shadowRoot = document.getElementById('outer').createShadowRoot();
+ var shadowRoot = document.getElementById('outer').attachShadow({mode: 'open'});
shadowRoot.appendChild(shadowDiv);
}
</script>
diff --git a/layout/reftests/webcomponents/basic-shadow-2.html b/layout/reftests/webcomponents/basic-shadow-2.html
index 587c47221..8e066997d 100644
--- a/layout/reftests/webcomponents/basic-shadow-2.html
+++ b/layout/reftests/webcomponents/basic-shadow-2.html
@@ -6,7 +6,7 @@
var shadowDiv = document.createElement("div");
shadowDiv.style.border = "10px solid green";
- var shadowRoot = document.getElementById('outer').createShadowRoot();
+ var shadowRoot = document.getElementById('outer').attachShadow({mode: 'open'});
shadowRoot.appendChild(shadowDiv);
var orangeDiv = document.createElement("div");
diff --git a/layout/reftests/webcomponents/basic-shadow-3.html b/layout/reftests/webcomponents/basic-shadow-3.html
index 2ae53b5a9..3226c4baa 100644
--- a/layout/reftests/webcomponents/basic-shadow-3.html
+++ b/layout/reftests/webcomponents/basic-shadow-3.html
@@ -6,7 +6,7 @@
var shadowDiv = document.createElement("div");
shadowDiv.style.border = "10px solid green";
- var shadowRoot = document.getElementById('outer').createShadowRoot();
+ var shadowRoot = document.getElementById('outer').attachShadow({mode: 'open'});
shadowRoot.appendChild(shadowDiv);
var orangeDiv = document.createElement("div");
diff --git a/layout/reftests/webcomponents/basic-shadow-4.html b/layout/reftests/webcomponents/basic-shadow-4.html
index 70f91773e..39dc51a9e 100644
--- a/layout/reftests/webcomponents/basic-shadow-4.html
+++ b/layout/reftests/webcomponents/basic-shadow-4.html
@@ -6,7 +6,7 @@
var shadowDiv = document.createElement("div");
shadowDiv.style.border = "10px solid green";
- var shadowRoot = document.getElementById('outer').createShadowRoot();
+ var shadowRoot = document.getElementById('outer').attachShadow({mode: 'open'});
shadowRoot.appendChild(shadowDiv);
var orangeDiv = document.createElement("div");
diff --git a/layout/reftests/webcomponents/basic-shadow-element-1-ref.html b/layout/reftests/webcomponents/basic-shadow-element-1-ref.html
deleted file mode 100644
index a47b9362a..000000000
--- a/layout/reftests/webcomponents/basic-shadow-element-1-ref.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-</head>
-<body>
-<div>
- <div style="width:100px; height:100px; background-color:green"></div><div style="width:100px; height:100px; background-color:orange">Hello World</div>
-</div>
-</body>
-</html>
diff --git a/layout/reftests/webcomponents/basic-shadow-element-1.html b/layout/reftests/webcomponents/basic-shadow-element-1.html
deleted file mode 100644
index e51bd8b72..000000000
--- a/layout/reftests/webcomponents/basic-shadow-element-1.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <script>
- function tweak() {
- var olderShadow = document.getElementById('outer').createShadowRoot();
- olderShadow.innerHTML = '<div style="width:100px; height:100px; background-color: orange"><content></content></div>';
-
- var youngerShadow = document.getElementById('outer').createShadowRoot();
- youngerShadow.innerHTML = '<div style="width:100px; height:100px; background-color: green"></div><shadow>Hello World</shadow>';
- }
- </script>
-</head>
-<body onload="tweak()">
-<div id="outer">
- <div style="width:300px; height:100px; background-color:red;"></div>
-</div>
-</body>
-</html>
diff --git a/layout/reftests/webcomponents/basic-slot-1-ref.html b/layout/reftests/webcomponents/basic-slot-1-ref.html
new file mode 100644
index 000000000..4f7418498
--- /dev/null
+++ b/layout/reftests/webcomponents/basic-slot-1-ref.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+ body { color: green; }
+ </style>
+ </head>
+ <body>
+ This text should be green
+ </body>
+</html>
diff --git a/layout/reftests/webcomponents/basic-slot-1.html b/layout/reftests/webcomponents/basic-slot-1.html
new file mode 100644
index 000000000..b31f4c1c3
--- /dev/null
+++ b/layout/reftests/webcomponents/basic-slot-1.html
@@ -0,0 +1,6 @@
+<!DOCTYPE HTML>
+<html>
+ <body>
+ <slot style="color: green">This text should be green</slot>
+ </body>
+</html>
diff --git a/layout/reftests/webcomponents/basic-slot-2-ref.html b/layout/reftests/webcomponents/basic-slot-2-ref.html
new file mode 100644
index 000000000..d4d1b8c06
--- /dev/null
+++ b/layout/reftests/webcomponents/basic-slot-2-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <style>
+ div {
+ width: 100px;
+ height: 100px;
+ background: green;
+ }
+ </style>
+</head>
+<body>
+ <p>There should be a green box below.</p>
+ <div></div>
+</body>
+</html>
diff --git a/layout/reftests/webcomponents/basic-slot-2.html b/layout/reftests/webcomponents/basic-slot-2.html
new file mode 100644
index 000000000..3754ace20
--- /dev/null
+++ b/layout/reftests/webcomponents/basic-slot-2.html
@@ -0,0 +1,7 @@
+<!DOCTYPE HTML>
+<html>
+ <body>
+ <p>There should be a green box below.</p>
+ <slot style="display: block; width: 100px; height: 100px; background: green;"></slot>
+ </body>
+</html>
diff --git a/layout/reftests/webcomponents/basic-slot-3-ref.html b/layout/reftests/webcomponents/basic-slot-3-ref.html
new file mode 100644
index 000000000..54be54848
--- /dev/null
+++ b/layout/reftests/webcomponents/basic-slot-3-ref.html
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<div>
+ <div style="color: green">This text should be green</div>
+</div>
+</body>
+</html>
diff --git a/layout/reftests/webcomponents/basic-slot-3.html b/layout/reftests/webcomponents/basic-slot-3.html
new file mode 100644
index 000000000..c00483fe2
--- /dev/null
+++ b/layout/reftests/webcomponents/basic-slot-3.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script>
+ function tweak() {
+ var slot = document.createElement("slot");
+ slot.style.color = "green";
+
+ var shadowRoot =
+ document.getElementById('outer').attachShadow({mode: 'open'});
+ shadowRoot.appendChild(slot);
+ }
+ </script>
+</head>
+<body onload="tweak()">
+<div id="outer">This text should be green</div>
+</body>
+</html>
diff --git a/layout/reftests/webcomponents/basic-slot-4.html b/layout/reftests/webcomponents/basic-slot-4.html
new file mode 100644
index 000000000..496a92651
--- /dev/null
+++ b/layout/reftests/webcomponents/basic-slot-4.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script>
+ function tweak() {
+ var slot = document.createElement("slot");
+ // The border shouldn't be visible, due to display: contents.
+ slot.style.border = "1px solid red";
+ slot.style.color = "green";
+
+ var shadowRoot =
+ document.getElementById('outer').attachShadow({mode: 'open'});
+ shadowRoot.appendChild(slot);
+ }
+ </script>
+</head>
+<body onload="tweak()">
+<div id="outer">This text should be green</div>
+</body>
+</html>
diff --git a/layout/reftests/webcomponents/cross-tree-selection-1.html b/layout/reftests/webcomponents/cross-tree-selection-1.html
index 1e4f02747..01e7317f2 100644
--- a/layout/reftests/webcomponents/cross-tree-selection-1.html
+++ b/layout/reftests/webcomponents/cross-tree-selection-1.html
@@ -3,6 +3,11 @@
<head>
<script>
function tweak() {
+ if (!document.body.createShadowRoot) {
+ document.documentElement.className = "";
+ return;
+ }
+
var host = document.getElementById("host");
var shadow = host.createShadowRoot();
diff --git a/layout/reftests/webcomponents/dynamic-insertion-point-distribution-1.html b/layout/reftests/webcomponents/dynamic-insertion-point-distribution-1.html
index c57f72b37..8919a9c6a 100644
--- a/layout/reftests/webcomponents/dynamic-insertion-point-distribution-1.html
+++ b/layout/reftests/webcomponents/dynamic-insertion-point-distribution-1.html
@@ -5,9 +5,13 @@
<body>
<div id="host"></div>
<script>
- var host = document.getElementById("host");
- var root = host.createShadowRoot();
- root.innerHTML = 'a <content></content> c';
+ var host, root;
+
+ function run() {
+ host = document.getElementById("host");
+ root = host.createShadowRoot();
+ root.innerHTML = 'a <content></content> c';
+ }
function tweak() {
var span = document.createElement("span");
@@ -19,7 +23,12 @@
document.documentElement.removeAttribute("class");
}
- window.addEventListener("MozReftestInvalidate", tweak, false);
+ if (document.body.createShadowRoot) {
+ run();
+ window.addEventListener("MozReftestInvalidate", tweak, false);
+ } else {
+ document.documentElement.className = "";
+ }
</script>
</body>
</html>
diff --git a/layout/reftests/webcomponents/dynamic-insertion-point-distribution-2.html b/layout/reftests/webcomponents/dynamic-insertion-point-distribution-2.html
index 29a850e90..c58b9cfbd 100644
--- a/layout/reftests/webcomponents/dynamic-insertion-point-distribution-2.html
+++ b/layout/reftests/webcomponents/dynamic-insertion-point-distribution-2.html
@@ -5,9 +5,13 @@
<body>
<div id="host"></div>
<script>
- var host = document.getElementById("host");
- var root = host.createShadowRoot();
- root.innerHTML = "<span>a</span>";
+ var host, root;
+
+ function run() {
+ host = document.getElementById("host");
+ root = host.createShadowRoot();
+ root.innerHTML = "<span>a</span>";
+ }
function tweak() {
var span = document.createElement("span");
@@ -20,7 +24,12 @@
document.documentElement.removeAttribute("class");
}
- window.addEventListener("MozReftestInvalidate", tweak, false);
+ if (document.body.createShadowRoot) {
+ run();
+ window.addEventListener("MozReftestInvalidate", tweak);
+ } else {
+ document.documentElement.className = "";
+ }
</script>
</body>
</html>
diff --git a/layout/reftests/webcomponents/dynamic-shadow-element-1-ref.html b/layout/reftests/webcomponents/dynamic-shadow-element-1-ref.html
deleted file mode 100644
index a3b5150f6..000000000
--- a/layout/reftests/webcomponents/dynamic-shadow-element-1-ref.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-</head>
-<body>
-<div>
- <div style="background-color: green"><span>Hello</span><span> </span><span>World</span></div>
-</div>
-</body>
-</html>
diff --git a/layout/reftests/webcomponents/dynamic-shadow-element-1.html b/layout/reftests/webcomponents/dynamic-shadow-element-1.html
deleted file mode 100644
index 0142164a1..000000000
--- a/layout/reftests/webcomponents/dynamic-shadow-element-1.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <script>
- function tweak() {
- var oldestShadow = document.getElementById('outer').createShadowRoot();
- oldestShadow.innerHTML = 'Hello';
-
- var olderShadow = document.getElementById('outer').createShadowRoot();
-
- var youngerShadow = document.getElementById('outer').createShadowRoot();
- youngerShadow.innerHTML = '<div style="background-color:green"><shadow></shadow></div>';
-
- olderShadow.innerHTML = '<shadow></shadow> World';
- }
- </script>
-</head>
-<body onload="tweak()">
-<div id="outer">
- <div style="width:300px; height:100px; background-color:red;"></div>
-</div>
-</body>
-</html>
diff --git a/layout/reftests/webcomponents/fallback-content-1.html b/layout/reftests/webcomponents/fallback-content-1.html
index ac3b5d02a..0bcd2abbd 100644
--- a/layout/reftests/webcomponents/fallback-content-1.html
+++ b/layout/reftests/webcomponents/fallback-content-1.html
@@ -8,13 +8,13 @@
shadowDiv.style.border = "10px solid green";
// Insertion point will match nothing and use fallback content.
- var insertionPoint = document.createElement("content");
- shadowDiv.appendChild(insertionPoint);
+ var slot = document.createElement("slot");
+ shadowDiv.appendChild(slot);
// Append three nodes as children to use as fallback content.
- insertionPoint.innerHTML = '<span style="background-color: orange">Hello</span> <span style="background-color: green">World</span>';
+ slot.innerHTML = '<span style="background-color: orange">Hello</span> <span style="background-color: green">World</span>';
- var shadowRoot = document.getElementById('outer').createShadowRoot();
+ var shadowRoot = document.getElementById('outer').attachShadow({mode: 'open'});
shadowRoot.appendChild(shadowDiv);
}
</script>
diff --git a/layout/reftests/webcomponents/input-transition-1.html b/layout/reftests/webcomponents/input-transition-1.html
index ede0fa40b..a4be5271b 100644
--- a/layout/reftests/webcomponents/input-transition-1.html
+++ b/layout/reftests/webcomponents/input-transition-1.html
@@ -5,19 +5,28 @@
<body>
<div id="host"></div>
<script>
- var host = document.getElementById("host");
- var root = host.createShadowRoot();
- root.innerHTML = '<style>input ~ div { background: red; transition: background 100ms; } input:checked ~ div { background: green; }</style><input id="one" type="checkbox"><div style="height: 50px; width: 50px;"></div>';
+ var host, root;
+
+ function run() {
+ host = document.getElementById("host");
+ root = host.createShadowRoot();
+ root.innerHTML = '<style>input ~ div { background: red; transition: background 100ms; } input:checked ~ div { background: green; }</style><input id="one" type="checkbox"><div style="height: 50px; width: 50px;"></div>';
+ }
function tweak() {
- var el = root.getElementById("one");
- el.checked = true;
- el.nextSibling.addEventListener("transitionend", function() {
- document.documentElement.removeAttribute("class");
- }, false);
+ var el = root.getElementById("one");
+ el.checked = true;
+ el.nextSibling.addEventListener("transitionend", function() {
+ setTimeout(()=>{document.documentElement.removeAttribute("class")}, 1000); // wait for the checkbox SVG image to load on Android
+ });
}
- window.addEventListener("MozReftestInvalidate", tweak, false);
+ if (document.body.createShadowRoot) {
+ run();
+ window.addEventListener("MozReftestInvalidate", tweak);
+ } else {
+ document.documentElement.className = "";
+ }
</script>
</body>
</html>
diff --git a/layout/reftests/webcomponents/nested-insertion-point-1.html b/layout/reftests/webcomponents/nested-insertion-point-1.html
index 66892029a..3d0d92f0d 100644
--- a/layout/reftests/webcomponents/nested-insertion-point-1.html
+++ b/layout/reftests/webcomponents/nested-insertion-point-1.html
@@ -7,19 +7,20 @@
var outerShadow = document.createElement("div");
outerShadow.style.border = "10px solid green";
- var outerInsertionPoint = document.createElement("content");
+ var outerInsertionPoint = document.createElement("slot");
outerShadow.appendChild(outerInsertionPoint);
// div with style "border: 10px solid orange"
var innerShadow = document.createElement("div");
innerShadow.style.border = "10px solid orange";
- var innerInsertionPoint = document.createElement("content");
- innerShadow.appendChild(innerInsertionPoint);
+ var slot = document.createElement("slot");
+ innerShadow.appendChild(slot);
- outerShadow.createShadowRoot().appendChild(innerShadow);
+ outerShadow.attachShadow({mode: 'open'}).appendChild(innerShadow);
- var shadowRoot = document.getElementById('outer').createShadowRoot();
+ var shadowRoot =
+ document.getElementById('outer').attachShadow({mode: 'open'});
shadowRoot.appendChild(outerShadow);
}
</script>
diff --git a/layout/reftests/webcomponents/nested-shadow-element-1.html b/layout/reftests/webcomponents/nested-shadow-element-1.html
deleted file mode 100644
index cfaad3d49..000000000
--- a/layout/reftests/webcomponents/nested-shadow-element-1.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <script>
- function tweak() {
- var olderShadow = document.getElementById('outer').createShadowRoot();
- olderShadow.innerHTML = '<content></content><span>World</span>';
-
- var youngerShadow = document.getElementById('outer').createShadowRoot();
- youngerShadow.innerHTML = '<div id="shadowparent"><shadow id="youngshadow"><span>Hello</span></shadow></div>';
-
- var shadowParent = youngerShadow.getElementById("shadowparent");
- var nestedShadow = shadowParent.createShadowRoot();
- nestedShadow.innerHTML = '<div style="background-color: green"><content></content></div>';
-
- // Dynamically append a span to the shadow element in the younger ShadowRoot to make sure
- // it is projected into the nested shadow.
- var appendedSpan = document.createElement("span");
- appendedSpan.textContent = ' ';
- youngerShadow.getElementById("youngshadow").appendChild(appendedSpan);
- }
- </script>
-</head>
-<body onload="tweak()">
-<div id="outer">
- <div style="width:300px; height:100px; background-color:red;"></div>
-</div>
-</body>
-</html>
diff --git a/layout/reftests/webcomponents/reframe-shadow-child-1.html b/layout/reftests/webcomponents/reframe-shadow-child-1.html
new file mode 100644
index 000000000..d953beb6d
--- /dev/null
+++ b/layout/reftests/webcomponents/reframe-shadow-child-1.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<template id="tmpl">
+ <div style="display: table">
+ Some text
+ <span style="display: table-cell">something</span>
+ More text
+ </div>
+</template>
+<div id="host"></div>
+<script>
+ let shadowRoot = document.getElementById("host").attachShadow({mode: 'open'});
+ let tmpl = document.getElementById("tmpl");
+ shadowRoot.appendChild(document.importNode(tmpl.content, true));
+ document.body.offsetTop;
+ shadowRoot.firstElementChild.querySelector("span").remove();
+</script>
diff --git a/layout/reftests/webcomponents/reframe-shadow-child-2.html b/layout/reftests/webcomponents/reframe-shadow-child-2.html
new file mode 100644
index 000000000..0ebbe7433
--- /dev/null
+++ b/layout/reftests/webcomponents/reframe-shadow-child-2.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<template id="tmpl">
+ <div style="display: block">
+ Some text
+ More text
+ </div>
+</template>
+<div id="host"></div>
+<script>
+ let shadowRoot = document.getElementById("host").attachShadow({mode: 'open'});
+ let tmpl = document.getElementById("tmpl");
+ shadowRoot.appendChild(document.importNode(tmpl.content, true));
+ document.body.offsetTop;
+ shadowRoot.firstElementChild.style.display = "table";
+</script>
diff --git a/layout/reftests/webcomponents/reftest.list b/layout/reftests/webcomponents/reftest.list
index beba21b18..6afbc2720 100644
--- a/layout/reftests/webcomponents/reftest.list
+++ b/layout/reftests/webcomponents/reftest.list
@@ -3,17 +3,17 @@ pref(dom.webcomponents.enabled,true) == basic-shadow-1.html basic-shadow-1-ref.h
pref(dom.webcomponents.enabled,true) == basic-shadow-2.html basic-shadow-2-ref.html
pref(dom.webcomponents.enabled,true) == basic-shadow-3.html basic-shadow-3-ref.html
pref(dom.webcomponents.enabled,true) == basic-shadow-4.html basic-shadow-4-ref.html
-pref(dom.webcomponents.enabled,true) == basic-insertion-point-1.html basic-insertion-point-1-ref.html
-pref(dom.webcomponents.enabled,true) == basic-insertion-point-2.html basic-insertion-point-2-ref.html
-pref(dom.webcomponents.enabled,true) == adjacent-insertion-points-1.html adjacent-insertion-points-1-ref.html
-pref(dom.webcomponents.enabled,true) == adjacent-insertion-points-2.html adjacent-insertion-points-2-ref.html
pref(dom.webcomponents.enabled,true) == fallback-content-1.html fallback-content-1-ref.html
pref(dom.webcomponents.enabled,true) == remove-insertion-point-1.html remove-insertion-point-1-ref.html
-pref(dom.webcomponents.enabled,true) == nested-insertion-point-1.html nested-insertion-point-1-ref.html
-pref(dom.webcomponents.enabled,true) == basic-shadow-element-1.html basic-shadow-element-1-ref.html
-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
+#bug 1421542 pref(dom.webcomponents.enabled,true) == nested-insertion-point-1.html nested-insertion-point-1-ref.html
+#bug 1421542 pref(dom.webcomponents.enabled,true) == update-dist-node-descendants-1.html update-dist-node-descendants-1-ref.html
pref(dom.webcomponents.enabled,true) == input-transition-1.html input-transition-1-ref.html
-pref(dom.webcomponents.enabled,true) == dynamic-insertion-point-distribution-1.html dynamic-insertion-point-distribution-1-ref.html
+#bug 1421542 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
pref(dom.webcomponents.enabled,true) == remove-append-shadow-host-1.html remove-append-shadow-host-1-ref.html
+pref(dom.webcomponents.enabled,true) == basic-slot-1.html basic-slot-1-ref.html
+pref(dom.webcomponents.enabled,true) == basic-slot-2.html basic-slot-2-ref.html
+pref(dom.webcomponents.enabled,true) == basic-slot-3.html basic-slot-3-ref.html
+pref(dom.webcomponents.enabled,true) == basic-slot-4.html basic-slot-3-ref.html
+pref(dom.webcomponents.enabled,true) == basic-slot-5.html basic-slot-5-ref.html
+pref(dom.webcomponents.enabled,true) == basic-slot-6.html basic-slot-6-ref.html
diff --git a/layout/reftests/webcomponents/remove-append-shadow-host-1.html b/layout/reftests/webcomponents/remove-append-shadow-host-1.html
index 85161565e..1a752eba6 100644
--- a/layout/reftests/webcomponents/remove-append-shadow-host-1.html
+++ b/layout/reftests/webcomponents/remove-append-shadow-host-1.html
@@ -6,7 +6,7 @@
<div id="container"><div id="host"></div></div>
<script>
var host = document.getElementById("host");
- var root = host.createShadowRoot();
+ var root = host.attachShadow({mode: 'open'});
root.innerHTML = 'inside shadow DOM';
var container = document.getElementById("container");
diff --git a/layout/reftests/webcomponents/remove-insertion-point-1.html b/layout/reftests/webcomponents/remove-insertion-point-1.html
index 195673ca8..1b7588daf 100644
--- a/layout/reftests/webcomponents/remove-insertion-point-1.html
+++ b/layout/reftests/webcomponents/remove-insertion-point-1.html
@@ -8,15 +8,15 @@
shadowDiv.style.border = "10px solid green";
// Insertion point will match nothing and use fallback content.
- var insertionPoint = document.createElement("content");
- shadowDiv.appendChild(insertionPoint);
+ var slot = document.createElement("slot");
+ shadowDiv.appendChild(slot);
- var shadowRoot = document.getElementById('outer').createShadowRoot();
+ var shadowRoot = document.getElementById('outer').attachShadow({mode: 'open'});
shadowRoot.appendChild(shadowDiv);
// Remove the insertion point from the ShadowRoot, "Hello" should no
// longer be rendered.
- shadowDiv.removeChild(insertionPoint);
+ shadowDiv.removeChild(slot);
}
</script>
</head>
diff --git a/layout/reftests/webcomponents/style-sharing-across-shadow.html b/layout/reftests/webcomponents/style-sharing-across-shadow.html
new file mode 100644
index 000000000..b41cf7479
--- /dev/null
+++ b/layout/reftests/webcomponents/style-sharing-across-shadow.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<style>
+ div { display: contents }
+</style>
+<div></div>
+<div></div>
+<script>
+ let divs = document.querySelectorAll('div');
+ divs[0].attachShadow({mode: 'open'}).innerHTML = `
+ <style>
+ * { color: green; }
+ </style>
+ <span>Should be green</span>
+ `;
+ divs[1].attachShadow({mode: 'open'}).innerHTML = `
+ <style>
+ * { color: initial; }
+ [foo] { }
+ </style>
+ <span>Should not be green</span>
+ `;
+</script>
diff --git a/layout/reftests/webcomponents/style-sharing.html b/layout/reftests/webcomponents/style-sharing.html
new file mode 100644
index 000000000..0a1e3c95c
--- /dev/null
+++ b/layout/reftests/webcomponents/style-sharing.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<div id="host"></div>
+<script>
+ let root = host.attachShadow({mode: 'open'});
+ root.innerHTML = `
+ <style>
+ #test {
+ color: green;
+ }
+ </style>
+ <span id="test">Should be green</span>
+ <span id="test2">Should not be green</span>
+ `;
+</script>
diff --git a/layout/reftests/webcomponents/update-dist-node-descendants-1.html b/layout/reftests/webcomponents/update-dist-node-descendants-1.html
index e2dd4ebb7..3ba96594b 100644
--- a/layout/reftests/webcomponents/update-dist-node-descendants-1.html
+++ b/layout/reftests/webcomponents/update-dist-node-descendants-1.html
@@ -5,17 +5,25 @@
<body>
<div id="outer"><span id="distnode">text</span></div>
<script>
-var shadowRoot = document.getElementById('outer').createShadowRoot();
-shadowRoot.innerHTML = '<div><content></content></div>';
-function tweak() {
- var distNode = document.getElementById("distnode");
- distNode.textContent = "Hello World";
-
- document.documentElement.removeAttribute("class");
+function run() {
+ var shadowRoot = document.getElementById('outer').createShadowRoot();
+ shadowRoot.innerHTML = '<div><content></content></div>';
}
-window.addEventListener("MozReftestInvalidate", tweak);
+ function tweak() {
+ var distNode = document.getElementById("distnode");
+ distNode.textContent = "Hello World";
+
+ document.documentElement.removeAttribute("class");
+ }
+
+if (document.body.createShadowRoot) {
+ run();
+ window.addEventListener("MozReftestInvalidate", tweak);
+} else {
+ document.documentElement.className = "";
+}
</script>
</body>
</html>
diff --git a/layout/style/CSSStyleSheet.cpp b/layout/style/CSSStyleSheet.cpp
index 71ca6e3f2..43d47100d 100644
--- a/layout/style/CSSStyleSheet.cpp
+++ b/layout/style/CSSStyleSheet.cpp
@@ -694,7 +694,7 @@ nsMediaList::GetMediaText(nsAString& aMediaText)
// nsCOMPtr<nsIDocument>
#define BEGIN_MEDIA_CHANGE(sheet, doc) \
if (sheet) { \
- doc = sheet->GetOwningDocument(); \
+ doc = sheet->GetAssociatedDocument(); \
} \
mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, true); \
if (sheet) { \
@@ -864,7 +864,8 @@ struct ChildSheetListBuilder {
void SetParentLinks(CSSStyleSheet* aSheet) {
aSheet->mParent = parent;
- aSheet->SetOwningDocument(parent->mDocument);
+ aSheet->SetAssociatedDocument(parent->mDocument,
+ parent->mDocumentAssociationMode);
}
static void ReparentChildList(CSSStyleSheet* aPrimarySheet,
@@ -872,7 +873,8 @@ struct ChildSheetListBuilder {
{
for (CSSStyleSheet *child = aFirstChild; child; child = child->mNext) {
child->mParent = aPrimarySheet;
- child->SetOwningDocument(aPrimarySheet->mDocument);
+ child->SetAssociatedDocument(aPrimarySheet->mDocument,
+ aPrimarySheet->mDocumentAssociationMode);
}
}
};
@@ -1359,16 +1361,22 @@ CSSStyleSheet::GetParentSheet() const
}
void
-CSSStyleSheet::SetOwningDocument(nsIDocument* aDocument)
-{ // not ref counted
+CSSStyleSheet::SetAssociatedDocument(nsIDocument* aDocument,
+ DocumentAssociationMode aAssociationMode)
+{
+ MOZ_ASSERT_IF(!aDocument, aAssociationMode == NotOwnedByDocument);
+
+ // not ref counted
mDocument = aDocument;
+ mDocumentAssociationMode = aAssociationMode;
+
// Now set the same document on all our child sheets....
// XXXbz this is a little bogus; see the XXX comment where we
// declare mFirstChild.
for (CSSStyleSheet* child = mInner->mFirstChild;
child; child = child->mNext) {
if (child->mParent == this) {
- child->SetOwningDocument(aDocument);
+ child->SetAssociatedDocument(aDocument, aAssociationMode);
}
}
}
diff --git a/layout/style/CSSStyleSheet.h b/layout/style/CSSStyleSheet.h
index 74e12291e..89189d781 100644
--- a/layout/style/CSSStyleSheet.h
+++ b/layout/style/CSSStyleSheet.h
@@ -129,7 +129,8 @@ public:
// style sheet owner info
CSSStyleSheet* GetParentSheet() const; // may be null
- void SetOwningDocument(nsIDocument* aDocument);
+ void SetAssociatedDocument(nsIDocument* aDocument,
+ DocumentAssociationMode aAssociationMode);
// Find the ID of the owner inner window.
uint64_t FindOwningWindowInnerID() const;
diff --git a/layout/style/DocumentStyleRootIterator.cpp b/layout/style/DocumentStyleRootIterator.cpp
new file mode 100644
index 000000000..af95c5c4f
--- /dev/null
+++ b/layout/style/DocumentStyleRootIterator.cpp
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DocumentStyleRootIterator.h"
+
+#include "nsContentUtils.h"
+
+namespace mozilla {
+
+DocumentStyleRootIterator::DocumentStyleRootIterator(nsIDocument* aDocument)
+ : mPosition(0)
+{
+ MOZ_COUNT_CTOR(DocumentStyleRootIterator);
+ if (Element* root = aDocument->GetRootElement()) {
+ mStyleRoots.AppendElement(root);
+ }
+ nsContentUtils::AppendDocumentLevelNativeAnonymousContentTo(
+ aDocument, mStyleRoots);
+}
+
+Element*
+DocumentStyleRootIterator::GetNextStyleRoot()
+{
+ for (;;) {
+ if (mPosition >= mStyleRoots.Length()) {
+ return nullptr;
+ }
+
+ nsIContent* next = mStyleRoots[mPosition];
+ ++mPosition;
+
+ if (next->IsElement()) {
+ return next->AsElement();
+ }
+ }
+}
+
+} // namespace mozilla
diff --git a/layout/style/DocumentStyleRootIterator.h b/layout/style/DocumentStyleRootIterator.h
new file mode 100644
index 000000000..7dcdc7fa1
--- /dev/null
+++ b/layout/style/DocumentStyleRootIterator.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef DocumentStyleRootIterator_h
+#define DocumentStyleRootIterator_h
+
+#include "nsTArray.h"
+
+class nsIContent;
+class nsIDocument;
+
+namespace mozilla {
+
+/**
+ * DocumentStyleRootIterator traverses the roots of the document from the
+ * perspective of the Servo-backed style system. This will first traverse
+ * the document root, followed by any document level native anonymous content.
+ */
+class DocumentStyleRootIterator
+{
+public:
+ explicit DocumentStyleRootIterator(nsIDocument* aDocument);
+ ~DocumentStyleRootIterator() { MOZ_COUNT_DTOR(DocumentStyleRootIterator); }
+
+ Element* GetNextStyleRoot();
+
+private:
+ AutoTArray<nsIContent*, 8> mStyleRoots;
+ uint32_t mPosition;
+};
+
+} // namespace mozilla
+
+#endif // DocumentStyleRootIterator_h
diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp
index 0ce337e29..9894ce8f4 100644
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -1334,7 +1334,7 @@ Loader::InsertSheetInDoc(StyleSheet* aSheet,
// XXX Need to cancel pending sheet loads for this element, if any
- int32_t sheetCount = aDocument->GetNumberOfStyleSheets();
+ int32_t sheetCount = aDocument->SheetCount();
/*
* Start the walk at the _end_ of the list, since in the typical
@@ -1346,7 +1346,7 @@ Loader::InsertSheetInDoc(StyleSheet* aSheet,
*/
int32_t insertionPoint;
for (insertionPoint = sheetCount - 1; insertionPoint >= 0; --insertionPoint) {
- StyleSheet* curSheet = aDocument->GetStyleSheetAt(insertionPoint);
+ StyleSheet* curSheet = aDocument->SheetAt(insertionPoint);
NS_ASSERTION(curSheet, "There must be a sheet here!");
nsCOMPtr<nsINode> sheetOwner = curSheet->GetOwnerNode();
if (sheetOwner && !aLinkingContent) {
@@ -2209,9 +2209,9 @@ Loader::LoadChildSheet(StyleSheet* aParentSheet,
nsCOMPtr<nsINode> owningNode;
- // check for an owning document: if none, don't bother walking up the parent
- // sheets
- if (aParentSheet->GetOwningDocument()) {
+ // check for an associated document: if none, don't bother walking up the
+ // parent sheets
+ if (aParentSheet->GetAssociatedDocument()) {
StyleSheet* topSheet = aParentSheet;
while (StyleSheet* parent = topSheet->GetParentSheet()) {
topSheet = parent;
diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp
index 519d17aa8..331e2322a 100644
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -339,7 +339,7 @@ ServoStyleSet::AddDocStyleSheet(ServoStyleSheet* aSheet,
mSheets[SheetType::Doc].RemoveElement(aSheet);
size_t index =
- aDocument->FindDocStyleSheetInsertionPoint(mSheets[SheetType::Doc], aSheet);
+ aDocument->FindDocStyleSheetInsertionPoint(mSheets[SheetType::Doc], *aSheet);
mSheets[SheetType::Doc].InsertElementAt(index, aSheet);
// Maintain a mirrored list of sheets on the servo side.
diff --git a/layout/style/ServoStyleSheet.cpp b/layout/style/ServoStyleSheet.cpp
index cfeae20d2..5f2a925b5 100644
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -30,19 +30,23 @@ ServoStyleSheet::HasRules() const
}
void
-ServoStyleSheet::SetOwningDocument(nsIDocument* aDocument)
+ServoStyleSheet::SetAssociatedDocument(nsIDocument* aDocument,
+ DocumentAssociationMode aAssociationMode)
{
+ MOZ_ASSERT_IF(!aDocument, aAssociationMode == NotOwnedByDocument);
+
// XXXheycam: Traverse to child ServoStyleSheets to set this, like
- // CSSStyleSheet::SetOwningDocument does.
+ // CSSStyleSheet::SetAssociatedDocument does.
mDocument = aDocument;
+ mDocumentAssociationMode = aAssociationMode;
}
ServoStyleSheet*
ServoStyleSheet::GetParentSheet() const
{
// XXXheycam: When we implement support for child sheets, we'll have
- // to fix SetOwningDocument to propagate the owning document down
+ // to fix SetAssociatedDocument to propagate the associated document down
// to the children.
MOZ_CRASH("stylo: not implemented");
}
diff --git a/layout/style/ServoStyleSheet.h b/layout/style/ServoStyleSheet.h
index 079f196eb..c54c15e7d 100644
--- a/layout/style/ServoStyleSheet.h
+++ b/layout/style/ServoStyleSheet.h
@@ -29,7 +29,8 @@ public:
bool HasRules() const;
- void SetOwningDocument(nsIDocument* aDocument);
+ void SetAssociatedDocument(nsIDocument* aDocument,
+ DocumentAssociationMode aAssociationMode);
ServoStyleSheet* GetParentSheet() const;
void AppendStyleSheet(ServoStyleSheet* aSheet);
diff --git a/layout/style/StyleRule.cpp b/layout/style/StyleRule.cpp
index 598cb7c74..aca97a505 100644
--- a/layout/style/StyleRule.cpp
+++ b/layout/style/StyleRule.cpp
@@ -1078,6 +1078,16 @@ public:
return mRule ? mRule->GetDocument() : nullptr;
}
+ virtual DocGroup* GetDocGroup() const override
+ {
+ if (!mRule) {
+ return nullptr;
+ }
+
+ nsIDocument* document = mRule->GetDocument();
+ return document ? document->GetDocGroup() : nullptr;
+ }
+
friend class css::DOMCSSStyleRule;
protected:
@@ -1209,13 +1219,13 @@ DOMCSSDeclarationImpl::SetCSSDeclaration(DeclarationBlock* aDecl)
NS_PRECONDITION(mRule,
"can only be called when |GetCSSDeclaration| returned a declaration");
- nsCOMPtr<nsIDocument> owningDoc;
+ nsCOMPtr<nsIDocument> doc;
RefPtr<CSSStyleSheet> sheet = mRule->GetStyleSheet();
if (sheet) {
- owningDoc = sheet->GetOwningDocument();
+ doc = sheet->GetAssociatedDocument();
}
- mozAutoDocUpdate updateBatch(owningDoc, UPDATE_STYLE, true);
+ mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, true);
mRule->SetDeclaration(aDecl->AsGecko());
@@ -1223,8 +1233,8 @@ DOMCSSDeclarationImpl::SetCSSDeclaration(DeclarationBlock* aDecl)
sheet->DidDirty();
}
- if (owningDoc) {
- owningDoc->StyleRuleChanged(sheet, mRule);
+ if (doc) {
+ doc->StyleRuleChanged(sheet, mRule);
}
return NS_OK;
}
diff --git a/layout/style/StyleSheet.cpp b/layout/style/StyleSheet.cpp
index f307f3918..f125cf97e 100644
--- a/layout/style/StyleSheet.cpp
+++ b/layout/style/StyleSheet.cpp
@@ -12,6 +12,8 @@
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/CSSStyleSheet.h"
+#include "mozAutoDocUpdate.h"
+#include "nsIMediaList.h"
#include "nsNullPrincipal.h"
namespace mozilla {
@@ -22,6 +24,7 @@ StyleSheet::StyleSheet(StyleBackendType aType, css::SheetParsingMode aParsingMod
, mParsingMode(aParsingMode)
, mType(aType)
, mDisabled(false)
+ , mDocumentAssociationMode(NotOwnedByDocument)
{
}
@@ -34,6 +37,9 @@ StyleSheet::StyleSheet(const StyleSheet& aCopy,
, mParsingMode(aCopy.mParsingMode)
, mType(aCopy.mType)
, mDisabled(aCopy.mDisabled)
+ // We only use this constructor during cloning. It's the cloner's
+ // responsibility to notify us if we end up being owned by a document.
+ , mDocumentAssociationMode(NotOwnedByDocument)
{
}
@@ -349,7 +355,7 @@ StyleSheet::AreRulesAvailable(nsIPrincipal& aSubjectPrincipal,
JSObject*
StyleSheet::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
- return CSSStyleSheetBinding::Wrap(aCx, this, aGivenProto);
+ return dom::CSSStyleSheetBinding::Wrap(aCx, this, aGivenProto);
}
} // namespace mozilla
diff --git a/layout/style/StyleSheet.h b/layout/style/StyleSheet.h
index 863f6d22f..7a1a71466 100644
--- a/layout/style/StyleSheet.h
+++ b/layout/style/StyleSheet.h
@@ -95,8 +95,22 @@ public:
inline bool HasRules() const;
// style sheet owner info
- nsIDocument* GetOwningDocument() const { return mDocument; }
- inline void SetOwningDocument(nsIDocument* aDocument);
+ enum DocumentAssociationMode {
+ // OwnedByDocument means mDocument owns us (possibly via a chain of other
+ // stylesheets).
+ OwnedByDocument,
+ // NotOwnedByDocument means we're owned by something that might have a
+ // different lifetime than mDocument.
+ NotOwnedByDocument
+ };
+ nsIDocument* GetAssociatedDocument() const { return mDocument; }
+ bool IsOwnedByDocument() const {
+ return mDocumentAssociationMode == OwnedByDocument;
+ }
+ // aDocument must not be null.
+ inline void SetAssociatedDocument(nsIDocument* aDocument,
+ DocumentAssociationMode aMode);
+ inline void ClearAssociatedDocument();
nsINode* GetOwnerNode() const { return mOwningNode; }
inline StyleSheet* GetParentSheet() const;
@@ -206,6 +220,11 @@ protected:
const StyleBackendType mType;
bool mDisabled;
+
+ // mDocumentAssociationMode determines whether mDocument directly owns us (in
+ // the sense that if it's known-live then we're known-live). Always
+ // NotOwnedByDocument when mDocument is null.
+ DocumentAssociationMode mDocumentAssociationMode;
};
} // namespace mozilla
diff --git a/layout/style/StyleSheetInlines.h b/layout/style/StyleSheetInlines.h
index d03a3741b..c0b8495f8 100644
--- a/layout/style/StyleSheetInlines.h
+++ b/layout/style/StyleSheetInlines.h
@@ -83,9 +83,17 @@ StyleSheet::HasRules() const
}
void
-StyleSheet::SetOwningDocument(nsIDocument* aDocument)
+StyleSheet::SetAssociatedDocument(nsIDocument* aDocument,
+ DocumentAssociationMode aAssociationMode)
{
- MOZ_STYLO_FORWARD(SetOwningDocument, (aDocument))
+ MOZ_ASSERT(aDocument);
+ MOZ_STYLO_FORWARD(SetAssociatedDocument, (aDocument, aAssociationMode))
+}
+
+void
+StyleSheet::ClearAssociatedDocument()
+{
+ MOZ_STYLO_FORWARD(SetAssociatedDocument, (nullptr, NotOwnedByDocument));
}
StyleSheet*
diff --git a/layout/style/crashtests/1017798-1.html b/layout/style/crashtests/1017798-1.html
index 097217d18..0460c8756 100644
--- a/layout/style/crashtests/1017798-1.html
+++ b/layout/style/crashtests/1017798-1.html
@@ -50,27 +50,27 @@ gaia_switch/examples/index.html from the Gaia repository.
window.GaiaSwitch = (function(win) {
// Extend from the HTMLElement prototype
- var proto = Object.create(HTMLElement.prototype);
+ class GaiaSwitch extends HTMLElement {
+ connectedCallback() {
+ var shadow = this.createShadowRoot();
+ this._template = template.content.cloneNode(true);
+ this._input = this._template.querySelector('input[type="checkbox"]');
+
+ var checked = this.getAttribute('checked');
+ if (checked !== null) {
+ this._input.checked = true;
+ }
- proto.createdCallback = function() {
- var shadow = this.createShadowRoot();
- this._template = template.content.cloneNode(true);
- this._input = this._template.querySelector('input[type="checkbox"]');
+ shadow.appendChild(this._template);
- var checked = this.getAttribute('checked');
- if (checked !== null) {
- this._input.checked = true;
+ ComponentUtils.style.call(this, '');
}
-
- shadow.appendChild(this._template);
-
- ComponentUtils.style.call(this, '');
};
/**
* Proxy the checked property to the input element.
*/
- Object.defineProperty( proto, 'checked', {
+ Object.defineProperty( GaiaSwitch.prototype, 'checked', {
get: function() {
return this._input.checked;
},
@@ -82,7 +82,7 @@ window.GaiaSwitch = (function(win) {
/**
* Proxy the name property to the input element.
*/
- Object.defineProperty( proto, 'name', {
+ Object.defineProperty( GaiaSwitch.prototype, 'name', {
get: function() {
return this.getAttribute('name');
},
diff --git a/layout/style/moz.build b/layout/style/moz.build
index 3dc2a19af..40b9fd659 100644
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -88,6 +88,7 @@ EXPORTS.mozilla += [
'CSSVariableValues.h',
'DeclarationBlock.h',
'DeclarationBlockInlines.h',
+ 'DocumentStyleRootIterator.h',
'HandleRefPtr.h',
'IncrementalClearCOMRuleArray.h',
'LayerAnimationInfo.h',
@@ -151,6 +152,7 @@ UNIFIED_SOURCES += [
'CSSVariableResolver.cpp',
'CSSVariableValues.cpp',
'Declaration.cpp',
+ 'DocumentStyleRootIterator.cpp',
'ErrorReporter.cpp',
'FontFace.cpp',
'FontFaceSet.cpp',
diff --git a/layout/style/nsAnimationManager.cpp b/layout/style/nsAnimationManager.cpp
index aa1b6fe78..04086a3ae 100644
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -367,7 +367,7 @@ UpdateOldAnimationPropertiesWithNew(
// Update the old from the new so we can keep the original object
// identity (and any expando properties attached to it).
if (aOld.GetEffect()) {
- AnimationEffectReadOnly* oldEffect = aOld.GetEffect();
+ dom::AnimationEffectReadOnly* oldEffect = aOld.GetEffect();
animationChanged = oldEffect->SpecifiedTiming() != aNewTiming;
oldEffect->SetSpecifiedTiming(aNewTiming);
diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h
index 701578338..12f43af5b 100644
--- a/layout/style/nsCSSPseudoClassList.h
+++ b/layout/style/nsCSSPseudoClassList.h
@@ -90,9 +90,6 @@ CSS_PSEUDO_CLASS(nthLastOfType, ":nth-last-of-type", 0, "")
// Match nodes that are HTML but not XHTML
CSS_PSEUDO_CLASS(mozIsHTML, ":-moz-is-html", 0, "")
-// Match all custom elements whose created callback has not yet been invoked
- CSS_STATE_PSEUDO_CLASS(unresolved, ":unresolved", 0, "", NS_EVENT_STATE_UNRESOLVED)
-
// Matches nodes that are in a native-anonymous subtree (i.e., nodes in
// a subtree of C++ anonymous content constructed by Gecko for its own
// purposes).
@@ -211,6 +208,19 @@ CSS_STATE_PSEUDO_CLASS(mozMathIncrementScriptLevel,
":-moz-math-increment-script-level", 0, "",
NS_EVENT_STATE_INCREMENT_SCRIPT_LEVEL)
+CSS_STATE_PSEUDO_CLASS(mozHasDirAttr, ":-moz-has-dir-attr",
+ CSS_PSEUDO_CLASS_ENABLED_IN_UA_SHEETS, "",
+ NS_EVENT_STATE_HAS_DIR_ATTR)
+CSS_STATE_PSEUDO_CLASS(mozDirAttrLTR, ":-moz-dir-attr-ltr",
+ CSS_PSEUDO_CLASS_ENABLED_IN_UA_SHEETS, "",
+ NS_EVENT_STATE_DIR_ATTR_LTR)
+CSS_STATE_PSEUDO_CLASS(mozDirAttrRTL, ":-moz-dir-attr-rtl",
+ CSS_PSEUDO_CLASS_ENABLED_IN_UA_SHEETS, "",
+ NS_EVENT_STATE_DIR_ATTR_RTL)
+CSS_STATE_PSEUDO_CLASS(mozDirAttrLikeAuto, ":-moz-dir-attr-like-auto",
+ CSS_PSEUDO_CLASS_ENABLED_IN_UA_SHEETS, "",
+ NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO)
+
// CSS 3 UI
// http://www.w3.org/TR/2004/CR-css3-ui-20040511/#pseudo-classes
CSS_STATE_PSEUDO_CLASS(required, ":required", 0, "", NS_EVENT_STATE_REQUIRED)
diff --git a/layout/style/nsCSSPseudoElements.h b/layout/style/nsCSSPseudoElements.h
index acf818a2c..64eb2f00c 100644
--- a/layout/style/nsCSSPseudoElements.h
+++ b/layout/style/nsCSSPseudoElements.h
@@ -36,6 +36,10 @@
#define CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE (1<<3)
// Is content prevented from parsing selectors containing this pseudo-element?
#define CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY (1<<4)
+// Can we use the ChromeOnly document.createElement(..., { pseudo: "::foo" })
+// API for creating pseudo-implementing native anonymous content in JS with this
+// pseudo-element?
+#define CSS_PSEUDO_ELEMENT_IS_JS_CREATED_NAC (1<<5)
namespace mozilla {
@@ -98,6 +102,11 @@ public:
static bool PseudoElementSupportsUserActionState(const Type aType);
+ static bool PseudoElementIsJSCreatedNAC(Type aType)
+ {
+ return PseudoElementHasFlags(aType, CSS_PSEUDO_ELEMENT_IS_JS_CREATED_NAC);
+ }
+
static bool IsEnabled(Type aType, EnabledState aEnabledState)
{
return !PseudoElementHasFlags(aType, CSS_PSEUDO_ELEMENT_UA_SHEET_ONLY) ||
diff --git a/layout/style/nsCSSRules.cpp b/layout/style/nsCSSRules.cpp
index 4b90b6f0c..dc79e471d 100644
--- a/layout/style/nsCSSRules.cpp
+++ b/layout/style/nsCSSRules.cpp
@@ -1515,6 +1515,13 @@ nsCSSFontFaceStyleDecl::GetParentObject()
return ContainingRule()->GetDocument();
}
+DocGroup*
+nsCSSFontFaceStyleDecl::GetDocGroup() const
+{
+ nsIDocument* document = ContainingRule()->GetDocument();
+ return document ? document->GetDocGroup() : nullptr;
+}
+
JSObject*
nsCSSFontFaceStyleDecl::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
{
@@ -1991,6 +1998,17 @@ nsCSSKeyframeStyleDeclaration::GetParentObject()
return mRule ? mRule->GetDocument() : nullptr;
}
+DocGroup*
+nsCSSKeyframeStyleDeclaration::GetDocGroup() const
+{
+ if (!mRule) {
+ return nullptr;
+ }
+
+ nsIDocument* document = mRule->GetDocument();
+ return document ? document->GetDocGroup() : nullptr;
+}
+
// -------------------------------------------
// nsCSSKeyframeRule
//
@@ -2538,6 +2556,17 @@ nsCSSPageStyleDeclaration::GetParentObject()
return mRule ? mRule->GetDocument() : nullptr;
}
+DocGroup*
+nsCSSPageStyleDeclaration::GetDocGroup() const
+{
+ if (!mRule) {
+ return nullptr;
+ }
+
+ nsIDocument* document = mRule->GetDocument();
+ return document ? document->GetDocGroup() : nullptr;
+}
+
// -------------------------------------------
// nsCSSPageRule
//
diff --git a/layout/style/nsCSSRules.h b/layout/style/nsCSSRules.h
index daefaf3f9..1bd468cb6 100644
--- a/layout/style/nsCSSRules.h
+++ b/layout/style/nsCSSRules.h
@@ -39,6 +39,11 @@ class nsMediaList;
namespace mozilla {
+namespace dom {
+class DocGroup;
+class DocGroup;
+} // namespace dom
+
class ErrorResult;
namespace css {
@@ -209,6 +214,7 @@ public:
using nsICSSDeclaration::GetPropertyCSSValue;
virtual nsINode *GetParentObject() override;
+ virtual mozilla::dom::DocGroup* GetDocGroup() const override;
virtual void IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aPropName) override;
nsresult GetPropertyValue(nsCSSFontDesc aFontDescID,
@@ -366,6 +372,7 @@ public:
nsICSSDeclaration)
virtual nsINode* GetParentObject() override;
+ virtual mozilla::dom::DocGroup* GetDocGroup() const override;
protected:
virtual ~nsCSSKeyframeStyleDeclaration();
@@ -496,6 +503,7 @@ public:
nsICSSDeclaration)
virtual nsINode *GetParentObject() override;
+ virtual mozilla::dom::DocGroup* GetDocGroup() const override;
protected:
virtual ~nsCSSPageStyleDeclaration();
diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp
index 910c1de8a..20e5651bd 100644
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -638,6 +638,34 @@ nsComputedDOMStyle::SetFrameStyleContext(nsStyleContext* aContext)
mStyleContext = aContext;
}
+/**
+ * The following function checks whether we need to explicitly resolve the style
+ * again, even though we have a style context coming from the frame.
+ *
+ * This basically checks whether the style is or may be under a ::first-line or
+ * ::first-letter frame, in which case we can't return the frame style, and we
+ * need to resolve it. See bug 505515.
+ */
+static bool
+MustReresolveStyle(const nsStyleContext* aContext)
+{
+ MOZ_ASSERT(aContext);
+
+ if (aContext->HasPseudoElementData()) {
+ if (!aContext->GetPseudo() ||
+ aContext->StyleSource().IsServoComputedValues()) {
+ // TODO(emilio): When ::first-line is supported in Servo, we may want to
+ // fix this to avoid re-resolving pseudo-element styles.
+ return true;
+ }
+
+ return aContext->GetParent() &&
+ aContext->GetParent()->HasPseudoElementData();
+ }
+
+ return false;
+}
+
void
nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
{
@@ -690,9 +718,20 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
// XXX the !mElement->IsHTMLElement(nsGkAtoms::area)
// check is needed due to bug 135040 (to avoid using
// mPrimaryFrame). Remove it once that's fixed.
- if (!mPseudo && mStyleType == eAll &&
- !mElement->IsHTMLElement(nsGkAtoms::area)) {
- mOuterFrame = mElement->GetPrimaryFrame();
+ if (mStyleType == eAll && !mElement->IsHTMLElement(nsGkAtoms::area)) {
+ mOuterFrame = nullptr;
+
+ if (!mPseudo) {
+ mOuterFrame = mElement->GetPrimaryFrame();
+ } else if (mPseudo == nsCSSPseudoElements::before ||
+ mPseudo == nsCSSPseudoElements::after) {
+ nsIAtom* property = mPseudo == nsCSSPseudoElements::before
+ ? nsGkAtoms::beforePseudoProperty
+ : nsGkAtoms::afterPseudoProperty;
+
+ auto* pseudo = static_cast<Element*>(mElement->GetProperty(property));
+ mOuterFrame = pseudo ? pseudo->GetPrimaryFrame() : nullptr;
+ }
mInnerFrame = mOuterFrame;
if (mOuterFrame) {
nsIAtom* type = mOuterFrame->GetType();
@@ -711,13 +750,15 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
}
}
- if (!mStyleContext || mStyleContext->HasPseudoElementData()) {
+ if (!mStyleContext || MustReresolveStyle(mStyleContext)) {
#ifdef DEBUG
if (mStyleContext) {
// We want to check that going through this path because of
// HasPseudoElementData is rare, because it slows us down a good
// bit. So check that we're really inside something associated
- // with a pseudo-element that contains elements.
+ // with a pseudo-element that contains elements. (We also allow
+ // the element to be NAC, just in case some chrome JS calls
+ // getComputedStyle on a NAC-implemented pseudo.)
nsStyleContext* topWithPseudoElementData = mStyleContext;
while (topWithPseudoElementData->GetParent()->HasPseudoElementData()) {
topWithPseudoElementData = topWithPseudoElementData->GetParent();
@@ -728,7 +769,8 @@ nsComputedDOMStyle::UpdateCurrentStyleSources(bool aNeedsLayoutFlush)
NS_LITERAL_STRING("we should be in a pseudo-element that is expected to contain elements ("));
assertMsg.Append(nsDependentString(pseudoAtom->GetUTF16String()));
assertMsg.Append(')');
- NS_ASSERTION(nsCSSPseudoElements::PseudoElementContainsElements(pseudo),
+ NS_ASSERTION(nsCSSPseudoElements::PseudoElementContainsElements(pseudo) ||
+ mElement->IsNativeAnonymous(),
NS_LossyConvertUTF16toASCII(assertMsg).get());
}
#endif
diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h
index e94d8dbf6..5af518c2e 100644
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -27,6 +27,7 @@
namespace mozilla {
namespace dom {
+class DocGroup;
class Element;
} // namespace dom
struct ComputedGridTrackInfo;
@@ -84,6 +85,11 @@ public:
return mElement;
}
+ virtual mozilla::dom::DocGroup* GetDocGroup() const override
+ {
+ return mElement ? mElement->GetDocGroup() : nullptr;
+ }
+
static already_AddRefed<nsStyleContext>
GetStyleContextForElement(mozilla::dom::Element* aElement, nsIAtom* aPseudo,
nsIPresShell* aPresShell,
diff --git a/layout/style/nsDOMCSSAttrDeclaration.cpp b/layout/style/nsDOMCSSAttrDeclaration.cpp
index ce638a9c2..7b659a8cc 100644
--- a/layout/style/nsDOMCSSAttrDeclaration.cpp
+++ b/layout/style/nsDOMCSSAttrDeclaration.cpp
@@ -178,6 +178,12 @@ nsDOMCSSAttributeDeclaration::GetParentObject()
return mElement;
}
+/* virtual */ DocGroup*
+nsDOMCSSAttributeDeclaration::GetDocGroup() const
+{
+ return mElement ? mElement->OwnerDoc()->GetDocGroup() : nullptr;
+}
+
NS_IMETHODIMP
nsDOMCSSAttributeDeclaration::SetPropertyValue(const nsCSSPropertyID aPropID,
const nsAString& aValue)
diff --git a/layout/style/nsDOMCSSAttrDeclaration.h b/layout/style/nsDOMCSSAttrDeclaration.h
index 7c0fbacc0..482d665ea 100644
--- a/layout/style/nsDOMCSSAttrDeclaration.h
+++ b/layout/style/nsDOMCSSAttrDeclaration.h
@@ -35,6 +35,8 @@ public:
NS_IMETHOD GetParentRule(nsIDOMCSSRule **aParent) override;
virtual nsINode* GetParentObject() override;
+ typedef mozilla::dom::DocGroup DocGroup;
+ virtual DocGroup* GetDocGroup() const override;
NS_IMETHOD SetPropertyValue(const nsCSSPropertyID aPropID,
const nsAString& aValue) override;
diff --git a/layout/style/nsDOMCSSDeclaration.cpp b/layout/style/nsDOMCSSDeclaration.cpp
index bd6c6069d..51ce8c335 100644
--- a/layout/style/nsDOMCSSDeclaration.cpp
+++ b/layout/style/nsDOMCSSDeclaration.cpp
@@ -267,7 +267,7 @@ nsDOMCSSDeclaration::GetCSSParsingEnvironmentForRule(css::Rule* aRule,
return;
}
- nsIDocument* document = sheet->GetOwningDocument();
+ nsIDocument* document = sheet->GetAssociatedDocument();
aCSSParseEnv.mSheetURI = sheet->GetSheetURI();
aCSSParseEnv.mBaseURI = sheet->GetBaseURI();
aCSSParseEnv.mPrincipal = sheet->Principal();
diff --git a/layout/style/nsICSSDeclaration.h b/layout/style/nsICSSDeclaration.h
index ff6ec4a78..fa80c17f5 100644
--- a/layout/style/nsICSSDeclaration.h
+++ b/layout/style/nsICSSDeclaration.h
@@ -31,6 +31,11 @@
#include "nsCOMPtr.h"
class nsINode;
+namespace mozilla {
+namespace dom {
+class DocGroup;
+} // namespace dom
+} // namespace mozilla
// dbeabbfa-6cb3-4f5c-aec2-dd558d9d681f
#define NS_ICSSDECLARATION_IID \
@@ -62,6 +67,7 @@ public:
const nsAString& aValue) = 0;
virtual nsINode *GetParentObject() = 0;
+ virtual mozilla::dom::DocGroup* GetDocGroup() const = 0;
// Also have to declare all the nsIDOMCSSStyleDeclaration methods,
// since we want to be able to call them from the WebIDL versions.
diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp
index 414eee4d4..558b9fa7f 100644
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -734,7 +734,7 @@ nsStyleSet::AddDocStyleSheet(CSSStyleSheet* aSheet, nsIDocument* aDocument)
bool present = sheets.RemoveElement(aSheet);
- size_t index = aDocument->FindDocStyleSheetInsertionPoint(sheets, aSheet);
+ size_t index = aDocument->FindDocStyleSheetInsertionPoint(sheets, *aSheet);
sheets.InsertElementAt(index, aSheet);
if (!present) {
diff --git a/layout/style/nsStyleUtil.cpp b/layout/style/nsStyleUtil.cpp
index 840cd03c3..9c3c0f449 100644
--- a/layout/style/nsStyleUtil.cpp
+++ b/layout/style/nsStyleUtil.cpp
@@ -8,6 +8,7 @@
#include "nsIContent.h"
#include "nsCSSProps.h"
+#include "nsContentUtils.h"
#include "nsRuleNode.h"
#include "nsROCSSPrimitiveValue.h"
#include "nsStyleStruct.h"
diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp
index 118702e8f..ace215a9f 100644
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -378,7 +378,7 @@ CSSTransition::HasLowerCompositeOrderThan(const CSSTransition& aOther) const
}
/* static */ Nullable<TimeDuration>
-CSSTransition::GetCurrentTimeAt(const DocumentTimeline& aTimeline,
+CSSTransition::GetCurrentTimeAt(const dom::DocumentTimeline& aTimeline,
const TimeStamp& aBaseTime,
const TimeDuration& aStartTime,
double aPlaybackRate)
@@ -395,7 +395,7 @@ CSSTransition::GetCurrentTimeAt(const DocumentTimeline& aTimeline,
}
void
-CSSTransition::SetEffectFromStyle(AnimationEffectReadOnly* aEffect)
+CSSTransition::SetEffectFromStyle(dom::AnimationEffectReadOnly* aEffect)
{
Animation::SetEffectNoUpdate(aEffect);
diff --git a/layout/style/res/forms.css b/layout/style/res/forms.css
index 95025221d..c91c2f739 100644
--- a/layout/style/res/forms.css
+++ b/layout/style/res/forms.css
@@ -1099,6 +1099,7 @@ input[type=number]::-moz-number-spin-box {
}
input[type=number]::-moz-number-spin-up {
+ writing-mode: horizontal-tb;
-moz-appearance: spinner-upbutton;
display: block; /* bug 926670 */
flex: none;
@@ -1116,6 +1117,7 @@ input[type=number]::-moz-number-spin-up {
}
input[type=number]::-moz-number-spin-down {
+ writing-mode: horizontal-tb;
-moz-appearance: spinner-downbutton;
display: block; /* bug 926670 */
flex: none;
diff --git a/layout/style/res/html.css b/layout/style/res/html.css
index 1f572467f..ea8efbe24 100644
--- a/layout/style/res/html.css
+++ b/layout/style/res/html.css
@@ -7,18 +7,18 @@
/* bidi */
-[dir] {
+:-moz-has-dir-attr {
unicode-bidi: isolate;
}
-[dir="rtl"] {
+:-moz-dir-attr-rtl {
direction: rtl;
}
-[dir="ltr"] {
+:-moz-dir-attr-ltr {
direction: ltr;
}
-bdi:dir(ltr), [dir="auto"]:dir(ltr) { direction: ltr; }
-bdi:dir(rtl), [dir="auto"]:dir(rtl) { direction: rtl; }
+:-moz-dir-attr-like-auto:dir(ltr) { direction: ltr; }
+:-moz-dir-attr-like-auto:dir(rtl) { direction: rtl; }
/* To ensure http://www.w3.org/TR/REC-html40/struct/dirlang.html#style-bidi:
*
@@ -89,10 +89,15 @@ xmp {
bdi, output {
unicode-bidi: isolate;
}
-bdo, bdo[dir] {
+/* We need the "bdo:-moz-has-dir-attr" bit because "bdo" has lower
+ specificity than the ":-moz-has-dir-attr" selector above. */
+bdo, bdo:-moz-has-dir-attr {
unicode-bidi: isolate-override;
}
-textarea[dir="auto"], pre[dir="auto"] { unicode-bidi: plaintext; }
+textarea:-moz-dir-attr-like-auto,
+pre:-moz-dir-attr-like-auto {
+ unicode-bidi: plaintext;
+}
/* blocks */
diff --git a/layout/style/res/ua.css b/layout/style/res/ua.css
index 931b32eb8..504f5dc57 100644
--- a/layout/style/res/ua.css
+++ b/layout/style/res/ua.css
@@ -471,3 +471,9 @@ div:-moz-native-anonymous.moz-custom-content-container {
width: 100%;
height: 100%;
}
+
+/* Shadow DOM v1
+ * https://drafts.csswg.org/css-scoping/#slots-in-shadow-tree */
+slot {
+ display: contents;
+} \ No newline at end of file
diff --git a/layout/style/test/chrome/chrome.ini b/layout/style/test/chrome/chrome.ini
index e34fce671..dd3bdf8f5 100644
--- a/layout/style/test/chrome/chrome.ini
+++ b/layout/style/test/chrome/chrome.ini
@@ -10,6 +10,7 @@ support-files =
mismatch.png
[test_author_specified_style.html]
+[test_bug1346623.html]
[test_bug418986-2.xul]
[test_bug1157097.html]
[test_bug1160724.xul]
diff --git a/layout/style/test/chrome/test_bug1346623.html b/layout/style/test/chrome/test_bug1346623.html
new file mode 100644
index 000000000..d24d66646
--- /dev/null
+++ b/layout/style/test/chrome/test_bug1346623.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for bug 1346623</title>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+</head>
+<body onload="startTest();">
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1346623">Mozilla Bug 1346623</a>
+<div id="display">
+
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+var Ci = Components.interfaces;
+var winUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+
+function startTest() {
+ // load some styles at the agent level
+ var css = `
+ #ac-parent { color: green; }
+ #ac-child.abc { }
+ `;
+ var sheetURL = "data:text/css," + encodeURIComponent(css);
+ winUtils.loadSheetUsingURIString(sheetURL, winUtils.AGENT_SHEET);
+
+ // add canvas anonymous content
+ var bq = document.createElement("blockquote");
+ bq.id = "ac-parent";
+ bq.textContent = "This blockquote text should be green.";
+ var div = document.createElement("div");
+ div.id = "ac-child";
+ div.textContent = " This div text should be green.";
+ bq.appendChild(div);
+ var ac = document.insertAnonymousContent(bq);
+ document.body.offsetWidth;
+
+ is(ac.getComputedStylePropertyValue("ac-child", "color"), "rgb(0, 128, 0)",
+ "color before reframing");
+
+ // reframe the root
+ document.documentElement.style.display = "flex";
+ document.body.offsetWidth;
+
+ // restyle the div
+ ac.setAttributeForElement("ac-child", "class", "abc");
+ document.body.offsetWidth;
+
+ is(ac.getComputedStylePropertyValue("ac-child", "color"), "rgb(0, 128, 0)",
+ "color after reframing");
+ SimpleTest.finish();
+}
+
+SimpleTest.waitForExplicitFinish();
+</script>
+</pre>
+</body>
+</html>