summaryrefslogtreecommitdiffstats
path: root/layout/painting/nsDisplayList.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/painting/nsDisplayList.cpp')
-rw-r--r--layout/painting/nsDisplayList.cpp174
1 files changed, 93 insertions, 81 deletions
diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp
index 78388d2185..0007f86c5e 100644
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -383,6 +383,36 @@ nsDisplayWrapList* nsDisplayListBuilder::MergeItems(
return merged;
}
+// FIXME(emilio): This whole business should ideally not be needed at all, but
+// there are a variety of hard-to-deal-with caret invalidation issues, like
+// bug 1888583, and caret changes are relatively uncommon, enough that it
+// probably isn't worth chasing all them down.
+void nsDisplayListBuilder::InvalidateCaretFramesIfNeeded() {
+ if (mPaintedCarets.IsEmpty()) {
+ return;
+ }
+ size_t i = mPaintedCarets.Length();
+ while (i--) {
+ nsCaret* caret = mPaintedCarets[i];
+ nsIFrame* oldCaret = caret->GetLastPaintedFrame();
+ nsRect caretRect;
+ nsIFrame* currentCaret = caret->GetPaintGeometry(&caretRect);
+ if (oldCaret == currentCaret) {
+ // Keep tracking this caret, it hasn't changed.
+ continue;
+ }
+ if (oldCaret) {
+ oldCaret->MarkNeedsDisplayItemRebuild();
+ }
+ if (currentCaret) {
+ currentCaret->MarkNeedsDisplayItemRebuild();
+ }
+ // If / when we paint this caret, we'll track it again.
+ caret->SetLastPaintedFrame(nullptr);
+ mPaintedCarets.RemoveElementAt(i);
+ }
+}
+
void nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter::
SetCurrentActiveScrolledRoot(
const ActiveScrolledRoot* aActiveScrolledRoot) {
@@ -650,7 +680,6 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
mCurrentContainerASR(nullptr),
mCurrentFrame(aReferenceFrame),
mCurrentReferenceFrame(aReferenceFrame),
- mCaretFrame(nullptr),
mScrollInfoItemsForHoisting(nullptr),
mFirstClipChainToDestroy(nullptr),
mTableBackgroundSet(nullptr),
@@ -718,21 +747,6 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
mRetainingDisplayList && StaticPrefs::layout_display_list_retain_sc();
}
-static PresShell* GetFocusedPresShell() {
- nsPIDOMWindowOuter* focusedWnd =
- nsFocusManager::GetFocusManager()->GetFocusedWindow();
- if (!focusedWnd) {
- return nullptr;
- }
-
- nsCOMPtr<nsIDocShell> focusedDocShell = focusedWnd->GetDocShell();
- if (!focusedDocShell) {
- return nullptr;
- }
-
- return focusedDocShell->GetPresShell();
-}
-
void nsDisplayListBuilder::BeginFrame() {
nsCSSRendering::BeginFrameTreesLocked();
@@ -742,26 +756,6 @@ void nsDisplayListBuilder::BeginFrame() {
mInTransform = false;
mInFilter = false;
mSyncDecodeImages = false;
-
- if (!mBuildCaret) {
- return;
- }
-
- RefPtr<PresShell> presShell = GetFocusedPresShell();
- if (presShell) {
- RefPtr<nsCaret> caret = presShell->GetCaret();
- mCaretFrame = caret->GetPaintGeometry(&mCaretRect);
-
- // The focused pres shell may not be in the document that we're
- // painting, or be in a popup. Check if the display root for
- // the caret matches the display root that we're painting, and
- // only use it if it matches.
- if (mCaretFrame &&
- nsLayoutUtils::GetDisplayRootFrame(mCaretFrame) !=
- nsLayoutUtils::GetDisplayRootFrame(mReferenceFrame)) {
- mCaretFrame = nullptr;
- }
- }
}
void nsDisplayListBuilder::AddEffectUpdate(dom::RemoteBrowser* aBrowser,
@@ -801,7 +795,6 @@ void nsDisplayListBuilder::EndFrame() {
FreeClipChains();
FreeTemporaryItems();
nsCSSRendering::EndFrameTreesLocked();
- mCaretFrame = nullptr;
}
void nsDisplayListBuilder::MarkFrameForDisplay(nsIFrame* aFrame,
@@ -1141,12 +1134,32 @@ void nsDisplayListBuilder::EnterPresShell(const nsIFrame* aReferenceFrame,
return;
}
- // Caret frames add visual area to their frame, but we don't update the
- // overflow area. Use flags to make sure we build display items for that frame
- // instead.
- if (mCaretFrame && mCaretFrame->PresShell() == state->mPresShell) {
- MarkFrameForDisplay(mCaretFrame, aReferenceFrame);
- }
+ state->mCaretFrame = [&]() -> nsIFrame* {
+ RefPtr<nsCaret> caret = state->mPresShell->GetCaret();
+ nsIFrame* currentCaret = caret->GetPaintGeometry(&mCaretRect);
+ if (!currentCaret) {
+ return nullptr;
+ }
+
+ // Check if the display root for the caret matches the display root that
+ // we're painting, and only use it if it matches. Likely we only need this
+ // for carets inside popups.
+ if (nsLayoutUtils::GetDisplayRootFrame(currentCaret) !=
+ nsLayoutUtils::GetDisplayRootFrame(aReferenceFrame)) {
+ return nullptr;
+ }
+
+ // Caret frames add visual area to their frame, but we don't update the
+ // overflow area. Use flags to make sure we build display items for that
+ // frame instead.
+ MOZ_ASSERT(currentCaret->PresShell() == state->mPresShell);
+ MarkFrameForDisplay(currentCaret, aReferenceFrame);
+ caret->SetLastPaintedFrame(currentCaret);
+ if (!mPaintedCarets.Contains(caret)) {
+ mPaintedCarets.AppendElement(std::move(caret));
+ }
+ return currentCaret;
+ }();
}
// A non-blank paint is a paint that does not just contain the canvas
@@ -2534,9 +2547,7 @@ struct ZSortItem {
};
struct ZOrderComparator {
- bool operator()(const ZSortItem& aLeft, const ZSortItem& aRight) const {
- // Note that we can't just take the difference of the two
- // z-indices here, because that might overflow a 32-bit int.
+ bool LessThan(const ZSortItem& aLeft, const ZSortItem& aRight) const {
return aLeft.zIndex < aRight.zIndex;
}
};
@@ -2549,7 +2560,7 @@ struct ContentComparator {
explicit ContentComparator(nsIContent* aCommonAncestor)
: mCommonAncestor(aCommonAncestor) {}
- bool operator()(nsDisplayItem* aLeft, nsDisplayItem* aRight) const {
+ bool LessThan(nsDisplayItem* aLeft, nsDisplayItem* aRight) const {
// It's possible that the nsIContent for aItem1 or aItem2 is in a
// subdocument of commonAncestor, because display items for subdocuments
// have been mixed into the same list. Ensure that we're looking at content
@@ -2562,7 +2573,8 @@ struct ContentComparator {
// Something weird going on
return true;
}
- return nsContentUtils::CompareTreePosition<TreeKind::Flat>(
+ return content1 != content2 &&
+ nsContentUtils::CompareTreePosition<TreeKind::Flat>(
content1, content2, mCommonAncestor) < 0;
}
};
@@ -4134,8 +4146,7 @@ bool nsDisplayCaret::CreateWebRenderCommands(
nscolor caretColor;
nsIFrame* frame =
mCaret->GetPaintGeometry(&caretRect, &hookRect, &caretColor);
- MOZ_ASSERT(frame == mFrame, "We're referring different frame");
- if (!frame) {
+ if (NS_WARN_IF(!frame) || NS_WARN_IF(frame != mFrame)) {
return true;
}
@@ -5196,7 +5207,7 @@ bool nsDisplayOwnLayer::CreateWebRenderCommands(
Maybe<wr::WrAnimationProperty> prop;
bool needsProp = aManager->LayerManager()->AsyncPanZoomEnabled() &&
(IsScrollThumbLayer() || IsZoomingLayer() ||
- ShouldGetFixedOrStickyAnimationId() ||
+ ShouldGetFixedAnimationId() ||
(IsRootScrollbarContainer() && HasDynamicToolbar()));
if (needsProp) {
@@ -5223,7 +5234,7 @@ bool nsDisplayOwnLayer::CreateWebRenderCommands(
params.prim_flags |= wr::PrimitiveFlags::IS_SCROLLBAR_CONTAINER;
}
if (IsZoomingLayer() ||
- (ShouldGetFixedOrStickyAnimationId() ||
+ (ShouldGetFixedAnimationId() ||
(IsRootScrollbarContainer() && HasDynamicToolbar()))) {
params.is_2d_scale_translation = true;
params.should_snap = true;
@@ -5239,9 +5250,8 @@ bool nsDisplayOwnLayer::CreateWebRenderCommands(
bool nsDisplayOwnLayer::UpdateScrollData(WebRenderScrollData* aData,
WebRenderLayerScrollData* aLayerData) {
- bool isRelevantToApz =
- (IsScrollThumbLayer() || IsScrollbarContainer() || IsZoomingLayer() ||
- ShouldGetFixedOrStickyAnimationId());
+ bool isRelevantToApz = (IsScrollThumbLayer() || IsScrollbarContainer() ||
+ IsZoomingLayer() || ShouldGetFixedAnimationId());
if (!isRelevantToApz) {
return false;
@@ -5256,16 +5266,11 @@ bool nsDisplayOwnLayer::UpdateScrollData(WebRenderScrollData* aData,
return true;
}
- if (IsFixedPositionLayer() && ShouldGetFixedOrStickyAnimationId()) {
+ if (IsFixedPositionLayer() && ShouldGetFixedAnimationId()) {
aLayerData->SetFixedPositionAnimationId(mWrAnimationId);
return true;
}
- if (IsStickyPositionLayer() && ShouldGetFixedOrStickyAnimationId()) {
- aLayerData->SetStickyPositionAnimationId(mWrAnimationId);
- return true;
- }
-
MOZ_ASSERT(IsScrollbarContainer() || IsScrollThumbLayer());
aLayerData->SetScrollbarData(mScrollbarData);
@@ -5447,7 +5452,7 @@ bool nsDisplayFixedPosition::UpdateScrollData(
return true;
}
-bool nsDisplayFixedPosition::ShouldGetFixedOrStickyAnimationId() {
+bool nsDisplayFixedPosition::ShouldGetFixedAnimationId() {
#if defined(MOZ_WIDGET_ANDROID)
return mFrame->PresContext()->IsRootContentDocumentCrossProcess() &&
nsLayoutUtils::ScrollIdForRootScrollFrame(mFrame->PresContext()) ==
@@ -5511,7 +5516,8 @@ nsDisplayStickyPosition::nsDisplayStickyPosition(
: nsDisplayOwnLayer(aBuilder, aFrame, aList, aActiveScrolledRoot),
mContainerASR(aContainerASR),
mClippedToDisplayPort(aClippedToDisplayPort),
- mShouldFlatten(false) {
+ mShouldFlatten(false),
+ mWrStickyAnimationId(0) {
MOZ_COUNT_CTOR(nsDisplayStickyPosition);
}
@@ -5727,12 +5733,27 @@ bool nsDisplayStickyPosition::CreateWebRenderCommands(
wr::LayoutVector2D applied = {
NSAppUnitsToFloatPixels(appliedOffset.x, auPerDevPixel),
NSAppUnitsToFloatPixels(appliedOffset.y, auPerDevPixel)};
+ bool needsProp = ShouldGetStickyAnimationId();
+ Maybe<wr::WrAnimationProperty> prop;
+ auto spatialKey = wr::SpatialKey(uint64_t(mFrame), GetPerFrameKey(),
+ wr::SpatialKeyKind::Sticky);
+ if (needsProp) {
+ RefPtr<WebRenderAPZAnimationData> animationData =
+ aManager->CommandBuilder()
+ .CreateOrRecycleWebRenderUserData<WebRenderAPZAnimationData>(
+ this);
+ mWrStickyAnimationId = animationData->GetAnimationId();
+
+ prop.emplace();
+ prop->id = mWrStickyAnimationId;
+ prop->key = spatialKey;
+ prop->effect_type = wr::WrAnimationType::Transform;
+ }
wr::WrSpatialId spatialId = aBuilder.DefineStickyFrame(
wr::ToLayoutRect(bounds), topMargin.ptrOr(nullptr),
rightMargin.ptrOr(nullptr), bottomMargin.ptrOr(nullptr),
- leftMargin.ptrOr(nullptr), vBounds, hBounds, applied,
- wr::SpatialKey(uint64_t(mFrame), GetPerFrameKey(),
- wr::SpatialKeyKind::Sticky));
+ leftMargin.ptrOr(nullptr), vBounds, hBounds, applied, spatialKey,
+ prop.ptrOr(nullptr));
saccHelper.emplace(aBuilder, spatialId);
aManager->CommandBuilder().PushOverrideForASR(mContainerASR, spatialId);
@@ -5801,6 +5822,10 @@ bool nsDisplayStickyPosition::UpdateScrollData(
->GetContent());
aLayerData->SetStickyPositionScrollContainerId(scrollId);
}
+
+ if (ShouldGetStickyAnimationId()) {
+ aLayerData->SetStickyPositionAnimationId(mWrStickyAnimationId);
+ }
}
// Return true if either there is a dynamic toolbar affecting this sticky
// item or the OwnLayer base implementation returns true for some other
@@ -5810,21 +5835,8 @@ bool nsDisplayStickyPosition::UpdateScrollData(
return ret;
}
-bool nsDisplayStickyPosition::ShouldGetFixedOrStickyAnimationId() {
-#if defined(MOZ_WIDGET_ANDROID)
- if (HasDynamicToolbar()) { // also implies being in the cross-process RCD
- StickyScrollContainer* stickyScrollContainer = GetStickyScrollContainer();
- if (stickyScrollContainer) {
- ScrollableLayerGuid::ViewID scrollId =
- nsLayoutUtils::FindOrCreateIDFor(stickyScrollContainer->ScrollFrame()
- ->GetScrolledFrame()
- ->GetContent());
- return nsLayoutUtils::ScrollIdForRootScrollFrame(mFrame->PresContext()) ==
- scrollId;
- }
- }
-#endif
- return false;
+bool nsDisplayStickyPosition::ShouldGetStickyAnimationId() const {
+ return HasDynamicToolbar(); // also implies being in the cross-process RCD
}
nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(