mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 02:14:43 +00:00
Bug 926292 - Put overlay scrollbars on top of the topmost positioned descendant of the scrolled frame. r=mats
This commit is contained in:
parent
79968503a5
commit
da8c6a19ca
@ -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);
|
||||
}
|
||||
|
@ -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<nsIFrame*> mMergedFrames;
|
||||
nsRect mBounds;
|
||||
// Overrides the ZIndex of our frame if > 0.
|
||||
int32_t mOverrideZIndex;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
26
layout/reftests/z-index/overlayscrollbar-sorting-1.html
Normal file
26
layout/reftests/z-index/overlayscrollbar-sorting-1.html
Normal file
@ -0,0 +1,26 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Test that overlay scrollbars are on top of positioned content</title>
|
||||
|
||||
<style>
|
||||
|
||||
#outer {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#content {
|
||||
height: 400px;
|
||||
background: cyan;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="outer"><div id="content"></div></div>
|
32
layout/reftests/z-index/overlayscrollbar-sorting-2.html
Normal file
32
layout/reftests/z-index/overlayscrollbar-sorting-2.html
Normal file
@ -0,0 +1,32 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Test that overlay scrollbars are covered by overlapping non-positioned siblings</title>
|
||||
|
||||
<style>
|
||||
|
||||
#outer {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
overflow: auto;
|
||||
background: cyan;
|
||||
}
|
||||
|
||||
#content {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
#cover {
|
||||
margin-top: -200px;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background: cyan;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="outer"><div id="content"></div></div>
|
||||
<div id="cover"></div>
|
33
layout/reftests/z-index/overlayscrollbar-sorting-3.html
Normal file
33
layout/reftests/z-index/overlayscrollbar-sorting-3.html
Normal file
@ -0,0 +1,33 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Test that overlay scrollbars are covered by overlapping positioned siblings</title>
|
||||
|
||||
<style>
|
||||
|
||||
#outer {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
overflow: auto;
|
||||
background: cyan;
|
||||
}
|
||||
|
||||
#content {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
#cover {
|
||||
margin-top: -200px;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background: cyan;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="outer"><div id="content"></div></div>
|
||||
<div id="cover"></div>
|
35
layout/reftests/z-index/overlayscrollbar-sorting-4.html
Normal file
35
layout/reftests/z-index/overlayscrollbar-sorting-4.html
Normal file
@ -0,0 +1,35 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Test that overlay scrollbars are covered by positioned siblings with higher z-index even when the scrollable frame has a positioned descendant</title>
|
||||
|
||||
<style>
|
||||
|
||||
#outer {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#content {
|
||||
height: 400px;
|
||||
background: cyan;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#cover {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background: cyan;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="cover"></div>
|
||||
<div id="outer"><div id="content"></div></div>
|
43
layout/reftests/z-index/overlayscrollbar-sorting-5.html
Normal file
43
layout/reftests/z-index/overlayscrollbar-sorting-5.html
Normal file
@ -0,0 +1,43 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Test that overlay scrollbars are on top of positioned siblings when the scrollable frame has a positioned descendant that's higher than the sibling</title>
|
||||
|
||||
<style>
|
||||
|
||||
#outer {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#content {
|
||||
height: 400px;
|
||||
background: cyan;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
/* This test has different behavior depending on the type of scrollbar used.
|
||||
* We want the scrollbar to be visible. When overlay scrollbars are used,
|
||||
* they should be visible even when #cover gets between #outer and #content,
|
||||
* but for non-overlay scrollbars, that would cover them so we disable the
|
||||
* cover.
|
||||
*/
|
||||
@media all and (-moz-overlay-scrollbars) {
|
||||
#cover {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
background: cyan;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="cover"></div>
|
||||
<div id="outer"><div id="content"></div></div>
|
@ -0,0 +1,24 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Reference without scrollbar</title>
|
||||
|
||||
<style>
|
||||
|
||||
#outer {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
overflow: auto;
|
||||
background: cyan;
|
||||
}
|
||||
|
||||
#content {
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="outer"><div id="content"></div></div>
|
@ -0,0 +1,24 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>Reference with scrollbar</title>
|
||||
|
||||
<style>
|
||||
|
||||
#outer {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
overflow: auto;
|
||||
background: cyan;
|
||||
}
|
||||
|
||||
#content {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="outer"><div id="content"></div></div>
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user