diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 84b0286710ab..564132935dda 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -1637,9 +1637,7 @@ static bool IsZOrderLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2, void* aClosure) { // Note that we can't just take the difference of the two // z-indices here, because that might overflow a 32-bit int. - int32_t index1 = nsLayoutUtils::GetZIndex(aItem1->Frame()); - int32_t index2 = nsLayoutUtils::GetZIndex(aItem2->Frame()); - return index1 <= index2; + return aItem1->ZIndex() <= aItem2->ZIndex(); } void nsDisplayList::SortByZOrder(nsDisplayListBuilder* aBuilder, @@ -1699,6 +1697,20 @@ nsDisplayItem::MaxActiveLayers() return sMaxLayers; } +int32_t +nsDisplayItem::ZIndex() const +{ + if (!mFrame->IsPositioned() && !mFrame->IsFlexItem()) + return 0; + + const nsStylePosition* position = mFrame->StylePosition(); + if (position->mZIndex.GetUnit() == eStyleUnit_Integer) + return position->mZIndex.GetIntValue(); + + // sort the auto and 0 elements together + return 0; +} + bool nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder, nsRegion* aVisibleRegion) { @@ -2958,7 +2970,9 @@ nsDisplayBoxShadowInner::ComputeVisibility(nsDisplayListBuilder* aBuilder, nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList) - : nsDisplayItem(aBuilder, aFrame) { + : nsDisplayItem(aBuilder, aFrame) + , mOverrideZIndex(0) +{ mList.AppendToTop(aList); UpdateBounds(aBuilder); @@ -3000,7 +3014,9 @@ nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayItem* aItem) - : nsDisplayItem(aBuilder, aFrame) { + : nsDisplayItem(aBuilder, aFrame) + , mOverrideZIndex(0) +{ mList.AppendToTop(aItem); UpdateBounds(aBuilder); @@ -3026,7 +3042,9 @@ nsDisplayWrapList::nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayItem* aItem, const nsIFrame* aReferenceFrame, const nsPoint& aToReferenceFrame) - : nsDisplayItem(aBuilder, aFrame, aReferenceFrame, aToReferenceFrame) { + : nsDisplayItem(aBuilder, aFrame, aReferenceFrame, aToReferenceFrame) + , mOverrideZIndex(0) +{ mList.AppendToTop(aItem); mBounds = mList.GetBounds(aBuilder); } diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 727ae35f1be4..02a4ffd31de9 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -840,6 +840,12 @@ public: * returns null. */ inline nsIFrame* Frame() const { return mFrame; } + /** + * Compute the used z-index of our frame; returns zero for elements to which + * z-index does not apply, and for z-index:auto. + * @note This can be overridden, @see nsDisplayWrapList::SetOverrideZIndex. + */ + virtual int32_t ZIndex() const; /** * The default bounds is the frame border rect. * @param aSnap *aSnap is set to true if the returned rect will be @@ -2447,7 +2453,7 @@ public: nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayItem* aItem, const nsIFrame* aReferenceFrame, const nsPoint& aToReferenceFrame); nsDisplayWrapList(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) - : nsDisplayItem(aBuilder, aFrame) {} + : nsDisplayItem(aBuilder, aFrame), mOverrideZIndex(0) {} virtual ~nsDisplayWrapList(); /** * Call this if the wrapped list is changed. @@ -2506,6 +2512,16 @@ public: } virtual nsDisplayList* GetChildren() MOZ_OVERRIDE { return &mList; } + virtual int32_t ZIndex() const MOZ_OVERRIDE + { + return (mOverrideZIndex > 0) ? mOverrideZIndex : nsDisplayItem::ZIndex(); + } + + void SetOverrideZIndex(int32_t aZIndex) + { + mOverrideZIndex = aZIndex; + } + /** * This creates a copy of this item, but wrapping aItem instead of * our existing list. Only gets called if this item returned nullptr @@ -2549,6 +2565,8 @@ protected: // this item's own frame. nsTArray mMergedFrames; nsRect mBounds; + // Overrides the ZIndex of our frame if > 0. + int32_t mOverrideZIndex; }; /** diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 80fce5a6cdfc..29c40af562f9 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -2496,20 +2496,6 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram return NS_OK; } -int32_t -nsLayoutUtils::GetZIndex(nsIFrame* aFrame) { - if (!aFrame->IsPositioned() && !aFrame->IsFlexItem()) - return 0; - - const nsStylePosition* position = - aFrame->StylePosition(); - if (position->mZIndex.GetUnit() == eStyleUnit_Integer) - return position->mZIndex.GetIntValue(); - - // sort the auto and 0 elements together - return 0; -} - /** * Uses a binary search for find where the cursor falls in the line of text * It also keeps track of the part of the string that has already been measured diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 0b6ca91ca306..a5eeeacec8c5 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -841,12 +841,6 @@ public: const nsRegion& aDirtyRegion, nscolor aBackstop, uint32_t aFlags = 0); - /** - * Compute the used z-index of aFrame; returns zero for elements to which - * z-index does not apply, and for z-index:auto - */ - static int32_t GetZIndex(nsIFrame* aFrame); - /** * Uses a binary search for find where the cursor falls in the line of text * It also keeps track of the part of the string that has already been measured diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 7f4cd185c07b..005c97973513 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -2024,13 +2024,10 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, // 3: negative z-index children. for (;;) { nsDisplayItem* item = set.PositionedDescendants()->GetBottom(); - if (item) { - nsIFrame* f = item->Frame(); - if (nsLayoutUtils::GetZIndex(f) < 0) { - set.PositionedDescendants()->RemoveBottom(); - resultList.AppendToTop(item); - continue; - } + if (item && item->ZIndex() < 0) { + set.PositionedDescendants()->RemoveBottom(); + resultList.AppendToTop(item); + continue; } break; } diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 73b9899bd53d..a42b95f6297a 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -2092,19 +2092,39 @@ ScrollFrameHelper::ScrollToImpl(nsPoint aPt, const nsRect& aRange, nsIAtom* aOri } } +static int32_t +MaxZIndexInList(nsDisplayList* aList, nsDisplayListBuilder* aBuilder) +{ + int32_t maxZIndex = 0; + for (nsDisplayItem* item = aList->GetBottom(); item; item = item->GetAbove()) { + maxZIndex = std::max(maxZIndex, item->ZIndex()); + } + return maxZIndex; +} + static void -AppendToTop(nsDisplayListBuilder* aBuilder, nsDisplayList* aDest, +AppendToTop(nsDisplayListBuilder* aBuilder, const nsDisplayListSet& aLists, nsDisplayList* aSource, nsIFrame* aSourceFrame, bool aOwnLayer, - uint32_t aFlags, mozilla::layers::FrameMetrics::ViewID aScrollTargetId) + uint32_t aFlags, mozilla::layers::FrameMetrics::ViewID aScrollTargetId, + bool aPositioned) { if (aSource->IsEmpty()) return; - if (aOwnLayer) { - aDest->AppendNewToTop( - new (aBuilder) nsDisplayOwnLayer(aBuilder, aSourceFrame, aSource, - aFlags, aScrollTargetId)); + + nsDisplayWrapList* newItem = aOwnLayer? + new (aBuilder) nsDisplayOwnLayer(aBuilder, aSourceFrame, aSource, + aFlags, aScrollTargetId) : + new (aBuilder) nsDisplayWrapList(aBuilder, aSourceFrame, aSource); + + nsDisplayList* positionedDescendants = aLists.PositionedDescendants(); + if (aPositioned && !positionedDescendants->IsEmpty()) { + // We want overlay scrollbars to always be on top of the scrolled content, + // but we don't want them to unnecessarily cover overlapping elements from + // outside our scroll frame. + newItem->SetOverrideZIndex(MaxZIndexInList(positionedDescendants, aBuilder)); + positionedDescendants->AppendNewToTop(newItem); } else { - aDest->AppendToTop(aSource); + aLists.BorderBackground()->AppendNewToTop(newItem); } } @@ -2163,14 +2183,6 @@ ScrollFrameHelper::AppendScrollPartsTo(nsDisplayListBuilder* aBuilder, aBuilder, scrollParts[i], aDirtyRect, partList, nsIFrame::DISPLAY_CHILD_FORCE_STACKING_CONTEXT); - // Don't append textarea resizers to the positioned descendants because - // we don't want them to float on top of overlapping elements. - bool appendToPositioned = aPositioned && - !(scrollParts[i] == mResizerBox && !mIsRoot); - - nsDisplayList* dest = appendToPositioned ? - aLists.PositionedDescendants() : aLists.BorderBackground(); - uint32_t flags = 0; if (scrollParts[i] == mVScrollbarBox) { flags |= nsDisplayOwnLayer::VERTICAL_SCROLLBAR; @@ -2181,9 +2193,9 @@ ScrollFrameHelper::AppendScrollPartsTo(nsDisplayListBuilder* aBuilder, // DISPLAY_CHILD_FORCE_STACKING_CONTEXT put everything into // partList.PositionedDescendants(). - ::AppendToTop(aBuilder, dest, + ::AppendToTop(aBuilder, aLists, partList.PositionedDescendants(), scrollParts[i], - aCreateLayer, flags, scrollTargetId); + aCreateLayer, flags, scrollTargetId, aPositioned); } } @@ -2601,8 +2613,6 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder, aBuilder, mScrolledFrame, mOuter); scrolledContent.BorderBackground()->AppendNewToBottom(layerItem); } - scrolledContent.MoveTo(aLists); - // Now display overlay scrollbars and the resizer, if we have one. #ifdef MOZ_WIDGET_GONK // TODO: only layerize the overlay scrollbars if this scrollframe can be @@ -2610,8 +2620,9 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder, // that's where we want the layerized scrollbars createLayersForScrollbars = true; #endif - AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, createLayersForScrollbars, - true); + AppendScrollPartsTo(aBuilder, aDirtyRect, scrolledContent, + createLayersForScrollbars, true); + scrolledContent.MoveTo(aLists); } bool diff --git a/layout/reftests/z-index/overlayscrollbar-sorting-1.html b/layout/reftests/z-index/overlayscrollbar-sorting-1.html new file mode 100644 index 000000000000..4e332da5dcf2 --- /dev/null +++ b/layout/reftests/z-index/overlayscrollbar-sorting-1.html @@ -0,0 +1,26 @@ + + + +Test that overlay scrollbars are on top of positioned content + + + +
diff --git a/layout/reftests/z-index/overlayscrollbar-sorting-2.html b/layout/reftests/z-index/overlayscrollbar-sorting-2.html new file mode 100644 index 000000000000..d57d748ea378 --- /dev/null +++ b/layout/reftests/z-index/overlayscrollbar-sorting-2.html @@ -0,0 +1,32 @@ + + + +Test that overlay scrollbars are covered by overlapping non-positioned siblings + + + +
+
diff --git a/layout/reftests/z-index/overlayscrollbar-sorting-3.html b/layout/reftests/z-index/overlayscrollbar-sorting-3.html new file mode 100644 index 000000000000..eb3e0dc16509 --- /dev/null +++ b/layout/reftests/z-index/overlayscrollbar-sorting-3.html @@ -0,0 +1,33 @@ + + + +Test that overlay scrollbars are covered by overlapping positioned siblings + + + +
+
diff --git a/layout/reftests/z-index/overlayscrollbar-sorting-4.html b/layout/reftests/z-index/overlayscrollbar-sorting-4.html new file mode 100644 index 000000000000..e1f9c07cda48 --- /dev/null +++ b/layout/reftests/z-index/overlayscrollbar-sorting-4.html @@ -0,0 +1,35 @@ + + + +Test that overlay scrollbars are covered by positioned siblings with higher z-index even when the scrollable frame has a positioned descendant + + + +
+
diff --git a/layout/reftests/z-index/overlayscrollbar-sorting-5.html b/layout/reftests/z-index/overlayscrollbar-sorting-5.html new file mode 100644 index 000000000000..c6106f3201a9 --- /dev/null +++ b/layout/reftests/z-index/overlayscrollbar-sorting-5.html @@ -0,0 +1,43 @@ + + + +Test that overlay scrollbars are on top of positioned siblings when the scrollable frame has a positioned descendant that's higher than the sibling + + + +
+
diff --git a/layout/reftests/z-index/overlayscrollbar-sorting-ref-hidden.html b/layout/reftests/z-index/overlayscrollbar-sorting-ref-hidden.html new file mode 100644 index 000000000000..7dcd8585a54a --- /dev/null +++ b/layout/reftests/z-index/overlayscrollbar-sorting-ref-hidden.html @@ -0,0 +1,24 @@ + + + +Reference without scrollbar + + + +
diff --git a/layout/reftests/z-index/overlayscrollbar-sorting-ref-visible.html b/layout/reftests/z-index/overlayscrollbar-sorting-ref-visible.html new file mode 100644 index 000000000000..f9424cd976bf --- /dev/null +++ b/layout/reftests/z-index/overlayscrollbar-sorting-ref-visible.html @@ -0,0 +1,24 @@ + + + +Reference with scrollbar + + + +
diff --git a/layout/reftests/z-index/reftest.list b/layout/reftests/z-index/reftest.list index 764ecb8d55fa..1a7a7794d05e 100644 --- a/layout/reftests/z-index/reftest.list +++ b/layout/reftests/z-index/reftest.list @@ -1,5 +1,15 @@ +# Make overlay scrollbars never fade out +default-preferences pref(layout.testing.overlay-scrollbars.always-visible,true) + == 480053-1.html 480053-1-ref.html == z-index-1.html z-index-1-ref.html != stacking-context-yes.html stacking-context-no.html == stacking-context-perspective.html stacking-context-yes.html == stacking-context-backface-visibility.html stacking-context-no.html + +fails-if(Android) != overlayscrollbar-sorting-ref-visible.html overlayscrollbar-sorting-ref-hidden.html +== overlayscrollbar-sorting-1.html overlayscrollbar-sorting-ref-visible.html +== overlayscrollbar-sorting-2.html overlayscrollbar-sorting-ref-hidden.html +== overlayscrollbar-sorting-3.html overlayscrollbar-sorting-ref-hidden.html +== overlayscrollbar-sorting-4.html overlayscrollbar-sorting-ref-hidden.html +== overlayscrollbar-sorting-5.html overlayscrollbar-sorting-ref-visible.html