mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-22 15:17:29 +09:00
Bug 1413619 - Fix insertion point computation when display: contents pseudos are involved.
Tag #1375
This commit is contained in:
parent
9b5061e795
commit
5b1452e120
10 changed files with 192 additions and 243 deletions
|
|
@ -192,17 +192,17 @@ FlattenedChildIterator::Init(bool aIgnoreXBL)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ExplicitChildIterator::Seek(nsIContent* aChildToFind)
|
ExplicitChildIterator::Seek(const nsIContent* aChildToFind)
|
||||||
{
|
{
|
||||||
if (aChildToFind->GetParent() == mParent &&
|
if (aChildToFind->GetParent() == mParent &&
|
||||||
!aChildToFind->IsRootOfAnonymousSubtree()) {
|
!aChildToFind->IsRootOfAnonymousSubtree()) {
|
||||||
// Fast path: just point ourselves to aChildToFind, which is a
|
// Fast path: just point ourselves to aChildToFind, which is a
|
||||||
// normal DOM child of ours.
|
// normal DOM child of ours.
|
||||||
MOZ_ASSERT(!nsContentUtils::IsContentInsertionPoint(aChildToFind));
|
mChild = const_cast<nsIContent*>(aChildToFind);
|
||||||
mChild = aChildToFind;
|
|
||||||
mIndexInInserted = 0;
|
mIndexInInserted = 0;
|
||||||
mDefaultChild = nullptr;
|
mDefaultChild = nullptr;
|
||||||
mIsFirst = false;
|
mIsFirst = false;
|
||||||
|
MOZ_ASSERT(!nsContentUtils::IsContentInsertionPoint(mChild));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -348,7 +348,7 @@ AllChildrenIterator::Get() const
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
AllChildrenIterator::Seek(nsIContent* aChildToFind)
|
AllChildrenIterator::Seek(const nsIContent* aChildToFind)
|
||||||
{
|
{
|
||||||
if (mPhase == eAtBegin || mPhase == eAtBeforeKid) {
|
if (mPhase == eAtBegin || mPhase == eAtBeforeKid) {
|
||||||
mPhase = eAtExplicitKids;
|
mPhase = eAtExplicitKids;
|
||||||
|
|
|
||||||
|
|
@ -58,13 +58,13 @@ public:
|
||||||
// found. This version can take shortcuts that the two-argument version
|
// found. This version can take shortcuts that the two-argument version
|
||||||
// can't, so can be faster (and in fact can be O(1) instead of O(N) in many
|
// can't, so can be faster (and in fact can be O(1) instead of O(N) in many
|
||||||
// cases).
|
// cases).
|
||||||
bool Seek(nsIContent* aChildToFind);
|
bool Seek(const nsIContent* aChildToFind);
|
||||||
|
|
||||||
// Looks for aChildToFind respecting insertion points until aChildToFind is found.
|
// Looks for aChildToFind respecting insertion points until aChildToFind is found.
|
||||||
// or aBound is found. If aBound is nullptr then the seek is unbounded. Returns
|
// or aBound is found. If aBound is nullptr then the seek is unbounded. Returns
|
||||||
// whether aChildToFind was found as an explicit child prior to encountering
|
// whether aChildToFind was found as an explicit child prior to encountering
|
||||||
// aBound.
|
// aBound.
|
||||||
bool Seek(nsIContent* aChildToFind, nsIContent* aBound)
|
bool Seek(const nsIContent* aChildToFind, nsIContent* aBound)
|
||||||
{
|
{
|
||||||
// It would be nice to assert that we find aChildToFind, but bz thinks that
|
// It would be nice to assert that we find aChildToFind, but bz thinks that
|
||||||
// we might not find aChildToFind when called from ContentInserted
|
// we might not find aChildToFind when called from ContentInserted
|
||||||
|
|
@ -131,19 +131,29 @@ class FlattenedChildIterator : public ExplicitChildIterator
|
||||||
public:
|
public:
|
||||||
explicit FlattenedChildIterator(const nsIContent* aParent,
|
explicit FlattenedChildIterator(const nsIContent* aParent,
|
||||||
bool aStartAtBeginning = true)
|
bool aStartAtBeginning = true)
|
||||||
: ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
|
: ExplicitChildIterator(aParent, aStartAtBeginning)
|
||||||
|
, mXBLInvolved(false)
|
||||||
|
, mOriginalContent(aParent)
|
||||||
{
|
{
|
||||||
Init(false);
|
Init(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
FlattenedChildIterator(FlattenedChildIterator&& aOther)
|
FlattenedChildIterator(FlattenedChildIterator&& aOther)
|
||||||
: ExplicitChildIterator(Move(aOther)), mXBLInvolved(aOther.mXBLInvolved) {}
|
: ExplicitChildIterator(Move(aOther))
|
||||||
|
, mXBLInvolved(aOther.mXBLInvolved)
|
||||||
|
, mOriginalContent(aOther.mOriginalContent)
|
||||||
|
{}
|
||||||
|
|
||||||
FlattenedChildIterator(const FlattenedChildIterator& aOther)
|
FlattenedChildIterator(const FlattenedChildIterator& aOther)
|
||||||
: ExplicitChildIterator(aOther), mXBLInvolved(aOther.mXBLInvolved) {}
|
: ExplicitChildIterator(aOther)
|
||||||
|
, mXBLInvolved(aOther.mXBLInvolved)
|
||||||
|
, mOriginalContent(aOther.mOriginalContent)
|
||||||
|
{}
|
||||||
|
|
||||||
bool XBLInvolved() { return mXBLInvolved; }
|
bool XBLInvolved() { return mXBLInvolved; }
|
||||||
|
|
||||||
|
const nsIContent* Parent() const { return mOriginalContent; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* This constructor is a hack to help AllChildrenIterator which sometimes
|
* This constructor is a hack to help AllChildrenIterator which sometimes
|
||||||
|
|
@ -151,7 +161,9 @@ protected:
|
||||||
*/
|
*/
|
||||||
FlattenedChildIterator(const nsIContent* aParent, uint32_t aFlags,
|
FlattenedChildIterator(const nsIContent* aParent, uint32_t aFlags,
|
||||||
bool aStartAtBeginning = true)
|
bool aStartAtBeginning = true)
|
||||||
: ExplicitChildIterator(aParent, aStartAtBeginning), mXBLInvolved(false)
|
: ExplicitChildIterator(aParent, aStartAtBeginning)
|
||||||
|
, mXBLInvolved(false)
|
||||||
|
, mOriginalContent(aParent)
|
||||||
{
|
{
|
||||||
bool ignoreXBL = aFlags & nsIContent::eAllButXBL;
|
bool ignoreXBL = aFlags & nsIContent::eAllButXBL;
|
||||||
Init(ignoreXBL);
|
Init(ignoreXBL);
|
||||||
|
|
@ -162,6 +174,8 @@ protected:
|
||||||
// For certain optimizations, nsCSSFrameConstructor needs to know if the
|
// For certain optimizations, nsCSSFrameConstructor needs to know if the
|
||||||
// child list of the element that we're iterating matches its .childNodes.
|
// child list of the element that we're iterating matches its .childNodes.
|
||||||
bool mXBLInvolved;
|
bool mXBLInvolved;
|
||||||
|
|
||||||
|
const nsIContent* mOriginalContent;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -179,12 +193,11 @@ public:
|
||||||
AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags,
|
AllChildrenIterator(const nsIContent* aNode, uint32_t aFlags,
|
||||||
bool aStartAtBeginning = true) :
|
bool aStartAtBeginning = true) :
|
||||||
FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
|
FlattenedChildIterator(aNode, aFlags, aStartAtBeginning),
|
||||||
mOriginalContent(aNode), mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
|
mAnonKidsIdx(aStartAtBeginning ? UINT32_MAX : 0),
|
||||||
mFlags(aFlags), mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) { }
|
mFlags(aFlags), mPhase(aStartAtBeginning ? eAtBegin : eAtEnd) { }
|
||||||
|
|
||||||
AllChildrenIterator(AllChildrenIterator&& aOther)
|
AllChildrenIterator(AllChildrenIterator&& aOther)
|
||||||
: FlattenedChildIterator(Move(aOther)),
|
: FlattenedChildIterator(Move(aOther)),
|
||||||
mOriginalContent(aOther.mOriginalContent),
|
|
||||||
mAnonKids(Move(aOther.mAnonKids)), mAnonKidsIdx(aOther.mAnonKidsIdx),
|
mAnonKids(Move(aOther.mAnonKids)), mAnonKidsIdx(aOther.mAnonKidsIdx),
|
||||||
mFlags(aOther.mFlags), mPhase(aOther.mPhase)
|
mFlags(aOther.mFlags), mPhase(aOther.mPhase)
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
@ -203,11 +216,10 @@ public:
|
||||||
// Seeks the given node in children of a parent element, starting from
|
// Seeks the given node in children of a parent element, starting from
|
||||||
// the current iterator's position, and sets the iterator at the given child
|
// the current iterator's position, and sets the iterator at the given child
|
||||||
// node if it was found.
|
// node if it was found.
|
||||||
bool Seek(nsIContent* aChildToFind);
|
bool Seek(const nsIContent* aChildToFind);
|
||||||
|
|
||||||
nsIContent* GetNextChild();
|
nsIContent* GetNextChild();
|
||||||
nsIContent* GetPreviousChild();
|
nsIContent* GetPreviousChild();
|
||||||
const nsIContent* Parent() const { return mOriginalContent; }
|
|
||||||
|
|
||||||
enum IteratorPhase
|
enum IteratorPhase
|
||||||
{
|
{
|
||||||
|
|
@ -225,8 +237,6 @@ private:
|
||||||
void AppendNativeAnonymousChildren();
|
void AppendNativeAnonymousChildren();
|
||||||
void AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame);
|
void AppendNativeAnonymousChildrenFromFrame(nsIFrame* aFrame);
|
||||||
|
|
||||||
const nsIContent* mOriginalContent;
|
|
||||||
|
|
||||||
// mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
|
// mAnonKids is an array of native anonymous children, mAnonKidsIdx is index
|
||||||
// in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is
|
// in the array. If mAnonKidsIdx < mAnonKids.Length() and mPhase is
|
||||||
// eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If
|
// eAtAnonKids then the iterator points at a child at mAnonKidsIdx index. If
|
||||||
|
|
|
||||||
|
|
@ -6662,115 +6662,147 @@ nsCSSFrameConstructor::IsValidSibling(nsIFrame* aSibling,
|
||||||
return true;
|
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*
|
nsIFrame*
|
||||||
nsCSSFrameConstructor::FindFrameForContentSibling(nsIContent* aContent,
|
nsCSSFrameConstructor::FindSiblingInternal(
|
||||||
nsIContent* aTargetContent,
|
FlattenedChildIterator aIter,
|
||||||
StyleDisplay& aTargetContentDisplay,
|
nsIContent* aTargetContent,
|
||||||
nsContainerFrame* aParentFrame,
|
StyleDisplay& aTargetContentDisplay)
|
||||||
bool aPrevSibling)
|
|
||||||
{
|
{
|
||||||
nsIFrame* sibling = aContent->GetPrimaryFrame();
|
auto adjust = [&](nsIFrame* aPotentialSiblingFrame) -> nsIFrame* {
|
||||||
if (!sibling && GetDisplayContentsStyleFor(aContent)) {
|
return AdjustSiblingFrame(
|
||||||
// A display:contents node - check if it has a ::before / ::after frame...
|
aPotentialSiblingFrame, aTargetContent, aTargetContentDisplay,
|
||||||
sibling = aPrevSibling ? nsLayoutUtils::GetAfterFrame(aContent)
|
aDirection);
|
||||||
: nsLayoutUtils::GetBeforeFrame(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);
|
|
||||||
|
|
||||||
// The recursion above has already done all the placeholder and
|
auto nextDomSibling = [](FlattenedChildIterator& aIter) -> nsIContent* {
|
||||||
// continuation fixups.
|
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) {
|
if (sibling) {
|
||||||
return sibling;
|
return sibling;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!sibling) {
|
}
|
||||||
// ... then ::after / ::before on the opposite end.
|
|
||||||
sibling = aPrevSibling ? nsLayoutUtils::GetAfterFrame(aContent)
|
return adjust(getFarPseudo(aIter.Parent()));
|
||||||
: nsLayoutUtils::GetBeforeFrame(aContent);
|
}
|
||||||
}
|
|
||||||
if (!sibling) {
|
nsIFrame*
|
||||||
return nullptr;
|
nsCSSFrameConstructor::AdjustSiblingFrame(
|
||||||
}
|
nsIFrame* aSibling,
|
||||||
} else if (!sibling || sibling->GetContent() != aContent) {
|
nsIContent* aTargetContent,
|
||||||
// XXX the GetContent() != aContent check is needed due to bug 135040.
|
mozilla::StyleDisplay& aTargetContentDisplay,
|
||||||
// Remove it once that's fixed.
|
SiblingDirection aDirection)
|
||||||
|
{
|
||||||
|
if (!aSibling) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the frame is out-of-flow, GetPrimaryFrame() will have returned the
|
if (aSibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
|
||||||
// out-of-flow frame; we want the placeholder.
|
aSibling = aSibling->GetPlaceholderFrame();
|
||||||
if (sibling->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
|
MOZ_ASSERT(aSibling);
|
||||||
nsIFrame* placeholderFrame = sibling->GetPlaceholderFrame();
|
|
||||||
NS_ASSERTION(placeholderFrame, "no placeholder for out-of-flow frame");
|
|
||||||
sibling = placeholderFrame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The frame we have now should never be a continuation.
|
MOZ_ASSERT(!aSibling->GetPrevContinuation(), "How?");
|
||||||
NS_ASSERTION(!sibling->GetPrevContinuation(), "How did that happen?");
|
if (aDirection == SiblingDirection::Backward) {
|
||||||
|
// The frame may be a ib-split frame (a split inline frame that contains a
|
||||||
if (aPrevSibling) {
|
// block). Get the last part of that split.
|
||||||
// The frame may be a ib-split frame (a split inline frame that
|
if (IsFramePartOfIBSplit(aSibling)) {
|
||||||
// contains a block). Get the last part of that split.
|
aSibling = GetLastIBSplitSibling(aSibling, true);
|
||||||
if (IsFramePartOfIBSplit(sibling)) {
|
|
||||||
sibling = GetLastIBSplitSibling(sibling, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The frame may have a continuation. If so, we want the last
|
// The frame may have a continuation. If so, we want the last
|
||||||
// non-overflow-container continuation as our previous sibling.
|
// non-overflow-container continuation as our previous sibling.
|
||||||
sibling = sibling->GetTailContinuation();
|
aSibling = aSibling->GetTailContinuation();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aTargetContent &&
|
if (!IsValidSibling(aSibling, aTargetContent, aTargetContentDisplay)) {
|
||||||
!IsValidSibling(sibling, aTargetContent, aTargetContentDisplay)) {
|
return nullptr;
|
||||||
sibling = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sibling;
|
return aSibling;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIFrame*
|
nsIFrame*
|
||||||
nsCSSFrameConstructor::FindPreviousSibling(FlattenedChildIterator aIter,
|
nsCSSFrameConstructor::FindPreviousSibling(const FlattenedChildIterator& aIter,
|
||||||
nsIContent* aTargetContent,
|
StyleDisplay& aTargetContentDisplay)
|
||||||
StyleDisplay& aTargetContentDisplay,
|
|
||||||
nsContainerFrame* aParentFrame)
|
|
||||||
{
|
{
|
||||||
// Note: not all content objects are associated with a frame (e.g., if it's
|
return FindSibling<SiblingDirection::Backward>(aIter, aTargetContentDisplay);
|
||||||
// `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 nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIFrame*
|
nsIFrame*
|
||||||
nsCSSFrameConstructor::FindNextSibling(FlattenedChildIterator aIter,
|
nsCSSFrameConstructor::FindNextSibling(const FlattenedChildIterator& aIter,
|
||||||
nsIContent* aTargetContent,
|
StyleDisplay& aTargetContentDisplay)
|
||||||
StyleDisplay& aTargetContentDisplay,
|
|
||||||
nsContainerFrame* aParentFrame)
|
|
||||||
{
|
{
|
||||||
while (nsIContent* sibling = aIter.GetNextChild()) {
|
return FindSibling<SiblingDirection::Forward>(aIter, aTargetContentDisplay);
|
||||||
MOZ_ASSERT(sibling != aTargetContent);
|
}
|
||||||
nsIFrame* nextSibling =
|
|
||||||
FindFrameForContentSibling(sibling, aTargetContent, aTargetContentDisplay,
|
|
||||||
aParentFrame, false);
|
|
||||||
|
|
||||||
if (nextSibling) {
|
template<nsCSSFrameConstructor::SiblingDirection aDirection>
|
||||||
// We found a next sibling, we're done!
|
nsIFrame*
|
||||||
return nextSibling;
|
nsCSSFrameConstructor::FindSibling(const FlattenedChildIterator& aIter,
|
||||||
|
StyleDisplay& aTargetContentDisplay)
|
||||||
|
{
|
||||||
|
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");
|
||||||
|
|
||||||
|
FlattenedChildIterator iter(parent);
|
||||||
|
iter.Seek(current);
|
||||||
|
sibling = FindSiblingInternal<aDirection>(
|
||||||
|
iter, targetContent, aTargetContentDisplay);
|
||||||
|
if (sibling) {
|
||||||
|
return sibling;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
current = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -6836,8 +6868,7 @@ nsCSSFrameConstructor::GetInsertionPrevSibling(InsertionPoint* aInsertion,
|
||||||
// Note that FindPreviousSibling is passed the iterator by value, so that
|
// Note that FindPreviousSibling is passed the iterator by value, so that
|
||||||
// the later usage of the iterator starts from the same place.
|
// the later usage of the iterator starts from the same place.
|
||||||
StyleDisplay childDisplay = UNSET_DISPLAY;
|
StyleDisplay childDisplay = UNSET_DISPLAY;
|
||||||
nsIFrame* prevSibling =
|
nsIFrame* prevSibling = FindPreviousSibling(iter, childDisplay);
|
||||||
FindPreviousSibling(iter, iter.Get(), childDisplay, aInsertion->mParentFrame);
|
|
||||||
|
|
||||||
// Now, find the geometric parent so that we can handle
|
// Now, find the geometric parent so that we can handle
|
||||||
// continuations properly. Use the prev sibling if we have it;
|
// continuations properly. Use the prev sibling if we have it;
|
||||||
|
|
@ -6850,34 +6881,7 @@ nsCSSFrameConstructor::GetInsertionPrevSibling(InsertionPoint* aInsertion,
|
||||||
iter.Seek(aEndSkipChild);
|
iter.Seek(aEndSkipChild);
|
||||||
iter.GetPreviousChild();
|
iter.GetPreviousChild();
|
||||||
}
|
}
|
||||||
nsIFrame* nextSibling =
|
nsIFrame* nextSibling = FindNextSibling(iter, childDisplay);
|
||||||
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 (nextSibling) {
|
||||||
aInsertion->mParentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
|
aInsertion->mParentFrame = nextSibling->GetParent()->GetContentInsertionFrame();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -8022,22 +8026,6 @@ nsCSSFrameConstructor::ContentRangeInserted(nsIContent* aContainer,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
FrameConstructionItemList items;
|
||||||
ParentType parentType = GetParentType(frameType);
|
ParentType parentType = GetParentType(frameType);
|
||||||
FlattenedChildIterator iter(aContainer);
|
FlattenedChildIterator iter(aContainer);
|
||||||
|
|
|
||||||
|
|
@ -1962,64 +1962,53 @@ private:
|
||||||
nsIFrame* aPrevSibling,
|
nsIFrame* aPrevSibling,
|
||||||
nsFrameItems& aFrameItems);
|
nsFrameItems& aFrameItems);
|
||||||
|
|
||||||
/**
|
// The direction in which we should look for siblings.
|
||||||
* Find the right frame to use for aContent when looking for sibling
|
enum class SiblingDirection
|
||||||
* frames for aTargetContent. If aPrevSibling is true, this
|
{
|
||||||
* will look for last continuations, etc, as necessary. This calls
|
Forward,
|
||||||
* IsValidSibling as needed; if that returns false it returns null.
|
Backward,
|
||||||
*
|
};
|
||||||
* @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
|
* Find the frame for the content immediately next to the one aIter points to,
|
||||||
* points to, following continuations if necessary. aIter is passed by
|
* in the direction SiblingDirection indicates, following continuations if
|
||||||
* value on purpose, so as not to modify the caller's iterator.
|
* necessary.
|
||||||
|
*
|
||||||
|
* 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()
|
* @param aIter should be positioned such that aIter.GetPreviousChild()
|
||||||
* is the first content to search for frames
|
* 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 the content aIter
|
||||||
* @param aTargetContentDisplay the CSS display enum for aTargetContent if
|
* points to if already known, UNSET_DISPLAY otherwise. It will be
|
||||||
* already known, UNSET_DISPLAY otherwise. It will be filled in
|
* filled in if needed.
|
||||||
* if needed.
|
|
||||||
* @param aParentFrame the nearest ancestor frame, used inernally for
|
|
||||||
* finding ::after / ::before frames
|
|
||||||
*/
|
*/
|
||||||
nsIFrame* FindPreviousSibling(mozilla::dom::FlattenedChildIterator aIter,
|
template<SiblingDirection>
|
||||||
nsIContent* aTargetContent,
|
nsIFrame* FindSibling(const mozilla::dom::FlattenedChildIterator& aIter,
|
||||||
mozilla::StyleDisplay& aTargetContentDisplay,
|
mozilla::StyleDisplay& aTargetContentDisplay);
|
||||||
nsContainerFrame* aParentFrame);
|
|
||||||
|
|
||||||
/**
|
// Helper for the implementation of FindSibling.
|
||||||
* Find the frame for the content node immediately following the one aIter
|
template<SiblingDirection>
|
||||||
* points to, following continuations if necessary. aIter is passed by value
|
nsIFrame* FindSiblingInternal(
|
||||||
* on purpose, so as not to modify the caller's iterator.
|
mozilla::dom::FlattenedChildIterator,
|
||||||
*
|
nsIContent* aTargetContent,
|
||||||
* @param aIter should be positioned such that aIter.GetNextChild()
|
mozilla::StyleDisplay& aTargetContentDisplay);
|
||||||
* is the first content to search for frames
|
|
||||||
* @param aTargetContent the content we're finding a sibling frame for
|
// An alias of FindSibling<SiblingDirection::Forward>.
|
||||||
* @param aTargetContentDisplay the CSS display enum for aTargetContent if
|
nsIFrame* FindNextSibling(const mozilla::dom::FlattenedChildIterator& aIter,
|
||||||
* already known, UNSET_DISPLAY otherwise. It will be filled in
|
mozilla::StyleDisplay& aTargetContentDisplay);
|
||||||
* if needed.
|
// An alias of FindSibling<SiblingDirection::Backwards>.
|
||||||
* @param aParentFrame the nearest ancestor frame, used inernally for
|
nsIFrame* FindPreviousSibling(const mozilla::dom::FlattenedChildIterator& aIter,
|
||||||
* finding ::after / ::before frames
|
mozilla::StyleDisplay& aTargetContentDisplay);
|
||||||
*/
|
|
||||||
nsIFrame* FindNextSibling(mozilla::dom::FlattenedChildIterator aIter,
|
// Given a potential first-continuation sibling frame for aTargetContent,
|
||||||
nsIContent* aTargetContent,
|
// verify that it is an actual valid sibling for it, and return the
|
||||||
mozilla::StyleDisplay& aTargetContentDisplay,
|
// appropriate continuation the new frame for aTargetContent should be
|
||||||
nsContainerFrame* aParentFrame);
|
// 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
|
// 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
|
// parent frame to point to the correct continuation of the parent frame to
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,8 @@ nsFrameManager::Destroy()
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
/* static */ nsStyleContext*
|
/* static */ nsStyleContext*
|
||||||
nsFrameManager::GetStyleContextInMap(UndisplayedMap* aMap, nsIContent* aContent)
|
nsFrameManager::GetStyleContextInMap(UndisplayedMap* aMap,
|
||||||
|
const nsIContent* aContent)
|
||||||
{
|
{
|
||||||
if (!aContent) {
|
if (!aContent) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ public:
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
// Mapping undisplayed content
|
// Mapping undisplayed content
|
||||||
nsStyleContext* GetUndisplayedContent(nsIContent* aContent)
|
nsStyleContext* GetUndisplayedContent(const nsIContent* aContent)
|
||||||
{
|
{
|
||||||
if (!mUndisplayedMap) {
|
if (!mUndisplayedMap) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -105,7 +105,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* Return the registered display:contents style context for aContent, if any.
|
* Return the registered display:contents style context for aContent, if any.
|
||||||
*/
|
*/
|
||||||
nsStyleContext* GetDisplayContentsStyleFor(nsIContent* aContent)
|
nsStyleContext* GetDisplayContentsStyleFor(const nsIContent* aContent)
|
||||||
{
|
{
|
||||||
if (!mDisplayContentsMap) {
|
if (!mDisplayContentsMap) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -185,7 +185,7 @@ public:
|
||||||
nsILayoutHistoryState* aState);
|
nsILayoutHistoryState* aState);
|
||||||
protected:
|
protected:
|
||||||
static nsStyleContext* GetStyleContextInMap(UndisplayedMap* aMap,
|
static nsStyleContext* GetStyleContextInMap(UndisplayedMap* aMap,
|
||||||
nsIContent* aContent);
|
const nsIContent* aContent);
|
||||||
static mozilla::UndisplayedNode*
|
static mozilla::UndisplayedNode*
|
||||||
GetAllUndisplayedNodesInMapFor(UndisplayedMap* aMap,
|
GetAllUndisplayedNodesInMapFor(UndisplayedMap* aMap,
|
||||||
nsIContent* aParentContent);
|
nsIContent* aParentContent);
|
||||||
|
|
|
||||||
|
|
@ -1587,33 +1587,6 @@ nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// static
|
||||||
nsIFrame*
|
nsIFrame*
|
||||||
nsLayoutUtils::GetCrossDocParentFrame(const nsIFrame* aFrame,
|
nsLayoutUtils::GetCrossDocParentFrame(const nsIFrame* aFrame,
|
||||||
|
|
|
||||||
|
|
@ -353,23 +353,6 @@ public:
|
||||||
*/
|
*/
|
||||||
static nsIFrame* GetRealPrimaryFrameFor(const nsIContent* aContent);
|
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
|
#ifdef DEBUG
|
||||||
// TODO: remove, see bug 598468.
|
// TODO: remove, see bug 598468.
|
||||||
static bool gPreventAssertInCompareTreePosition;
|
static bool gPreventAssertInCompareTreePosition;
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,7 @@ asserts(0-10) == grid-fragmentation-015.html grid-fragmentation-015-ref.html # b
|
||||||
== grid-fragmentation-dyn5-019.html grid-fragmentation-019-ref.html
|
== grid-fragmentation-dyn5-019.html grid-fragmentation-019-ref.html
|
||||||
== grid-fragmentation-dyn1-020.html grid-fragmentation-020-ref.html
|
== grid-fragmentation-dyn1-020.html grid-fragmentation-020-ref.html
|
||||||
== grid-fragmentation-dyn2-020.html grid-fragmentation-020-ref.html
|
== grid-fragmentation-dyn2-020.html grid-fragmentation-020-ref.html
|
||||||
!= grid-fragmentation-dyn1-021.html grid-fragmentation-021-ref.html # bug 1251799
|
== grid-fragmentation-dyn1-021.html grid-fragmentation-021-ref.html
|
||||||
== grid-fragmentation-dyn2-021.html grid-fragmentation-021-ref.html
|
== grid-fragmentation-dyn2-021.html grid-fragmentation-021-ref.html
|
||||||
== grid-fragmentation-dyn3-021.html grid-fragmentation-021-ref.html
|
== grid-fragmentation-dyn3-021.html grid-fragmentation-021-ref.html
|
||||||
== grid-fragmentation-dyn4-021.html grid-fragmentation-021-ref.html
|
== grid-fragmentation-dyn4-021.html grid-fragmentation-021-ref.html
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>CSS Test Reference</title>
|
||||||
|
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||||
|
PASS
|
||||||
Loading…
Add table
Add a link
Reference in a new issue