зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1303605: Remove the undisplayed maps. r=bz,mats
This is mostly code removal, changing GetDisplayContentsStyle(..) checks by an FFI call to Servo. The tricky parts are: * MaybeCreateLazily, which I fixed to avoid setting bits under display: none stuff. This was a pre-existing problem, which was wallpapered by the sc->IsInDisplayNoneSubtree() check, which effectively made the whole assertion useless (see bug 1381017 for the only crashtest that hit this though). * ContentRemoved, where we can no longer know for sure whether the element is actually display: contents if we're removing it as a response to a style change. See the comment there. That kinda sucks, but that case is relatively weird, and it's better than adding tons of complexity to handle that. * GetParentComputedStyle, which also has a comment there. Also, this function has only one caller now, so we should maybe try to remove it. The different assertions after DestroyFramesForAndRestyle are changed for a single assertion in the function itself, and the node bit used as an optimization to avoid hashtable lookups is taken back. MozReview-Commit-ID: AZm822QnhF9
This commit is contained in:
Родитель
295a8f58b3
Коммит
c0f2f96f66
|
@ -1250,7 +1250,6 @@ Element::AttachShadowInternal(ShadowRootMode aMode, ErrorResult& aError)
|
|||
if (nsIDocument* doc = GetComposedDoc()) {
|
||||
if (nsIPresShell* shell = doc->GetShell()) {
|
||||
shell->DestroyFramesForAndRestyle(this);
|
||||
MOZ_ASSERT(!shell->FrameConstructor()->GetDisplayContentsStyleFor(this));
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(!GetPrimaryFrame());
|
||||
|
|
|
@ -1573,9 +1573,6 @@ private:
|
|||
// Set if the element might have any kind of anonymous content children,
|
||||
// which would not be found through the element's children list.
|
||||
ElementMayHaveAnonymousChildren,
|
||||
// Set if this node has at some point (and may still have)
|
||||
// display:none or display:contents children.
|
||||
NodeMayHaveChildrenWithLayoutBoxesDisabled,
|
||||
// Guard value
|
||||
BooleanFlagCount
|
||||
};
|
||||
|
@ -1701,19 +1698,6 @@ public:
|
|||
void SetMayHaveAnonymousChildren() { SetBoolFlag(ElementMayHaveAnonymousChildren); }
|
||||
bool MayHaveAnonymousChildren() const { return GetBoolFlag(ElementMayHaveAnonymousChildren); }
|
||||
|
||||
void SetMayHaveChildrenWithLayoutBoxesDisabled()
|
||||
{
|
||||
SetBoolFlag(NodeMayHaveChildrenWithLayoutBoxesDisabled);
|
||||
}
|
||||
void UnsetMayHaveChildrenWithLayoutBoxesDisabled()
|
||||
{
|
||||
ClearBoolFlag(NodeMayHaveChildrenWithLayoutBoxesDisabled);
|
||||
}
|
||||
bool MayHaveChildrenWithLayoutBoxesDisabled() const
|
||||
{
|
||||
return GetBoolFlag(NodeMayHaveChildrenWithLayoutBoxesDisabled);
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
|
||||
void SetIsInDocument() { SetBoolFlag(IsInDocument); }
|
||||
|
|
|
@ -2977,9 +2977,44 @@ nsIPresShell::SlotAssignmentWillChange(Element& aElement,
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
AssertNoFramesInSubtree(nsIContent* aContent)
|
||||
{
|
||||
for (nsIContent* c = aContent; c; c = c->GetNextNode(aContent)) {
|
||||
MOZ_ASSERT(!c->GetPrimaryFrame());
|
||||
if (auto* shadowRoot = c->GetShadowRoot()) {
|
||||
AssertNoFramesInSubtree(shadowRoot);
|
||||
}
|
||||
if (auto* binding = c->GetXBLBinding()) {
|
||||
if (auto* bindingWithContent = binding->GetBindingWithContent()) {
|
||||
nsIContent* anonContent = bindingWithContent->GetAnonymousContent();
|
||||
MOZ_ASSERT(!anonContent->GetPrimaryFrame());
|
||||
|
||||
// Need to do this instead of just AssertNoFramesInSubtree(anonContent),
|
||||
// because the parent of the children of the <content> element isn't the
|
||||
// <content> element, but the bound element, and that confuses
|
||||
// GetNextNode a lot.
|
||||
for (nsIContent* child = anonContent->GetFirstChild();
|
||||
child;
|
||||
child = child->GetNextSibling()) {
|
||||
AssertNoFramesInSubtree(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
nsIPresShell::DestroyFramesForAndRestyle(Element* aElement)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
auto postCondition = mozilla::MakeScopeExit([&]() {
|
||||
AssertNoFramesInSubtree(aElement);
|
||||
});
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(aElement);
|
||||
if (MOZ_UNLIKELY(!mDidInitialize)) {
|
||||
return;
|
||||
|
@ -4527,8 +4562,6 @@ PresShell::ContentRemoved(nsIContent* aChild, nsIContent* aPreviousSibling)
|
|||
: container->GetFirstChild();
|
||||
}
|
||||
|
||||
mPresContext->RestyleManager()->ContentRemoved(container, aChild, oldNextSibling);
|
||||
|
||||
// After removing aChild from tree we should save information about live ancestor
|
||||
if (mPointerEventTarget &&
|
||||
nsContentUtils::ContentIsDescendantOf(mPointerEventTarget, aChild)) {
|
||||
|
@ -4538,6 +4571,12 @@ PresShell::ContentRemoved(nsIContent* aChild, nsIContent* aPreviousSibling)
|
|||
mFrameConstructor->ContentRemoved(
|
||||
aChild->GetParent(), aChild, oldNextSibling,
|
||||
nsCSSFrameConstructor::REMOVE_CONTENT);
|
||||
|
||||
// NOTE(emilio): It's important that this goes after the frame constructor
|
||||
// stuff, otherwise the frame constructor can't see elements which are
|
||||
// display: contents / display: none, because we'd have cleared all the style
|
||||
// data from there.
|
||||
mPresContext->RestyleManager()->ContentRemoved(container, aChild, oldNextSibling);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -848,18 +848,20 @@ ServoRestyleManager::ProcessPostTraversal(
|
|||
// Hold the ComputedStyle alive, because it could become a dangling pointer
|
||||
// during the replacement. In practice it's not a huge deal, but better not
|
||||
// playing with dangling pointers if not needed.
|
||||
RefPtr<ComputedStyle> oldComputedStyle =
|
||||
//
|
||||
// NOTE(emilio): We could keep around the old computed style for display:
|
||||
// contents elements too, but we don't really need it right now.
|
||||
RefPtr<ComputedStyle> oldOrDisplayContentsStyle =
|
||||
styleFrame ? styleFrame->Style() : nullptr;
|
||||
|
||||
ComputedStyle* displayContentsStyle = nullptr;
|
||||
// FIXME(emilio, bug 1303605): This can be simpler for Servo.
|
||||
// Note that we intentionally don't check for display: none content.
|
||||
if (!oldComputedStyle) {
|
||||
displayContentsStyle =
|
||||
PresContext()->FrameConstructor()->GetDisplayContentsStyleFor(aElement);
|
||||
if (displayContentsStyle) {
|
||||
oldComputedStyle = displayContentsStyle;
|
||||
}
|
||||
MOZ_ASSERT(!(styleFrame && Servo_Element_IsDisplayContents(aElement)),
|
||||
"display: contents node has a frame, yet we didn't reframe it"
|
||||
" above?");
|
||||
const bool isDisplayContents =
|
||||
!styleFrame && Servo_Element_IsDisplayContents(aElement);
|
||||
if (isDisplayContents) {
|
||||
oldOrDisplayContentsStyle =
|
||||
aRestyleState.StyleSet().ResolveServoStyle(aElement);
|
||||
}
|
||||
|
||||
Maybe<ServoRestyleState> thisFrameRestyleState;
|
||||
|
@ -879,17 +881,19 @@ ServoRestyleManager::ProcessPostTraversal(
|
|||
RefPtr<ComputedStyle> upToDateContext =
|
||||
wasRestyled
|
||||
? aRestyleState.StyleSet().ResolveServoStyle(aElement)
|
||||
: oldComputedStyle;
|
||||
: oldOrDisplayContentsStyle;
|
||||
|
||||
ServoPostTraversalFlags childrenFlags =
|
||||
wasRestyled ? ServoPostTraversalFlags::ParentWasRestyled
|
||||
: ServoPostTraversalFlags::Empty;
|
||||
|
||||
if (wasRestyled && oldComputedStyle) {
|
||||
MOZ_ASSERT(styleFrame || displayContentsStyle);
|
||||
MOZ_ASSERT(oldComputedStyle->ComputedData() != upToDateContext->ComputedData());
|
||||
if (wasRestyled && oldOrDisplayContentsStyle) {
|
||||
MOZ_ASSERT(styleFrame || isDisplayContents);
|
||||
|
||||
upToDateContext->ResolveSameStructsAs(oldComputedStyle);
|
||||
// Note that upToDateContext could be the same as oldOrDisplayContentsStyle,
|
||||
// but it doesn't matter, since the only point of it is calling FinishStyle
|
||||
// on the relevant structs, and those don't matter for display: contents.
|
||||
upToDateContext->ResolveSameStructsAs(oldOrDisplayContentsStyle);
|
||||
|
||||
// We want to walk all the continuations here, even the ones with different
|
||||
// styles. In practice, the only reason we get continuations with different
|
||||
|
@ -906,12 +910,6 @@ ServoRestyleManager::ProcessPostTraversal(
|
|||
f->SetComputedStyle(upToDateContext);
|
||||
}
|
||||
|
||||
if (MOZ_UNLIKELY(displayContentsStyle)) {
|
||||
MOZ_ASSERT(!styleFrame);
|
||||
PresContext()->FrameConstructor()->
|
||||
ChangeRegisteredDisplayContentsStyleFor(aElement, upToDateContext);
|
||||
}
|
||||
|
||||
if (styleFrame) {
|
||||
UpdateAdditionalComputedStyles(styleFrame, aRestyleState);
|
||||
}
|
||||
|
@ -938,9 +936,11 @@ ServoRestyleManager::ProcessPostTraversal(
|
|||
AddLayerChangesForAnimation(
|
||||
styleFrame, aElement, aRestyleState.ChangeList());
|
||||
|
||||
childrenFlags |= SendA11yNotifications(mPresContext, aElement,
|
||||
oldComputedStyle,
|
||||
upToDateContext, aFlags);
|
||||
childrenFlags |= SendA11yNotifications(mPresContext,
|
||||
aElement,
|
||||
oldOrDisplayContentsStyle,
|
||||
upToDateContext,
|
||||
aFlags);
|
||||
}
|
||||
|
||||
const bool traverseElementChildren =
|
||||
|
@ -952,7 +952,7 @@ ServoRestyleManager::ProcessPostTraversal(
|
|||
StyleChildrenIterator it(aElement);
|
||||
TextPostTraversalState textState(*aElement,
|
||||
upToDateContext,
|
||||
displayContentsStyle && wasRestyled,
|
||||
isDisplayContents && wasRestyled,
|
||||
childrenRestyleState);
|
||||
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
|
||||
if (traverseElementChildren && n->IsElement()) {
|
||||
|
@ -1585,6 +1585,8 @@ ServoRestyleManager::DoReparentComputedStyle(nsIFrame* aFrame,
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(emilio): This is the only caller of GetParentComputedStyle, let's try
|
||||
// to remove it?
|
||||
nsIFrame* providerFrame;
|
||||
ComputedStyle* newParentStyle =
|
||||
aFrame->GetParentComputedStyle(&providerFrame);
|
||||
|
|
|
@ -417,6 +417,21 @@ IsInlineFrame(const nsIFrame* aFrame)
|
|||
return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
|
||||
}
|
||||
|
||||
/**
|
||||
* True for display: contents elements.
|
||||
*/
|
||||
static inline bool
|
||||
IsDisplayContents(const Element* aElement)
|
||||
{
|
||||
return aElement->HasServoData() && Servo_Element_IsDisplayContents(aElement);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsDisplayContents(const nsIContent* aContent)
|
||||
{
|
||||
return aContent->IsElement() && IsDisplayContents(aContent->AsElement());
|
||||
}
|
||||
|
||||
/**
|
||||
* True if aFrame is an instance of an SVG frame class or is an inline/block
|
||||
* frame being used for SVG text.
|
||||
|
@ -1633,8 +1648,6 @@ nsCSSFrameConstructor::NotifyDestroyingFrame(nsIFrame* aFrame)
|
|||
}
|
||||
|
||||
RestyleManager()->NotifyDestroyingFrame(aFrame);
|
||||
|
||||
nsFrameManager::NotifyDestroyingFrame(aFrame);
|
||||
}
|
||||
|
||||
struct nsGenConInitializer {
|
||||
|
@ -2467,7 +2480,6 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
|
|||
"Scrollbars should have been propagated to the viewport");
|
||||
|
||||
if (MOZ_UNLIKELY(display->mDisplay == StyleDisplay::None)) {
|
||||
RegisterDisplayNoneStyleFor(aDocElement, computedStyle);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -5597,14 +5609,7 @@ nsCSSFrameConstructor::SetAsUndisplayedContent(nsFrameConstructorState& aState,
|
|||
}
|
||||
return;
|
||||
}
|
||||
NS_ASSERTION(!aIsGeneratedContent, "Should have had pseudo type");
|
||||
|
||||
if (aState.mCreatingExtraFrames) {
|
||||
MOZ_ASSERT(GetDisplayNoneStyleFor(aContent),
|
||||
"should have called RegisterDisplayNoneStyleFor earlier");
|
||||
return;
|
||||
}
|
||||
aList.AppendUndisplayedItem(aContent, aComputedStyle);
|
||||
MOZ_ASSERT(!aIsGeneratedContent, "Should have had pseudo type");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -5827,16 +5832,6 @@ nsCSSFrameConstructor::AddFrameConstructionItemsInternal(nsFrameConstructorState
|
|||
// Figure out what should happen for display: contents in MathML.
|
||||
if (display->mDisplay == StyleDisplay::Contents &&
|
||||
!foundMathMLData) {
|
||||
if (!GetDisplayContentsStyleFor(aContent)) {
|
||||
MOZ_ASSERT(computedStyle->GetPseudo() || !isGeneratedContent,
|
||||
"Should have had pseudo type");
|
||||
aState.mFrameManager->RegisterDisplayContentsStyleFor(aContent,
|
||||
computedStyle);
|
||||
} else {
|
||||
aState.mFrameManager->ChangeRegisteredDisplayContentsStyleFor(aContent,
|
||||
computedStyle);
|
||||
}
|
||||
|
||||
if (aParentFrame) {
|
||||
aParentFrame->AddStateBits(NS_FRAME_MAY_HAVE_GENERATED_CONTENT);
|
||||
}
|
||||
|
@ -6492,6 +6487,9 @@ nsCSSFrameConstructor::FindSiblingInternal(
|
|||
};
|
||||
|
||||
while (nsIContent* sibling = nextDomSibling(aIter)) {
|
||||
// NOTE(emilio): It's important to check GetPrimaryFrame() before
|
||||
// IsDisplayContents to get the correct insertion point when multiple
|
||||
// siblings go from display: non-none to display: contents.
|
||||
if (nsIFrame* primaryFrame = sibling->GetPrimaryFrame()) {
|
||||
// XXX the GetContent() == sibling check is needed due to bug 135040.
|
||||
// Remove it once that's fixed.
|
||||
|
@ -6502,7 +6500,7 @@ nsCSSFrameConstructor::FindSiblingInternal(
|
|||
}
|
||||
}
|
||||
|
||||
if (GetDisplayContentsStyleFor(sibling)) {
|
||||
if (IsDisplayContents(sibling)) {
|
||||
if (nsIFrame* frame = adjust(getNearPseudo(sibling))) {
|
||||
return frame;
|
||||
}
|
||||
|
@ -6587,7 +6585,7 @@ nsCSSFrameConstructor::FindSibling(const FlattenedChildIterator& aIter,
|
|||
// 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)) {
|
||||
while (IsDisplayContents(current)) {
|
||||
const nsIContent* parent = current->GetFlattenedTreeParent();
|
||||
MOZ_ASSERT(parent, "No display: contents on the root");
|
||||
|
||||
|
@ -6703,7 +6701,7 @@ nsCSSFrameConstructor::GetContentInsertionFrameFor(nsIContent* aContent)
|
|||
{
|
||||
nsIFrame* frame;
|
||||
while (!(frame = aContent->GetPrimaryFrame())) {
|
||||
if (!GetDisplayContentsStyleFor(aContent)) {
|
||||
if (!IsDisplayContents(aContent)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -6829,9 +6827,7 @@ nsCSSFrameConstructor::CheckBitsForLazyFrameConstruction(nsIContent* aParent)
|
|||
noPrimaryFrame = needsFrameBitSet = false;
|
||||
}
|
||||
if (!noPrimaryFrame && !content->GetPrimaryFrame()) {
|
||||
ComputedStyle* sc = GetDisplayNoneStyleFor(content);
|
||||
noPrimaryFrame = !GetDisplayContentsStyleFor(content) &&
|
||||
(sc && !sc->IsInDisplayNoneSubtree());
|
||||
noPrimaryFrame = !IsDisplayContents(content);
|
||||
}
|
||||
if (!needsFrameBitSet && content->HasFlag(NODE_NEEDS_FRAME)) {
|
||||
needsFrameBitSet = true;
|
||||
|
@ -6882,12 +6878,16 @@ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
|
|||
|
||||
// We can construct lazily; just need to set suitable bits in the content
|
||||
// tree.
|
||||
nsIContent* parent = aChild->GetFlattenedTreeParent();
|
||||
Element* parent = aChild->GetFlattenedTreeParentElement();
|
||||
if (!parent) {
|
||||
// Not part of the flat tree, nothing to do.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Servo_Element_IsDisplayNone(parent)) {
|
||||
// Nothing to do either.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set NODE_NEEDS_FRAME on the new nodes.
|
||||
if (aOperation == CONTENTINSERT) {
|
||||
|
@ -6911,7 +6911,7 @@ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
|
|||
}
|
||||
|
||||
CheckBitsForLazyFrameConstruction(parent);
|
||||
parent->AsElement()->NoteDescendantsNeedFramesForServo();
|
||||
parent->NoteDescendantsNeedFramesForServo();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -6927,9 +6927,7 @@ nsCSSFrameConstructor::IssueSingleInsertNofications(nsIContent* aContainer,
|
|||
child = child->GetNextSibling()) {
|
||||
// listboxes suck.
|
||||
MOZ_ASSERT(MaybeGetListBoxBodyFrame(aContainer, child) ||
|
||||
(!child->GetPrimaryFrame() &&
|
||||
!GetDisplayNoneStyleFor(child) &&
|
||||
!GetDisplayContentsStyleFor(child)));
|
||||
!child->GetPrimaryFrame());
|
||||
|
||||
// Call ContentRangeInserted with this node.
|
||||
ContentRangeInserted(aContainer, child, child->GetNextSibling(),
|
||||
|
@ -7094,9 +7092,9 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
|
|||
child = child->GetNextSibling()) {
|
||||
// XXX the GetContent() != child check is needed due to bug 135040.
|
||||
// Remove it once that's fixed.
|
||||
NS_ASSERTION(!child->GetPrimaryFrame() ||
|
||||
child->GetPrimaryFrame()->GetContent() != child,
|
||||
"asked to construct a frame for a node that already has a frame");
|
||||
MOZ_ASSERT(!child->GetPrimaryFrame() ||
|
||||
child->GetPrimaryFrame()->GetContent() != child,
|
||||
"asked to construct a frame for a node that already has a frame");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -7172,7 +7170,7 @@ nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
|
|||
// Deal with possible :after generated content on the parent, or display:
|
||||
// contents.
|
||||
nsIFrame* nextSibling = nullptr;
|
||||
if (GetDisplayContentsStyleFor(insertion.mContainer) ||
|
||||
if (IsDisplayContents(insertion.mContainer) ||
|
||||
nsLayoutUtils::GetAfterFrame(insertion.mContainer)) {
|
||||
FlattenedChildIterator iter(insertion.mContainer);
|
||||
iter.Seek(insertion.mContainer->GetLastChild());
|
||||
|
@ -7577,7 +7575,8 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
|
|||
|
||||
// Otherwise, we've got parent content. Find its frame.
|
||||
NS_ASSERTION(!parentFrame || parentFrame->GetContent() == aContainer ||
|
||||
GetDisplayContentsStyleFor(aContainer), "New XBL code is possibly wrong!");
|
||||
IsDisplayContents(aContainer),
|
||||
"New XBL code is possibly wrong!");
|
||||
|
||||
if (aInsertionKind == InsertionKind::Async &&
|
||||
MaybeConstructLazily(CONTENTINSERT, aStartChild)) {
|
||||
|
@ -7997,28 +7996,6 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
|
|||
// XXXbz the GetContent() != aChild check is needed due to bug 135040.
|
||||
// Remove it once that's fixed.
|
||||
childFrame = nullptr;
|
||||
UnregisterDisplayNoneStyleFor(aChild, aContainer);
|
||||
}
|
||||
MOZ_ASSERT(!childFrame || !GetDisplayContentsStyleFor(aChild),
|
||||
"display:contents nodes shouldn't have a frame");
|
||||
if (!childFrame && GetDisplayContentsStyleFor(aChild)) {
|
||||
// NOTE(emilio): We may iterate through ::before and ::after here and they
|
||||
// may be gone after the respective ContentRemoved call. Right now
|
||||
// StyleChildrenIterator handles that properly, so it's not an issue.
|
||||
StyleChildrenIterator iter(aChild);
|
||||
for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
|
||||
if (c->GetPrimaryFrame() || GetDisplayContentsStyleFor(c)) {
|
||||
LAYOUT_PHASE_TEMP_EXIT();
|
||||
bool didReconstruct =
|
||||
ContentRemoved(aChild, c, nullptr, REMOVE_FOR_RECONSTRUCTION);
|
||||
LAYOUT_PHASE_TEMP_REENTER();
|
||||
if (didReconstruct) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
UnregisterDisplayContentsStyleFor(aChild, aContainer);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
|
@ -8031,17 +8008,17 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
|
|||
// If we're removing the root, then make sure to remove things starting at
|
||||
// the viewport's child instead of the primary frame (which might even be
|
||||
// null if the root had an XBL binding or display:none, even though the
|
||||
// frames above it got created). We do the adjustment after the childFrame
|
||||
// check above, because we do want to clear any undisplayed content we might
|
||||
// have for the root. Detecting removal of a root is a little exciting; in
|
||||
// particular, having a null aContainer is necessary but NOT sufficient. Due
|
||||
// to how we process reframes, the content node might not even be in our
|
||||
// document by now. So explicitly check whether the viewport's first kid's
|
||||
// content node is aChild.
|
||||
// frames above it got created). Detecting removal of a root is a little
|
||||
// exciting; in particular, having a null aContainer is necessary but NOT
|
||||
// sufficient. Due to how we process reframes, the content node might not
|
||||
// even be in our document by now. So explicitly check whether the viewport's
|
||||
// first kid's content node is aChild.
|
||||
//
|
||||
// FIXME(emilio): I think the "might not be in our document" bit is impossible
|
||||
// now.
|
||||
bool isRoot = false;
|
||||
if (!aContainer) {
|
||||
nsIFrame* viewport = GetRootFrame();
|
||||
if (viewport) {
|
||||
if (nsIFrame* viewport = GetRootFrame()) {
|
||||
nsIFrame* firstChild = viewport->PrincipalChildList().FirstChild();
|
||||
if (firstChild && firstChild->GetContent() == aChild) {
|
||||
isRoot = true;
|
||||
|
@ -8051,6 +8028,45 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
|
|||
}
|
||||
}
|
||||
|
||||
// We need to be conservative about when to determine whether something has
|
||||
// display: contents or not because at this point our actual display may be
|
||||
// different.
|
||||
//
|
||||
// Consider the case of:
|
||||
//
|
||||
// <div id="A" style="display: contents"><div id="B"></div></div>
|
||||
//
|
||||
// If we reconstruct A because its display changed to "none", we still need to
|
||||
// cleanup the frame on B, but A's display is now "none", so we can't poke at
|
||||
// the style of it.
|
||||
//
|
||||
// FIXME(emilio, bug 1450366): We can make this faster without adding much
|
||||
// complexity for the display: none -> other case, which right now
|
||||
// unnecessarily walks the content tree down.
|
||||
auto CouldHaveBeenDisplayContents = [aFlags](nsIContent* aContent) -> bool {
|
||||
return aFlags == REMOVE_FOR_RECONSTRUCTION || IsDisplayContents(aContent);
|
||||
};
|
||||
|
||||
if (!childFrame && CouldHaveBeenDisplayContents(aChild)) {
|
||||
// NOTE(emilio): We may iterate through ::before and ::after here and they
|
||||
// may be gone after the respective ContentRemoved call. Right now
|
||||
// StyleChildrenIterator handles that properly, so it's not an issue.
|
||||
StyleChildrenIterator iter(aChild);
|
||||
for (nsIContent* c = iter.GetNextChild(); c; c = iter.GetNextChild()) {
|
||||
if (c->GetPrimaryFrame() || CouldHaveBeenDisplayContents(aChild)) {
|
||||
LAYOUT_PHASE_TEMP_EXIT();
|
||||
bool didReconstruct =
|
||||
ContentRemoved(aChild, c, nullptr, REMOVE_FOR_RECONSTRUCTION);
|
||||
LAYOUT_PHASE_TEMP_REENTER();
|
||||
if (didReconstruct) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (childFrame) {
|
||||
InvalidateCanvasIfNeeded(mPresShell, aChild);
|
||||
|
||||
|
@ -8143,7 +8159,6 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
|
|||
if (!childFrame || childFrame->GetContent() != aChild) {
|
||||
// XXXbz the GetContent() != aChild check is needed due to bug 135040.
|
||||
// Remove it once that's fixed.
|
||||
UnregisterDisplayNoneStyleFor(aChild, aContainer);
|
||||
return false;
|
||||
}
|
||||
parentFrame = childFrame->GetParent();
|
||||
|
@ -10170,7 +10185,6 @@ nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aSta
|
|||
CreateNeededPseudoInternalRubyBoxes(aState, aItems, aParentFrame);
|
||||
CreateNeededPseudoSiblings(aState, aItems, aParentFrame);
|
||||
|
||||
aItems.SetTriedConstructingFrames();
|
||||
for (FCItemIterator iter(aItems); !iter.IsDone(); iter.Next()) {
|
||||
NS_ASSERTION(iter.item().DesiredParentType() == GetParentType(aParentFrame),
|
||||
"Needed pseudos didn't get created; expect bad things");
|
||||
|
@ -12231,8 +12245,7 @@ Iterator::AppendItemsToList(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd,
|
|||
|
||||
// We can't just move our guts to the other list if it already has
|
||||
// some information or if we're not moving our entire list.
|
||||
if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty() ||
|
||||
!aTargetList.mUndisplayedItems.IsEmpty()) {
|
||||
if (!AtStart() || !aEnd.IsDone() || !aTargetList.IsEmpty()) {
|
||||
do {
|
||||
AppendItemToList(aTargetList);
|
||||
} while (*this != aEnd);
|
||||
|
@ -12250,9 +12263,6 @@ Iterator::AppendItemsToList(nsCSSFrameConstructor* aFCtor, const Iterator& aEnd,
|
|||
memcpy(aTargetList.mDesiredParentCounts, mList.mDesiredParentCounts,
|
||||
sizeof(aTargetList.mDesiredParentCounts));
|
||||
|
||||
// Swap out undisplayed item arrays, before we nuke the array on our end
|
||||
aTargetList.mUndisplayedItems.SwapElements(mList.mUndisplayedItems);
|
||||
|
||||
// reset mList
|
||||
mList.Reset(aFCtor);
|
||||
|
||||
|
|
|
@ -833,7 +833,6 @@ private:
|
|||
void SetParentHasNoXBLChildren(bool aHasNoXBLChildren) {
|
||||
mParentHasNoXBLChildren = aHasNoXBLChildren;
|
||||
}
|
||||
void SetTriedConstructingFrames() { mTriedConstructingFrames = true; }
|
||||
bool HasLineBoundaryAtStart() { return mLineBoundaryAtStart; }
|
||||
bool HasLineBoundaryAtEnd() { return mLineBoundaryAtEnd; }
|
||||
bool ParentHasNoXBLChildren() { return mParentHasNoXBLChildren; }
|
||||
|
@ -888,11 +887,6 @@ private:
|
|||
return item;
|
||||
}
|
||||
|
||||
void AppendUndisplayedItem(nsIContent* aContent,
|
||||
ComputedStyle* aComputedStyle) {
|
||||
mUndisplayedItems.AppendElement(UndisplayedItem(aContent, aComputedStyle));
|
||||
}
|
||||
|
||||
void InlineItemAdded() { ++mInlineCount; }
|
||||
void BlockItemAdded() { ++mBlockCount; }
|
||||
void LineParticipantItemAdded() { ++mLineParticipantCount; }
|
||||
|
@ -1024,8 +1018,7 @@ private:
|
|||
mItemCount(0),
|
||||
mLineBoundaryAtStart(false),
|
||||
mLineBoundaryAtEnd(false),
|
||||
mParentHasNoXBLChildren(false),
|
||||
mTriedConstructingFrames(false)
|
||||
mParentHasNoXBLChildren(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(FrameConstructionItemList);
|
||||
memset(mDesiredParentCounts, 0, sizeof(mDesiredParentCounts));
|
||||
|
@ -1036,16 +1029,6 @@ private:
|
|||
while (FrameConstructionItem* item = mItems.popFirst()) {
|
||||
item->Delete(aFCtor);
|
||||
}
|
||||
|
||||
// Create the undisplayed entries for our mUndisplayedItems, if any, but
|
||||
// only if we have tried constructing frames for this item list. If we
|
||||
// haven't, then we're just throwing it away and will probably try again.
|
||||
if (!mUndisplayedItems.IsEmpty() && mTriedConstructingFrames) {
|
||||
for (uint32_t i = 0; i < mUndisplayedItems.Length(); ++i) {
|
||||
UndisplayedItem& item = mUndisplayedItems[i];
|
||||
aFCtor->RegisterDisplayNoneStyleFor(item.mContent, item.mComputedStyle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent stack instances (except as AutoFrameConstructionItemList).
|
||||
|
@ -1081,7 +1064,6 @@ private:
|
|||
// should be either +1 or -1 depending on which is happening.
|
||||
void AdjustCountsForItem(FrameConstructionItem* aItem, int32_t aDelta);
|
||||
|
||||
nsTArray<UndisplayedItem> mUndisplayedItems;
|
||||
mozilla::LinkedList<FrameConstructionItem> mItems;
|
||||
uint32_t mInlineCount;
|
||||
uint32_t mBlockCount;
|
||||
|
@ -1096,8 +1078,6 @@ private:
|
|||
bool mLineBoundaryAtEnd;
|
||||
// True if the parent is guaranteed to have no XBL anonymous children
|
||||
bool mParentHasNoXBLChildren;
|
||||
// True if we have tried constructing frames from this list
|
||||
bool mTriedConstructingFrames;
|
||||
};
|
||||
|
||||
/* A struct representing a list of FrameConstructionItems on the stack. */
|
||||
|
|
|
@ -40,59 +40,6 @@
|
|||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
/**
|
||||
* The undisplayed map is a class that maps a parent content node to the
|
||||
* undisplayed content children, and their ComputedStyles.
|
||||
*
|
||||
* The linked list of nodes holds strong references to the ComputedStyle and the
|
||||
* content.
|
||||
*/
|
||||
class nsFrameManager::UndisplayedMap :
|
||||
private nsClassHashtable<nsPtrHashKey<nsIContent>,
|
||||
LinkedList<UndisplayedNode>>
|
||||
{
|
||||
typedef nsClassHashtable<nsPtrHashKey<nsIContent>, LinkedList<UndisplayedNode>> base_type;
|
||||
|
||||
public:
|
||||
UndisplayedMap();
|
||||
~UndisplayedMap();
|
||||
|
||||
UndisplayedNode* GetFirstNode(nsIContent* aParentContent);
|
||||
|
||||
void AddNodeFor(nsIContent* aParentContent,
|
||||
nsIContent* aChild,
|
||||
ComputedStyle* aStyle);
|
||||
|
||||
void RemoveNodeFor(nsIContent* aParentContent, UndisplayedNode* aNode);
|
||||
|
||||
void RemoveNodesFor(nsIContent* aParentContent);
|
||||
|
||||
nsAutoPtr<LinkedList<UndisplayedNode>>
|
||||
UnlinkNodesFor(nsIContent* aParentContent);
|
||||
|
||||
// Removes all entries from the hash table
|
||||
void Clear();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* All functions that are entry points into code that handles "parent"
|
||||
* objects (used as the hash table keys) must ensure that the parent objects
|
||||
* that they act on (and pass to other code) have been normalized by calling
|
||||
* this method.
|
||||
*/
|
||||
static nsIContent* GetApplicableParent(nsIContent* aParent);
|
||||
|
||||
void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
|
||||
|
||||
protected:
|
||||
LinkedList<UndisplayedNode>* GetListFor(nsIContent* aParentContent);
|
||||
LinkedList<UndisplayedNode>* GetOrCreateListFor(nsIContent* aParentContent);
|
||||
void AppendNodeFor(UndisplayedNode* aNode, nsIContent* aParentContent);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
nsFrameManager::~nsFrameManager()
|
||||
|
@ -113,357 +60,9 @@ nsFrameManager::Destroy()
|
|||
mRootFrame = nullptr;
|
||||
}
|
||||
|
||||
delete mDisplayNoneMap;
|
||||
mDisplayNoneMap = nullptr;
|
||||
delete mDisplayContentsMap;
|
||||
mDisplayContentsMap = nullptr;
|
||||
|
||||
mPresShell = nullptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/* static */ nsIContent*
|
||||
nsFrameManager::ParentForUndisplayedMap(const nsIContent* aContent)
|
||||
{
|
||||
MOZ_ASSERT(aContent);
|
||||
|
||||
nsIContent* parent = aContent->GetParentElementCrossingShadowRoot();
|
||||
|
||||
// Normalize the parent:
|
||||
parent = UndisplayedMap::GetApplicableParent(parent);
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
/* static */ ComputedStyle*
|
||||
nsFrameManager::GetComputedStyleInMap(UndisplayedMap* aMap,
|
||||
const nsIContent* aContent)
|
||||
{
|
||||
UndisplayedNode* node = GetUndisplayedNodeInMapFor(aMap, aContent);
|
||||
return node ? node->mStyle.get() : nullptr;
|
||||
}
|
||||
|
||||
/* static */ UndisplayedNode*
|
||||
nsFrameManager::GetUndisplayedNodeInMapFor(UndisplayedMap* aMap,
|
||||
const nsIContent* aContent)
|
||||
{
|
||||
if (!aContent) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// This function is an entry point into UndisplayedMap handling code, so the
|
||||
// parent that we act on must be normalized by GetApplicableParent (as per
|
||||
// that function's documentation). We rely on ParentForUndisplayedMap to
|
||||
// have done that for us.
|
||||
nsIContent* parent = ParentForUndisplayedMap(aContent);
|
||||
|
||||
for (UndisplayedNode* node = aMap->GetFirstNode(parent);
|
||||
node; node = node->getNext()) {
|
||||
if (node->mContent == aContent)
|
||||
return node;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/* static */ UndisplayedNode*
|
||||
nsFrameManager::GetAllUndisplayedNodesInMapFor(UndisplayedMap* aMap,
|
||||
nsIContent* aParentContent)
|
||||
{
|
||||
return aMap ? aMap->GetFirstNode(aParentContent) : nullptr;
|
||||
}
|
||||
|
||||
UndisplayedNode*
|
||||
nsFrameManager::GetAllRegisteredDisplayNoneStylesIn(nsIContent* aParentContent)
|
||||
{
|
||||
return GetAllUndisplayedNodesInMapFor(mDisplayNoneMap, aParentContent);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsFrameManager::SetComputedStyleInMap(UndisplayedMap* aMap,
|
||||
nsIContent* aContent,
|
||||
ComputedStyle* aComputedStyle)
|
||||
{
|
||||
MOZ_ASSERT(!aComputedStyle->GetPseudo(),
|
||||
"Should only have actual elements here");
|
||||
|
||||
#if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_BOX_CONTENTS_MAP)
|
||||
static int i = 0;
|
||||
printf("SetComputedStyleInMap(%d): p=%p \n", i++, (void *)aContent);
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(!GetComputedStyleInMap(aMap, aContent),
|
||||
"Already have an entry for aContent");
|
||||
|
||||
// This function is an entry point into UndisplayedMap handling code, so the
|
||||
// parent that we act on must be normalized by GetApplicableParent (as per
|
||||
// that function's documentation). We rely on ParentForUndisplayedMap to
|
||||
// have done that for us.
|
||||
nsIContent* parent = ParentForUndisplayedMap(aContent);
|
||||
MOZ_ASSERT(parent || !aContent->GetParent(), "no non-elements");
|
||||
|
||||
#ifdef DEBUG
|
||||
nsIPresShell* shell = aComputedStyle->PresContext()->PresShell();
|
||||
NS_ASSERTION(parent || (shell && shell->GetDocument() &&
|
||||
shell->GetDocument()->GetRootElement() == aContent),
|
||||
"undisplayed content must have a parent, unless it's the root "
|
||||
"element");
|
||||
#endif
|
||||
|
||||
// We set this bit as an optimization so that we can can know when a content
|
||||
// node may have |display:none| or |display:contents| children. This allows
|
||||
// other parts of the code to avoid checking for such children in
|
||||
// mDisplayNoneMap and mDisplayContentsMap if the bit isn't present on a node
|
||||
// that it's handling.
|
||||
if (parent) {
|
||||
parent->SetMayHaveChildrenWithLayoutBoxesDisabled();
|
||||
}
|
||||
|
||||
aMap->AddNodeFor(parent, aContent, aComputedStyle);
|
||||
}
|
||||
|
||||
void
|
||||
nsFrameManager::RegisterDisplayNoneStyleFor(nsIContent* aContent,
|
||||
ComputedStyle* aComputedStyle)
|
||||
{
|
||||
if (!mDisplayNoneMap) {
|
||||
mDisplayNoneMap = new UndisplayedMap;
|
||||
}
|
||||
SetComputedStyleInMap(mDisplayNoneMap, aContent, aComputedStyle);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
nsFrameManager::ChangeComputedStyleInMap(UndisplayedMap* aMap,
|
||||
nsIContent* aContent,
|
||||
ComputedStyle* aComputedStyle)
|
||||
{
|
||||
MOZ_ASSERT(aMap, "expecting a map");
|
||||
|
||||
#if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_BOX_CONTENTS_MAP)
|
||||
static int i = 0;
|
||||
printf("ChangeComputedStyleInMap(%d): p=%p \n", i++, (void *)aContent);
|
||||
#endif
|
||||
|
||||
// This function is an entry point into UndisplayedMap handling code, so the
|
||||
// parent that we act on must be normalized by GetApplicableParent (as per
|
||||
// that function's documentation). We rely on ParentForUndisplayedMap to
|
||||
// have done that for us.
|
||||
nsIContent* parent = ParentForUndisplayedMap(aContent);
|
||||
MOZ_ASSERT(parent || !aContent->GetParent(), "no non-elements");
|
||||
|
||||
for (UndisplayedNode* node = aMap->GetFirstNode(parent);
|
||||
node; node = node->getNext()) {
|
||||
if (node->mContent == aContent) {
|
||||
node->mStyle = aComputedStyle;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_CRASH("couldn't find the entry to change");
|
||||
}
|
||||
|
||||
void
|
||||
nsFrameManager::UnregisterDisplayNoneStyleFor(nsIContent* aContent,
|
||||
nsIContent* aParentContent)
|
||||
{
|
||||
#ifdef DEBUG_UNDISPLAYED_MAP
|
||||
static int i = 0;
|
||||
printf("ClearUndisplayedContent(%d): content=%p parent=%p --> ", i++, (void *)aContent, (void*)aParentContent);
|
||||
#endif
|
||||
|
||||
if (!mDisplayNoneMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This function is an entry point into UndisplayedMap handling code, so we
|
||||
// must call GetApplicableParent so the parent we pass around is correct.
|
||||
aParentContent = UndisplayedMap::GetApplicableParent(aParentContent);
|
||||
|
||||
if (aParentContent &&
|
||||
!aParentContent->MayHaveChildrenWithLayoutBoxesDisabled()) {
|
||||
MOZ_ASSERT(!mDisplayNoneMap->GetFirstNode(aParentContent),
|
||||
"MayHaveChildrenWithLayoutBoxesDisabled bit out of sync - "
|
||||
"may fail to remove node from mDisplayNoneMap");
|
||||
return;
|
||||
}
|
||||
|
||||
UndisplayedNode* node = mDisplayNoneMap->GetFirstNode(aParentContent);
|
||||
|
||||
const bool haveOneDisplayNoneChild = node && !node->getNext();
|
||||
|
||||
for (; node; node = node->getNext()) {
|
||||
if (node->mContent == aContent) {
|
||||
mDisplayNoneMap->RemoveNodeFor(aParentContent, node);
|
||||
|
||||
#ifdef DEBUG_UNDISPLAYED_MAP
|
||||
printf( "REMOVED!\n");
|
||||
#endif
|
||||
// make sure that there are no more entries for the same content
|
||||
MOZ_ASSERT(!GetDisplayNoneStyleFor(aContent),
|
||||
"Found more undisplayed content data after removal");
|
||||
|
||||
if (haveOneDisplayNoneChild) {
|
||||
// There are no more children of aParentContent in mDisplayNoneMap.
|
||||
MOZ_ASSERT(!mDisplayNoneMap->GetFirstNode(aParentContent),
|
||||
"Bad UnsetMayHaveChildrenWithLayoutBoxesDisabled call");
|
||||
// If we also know that none of its children are in mDisplayContentsMap
|
||||
// then we can call UnsetMayHaveChildrenWithLayoutBoxesDisabled. We
|
||||
// don't want to check mDisplayContentsMap though since that involves a
|
||||
// hash table lookup in relatively hot code. Still, we know there are
|
||||
// no children in mDisplayContentsMap if the map is empty, so we do
|
||||
// check for that.
|
||||
if (aParentContent && !mDisplayContentsMap) {
|
||||
aParentContent->UnsetMayHaveChildrenWithLayoutBoxesDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_UNDISPLAYED_MAP
|
||||
printf( "not found.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nsFrameManager::ClearAllMapsFor(nsIContent* aParentContent)
|
||||
{
|
||||
#if defined(DEBUG_UNDISPLAYED_MAP) || defined(DEBUG_DISPLAY_CONTENTS_MAP)
|
||||
static int i = 0;
|
||||
printf("ClearAllMapsFor(%d): parent=%p \n", i++, aParentContent);
|
||||
#endif
|
||||
|
||||
if (!aParentContent ||
|
||||
aParentContent->MayHaveChildrenWithLayoutBoxesDisabled()) {
|
||||
if (mDisplayNoneMap) {
|
||||
mDisplayNoneMap->RemoveNodesFor(aParentContent);
|
||||
}
|
||||
if (mDisplayContentsMap) {
|
||||
nsAutoPtr<LinkedList<UndisplayedNode>> list =
|
||||
mDisplayContentsMap->UnlinkNodesFor(aParentContent);
|
||||
if (list) {
|
||||
while (UndisplayedNode* node = list->popFirst()) {
|
||||
ClearAllMapsFor(node->mContent);
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (aParentContent) {
|
||||
aParentContent->UnsetMayHaveChildrenWithLayoutBoxesDisabled();
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
else {
|
||||
if (mDisplayNoneMap) {
|
||||
MOZ_ASSERT(!mDisplayNoneMap->GetFirstNode(aParentContent),
|
||||
"We failed to remove a node from mDisplayNoneMap");
|
||||
}
|
||||
if (mDisplayContentsMap) {
|
||||
MOZ_ASSERT(!mDisplayContentsMap->GetFirstNode(aParentContent),
|
||||
"We failed to remove a node from mDisplayContentsMap");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Need to look at aParentContent's content list due to XBL insertions.
|
||||
// Nodes in aParentContent's content list do not have aParentContent as a
|
||||
// parent, but are treated as children of aParentContent. We iterate over
|
||||
// the flattened content list and just ignore any nodes we don't care about.
|
||||
FlattenedChildIterator iter(aParentContent);
|
||||
for (nsIContent* child = iter.GetNextChild(); child; child = iter.GetNextChild()) {
|
||||
auto parent = child->GetParent();
|
||||
if (parent != aParentContent) {
|
||||
UnregisterDisplayNoneStyleFor(child, parent);
|
||||
UnregisterDisplayContentsStyleFor(child, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
nsFrameManager::RegisterDisplayContentsStyleFor(nsIContent* aContent,
|
||||
ComputedStyle* aComputedStyle)
|
||||
{
|
||||
if (!mDisplayContentsMap) {
|
||||
mDisplayContentsMap = new UndisplayedMap;
|
||||
}
|
||||
SetComputedStyleInMap(mDisplayContentsMap, aContent, aComputedStyle);
|
||||
}
|
||||
|
||||
UndisplayedNode*
|
||||
nsFrameManager::GetAllRegisteredDisplayContentsStylesIn(nsIContent* aParentContent)
|
||||
{
|
||||
return GetAllUndisplayedNodesInMapFor(mDisplayContentsMap, aParentContent);
|
||||
}
|
||||
|
||||
void
|
||||
nsFrameManager::UnregisterDisplayContentsStyleFor(nsIContent* aContent,
|
||||
nsIContent* aParentContent)
|
||||
{
|
||||
#ifdef DEBUG_DISPLAY_CONTENTS_MAP
|
||||
static int i = 0;
|
||||
printf("ClearDisplayContents(%d): content=%p parent=%p --> ", i++, (void *)aContent, (void*)aParentContent);
|
||||
#endif
|
||||
|
||||
if (!mDisplayContentsMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This function is an entry point into UndisplayedMap handling code, so we
|
||||
// must call GetApplicableParent so the parent we pass around is correct.
|
||||
aParentContent = UndisplayedMap::GetApplicableParent(aParentContent);
|
||||
|
||||
if (aParentContent &&
|
||||
!aParentContent->MayHaveChildrenWithLayoutBoxesDisabled()) {
|
||||
MOZ_ASSERT(!mDisplayContentsMap->GetFirstNode(aParentContent),
|
||||
"MayHaveChildrenWithLayoutBoxesDisabled bit out of sync - "
|
||||
"may fail to remove node from mDisplayContentsMap");
|
||||
return;
|
||||
}
|
||||
|
||||
UndisplayedNode* node = mDisplayContentsMap->GetFirstNode(aParentContent);
|
||||
|
||||
const bool haveOneDisplayContentsChild = node && !node->getNext();
|
||||
|
||||
for (; node; node = node->getNext()) {
|
||||
if (node->mContent == aContent) {
|
||||
mDisplayContentsMap->RemoveNodeFor(aParentContent, node);
|
||||
|
||||
#ifdef DEBUG_DISPLAY_CONTENTS_MAP
|
||||
printf( "REMOVED!\n");
|
||||
#endif
|
||||
// make sure that there are no more entries for the same content
|
||||
MOZ_ASSERT(!GetDisplayContentsStyleFor(aContent),
|
||||
"Found more entries for aContent after removal");
|
||||
ClearAllMapsFor(aContent);
|
||||
|
||||
if (haveOneDisplayContentsChild) {
|
||||
// There are no more children of aParentContent in mDisplayContentsMap.
|
||||
MOZ_ASSERT(!mDisplayContentsMap->GetFirstNode(aParentContent),
|
||||
"Bad UnsetMayHaveChildrenWithLayoutBoxesDisabled call");
|
||||
// If we also know that none of its children are in mDisplayNoneMap
|
||||
// then we can call UnsetMayHaveChildrenWithLayoutBoxesDisabled. We
|
||||
// don't want to check mDisplayNoneMap though since that involves a
|
||||
// hash table lookup in relatively hot code. Still, we know there are
|
||||
// no children in mDisplayNoneMap if the map is empty, so we do
|
||||
// check for that.
|
||||
if (aParentContent && !mDisplayNoneMap) {
|
||||
aParentContent->UnsetMayHaveChildrenWithLayoutBoxesDisabled();
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_DISPLAY_CONTENTS_MAP
|
||||
printf( "not found.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
void
|
||||
nsFrameManager::AppendFrames(nsContainerFrame* aParentFrame,
|
||||
|
@ -535,15 +134,6 @@ nsFrameManager::RemoveFrame(ChildListID aListID,
|
|||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void
|
||||
nsFrameManager::NotifyDestroyingFrame(nsIFrame* aFrame)
|
||||
{
|
||||
nsIContent* content = aFrame->GetContent();
|
||||
if (content && content->GetPrimaryFrame() == aFrame) {
|
||||
ClearAllMapsFor(content);
|
||||
}
|
||||
}
|
||||
|
||||
// Capture state for a given frame.
|
||||
// Accept a content id here, in some cases we may not have content (scroll position)
|
||||
void
|
||||
|
@ -678,14 +268,7 @@ nsFrameManager::RestoreFrameState(nsIFrame* aFrame,
|
|||
void
|
||||
nsFrameManager::DestroyAnonymousContent(already_AddRefed<nsIContent> aContent)
|
||||
{
|
||||
nsCOMPtr<nsIContent> content = aContent;
|
||||
if (content) {
|
||||
// Invoke ClearAllMapsFor before unbinding from the tree. When we unbind,
|
||||
// we remove the mPrimaryFrame pointer, which is used by the frame
|
||||
// teardown code to determine whether to invoke ClearAllMapsFor or not.
|
||||
// These maps will go away when we drop support for the old style system.
|
||||
ClearAllMapsFor(content);
|
||||
|
||||
if (nsCOMPtr<nsIContent> content = aContent) {
|
||||
content->UnbindFromTree();
|
||||
}
|
||||
}
|
||||
|
@ -694,168 +277,4 @@ void
|
|||
nsFrameManager::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
|
||||
{
|
||||
aSizes.mLayoutPresShellSize += aSizes.mState.mMallocSizeOf(this);
|
||||
if (mDisplayNoneMap) {
|
||||
mDisplayNoneMap->AddSizeOfIncludingThis(aSizes);
|
||||
}
|
||||
if (mDisplayContentsMap) {
|
||||
mDisplayContentsMap->AddSizeOfIncludingThis(aSizes);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
nsFrameManager::UndisplayedMap::UndisplayedMap()
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsFrameManager::UndisplayedMap);
|
||||
}
|
||||
|
||||
nsFrameManager::UndisplayedMap::~UndisplayedMap(void)
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsFrameManager::UndisplayedMap);
|
||||
Clear();
|
||||
}
|
||||
|
||||
void
|
||||
nsFrameManager::UndisplayedMap::Clear()
|
||||
{
|
||||
for (auto iter = Iter(); !iter.Done(); iter.Next()) {
|
||||
auto* list = iter.UserData();
|
||||
while (auto* node = list->popFirst()) {
|
||||
delete node;
|
||||
}
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsIContent*
|
||||
nsFrameManager::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 (aParent && aParent->IsActiveChildrenElement()) {
|
||||
return aParent->GetParent();
|
||||
}
|
||||
|
||||
return aParent;
|
||||
}
|
||||
|
||||
LinkedList<UndisplayedNode>*
|
||||
nsFrameManager::UndisplayedMap::GetListFor(nsIContent* aParent)
|
||||
{
|
||||
MOZ_ASSERT(aParent == GetApplicableParent(aParent),
|
||||
"The parent that we use as the hash key must have been normalized");
|
||||
|
||||
LinkedList<UndisplayedNode>* list;
|
||||
if (Get(aParent, &list)) {
|
||||
return list;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LinkedList<UndisplayedNode>*
|
||||
nsFrameManager::UndisplayedMap::GetOrCreateListFor(nsIContent* aParent)
|
||||
{
|
||||
MOZ_ASSERT(aParent == GetApplicableParent(aParent),
|
||||
"The parent that we use as the hash key must have been normalized");
|
||||
|
||||
return LookupOrAdd(aParent);
|
||||
}
|
||||
|
||||
|
||||
UndisplayedNode*
|
||||
nsFrameManager::UndisplayedMap::GetFirstNode(nsIContent* aParentContent)
|
||||
{
|
||||
auto* list = GetListFor(aParentContent);
|
||||
return list ? list->getFirst() : nullptr;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsFrameManager::UndisplayedMap::AppendNodeFor(UndisplayedNode* aNode,
|
||||
nsIContent* aParentContent)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
nsFrameManager::UndisplayedMap::AddNodeFor(nsIContent* aParentContent,
|
||||
nsIContent* aChild,
|
||||
ComputedStyle* aStyle)
|
||||
{
|
||||
UndisplayedNode* node = new UndisplayedNode(aChild, aStyle);
|
||||
AppendNodeFor(node, aParentContent);
|
||||
}
|
||||
|
||||
void
|
||||
nsFrameManager::UndisplayedMap::RemoveNodeFor(nsIContent* aParentContent,
|
||||
UndisplayedNode* aNode)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
auto list = GetListFor(aParentContent);
|
||||
MOZ_ASSERT(list, "content not in map");
|
||||
aNode->removeFrom(*list);
|
||||
#else
|
||||
aNode->remove();
|
||||
#endif
|
||||
delete aNode;
|
||||
}
|
||||
|
||||
|
||||
nsAutoPtr<LinkedList<UndisplayedNode>>
|
||||
nsFrameManager::UndisplayedMap::UnlinkNodesFor(nsIContent* aParentContent)
|
||||
{
|
||||
nsAutoPtr<LinkedList<UndisplayedNode>> list;
|
||||
Remove(GetApplicableParent(aParentContent), &list);
|
||||
return list;
|
||||
}
|
||||
|
||||
void
|
||||
nsFrameManager::UndisplayedMap::RemoveNodesFor(nsIContent* aParentContent)
|
||||
{
|
||||
nsAutoPtr<LinkedList<UndisplayedNode>> list = UnlinkNodesFor(aParentContent);
|
||||
if (list) {
|
||||
while (auto* node = list->popFirst()) {
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsFrameManager::UndisplayedMap::
|
||||
AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
|
||||
{
|
||||
MallocSizeOf mallocSizeOf = aSizes.mState.mMallocSizeOf;
|
||||
aSizes.mLayoutPresShellSize += ShallowSizeOfIncludingThis(mallocSizeOf);
|
||||
|
||||
nsWindowSizes staleSizes(aSizes.mState);
|
||||
for (auto iter = ConstIter(); !iter.Done(); iter.Next()) {
|
||||
const LinkedList<UndisplayedNode>* list = iter.UserData();
|
||||
aSizes.mLayoutPresShellSize += list->sizeOfExcludingThis(mallocSizeOf);
|
||||
for (const UndisplayedNode* node = list->getFirst();
|
||||
node; node = node->getNext()) {
|
||||
ComputedStyle* computedStyle = node->mStyle;
|
||||
if (!aSizes.mState.HaveSeenPtr(computedStyle)) {
|
||||
computedStyle->AddSizeOfIncludingThis(
|
||||
staleSizes, &aSizes.mLayoutComputedValuesStale);
|
||||
}
|
||||
}
|
||||
}
|
||||
aSizes.mLayoutComputedValuesStale += staleSizes.getTotalSize();
|
||||
}
|
||||
|
|
|
@ -19,10 +19,6 @@ class nsILayoutHistoryState;
|
|||
class nsIPresShell;
|
||||
class nsPlaceholderFrame;
|
||||
class nsWindowSizes;
|
||||
namespace mozilla {
|
||||
class ComputedStyle;
|
||||
struct UndisplayedNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frame manager interface. The frame manager serves one purpose:
|
||||
|
@ -35,16 +31,12 @@ struct UndisplayedNode;
|
|||
*/
|
||||
class nsFrameManager
|
||||
{
|
||||
typedef mozilla::ComputedStyle ComputedStyle;
|
||||
typedef mozilla::layout::FrameChildListID ChildListID;
|
||||
typedef mozilla::UndisplayedNode UndisplayedNode;
|
||||
|
||||
public:
|
||||
explicit nsFrameManager(nsIPresShell* aPresShell)
|
||||
: mPresShell(aPresShell)
|
||||
, mRootFrame(nullptr)
|
||||
, mDisplayNoneMap(nullptr)
|
||||
, mDisplayContentsMap(nullptr)
|
||||
, mIsDestroyingFrames(false)
|
||||
{
|
||||
MOZ_ASSERT(mPresShell, "need a pres shell");
|
||||
|
@ -72,98 +64,6 @@ public:
|
|||
*/
|
||||
void Destroy();
|
||||
|
||||
|
||||
// display:none and display:contents content does not get an nsIFrame. To
|
||||
// enable the style for such content to be obtained we store them in a
|
||||
// couple of hash tables. The following methods provide the API that's used
|
||||
// to set, reset, obtain and clear these styles.
|
||||
//
|
||||
// FIXME(stylo-everywhere): This should go away now.
|
||||
|
||||
/**
|
||||
* Register the style for the display:none content, aContent.
|
||||
*/
|
||||
void RegisterDisplayNoneStyleFor(nsIContent* aContent,
|
||||
ComputedStyle* aComputedStyle);
|
||||
|
||||
/**
|
||||
* Register the style for the display:contents content, aContent.
|
||||
*/
|
||||
void RegisterDisplayContentsStyleFor(nsIContent* aContent,
|
||||
ComputedStyle* aComputedStyle);
|
||||
|
||||
/**
|
||||
* Change the style for the display:none content, aContent.
|
||||
*/
|
||||
void ChangeRegisteredDisplayNoneStyleFor(nsIContent* aContent,
|
||||
ComputedStyle* aComputedStyle)
|
||||
{
|
||||
ChangeComputedStyleInMap(mDisplayNoneMap, aContent, aComputedStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the style for the display:contents content, aContent.
|
||||
*/
|
||||
void ChangeRegisteredDisplayContentsStyleFor(nsIContent* aContent,
|
||||
ComputedStyle* aComputedStyle)
|
||||
{
|
||||
ChangeComputedStyleInMap(mDisplayContentsMap, aContent, aComputedStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the style for the display:none content, aContent, if any.
|
||||
*/
|
||||
ComputedStyle* GetDisplayNoneStyleFor(const nsIContent* aContent)
|
||||
{
|
||||
if (!mDisplayNoneMap) {
|
||||
return nullptr;
|
||||
}
|
||||
return GetComputedStyleInMap(mDisplayNoneMap, aContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the style for the display:contents content, aContent, if any.
|
||||
*/
|
||||
ComputedStyle* GetDisplayContentsStyleFor(const nsIContent* aContent)
|
||||
{
|
||||
if (!mDisplayContentsMap) {
|
||||
return nullptr;
|
||||
}
|
||||
return GetComputedStyleInMap(mDisplayContentsMap, aContent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the linked list of UndisplayedNodes that contain the styles that
|
||||
* been registered for the display:none children of aParentContent.
|
||||
*/
|
||||
UndisplayedNode*
|
||||
GetAllRegisteredDisplayNoneStylesIn(nsIContent* aParentContent);
|
||||
|
||||
/**
|
||||
* Return the linked list of UndisplayedNodes that contain the styles
|
||||
* that have been registered for the display:contents children of
|
||||
* aParentContent.
|
||||
*/
|
||||
UndisplayedNode*
|
||||
GetAllRegisteredDisplayContentsStylesIn(nsIContent* aParentContent);
|
||||
|
||||
/**
|
||||
* Unregister the style for the display:none content, aContent, if
|
||||
* any. If found, then this method also unregisters the styles for any
|
||||
* display:contents and display:none descendants of aContent.
|
||||
*/
|
||||
void UnregisterDisplayNoneStyleFor(nsIContent* aContent,
|
||||
nsIContent* aParentContent);
|
||||
|
||||
/**
|
||||
* Unregister the style for the display:contents content, aContent, if any.
|
||||
* If found, then this method also unregisters the style for any
|
||||
* display:contents and display:none descendants of aContent.
|
||||
*/
|
||||
void UnregisterDisplayContentsStyleFor(nsIContent* aContent,
|
||||
nsIContent* aParentContent);
|
||||
|
||||
|
||||
// Functions for manipulating the frame model
|
||||
void AppendFrames(nsContainerFrame* aParentFrame,
|
||||
ChildListID aListID,
|
||||
|
@ -176,12 +76,6 @@ public:
|
|||
|
||||
void RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame);
|
||||
|
||||
/*
|
||||
* Notification that a frame is about to be destroyed. This allows any
|
||||
* outstanding references to the frame to be cleaned up.
|
||||
*/
|
||||
void NotifyDestroyingFrame(nsIFrame* aFrame);
|
||||
|
||||
/*
|
||||
* Capture/restore frame state for the frame subtree rooted at aFrame.
|
||||
* aState is the document state storage object onto which each frame
|
||||
|
@ -207,33 +101,9 @@ public:
|
|||
void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
|
||||
|
||||
protected:
|
||||
class UndisplayedMap;
|
||||
|
||||
static nsIContent* ParentForUndisplayedMap(const nsIContent* aContent);
|
||||
|
||||
void ClearAllMapsFor(nsIContent* aParentContent);
|
||||
|
||||
static ComputedStyle* GetComputedStyleInMap(UndisplayedMap* aMap,
|
||||
const nsIContent* aContent);
|
||||
static UndisplayedNode* GetUndisplayedNodeInMapFor(UndisplayedMap* aMap,
|
||||
const nsIContent* aContent);
|
||||
static UndisplayedNode* GetAllUndisplayedNodesInMapFor(UndisplayedMap* aMap,
|
||||
nsIContent* aParentContent);
|
||||
static void SetComputedStyleInMap(
|
||||
UndisplayedMap* aMap,
|
||||
nsIContent* aContent,
|
||||
ComputedStyle* aComputedStyle);
|
||||
|
||||
static void ChangeComputedStyleInMap(
|
||||
UndisplayedMap* aMap,
|
||||
nsIContent* aContent,
|
||||
ComputedStyle* aComputedStyle);
|
||||
|
||||
// weak link, because the pres shell owns us
|
||||
nsIPresShell* MOZ_NON_OWNING_REF mPresShell;
|
||||
nsIFrame* mRootFrame;
|
||||
UndisplayedMap* mDisplayNoneMap;
|
||||
UndisplayedMap* mDisplayContentsMap;
|
||||
bool mIsDestroyingFrames; // The frame manager is destroying some frame(s).
|
||||
};
|
||||
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "nsStyleChangeList.h"
|
||||
|
||||
#include "mozilla/dom/ElementInlines.h"
|
||||
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsIFrame.h"
|
||||
|
@ -29,9 +31,9 @@ nsStyleChangeList::AppendChange(nsIFrame* aFrame, nsIContent* aContent, nsChange
|
|||
// XXXbz we should make this take Element instead of nsIContent
|
||||
MOZ_ASSERT(!aContent || aContent->IsElement() ||
|
||||
// display:contents elements posts the changes for their children:
|
||||
(aFrame && aContent->GetParent() &&
|
||||
aFrame->PresContext()->FrameConstructor()->
|
||||
GetDisplayContentsStyleFor(aContent->GetParent())) ||
|
||||
(aFrame && aContent->GetFlattenedTreeParentElementForStyle() &&
|
||||
Servo_Element_IsDisplayContents(
|
||||
aContent->GetFlattenedTreeParentElementForStyle())) ||
|
||||
(aContent->IsNodeOfType(nsINode::eTEXT) &&
|
||||
aContent->HasFlag(NODE_NEEDS_FRAME) &&
|
||||
aHint & nsChangeHint_ReconstructFrame),
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ComputedStyle.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/dom/ElementInlines.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/PathHelpers.h"
|
||||
#include "mozilla/Sprintf.h"
|
||||
|
@ -106,6 +107,8 @@
|
|||
#include "mozilla/LookAndFeel.h"
|
||||
#include "mozilla/MouseEvents.h"
|
||||
#include "mozilla/ServoStyleSet.h"
|
||||
#include "mozilla/ServoStyleSetInlines.h"
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
#include "mozilla/gfx/Tools.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "ActiveLayerTracker.h"
|
||||
|
@ -9901,8 +9904,8 @@ nsFrame::DoGetParentComputedStyle(nsIFrame** aProviderFrame) const
|
|||
// Handle display:contents and the root frame, when there's no parent frame
|
||||
// to inherit from.
|
||||
if (MOZ_LIKELY(mContent)) {
|
||||
nsIContent* parentContent = mContent->GetFlattenedTreeParent();
|
||||
if (MOZ_LIKELY(parentContent)) {
|
||||
Element* parentElement = mContent->GetFlattenedTreeParentElement();
|
||||
if (MOZ_LIKELY(parentElement)) {
|
||||
nsAtom* pseudo = Style()->GetPseudo();
|
||||
if (!pseudo || !mContent->IsElement() ||
|
||||
(!nsCSSAnonBoxes::IsAnonBox(pseudo) &&
|
||||
|
@ -9913,10 +9916,15 @@ nsFrame::DoGetParentComputedStyle(nsIFrame** aProviderFrame) const
|
|||
/* if next is true then it's really a request for the table frame's
|
||||
parent context, see nsTable[Outer]Frame::GetParentComputedStyle. */
|
||||
pseudo == nsCSSAnonBoxes::tableWrapper) {
|
||||
nsCSSFrameConstructor* fm = PresContext()->FrameConstructor();
|
||||
ComputedStyle* sc = fm->GetDisplayContentsStyleFor(parentContent);
|
||||
if (MOZ_UNLIKELY(sc)) {
|
||||
return sc;
|
||||
if (Servo_Element_IsDisplayContents(parentElement)) {
|
||||
RefPtr<ComputedStyle> style =
|
||||
PresShell()->StyleSet()->ResolveServoStyle(parentElement);
|
||||
// NOTE(emilio): we return a weak reference because the element also
|
||||
// holds the style context alive. This is a bit silly (we could've
|
||||
// returned a weak ref directly), but it's probably not worth
|
||||
// optimizing, given this function has just one caller which is rare,
|
||||
// and this path is rare itself.
|
||||
return style;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -1588,6 +1588,13 @@ nsFrameSelection::RepaintSelection(SelectionType aSelectionType)
|
|||
return mDomSelections[index]->Repaint(mShell->GetPresContext());
|
||||
}
|
||||
|
||||
static bool
|
||||
IsDisplayContents(const nsIContent* aContent)
|
||||
{
|
||||
return aContent->IsElement() && aContent->AsElement()->HasServoData() &&
|
||||
Servo_Element_IsDisplayContents(aContent->AsElement());
|
||||
}
|
||||
|
||||
nsIFrame*
|
||||
nsFrameSelection::GetFrameForNodeOffset(nsIContent* aNode,
|
||||
int32_t aOffset,
|
||||
|
@ -1600,8 +1607,7 @@ nsFrameSelection::GetFrameForNodeOffset(nsIContent* aNode,
|
|||
if (aOffset < 0)
|
||||
return nullptr;
|
||||
|
||||
if (!aNode->GetPrimaryFrame() &&
|
||||
!mShell->FrameConstructor()->GetDisplayContentsStyleFor(aNode)) {
|
||||
if (!aNode->GetPrimaryFrame() && !IsDisplayContents(aNode)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxUtils.h"
|
||||
#include "mozilla/dom/ElementInlines.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/ServoStyleSetInlines.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
@ -215,14 +217,15 @@ nsPlaceholderFrame::GetParentComputedStyleForOutOfFlow(nsIFrame** aProviderFrame
|
|||
{
|
||||
NS_PRECONDITION(GetParent(), "How can we not have a parent here?");
|
||||
|
||||
nsIContent* parentContent = mContent ? mContent->GetFlattenedTreeParent() : nullptr;
|
||||
if (parentContent) {
|
||||
ComputedStyle* sc =
|
||||
PresContext()->FrameConstructor()->GetDisplayContentsStyleFor(parentContent);
|
||||
if (sc) {
|
||||
*aProviderFrame = nullptr;
|
||||
return sc;
|
||||
}
|
||||
Element* parentElement =
|
||||
mContent ? mContent->GetFlattenedTreeParentElement() : nullptr;
|
||||
if (parentElement && Servo_Element_IsDisplayContents(parentElement)) {
|
||||
RefPtr<ComputedStyle> style =
|
||||
PresShell()->StyleSet()->ResolveServoStyle(parentElement);
|
||||
*aProviderFrame = nullptr;
|
||||
// See the comment in GetParentComputedStyle to see why returning this as a
|
||||
// weak ref is fine.
|
||||
return style;
|
||||
}
|
||||
|
||||
return GetLayoutParentStyleForOutOfFlow(aProviderFrame);
|
||||
|
|
|
@ -37,6 +37,9 @@ SERVO_BINDING_FUNC(Servo_Element_GetPseudoComputedValues,
|
|||
SERVO_BINDING_FUNC(Servo_Element_IsDisplayNone,
|
||||
bool,
|
||||
RawGeckoElementBorrowed element)
|
||||
SERVO_BINDING_FUNC(Servo_Element_IsDisplayContents,
|
||||
bool,
|
||||
RawGeckoElementBorrowed element)
|
||||
SERVO_BINDING_FUNC(Servo_Element_IsPrimaryStyleReusedViaRuleNode,
|
||||
bool,
|
||||
RawGeckoElementBorrowed element)
|
||||
|
|
Загрузка…
Ссылка в новой задаче