diff options
Diffstat (limited to 'layout/painting/nsDisplayList.cpp')
-rw-r--r-- | layout/painting/nsDisplayList.cpp | 174 |
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( |