summaryrefslogtreecommitdiff
path: root/layout/generic
diff options
context:
space:
mode:
Diffstat (limited to 'layout/generic')
-rw-r--r--layout/generic/DetailsFrame.cpp9
-rw-r--r--layout/generic/DetailsFrame.h6
-rw-r--r--layout/generic/ReflowInput.cpp3
-rw-r--r--layout/generic/Selection.h4
-rw-r--r--layout/generic/crashtests/1381134-2.html45
-rw-r--r--layout/generic/crashtests/1381134.html45
-rw-r--r--layout/generic/crashtests/crashtests.list2
-rw-r--r--layout/generic/nsAbsoluteContainingBlock.cpp21
-rw-r--r--layout/generic/nsBlockFrame.cpp15
-rw-r--r--layout/generic/nsFirstLetterFrame.cpp3
-rw-r--r--layout/generic/nsFrame.cpp61
-rw-r--r--layout/generic/nsHTMLParts.h3
-rw-r--r--layout/generic/nsIAnonymousContentCreator.h17
-rw-r--r--layout/generic/nsIFrame.h24
-rw-r--r--layout/generic/nsIFrameInlines.h13
-rw-r--r--layout/generic/nsImageFrame.cpp14
-rw-r--r--layout/generic/nsPlaceholderFrame.cpp5
-rw-r--r--layout/generic/nsSelection.cpp103
-rw-r--r--layout/generic/nsTextFrame.cpp3
19 files changed, 264 insertions, 132 deletions
diff --git a/layout/generic/DetailsFrame.cpp b/layout/generic/DetailsFrame.cpp
index 1d28bbe960..389a476cba 100644
--- a/layout/generic/DetailsFrame.cpp
+++ b/layout/generic/DetailsFrame.cpp
@@ -129,3 +129,12 @@ DetailsFrame::AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
aElements.AppendElement(mDefaultSummary);
}
}
+
+bool
+DetailsFrame::HasMainSummaryFrame(nsIFrame* aSummaryFrame)
+{
+ nsIFrame* firstChild =
+ nsPlaceholderFrame::GetRealFrameFor(mFrames.FirstChild());
+
+ return aSummaryFrame == firstChild;
+}
diff --git a/layout/generic/DetailsFrame.h b/layout/generic/DetailsFrame.h
index 1eb4ea87be..4ae177f16f 100644
--- a/layout/generic/DetailsFrame.h
+++ b/layout/generic/DetailsFrame.h
@@ -54,6 +54,12 @@ public:
void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter) override;
+ // Returns true if |aSummaryFrame| is the main summary (i.e. the first child
+ // of this details frame).
+ // This function is used when the summary element is removed from the parent
+ // details element since at that moment the summary element has been already
+ // removed from the details element children.
+ bool HasMainSummaryFrame(nsIFrame* aSummaryFrame);
private:
nsCOMPtr<nsIContent> mDefaultSummary;
diff --git a/layout/generic/ReflowInput.cpp b/layout/generic/ReflowInput.cpp
index 78eca8c6cb..9f7b4368c3 100644
--- a/layout/generic/ReflowInput.cpp
+++ b/layout/generic/ReflowInput.cpp
@@ -1564,8 +1564,7 @@ ReflowInput::InitAbsoluteConstraints(nsPresContext* aPresContext,
// have been if it had been in the flow
nsHypotheticalPosition hypotheticalPos;
if ((iStartIsAuto && iEndIsAuto) || (bStartIsAuto && bEndIsAuto)) {
- nsIFrame* placeholderFrame =
- aPresContext->PresShell()->GetPlaceholderFrameFor(mFrame);
+ nsPlaceholderFrame* placeholderFrame = mFrame->GetPlaceholderFrame();
NS_ASSERTION(placeholderFrame, "no placeholder frame");
if (placeholderFrame->HasAnyStateBits(
diff --git a/layout/generic/Selection.h b/layout/generic/Selection.h
index 5414d15c12..cc696a7c78 100644
--- a/layout/generic/Selection.h
+++ b/layout/generic/Selection.h
@@ -31,6 +31,9 @@ class nsHTMLCopyEncoder;
namespace mozilla {
class ErrorResult;
struct AutoPrepareFocusRange;
+namespace dom {
+class DocGroup;
+} // namespace dom
} // namespace mozilla
struct RangeData
@@ -73,6 +76,7 @@ public:
nsresult EndBatchChangesInternal(int16_t aReason = nsISelectionListener::NO_REASON);
nsIDocument* GetParentObject() const;
+ DocGroup* GetDocGroup() const;
// utility methods for scrolling the selection into view
nsPresContext* GetPresContext() const;
diff --git a/layout/generic/crashtests/1381134-2.html b/layout/generic/crashtests/1381134-2.html
new file mode 100644
index 0000000000..d3ac73507a
--- /dev/null
+++ b/layout/generic/crashtests/1381134-2.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+addEventListener("DOMContentLoaded", () => {
+ [d1, d2] = document.getElementsByTagName("div");
+ [s1, s2] = document.getElementsByTagName("span")
+ d3 = document.createElement("div")
+ d4 = document.createElement("div")
+ d4.setAttribute("class", "grid")
+ d3.appendChild(d4)
+ d1.appendChild(document.createElement("span"))
+ setTimeout(() => {
+ d2.removeChild(s2)
+ setTimeout(() => {
+ d2.insertBefore(d3, s1)
+ }, 100)
+ }, 100)
+})
+</script>
+<style>
+.columns {
+ columns: 3;
+}
+.grid {
+ border:5px solid;
+ counter-reset: item;
+}
+.grid * { display:block; }
+span { display:contents; }
+span::before { content: counter(item) ":before"; }
+span::after { content: counter(item) ":after"; }
+</style>
+</head>
+<body>
+<div class=columns>
+<div class=grid>
+<c></c>
+<span><c></c></span>
+<span><c></c></span>
+</div>
+</div>
+</body>
+</html>
diff --git a/layout/generic/crashtests/1381134.html b/layout/generic/crashtests/1381134.html
new file mode 100644
index 0000000000..a45fa04ecb
--- /dev/null
+++ b/layout/generic/crashtests/1381134.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+<script>
+addEventListener("DOMContentLoaded", () => {
+ [d1, d2] = document.getElementsByTagName("div");
+ [s1, s2] = document.getElementsByTagName("span")
+ d3 = document.createElement("div")
+ d4 = document.createElement("div")
+ d4.setAttribute("class", "grid")
+ d3.appendChild(d4)
+ d1.appendChild(document.createElement("span"))
+ setTimeout(() => {
+ d2.removeChild(s2)
+ setTimeout(() => {
+ d2.insertBefore(d3, s1)
+ }, 100)
+ }, 100)
+})
+</script>
+<style>
+.columns {
+ columns: 3;
+}
+.grid {
+ display: grid;
+ border:5px solid;
+ counter-reset: item;
+}
+span { display:contents; }
+span::before { content: counter(item) ":before"; }
+span::after { content: counter(item) ":after"; }
+</style>
+</head>
+<body>
+<div class=columns>
+<div class=grid>
+<c></c>
+<span><c></c></span>
+<span><c></c></span>
+</div>
+</div>
+</body>
+</html>
diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list
index a3c0d62c68..1a597e51c0 100644
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -642,3 +642,5 @@ load 1278461-1.html
load 1278461-2.html
load 1304441.html
load 1316649.html
+load 1381134.html
+load 1381134-2.html
diff --git a/layout/generic/nsAbsoluteContainingBlock.cpp b/layout/generic/nsAbsoluteContainingBlock.cpp
index e3c847d01b..a92a2062d5 100644
--- a/layout/generic/nsAbsoluteContainingBlock.cpp
+++ b/layout/generic/nsAbsoluteContainingBlock.cpp
@@ -338,17 +338,9 @@ nsAbsoluteContainingBlock::DoMarkFramesDirty(bool aMarkAllDirty)
// Given an out-of-flow frame, this method returns the parent frame of
// its placeholder frame, if that parent is a nsContainerFrame.
static nsContainerFrame*
-GetPlaceholderContainer(nsPresContext* aPresContext,
- nsIFrame* aPositionedFrame)
+GetPlaceholderContainer(nsIFrame* aPositionedFrame)
{
- MOZ_ASSERT(aPositionedFrame, "need non-null frame");
- MOZ_ASSERT(aPositionedFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW),
- "expecting abspos frame");
- MOZ_ASSERT(aPresContext && aPresContext == aPositionedFrame->PresContext(),
- "need non-null pres context which matches our frame");
-
- nsIFrame* placeholder =
- aPresContext->PresShell()->GetPlaceholderFrameFor(aPositionedFrame);
+ nsIFrame* placeholder = aPositionedFrame->GetPlaceholderFrame();
if (!placeholder) {
return nullptr;
@@ -557,8 +549,7 @@ nsAbsoluteContainingBlock::ResolveSizeDependentOffsets(
aOffsets->IEnd(outerWM) - aMargin.IStartEnd(outerWM) -
aKidSize.ISize(outerWM);
} else if (aKidReflowInput.mFlags.mIOffsetsNeedCSSAlign) {
- placeholderContainer = GetPlaceholderContainer(aPresContext,
- aKidReflowInput.mFrame);
+ placeholderContainer = GetPlaceholderContainer(aKidReflowInput.mFrame);
nscoord offset = OffsetToAlignedStaticPos(aKidReflowInput, aKidSize,
logicalCBSizeOuterWM,
placeholderContainer,
@@ -579,8 +570,7 @@ nsAbsoluteContainingBlock::ResolveSizeDependentOffsets(
aKidSize.BSize(outerWM);
} else if (aKidReflowInput.mFlags.mBOffsetsNeedCSSAlign) {
if (!placeholderContainer) {
- placeholderContainer = GetPlaceholderContainer(aPresContext,
- aKidReflowInput.mFrame);
+ placeholderContainer = GetPlaceholderContainer(aKidReflowInput.mFrame);
}
nscoord offset = OffsetToAlignedStaticPos(aKidReflowInput, aKidSize,
logicalCBSizeOuterWM,
@@ -655,8 +645,7 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat
// due to the multiple coordinate spaces in play, we use a convenience flag
// to simply have the child's ReflowInput give it a static position at its
// abs.pos. CB origin, and then we'll align & offset it from there.
- nsIFrame* placeholder =
- aPresContext->PresShell()->GetPlaceholderFrameFor(aKidFrame);
+ nsIFrame* placeholder = aKidFrame->GetPlaceholderFrame();
if (placeholder && placeholder->GetParent() == aDelegatingFrame) {
rsFlags |= ReflowInput::STATIC_POS_IS_CB_ORIGIN;
}
diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp
index a37bfc06bd..8fec6cd6a6 100644
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -4336,8 +4336,7 @@ CheckPlaceholderInLine(nsIFrame* aBlock, nsLineBox* aLine, nsFloatCache* aFC)
"float in a line should never be a continuation");
NS_ASSERTION(!(aFC->mFloat->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT),
"float in a line should never be a pushed float");
- nsIFrame* ph = aBlock->PresContext()->FrameManager()->
- GetPlaceholderFrameFor(aFC->mFloat->FirstInFlow());
+ nsIFrame* ph = aFC->mFloat->FirstInFlow()->GetPlaceholderFrame();
for (nsIFrame* f = ph; f; f = f->GetParent()) {
if (f->GetParent() == aBlock)
return aLine->Contains(f);
@@ -4939,9 +4938,8 @@ nsBlockFrame::DrainSelfPushedFloats()
if (f->GetPrevContinuation()) {
// FIXME
} else {
- nsPlaceholderFrame *placeholder =
- presContext->FrameManager()->GetPlaceholderFrameFor(f);
- nsIFrame *floatOriginalParent = presContext->PresShell()->
+ nsPlaceholderFrame* placeholder = f->GetPlaceholderFrame();
+ nsIFrame* floatOriginalParent = presContext->PresShell()->
FrameConstructor()->GetFloatContainingBlock(placeholder);
if (floatOriginalParent != this) {
// This is a first continuation that was pushed from one of our
@@ -5565,7 +5563,7 @@ FindChildContaining(nsBlockFrame* aFrame, nsIFrame* aFindFrame)
return nullptr;
if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW))
break;
- aFindFrame = aFrame->PresContext()->FrameManager()->GetPlaceholderFrameFor(child);
+ aFindFrame = child->GetPlaceholderFrame();
}
return child;
@@ -6847,9 +6845,8 @@ nsBlockFrame::ChildIsDirty(nsIFrame* aChild)
AddStateBits(NS_BLOCK_LOOK_FOR_DIRTY_FRAMES);
} else {
NS_ASSERTION(aChild->IsFloating(), "should be a float");
- nsIFrame *thisFC = FirstContinuation();
- nsIFrame *placeholderPath =
- PresContext()->FrameManager()->GetPlaceholderFrameFor(aChild);
+ nsIFrame* thisFC = FirstContinuation();
+ nsIFrame* placeholderPath = aChild->GetPlaceholderFrame();
// SVG code sometimes sends FrameNeedsReflow notifications during
// frame destruction, leading to null placeholders, but we're safe
// ignoring those.
diff --git a/layout/generic/nsFirstLetterFrame.cpp b/layout/generic/nsFirstLetterFrame.cpp
index 980e1e9bed..5f561c7593 100644
--- a/layout/generic/nsFirstLetterFrame.cpp
+++ b/layout/generic/nsFirstLetterFrame.cpp
@@ -320,8 +320,7 @@ nsFirstLetterFrame::CreateContinuationForFloatingParent(nsPresContext* aPresCont
*aContinuation = nullptr;
nsIPresShell* presShell = aPresContext->PresShell();
- nsPlaceholderFrame* placeholderFrame =
- presShell->FrameManager()->GetPlaceholderFrameFor(this);
+ nsPlaceholderFrame* placeholderFrame = GetPlaceholderFrame();
nsContainerFrame* parent = placeholderFrame->GetParent();
nsIFrame* continuation = presShell->FrameConstructor()->
diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp
index 0d0c7108cc..ea29c6945e 100644
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -633,8 +633,7 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
nsIPresShell *shell = presContext->GetPresShell();
if (mState & NS_FRAME_OUT_OF_FLOW) {
- nsPlaceholderFrame* placeholder =
- shell->FrameManager()->GetPlaceholderFrameFor(this);
+ nsPlaceholderFrame* placeholder = GetPlaceholderFrame();
NS_ASSERTION(!placeholder || (aDestructRoot != this),
"Don't call Destroy() on OOFs, call Destroy() on the placeholder.");
NS_ASSERTION(!placeholder ||
@@ -642,7 +641,6 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
"Placeholder relationship should have been torn down already; "
"this might mean we have a stray placeholder in the tree.");
if (placeholder) {
- shell->FrameManager()->UnregisterPlaceholderFrame(placeholder);
placeholder->SetOutOfFlowFrame(nullptr);
}
}
@@ -8073,9 +8071,8 @@ int32_t
nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainingBlock)
{
NS_ASSERTION(aFrame, "null aFrame");
- nsFrameManager* frameManager = aFrame->PresContext()->FrameManager();
- nsIFrame *blockFrame = aFrame;
- nsIFrame *thisBlock;
+ nsIFrame* blockFrame = aFrame;
+ nsIFrame* thisBlock;
nsAutoLineIterator it;
nsresult result = NS_ERROR_FAILURE;
while (NS_FAILED(result) && blockFrame)
@@ -8088,7 +8085,7 @@ nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainin
// abspos continuations don't have placeholders, get the fif
thisBlock = thisBlock->FirstInFlow();
}
- thisBlock = frameManager->GetPlaceholderFrameFor(thisBlock);
+ thisBlock = thisBlock->GetPlaceholderFrame();
if (!thisBlock)
return -1;
}
@@ -8918,6 +8915,8 @@ GetIBSplitSiblingForAnonymousBlock(const nsIFrame* aFrame)
*
* Also skip anonymous scrolled-content parents; inherit directly from the
* outer scroll frame.
+ *
+ * Also skip NAC parents if the child frame is NAC.
*/
static nsIFrame*
GetCorrectedParent(const nsIFrame* aFrame)
@@ -8943,6 +8942,32 @@ GetCorrectedParent(const nsIFrame* aFrame)
if (pseudo == nsCSSAnonBoxes::tableWrapper) {
pseudo = aFrame->PrincipalChildList().FirstChild()->StyleContext()->GetPseudo();
}
+
+ // Prevent NAC from inheriting NAC. This partially duplicates the logic
+ // implemented in nsCSSFrameConstructor::AddFCItemsForAnonymousContent, and is
+ // necessary so that restyle inherits style contexts in the same way as the
+ // initial styling performed in frame construction.
+ //
+ // It would be nice to put it in CorrectStyleParentFrame and therefore share
+ // it, but that would lose the information of whether the _child_ is NAC,
+ // since CorrectStyleParentFrame only knows about the prospective _parent_.
+ // This duplication and complexity will go away when we fully switch to the
+ // Servo style system, where all this can be handled much more naturally.
+ //
+ // We need to take special care not to disrupt the style inheritance of frames
+ // whose content is NAC but who implement a pseudo (like an anonymous
+ // box, or a non-NAC-backed pseudo like ::first-line) that does not match the
+ // one that the NAC implements, if any.
+ nsIContent* content = aFrame->GetContent();
+ Element* element =
+ content && content->IsElement() ? content->AsElement() : nullptr;
+ if (element && element->IsNativeAnonymous() && !element->IsNativeScrollbarContent() &&
+ element->GetPseudoElementType() == aFrame->StyleContext()->GetPseudoType()) {
+ while (parent->GetContent() && parent->GetContent()->IsNativeAnonymous()) {
+ parent = parent->GetInFlowParent();
+ }
+ }
+
return nsFrame::CorrectStyleParentFrame(parent, pseudo);
}
@@ -9012,7 +9037,9 @@ nsStyleContext*
nsFrame::DoGetParentStyleContext(nsIFrame** aProviderFrame) const
{
*aProviderFrame = nullptr;
- nsFrameManager* fm = PresContext()->FrameManager();
+
+ // Handle display:contents and the root frame, when there's no parent frame
+ // to inherit from.
if (MOZ_LIKELY(mContent)) {
nsIContent* parentContent = mContent->GetFlattenedTreeParent();
if (MOZ_LIKELY(parentContent)) {
@@ -9026,6 +9053,7 @@ nsFrame::DoGetParentStyleContext(nsIFrame** aProviderFrame) const
/* if next is true then it's really a request for the table frame's
parent context, see nsTable[Outer]Frame::GetParentStyleContext. */
pseudo == nsCSSAnonBoxes::tableWrapper) {
+ nsFrameManager* fm = PresContext()->FrameManager();
nsStyleContext* sc = fm->GetDisplayContentsStyleFor(parentContent);
if (MOZ_UNLIKELY(sc)) {
return sc;
@@ -9062,7 +9090,7 @@ nsFrame::DoGetParentStyleContext(nsIFrame** aProviderFrame) const
// We're an out-of-flow frame. For out-of-flow frames, we must
// resolve underneath the placeholder's parent. The placeholder is
// reached from the first-in-flow.
- nsIFrame* placeholder = fm->GetPlaceholderFrameFor(FirstInFlow());
+ nsIFrame* placeholder = FirstInFlow()->GetPlaceholderFrame();
if (!placeholder) {
NS_NOTREACHED("no placeholder frame for out-of-flow frame");
*aProviderFrame = GetCorrectedParent(this);
@@ -9977,19 +10005,16 @@ nsIFrame::IsPseudoStackingContextFromStyle() {
Element*
nsIFrame::GetPseudoElement(CSSPseudoElementType aType)
{
- nsIFrame* frame = nullptr;
+ if (!mContent) {
+ return nullptr;
+ }
if (aType == CSSPseudoElementType::before) {
- frame = nsLayoutUtils::GetBeforeFrame(this);
- } else if (aType == CSSPseudoElementType::after) {
- frame = nsLayoutUtils::GetAfterFrame(this);
+ return nsLayoutUtils::GetBeforePseudo(mContent);
}
- if (frame) {
- nsIContent* content = frame->GetContent();
- if (content->IsElement()) {
- return content->AsElement();
- }
+ if (aType == CSSPseudoElementType::after) {
+ return nsLayoutUtils::GetAfterPseudo(mContent);
}
return nullptr;
diff --git a/layout/generic/nsHTMLParts.h b/layout/generic/nsHTMLParts.h
index 89a7a6edde..243c432b2f 100644
--- a/layout/generic/nsHTMLParts.h
+++ b/layout/generic/nsHTMLParts.h
@@ -11,6 +11,7 @@
#include "nscore.h"
#include "nsISupports.h"
#include "nsIFrame.h"
+class nsComboboxControlFrame;
class nsIAtom;
class nsNodeInfoManager;
class nsIContent;
@@ -161,7 +162,7 @@ nsIFrame*
NS_NewNativeSelectControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
nsContainerFrame*
NS_NewListControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
-nsContainerFrame*
+nsComboboxControlFrame*
NS_NewComboboxControlFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, nsFrameState aFlags);
nsIFrame*
NS_NewProgressFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
diff --git a/layout/generic/nsIAnonymousContentCreator.h b/layout/generic/nsIAnonymousContentCreator.h
index e7d4399b6b..5167178b83 100644
--- a/layout/generic/nsIAnonymousContentCreator.h
+++ b/layout/generic/nsIAnonymousContentCreator.h
@@ -34,12 +34,7 @@ public:
mContent(aContent)
{}
- ContentInfo(nsIContent* aContent, nsStyleContext* aStyleContext) :
- mContent(aContent), mStyleContext(aStyleContext)
- {}
-
nsIContent* mContent;
- RefPtr<nsStyleContext> mStyleContext;
nsTArray<ContentInfo> mChildren;
};
@@ -66,18 +61,12 @@ public:
* Appends "native" anonymous children created by CreateAnonymousContent()
* to the given content list depending on the filter.
*
- * @see nsIContent::GetChildren for set of values used for filter.
+ * @see nsIContent::GetChildren for set of values used for filter. Currently,
+ * eSkipPlaceholderContent is the only flag that any implementation of
+ * this method heeds.
*/
virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
uint32_t aFilter) = 0;
-
- /**
- * Implementations can override this method to create special frames for the
- * anonymous content returned from CreateAnonymousContent.
- * By default this method returns nullptr, which means the default frame
- * is created.
- */
- virtual nsIFrame* CreateFrameFor(nsIContent* aContent) { return nullptr; }
};
#endif
diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h
index 93eb95099a..e22dd690a8 100644
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -82,6 +82,7 @@ class nsLineList_iterator;
class nsAbsoluteContainingBlock;
class nsIContent;
class nsContainerFrame;
+class nsPlaceholderFrame;
struct nsPeekOffsetStruct;
struct nsPoint;
@@ -721,6 +722,23 @@ public:
* Accessor functions for geometric parent.
*/
nsContainerFrame* GetParent() const { return mParent; }
+
+ /**
+ * Gets the parent of a frame, using the parent of the placeholder for
+ * out-of-flow frames.
+ */
+ inline nsContainerFrame* GetInFlowParent();
+
+ /**
+ * Return the placeholder for this frame (which must be out-of-flow).
+ * @note this will only return non-null if |this| is the first-in-flow
+ * although we don't assert that here for legacy reasons.
+ */
+ inline nsPlaceholderFrame* GetPlaceholderFrame() const {
+ MOZ_ASSERT(HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
+ return GetProperty(PlaceholderFrameProperty());
+ }
+
/**
* Set this frame's parent to aParent.
* If the frame may have moved into or out of a scrollframe's
@@ -1040,6 +1058,8 @@ public:
NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(BidiDataProperty, mozilla::FrameBidiData)
+ NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(PlaceholderFrameProperty, nsPlaceholderFrame)
+
mozilla::FrameBidiData GetBidiData()
{
return GetProperty(BidiDataProperty());
@@ -1055,10 +1075,6 @@ public:
return GetBidiData().embeddingLevel;
}
- nsTArray<nsIContent*>* GetGenConPseudos() {
- return GetProperty(GenConProperty());
- }
-
/**
* Return the distance between the border edge of the frame and the
* margin edge of the frame. Like GetRect(), returns the dimensions
diff --git a/layout/generic/nsIFrameInlines.h b/layout/generic/nsIFrameInlines.h
index eb9a7202a3..a3da7ebca9 100644
--- a/layout/generic/nsIFrameInlines.h
+++ b/layout/generic/nsIFrameInlines.h
@@ -8,8 +8,10 @@
#define nsIFrameInlines_h___
#include "nsContainerFrame.h"
+#include "nsPlaceholderFrame.h"
#include "nsStyleStructInlines.h"
#include "nsCSSAnonBoxes.h"
+#include "nsFrameManager.h"
bool
nsIFrame::IsFlexItem() const
@@ -160,4 +162,15 @@ nsIFrame::BaselineBOffset(mozilla::WritingMode aWM,
return SynthesizeBaselineBOffsetFromBorderBox(aWM, aBaselineGroup);
}
+nsContainerFrame*
+nsIFrame::GetInFlowParent()
+{
+ if (GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
+ nsIFrame* ph = FirstContinuation()->GetProperty(nsIFrame::PlaceholderFrameProperty());
+ return ph->GetParent();
+ }
+
+ return GetParent();
+}
+
#endif
diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp
index c64520f2ea..ee35ecad81 100644
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1836,7 +1836,7 @@ nsImageFrame::ShouldDisplaySelection()
int32_t thisOffset = parentContent->IndexOf(mContent);
nsCOMPtr<nsIDOMNode> parentNode = do_QueryInterface(parentContent);
nsCOMPtr<nsIDOMNode> rangeNode;
- int32_t rangeOffset;
+ uint32_t rangeOffset;
nsCOMPtr<nsIDOMRange> range;
selection->GetRangeAt(0,getter_AddRefs(range));
if (range)
@@ -1844,12 +1844,16 @@ nsImageFrame::ShouldDisplaySelection()
range->GetStartContainer(getter_AddRefs(rangeNode));
range->GetStartOffset(&rangeOffset);
- if (parentNode && rangeNode && (rangeNode == parentNode) && rangeOffset == thisOffset)
- {
+ if (parentNode && rangeNode && rangeNode == parentNode &&
+ static_cast<int32_t>(rangeOffset) == thisOffset) {
range->GetEndContainer(getter_AddRefs(rangeNode));
range->GetEndOffset(&rangeOffset);
- if ((rangeNode == parentNode) && (rangeOffset == (thisOffset +1))) //+1 since that would mean this whole content is selected only
- return false; //do not allow nsFrame do draw any further selection
+ // +1 since that would mean this whole content is selected only
+ if (rangeNode == parentNode &&
+ static_cast<int32_t>(rangeOffset) == thisOffset + 1) {
+ // Do not allow nsFrame do draw any further selection
+ return false;
+ }
}
}
}
diff --git a/layout/generic/nsPlaceholderFrame.cpp b/layout/generic/nsPlaceholderFrame.cpp
index bd380a2d98..62370a06a4 100644
--- a/layout/generic/nsPlaceholderFrame.cpp
+++ b/layout/generic/nsPlaceholderFrame.cpp
@@ -156,16 +156,15 @@ nsPlaceholderFrame::DestroyFrom(nsIFrame* aDestructRoot)
{
nsIFrame* oof = mOutOfFlowFrame;
if (oof) {
- // Unregister out-of-flow frame
- nsFrameManager* fm = PresContext()->GetPresShell()->FrameManager();
- fm->UnregisterPlaceholderFrame(this);
mOutOfFlowFrame = nullptr;
+ oof->DeleteProperty(nsIFrame::PlaceholderFrameProperty());
// If aDestructRoot is not an ancestor of the out-of-flow frame,
// then call RemoveFrame on it here.
// Also destroy it here if it's a popup frame. (Bug 96291)
if ((GetStateBits() & PLACEHOLDER_FOR_POPUP) ||
!nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, oof)) {
ChildListID listId = nsLayoutUtils::GetChildListNameFor(oof);
+ nsFrameManager* fm = PresContext()->GetPresShell()->FrameManager();
fm->RemoveFrame(listId, oof);
}
// else oof will be destroyed by its parent
diff --git a/layout/generic/nsSelection.cpp b/layout/generic/nsSelection.cpp
index 5ccb2d8bf8..919ab0815a 100644
--- a/layout/generic/nsSelection.cpp
+++ b/layout/generic/nsSelection.cpp
@@ -1788,8 +1788,7 @@ nsFrameSelection::TakeFocus(nsIContent* aNewFocus,
RefPtr<nsRange> newRange = new nsRange(aNewFocus);
- newRange->SetStart(aNewFocus, aContentOffset);
- newRange->SetEnd(aNewFocus, aContentOffset);
+ newRange->CollapseTo(aNewFocus, aContentOffset);
mDomSelections[index]->AddRange(newRange);
mBatching = batching;
mChangesDuringBatching = changes;
@@ -3352,10 +3351,11 @@ nsFrameSelection::CreateAndAddRange(nsINode *aParentNode, int32_t aOffset)
RefPtr<nsRange> range = new nsRange(aParentNode);
// Set range around child at given offset
- nsresult result = range->SetStart(aParentNode, aOffset);
- if (NS_FAILED(result)) return result;
- result = range->SetEnd(aParentNode, aOffset+1);
- if (NS_FAILED(result)) return result;
+ nsresult rv = range->SetStartAndEnd(aParentNode, aOffset,
+ aParentNode, aOffset + 1);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
int8_t index = GetIndexFromSelectionType(SelectionType::eNormal);
if (!mDomSelections[index])
@@ -3521,6 +3521,18 @@ Selection::GetParentObject() const
return nullptr;
}
+DocGroup*
+Selection::GetDocGroup() const
+{
+ nsIPresShell* shell = GetPresShell();
+ if (!shell) {
+ return nullptr;
+ }
+
+ nsIDocument* doc = shell->GetDocument();
+ return doc ? doc->GetDocGroup() : nullptr;
+}
+
NS_IMPL_CYCLE_COLLECTION_CLASS(Selection)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Selection)
@@ -3780,13 +3792,12 @@ Selection::SubtractRange(RangeData* aRange, nsRange* aSubtract,
// We need to add a new RangeData to the output, running from
// the end of aSubtract to the end of range
RefPtr<nsRange> postOverlap = new nsRange(aSubtract->GetEndParent());
-
- rv =
- postOverlap->SetStart(aSubtract->GetEndParent(), aSubtract->EndOffset());
- NS_ENSURE_SUCCESS(rv, rv);
- rv =
- postOverlap->SetEnd(range->GetEndParent(), range->EndOffset());
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = postOverlap->SetStartAndEnd(
+ aSubtract->GetEndParent(), aSubtract->EndOffset(),
+ range->GetEndParent(), range->EndOffset());
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
if (!postOverlap->Collapsed()) {
if (!aOutput->InsertElementAt(0, RangeData(postOverlap)))
return NS_ERROR_OUT_OF_MEMORY;
@@ -3799,12 +3810,12 @@ Selection::SubtractRange(RangeData* aRange, nsRange* aSubtract,
// the start of the range to the start of aSubtract
RefPtr<nsRange> preOverlap = new nsRange(range->GetStartParent());
- nsresult rv =
- preOverlap->SetStart(range->GetStartParent(), range->StartOffset());
- NS_ENSURE_SUCCESS(rv, rv);
- rv =
- preOverlap->SetEnd(aSubtract->GetStartParent(), aSubtract->StartOffset());
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = preOverlap->SetStartAndEnd(
+ range->GetStartParent(), range->StartOffset(),
+ aSubtract->GetStartParent(), aSubtract->StartOffset());
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
if (!preOverlap->Collapsed()) {
if (!aOutput->InsertElementAt(0, RangeData(preOverlap)))
@@ -4120,13 +4131,15 @@ Selection::GetType(int16_t* aType)
static inline bool
RangeMatchesBeginPoint(nsRange* aRange, nsINode* aNode, int32_t aOffset)
{
- return aRange->GetStartParent() == aNode && aRange->StartOffset() == aOffset;
+ return aRange->GetStartParent() == aNode &&
+ static_cast<int32_t>(aRange->StartOffset()) == aOffset;
}
static inline bool
RangeMatchesEndPoint(nsRange* aRange, nsINode* aNode, int32_t aOffset)
{
- return aRange->GetEndParent() == aNode && aRange->EndOffset() == aOffset;
+ return aRange->GetEndParent() == aNode &&
+ static_cast<int32_t>(aRange->EndOffset()) == aOffset;
}
// Selection::EqualsRangeAtPoint
@@ -5186,12 +5199,7 @@ Selection::Collapse(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
}
RefPtr<nsRange> range = new nsRange(parentNode);
- result = range->SetEnd(parentNode, aOffset);
- if (NS_FAILED(result)) {
- aRv.Throw(result);
- return;
- }
- result = range->SetStart(parentNode, aOffset);
+ result = range->CollapseTo(parentNode, aOffset);
if (NS_FAILED(result)) {
aRv.Throw(result);
return;
@@ -5579,11 +5587,8 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
return;
}
SetDirection(eDirNext);
- res = difRange->SetEnd(range->GetEndParent(), range->EndOffset());
- nsresult tmp = difRange->SetStart(focusNode, focusOffset);
- if (NS_FAILED(tmp)) {
- res = tmp;
- }
+ res = difRange->SetStartAndEnd(focusNode, focusOffset,
+ range->GetEndParent(), range->EndOffset());
if (NS_FAILED(res)) {
aRv.Throw(res);
return;
@@ -5611,11 +5616,8 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
}
else if (result3 <= 0 && result2 >= 0) {//a,2,1 or a2,1 or a,21 or a21
//deselect from 2 to 1
- res = difRange->SetEnd(focusNode, focusOffset);
- difRange->SetStart(aParentNode, aOffset, aRv);
- if (aRv.Failed()) {
- return;
- }
+ res = difRange->SetStartAndEnd(&aParentNode, aOffset,
+ focusNode, focusOffset);
if (NS_FAILED(res)) {
aRv.Throw(res);
return;
@@ -5678,11 +5680,8 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
}
else if (result2 <= 0 && result3 >= 0) {//1,2,a or 12,a or 1,2a or 12a
//deselect from 1 to 2
- difRange->SetEnd(aParentNode, aOffset, aRv);
- res = difRange->SetStart(focusNode, focusOffset);
- if (aRv.Failed()) {
- return;
- }
+ res = difRange->SetStartAndEnd(focusNode, focusOffset,
+ &aParentNode, aOffset);
if (NS_FAILED(res)) {
aRv.Throw(res);
return;
@@ -5713,15 +5712,9 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
}
//deselect from a to 1
if (focusNode != anchorNode || focusOffset!= anchorOffset) {//if collapsed diff dont do anything
- res = difRange->SetStart(anchorNode, anchorOffset);
- nsresult tmp = difRange->SetEnd(focusNode, focusOffset);
- if (NS_FAILED(tmp)) {
- res = tmp;
- }
- tmp = SetAnchorFocusToRange(range);
- if (NS_FAILED(tmp)) {
- res = tmp;
- }
+ res = difRange->SetStartAndEnd(anchorNode, anchorOffset,
+ focusNode, focusOffset);
+ nsresult tmp = SetAnchorFocusToRange(range);
if (NS_FAILED(res)) {
aRv.Throw(res);
return;
@@ -5746,11 +5739,9 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
return;
}
SetDirection(eDirPrevious);
- res = difRange->SetEnd(focusNode, focusOffset);
- nsresult tmp = difRange->SetStart(range->GetStartParent(), range->StartOffset());
- if (NS_FAILED(tmp)) {
- res = tmp;
- }
+ res = difRange->SetStartAndEnd(
+ range->GetStartParent(), range->StartOffset(),
+ focusNode, focusOffset);
if (NS_FAILED(res)) {
aRv.Throw(res);
return;
diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp
index 59ef020ce2..6875f33e88 100644
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -1383,8 +1383,7 @@ BuildTextRuns(DrawTarget* aDrawTarget, nsTextFrame* aForFrame,
nsIFrame* lineContainerChild = aForFrame;
if (!aLineContainer) {
if (aForFrame->IsFloatingFirstLetterChild()) {
- lineContainerChild = aForFrame->PresContext()->PresShell()->
- GetPlaceholderFrameFor(aForFrame->GetParent());
+ lineContainerChild = aForFrame->GetParent()->GetPlaceholderFrame();
}
aLineContainer = FindLineContainer(lineContainerChild);
} else {