mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-09 01:08:39 +09:00
Bug 1355351 - Make pseudo-elements return the correct style via getComputedStyle
* Add a node property to access the ::before and ::after pseudo-elements * Look for the frame for ::before and ::after pseudos * Clean up pseudo-element props * Simplify nsLayoutUtils callers, and make child iterators notice display: contents pseudos Tag #1375
This commit is contained in:
parent
6b48075b57
commit
d3ffda520f
16 changed files with 188 additions and 241 deletions
|
|
@ -3626,14 +3626,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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
return aContent->GetPrimaryFrame();
|
||||
}
|
||||
|
||||
if (!primaryFrame) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 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 "
|
||||
|
|
|
|||
|
|
@ -1832,11 +1832,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();
|
||||
|
||||
|
|
@ -1864,6 +1860,13 @@ 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);
|
||||
|
||||
|
|
@ -6079,6 +6082,9 @@ 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.
|
||||
|
||||
nsIFrame::ContentArray* value =
|
||||
aOwnerFrame->GetProperty(nsIFrame::GenConProperty());
|
||||
if (!value) {
|
||||
|
|
@ -6340,7 +6346,7 @@ AdjustAppendParentForAfterContent(nsFrameManager* aFrameManager,
|
|||
// 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() ||
|
||||
if (aParentFrame->GetProperty(nsIFrame::GenConProperty()) ||
|
||||
nsLayoutUtils::HasPseudoStyle(aContainer, aParentFrame->StyleContext(),
|
||||
CSSPseudoElementType::after,
|
||||
aParentFrame->PresContext()) ||
|
||||
|
|
@ -6669,9 +6675,8 @@ nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent* aContent,
|
|||
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);
|
||||
sibling = aPrevSibling ? nsLayoutUtils::GetAfterFrame(aContent)
|
||||
: nsLayoutUtils::GetBeforeFrame(aContent);
|
||||
if (!sibling) {
|
||||
// ... then recurse into children ...
|
||||
const bool forward = !aPrevSibling;
|
||||
|
|
@ -6682,9 +6687,8 @@ nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent* aContent,
|
|||
}
|
||||
if (!sibling) {
|
||||
// ... then ::after / ::before on the opposite end.
|
||||
sibling = aPrevSibling ?
|
||||
nsLayoutUtils::GetBeforeFrameForContent(aParentFrame, aContent) :
|
||||
nsLayoutUtils::GetAfterFrameForContent(aParentFrame, aContent);
|
||||
sibling = aPrevSibling ? nsLayoutUtils::GetAfterFrame(aContent)
|
||||
: nsLayoutUtils::GetBeforeFrame(aContent);
|
||||
}
|
||||
if (!sibling) {
|
||||
return nullptr;
|
||||
|
|
@ -8291,26 +8295,23 @@ 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;
|
||||
}
|
||||
while (!ancestor->GetPrimaryFrame()) {
|
||||
// FIXME(emilio): Should this use the flattened tree parent instead?
|
||||
ancestor = ancestor->GetParent();
|
||||
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;
|
||||
}
|
||||
|
||||
nsIFrame* ancestorFrame = ancestor->GetPrimaryFrame();
|
||||
if (ancestorFrame->GetProperty(nsIFrame::GenConProperty())) {
|
||||
*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;
|
||||
}
|
||||
|
||||
FlattenedChildIterator iter(aChild);
|
||||
|
|
|
|||
|
|
@ -1486,90 +1486,38 @@ nsLayoutUtils::GetChildListNameFor(nsIFrame* aChildFrame)
|
|||
return id;
|
||||
}
|
||||
|
||||
/*static*/ nsIFrame*
|
||||
nsLayoutUtils::GetBeforeFrameForContent(nsIFrame* aFrame,
|
||||
const nsIContent* aContent)
|
||||
static Element*
|
||||
GetPseudo(const nsIContent* aContent, nsIAtom* aPseudoProperty)
|
||||
{
|
||||
// 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;
|
||||
MOZ_ASSERT(aPseudoProperty == nsGkAtoms::beforePseudoProperty ||
|
||||
aPseudoProperty == nsGkAtoms::afterPseudoProperty);
|
||||
return static_cast<Element*>(aContent->GetProperty(aPseudoProperty));
|
||||
}
|
||||
|
||||
/*static*/ Element*
|
||||
nsLayoutUtils::GetBeforePseudo(const nsIContent* aContent)
|
||||
{
|
||||
return GetPseudo(aContent, nsGkAtoms::beforePseudoProperty);
|
||||
}
|
||||
|
||||
/*static*/ nsIFrame*
|
||||
nsLayoutUtils::GetBeforeFrame(nsIFrame* aFrame)
|
||||
nsLayoutUtils::GetBeforeFrame(const nsIContent* aContent)
|
||||
{
|
||||
return GetBeforeFrameForContent(aFrame, aFrame->GetContent());
|
||||
Element* pseudo = GetBeforePseudo(aContent);
|
||||
return pseudo ? pseudo->GetPrimaryFrame() : nullptr;
|
||||
}
|
||||
|
||||
/*static*/ Element*
|
||||
nsLayoutUtils::GetAfterPseudo(const nsIContent* aContent)
|
||||
{
|
||||
return GetPseudo(aContent, nsGkAtoms::afterPseudoProperty);
|
||||
}
|
||||
|
||||
/*static*/ nsIFrame*
|
||||
nsLayoutUtils::GetAfterFrameForContent(nsIFrame* aFrame,
|
||||
const nsIContent* aContent)
|
||||
nsLayoutUtils::GetAfterFrame(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;
|
||||
}
|
||||
|
||||
/*static*/ nsIFrame*
|
||||
nsLayoutUtils::GetAfterFrame(nsIFrame* aFrame)
|
||||
{
|
||||
return GetAfterFrameForContent(aFrame, aFrame->GetContent());
|
||||
Element* pseudo = GetAfterPseudo(aContent);
|
||||
return pseudo ? pseudo->GetPrimaryFrame() : nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue