summaryrefslogtreecommitdiff
path: root/layout/base
diff options
context:
space:
mode:
Diffstat (limited to 'layout/base')
-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
23 files changed, 1143 insertions, 1654 deletions
diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp
index 124b5535e0..5c599e1ef6 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 e22fe90581..3b60b331a6 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 6ef048a19e..1a3cae4bfe 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 8be04d12c1..bee1fc6d9e 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 cc374edd52..8d6ca9142b 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 42ca23bb10..0659ab8571 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 6856171c18..b6bb63d085 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 82c1e25fae..a0484f3325 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 0000000000..bd577ae24d
--- /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 0000000000..667618141b
--- /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 0000000000..08a56106db
--- /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 6ded4ff3f2..9b09d1c843 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 37cd3e45ee..fc458b5ebf 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 7d1b8d42ff..0de00a90ca 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 97b022da8b..be8cd7147d 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 1b9148314f..ae7477d3d3 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 757dce7e5c..bb192b64f4 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 40fb5ff30c..76dd40af1a 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 865f5534c6..5f83b9c153 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 21d20c69fa..7496a49463 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 bba1f32652..36a43e46ba 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 264b52b18d..bd5125637f 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 f20370d73a..628e613c88 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;