Bug 1531609 part 2 - Implement overflow:clip/visible combinations. r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D73717
This commit is contained in:
Mats Palmgren 2020-07-31 15:31:36 +00:00
Родитель 92b8f0f77a
Коммит c875610606
29 изменённых файлов: 540 добавлений и 166 удалений

Просмотреть файл

@ -9,8 +9,34 @@
namespace mozilla {
ScrollStyles::ScrollStyles(const nsStyleDisplay& aDisplay)
: mHorizontal(aDisplay.mOverflowX), mVertical(aDisplay.mOverflowY) {}
// https://drafts.csswg.org/css-overflow/#overflow-propagation
// "If `visible` is applied to the viewport, it must be interpreted as `auto`.
// If `clip` is applied to the viewport, it must be interpreted as `hidden`."
static StyleOverflow MapOverflowValueForViewportPropagation(StyleOverflow aOverflow) {
switch (aOverflow) {
case StyleOverflow::Visible:
return StyleOverflow::Auto;
case StyleOverflow::Clip:
return StyleOverflow::Hidden;
default:
return aOverflow;
}
}
ScrollStyles::ScrollStyles(StyleOverflow aH, StyleOverflow aV)
: mHorizontal(aH), mVertical(aV) {
MOZ_ASSERT(mHorizontal == StyleOverflow::Auto ||
mHorizontal == StyleOverflow::Hidden ||
mHorizontal == StyleOverflow::Scroll);
MOZ_ASSERT(mVertical == StyleOverflow::Auto ||
mVertical == StyleOverflow::Hidden ||
mVertical == StyleOverflow::Scroll);
}
ScrollStyles::ScrollStyles(const nsStyleDisplay& aDisplay,
MapOverflowToValidScrollStyleTag)
: ScrollStyles(MapOverflowValueForViewportPropagation(aDisplay.mOverflowX),
MapOverflowValueForViewportPropagation(aDisplay.mOverflowY)) {}
bool ScrollStyles::IsHiddenInBothDirections() const {
return mHorizontal == StyleOverflow::Hidden &&

Просмотреть файл

@ -8,7 +8,6 @@
#define mozilla_ScrollStyles_h
#include <stdint.h>
#include "mozilla/dom/WindowBinding.h"
// Forward declarations
struct nsStyleDisplay;
@ -17,17 +16,20 @@ namespace mozilla {
enum class StyleOverflow : uint8_t;
// NOTE: Only styles that are propagated from the <body> should end up in this
// class.
struct ScrollStyles {
// Always one of Scroll, Hidden, or Auto
// Always one of Scroll, Hidden, or Auto.
StyleOverflow mHorizontal;
StyleOverflow mVertical;
ScrollStyles(StyleOverflow aH, StyleOverflow aV)
: mHorizontal(aH), mVertical(aV) {}
ScrollStyles(StyleOverflow aH, StyleOverflow aV);
// NOTE: This ctor maps `visible` to `auto` and `clip` to `hidden`.
// It's used for styles that are propagated from the <body> and for
// scroll frames (which we create also for overflow:clip/visible in
// some cases, e.g. form controls).
enum MapOverflowToValidScrollStyleTag { MapOverflowToValidScrollStyle };
ScrollStyles(const nsStyleDisplay&, MapOverflowToValidScrollStyleTag);
explicit ScrollStyles(const nsStyleDisplay&);
bool operator==(const ScrollStyles& aStyles) const {
return aStyles.mHorizontal == mHorizontal && aStyles.mVertical == mVertical;
}

Просмотреть файл

@ -1085,16 +1085,12 @@ static bool CheckOverflow(const ComputedStyle* aComputedStyle,
return false;
}
if (display->mOverflowX == StyleOverflow::Visible) {
MOZ_ASSERT(display->mOverflowY == StyleOverflow::Visible);
if (display->mOverflowX == StyleOverflow::Visible &&
display->mOverflowY == StyleOverflow::Visible) {
return false;
}
if (display->mOverflowX == StyleOverflow::Clip) {
*aStyles = ScrollStyles(StyleOverflow::Hidden, StyleOverflow::Hidden);
} else {
*aStyles = ScrollStyles(*display);
}
*aStyles = ScrollStyles(*display, ScrollStyles::MapOverflowToValidScrollStyle);
return true;
}

Просмотреть файл

@ -9,14 +9,21 @@
#ifndef nsPresContext_h___
#define nsPresContext_h___
#include "mozilla/AppUnits.h"
#include "mozilla/Attributes.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/MediaEmulationData.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/NotNull.h"
#include "mozilla/ScrollStyles.h"
#include "mozilla/PreferenceSheet.h"
#include "mozilla/PresShellForwards.h"
#include "mozilla/ScrollStyles.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
#include "nsColor.h"
#include "nsCompatibility.h"
#include "nsCoord.h"
#include "nsCOMPtr.h"
#include "nsRect.h"
@ -32,11 +39,6 @@
#include "gfxTypes.h"
#include "gfxRect.h"
#include "nsTArray.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/AppUnits.h"
#include "mozilla/MediaEmulationData.h"
#include "mozilla/PresShellForwards.h"
#include "prclist.h"
#include "nsThreadUtils.h"
#include "Units.h"
@ -131,6 +133,8 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
using Encoding = mozilla::Encoding;
template <typename T>
using NotNull = mozilla::NotNull<T>;
template <typename T>
using Maybe = mozilla::Maybe<T>;
using MediaEmulationData = mozilla::MediaEmulationData;
using StylePrefersColorScheme = mozilla::StylePrefersColorScheme;
@ -1220,7 +1224,7 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
mozilla::TimeStamp mReflowStartTime;
mozilla::Maybe<TransactionId> mFirstContentfulPaintTransactionId;
Maybe<TransactionId> mFirstContentfulPaintTransactionId;
mozilla::UniquePtr<mozilla::MediaFeatureChange>
mPendingMediaFeatureValuesChange;

Просмотреть файл

@ -1254,9 +1254,12 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
Maybe<ReflowInput> mutableReflowInput;
// If we have non-auto block size, we're clipping our kids and we fit,
// make sure our kids fit too.
const PhysicalAxes physicalBlockAxis =
wm.IsVertical() ? PhysicalAxes::Horizontal : PhysicalAxes::Vertical;
if (aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE &&
aReflowInput.ComputedBSize() != NS_UNCONSTRAINEDSIZE &&
ShouldApplyOverflowClipping(aReflowInput.mStyleDisplay)) {
(ShouldApplyOverflowClipping(aReflowInput.mStyleDisplay) &
physicalBlockAxis)) {
LogicalMargin blockDirExtras = aReflowInput.ComputedLogicalBorderPadding();
if (GetLogicalSkipSides().BStart()) {
blockDirExtras.BStart(wm) = 0;
@ -2042,7 +2045,7 @@ void nsBlockFrame::ComputeOverflowAreas(const nsRect& aBounds,
// XXX_perf: This can be done incrementally. It is currently one of
// the things that makes incremental reflow O(N^2).
nsOverflowAreas areas(aBounds, aBounds);
if (!ShouldApplyOverflowClipping(aDisplay)) {
if (ShouldApplyOverflowClipping(aDisplay) != PhysicalAxes::Both) {
for (const auto& line : Lines()) {
if (aDisplay->IsContainLayout()) {
// If we have layout containment, we should only consider our child's

Просмотреть файл

@ -4314,7 +4314,8 @@ ScrollStyles ScrollFrameHelper::GetScrollStylesFromFrame() const {
}
if (!mIsRoot) {
return ScrollStyles(*mOuter->StyleDisplay());
return ScrollStyles(*mOuter->StyleDisplay(),
ScrollStyles::MapOverflowToValidScrollStyle);
}
ScrollStyles result = presContext->GetViewportScrollStylesOverride();

Просмотреть файл

@ -854,7 +854,7 @@ class nsHTMLScrollFrame : public nsContainerFrame,
return mHelper.GetScrolledFrame()->GetContentInsertionFrame();
}
bool DoesClipChildren() final { return true; }
bool DoesClipChildrenInBothAxes() final { return true; }
nsPoint GetPositionOfChildIgnoringScrolling(const nsIFrame* aChild) final {
nsPoint pt = aChild->GetPosition();
@ -1298,7 +1298,7 @@ class nsXULScrollFrame final : public nsBoxFrame,
return mHelper.GetScrolledFrame()->GetContentInsertionFrame();
}
bool DoesClipChildren() final { return true; }
bool DoesClipChildrenInBothAxes() final { return true; }
nsPoint GetPositionOfChildIgnoringScrolling(const nsIFrame* aChild) final {
nsPoint pt = aChild->GetPosition();

Просмотреть файл

@ -1778,7 +1778,7 @@ bool nsIFrame::Extend3DContext(const nsStyleDisplay* aStyleDisplay,
return false;
}
return !ShouldApplyOverflowClipping(disp) &&
return ShouldApplyOverflowClipping(disp) == PhysicalAxes::None &&
!GetClipPropClipRect(disp, effects, GetSize()) &&
!SVGIntegrationUtils::UsingEffectsForFrame(this);
}
@ -2653,17 +2653,18 @@ Maybe<nsRect> nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp,
* handled by constructing a dedicated nsHTML/XULScrollFrame, set up clipping
* for that overflow in aBuilder->ClipState() to clip all containing-block
* descendants.
*
* Return true if clipping was applied.
*/
static void ApplyOverflowClipping(
nsDisplayListBuilder* aBuilder, const nsIFrame* aFrame,
nsIFrame::PhysicalAxes aClipAxes,
DisplayListClipState::AutoClipMultiple& aClipState) {
// Only 'clip' is handled here (and 'hidden' for table frames, and any
// non-'visible' value for blocks in a paginated context).
// We allow 'clip' to apply to any kind of frame. This is required by
// comboboxes which make their display text (an inline frame) have clipping.
MOZ_ASSERT(aFrame->ShouldApplyOverflowClipping(aFrame->StyleDisplay()));
MOZ_ASSERT(aClipAxes != nsIFrame::PhysicalAxes::None);
MOZ_ASSERT(aFrame->ShouldApplyOverflowClipping(aFrame->StyleDisplay()) ==
aClipAxes);
nsRect clipRect;
bool haveRadii = false;
@ -2689,6 +2690,20 @@ static void ApplyOverflowClipping(
bp.ApplySkipSides(aFrame->GetSkipSides());
nsRect rect(nsPoint(0, 0), aFrame->GetSize());
rect.Deflate(bp);
if (MOZ_UNLIKELY(!(aClipAxes & nsIFrame::PhysicalAxes::Horizontal))) {
// NOTE(mats) We shouldn't be clipping at all in this dimension really,
// but clipping in just one axis isn't supported by our GFX APIs so we
// clip to our visual overflow rect instead.
nsRect o = aFrame->InkOverflowRect();
rect.x = o.x;
rect.width = o.width;
}
if (MOZ_UNLIKELY(!(aClipAxes & nsIFrame::PhysicalAxes::Vertical))) {
// See the note above.
nsRect o = aFrame->InkOverflowRect();
rect.y = o.y;
rect.height = o.height;
}
clipRect = rect + aBuilder->ToReferenceFrame(aFrame);
haveRadii = aFrame->GetBoxBorderRadii(radii, bp, false);
aClipState.ClipContainingBlockDescendantsExtra(clipRect,
@ -3989,8 +4004,9 @@ void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
placeholder ? placeholder->GetOutOfFlowFrame() : child;
nsIFrame* parent = childOrOutOfFlow->GetParent();
const bool shouldApplyOverflowClip =
parent->ShouldApplyOverflowClipping(parent->StyleDisplay());
const auto* parentDisplay = parent->StyleDisplay();
const auto overflowClipAxes =
parent->ShouldApplyOverflowClipping(parentDisplay);
const bool isPaintingToWindow = aBuilder->IsPaintingToWindow();
const bool doingShortcut =
@ -3999,8 +4015,8 @@ void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// Animations may change the stacking context state.
// ShouldApplyOverflowClipping is affected by the parent style, which does
// not invalidate the NS_FRAME_SIMPLE_DISPLAYLIST bit.
!(shouldApplyOverflowClip || child->MayHaveTransformAnimation() ||
child->MayHaveOpacityAnimation());
!(overflowClipAxes != PhysicalAxes::None ||
child->MayHaveTransformAnimation() || child->MayHaveOpacityAnimation());
if (aBuilder->IsForPainting()) {
aBuilder->ClearWillChangeBudgetStatus(child);
@ -4180,8 +4196,8 @@ void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// FIXME(emilio): Why can't we handle this more similarly to `clip` (on the
// parent, rather than on the children)? Would ClipContentDescendants do what
// we want?
if (shouldApplyOverflowClip) {
ApplyOverflowClipping(aBuilder, parent, clipState);
if (overflowClipAxes != PhysicalAxes::None) {
ApplyOverflowClipping(aBuilder, parent, overflowClipAxes, clipState);
awayFromCommonPath = true;
}
@ -7381,7 +7397,7 @@ bool nsIFrame::ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) {
/* virtual */
void nsIFrame::UnionChildOverflow(nsOverflowAreas& aOverflowAreas) {
if (!DoesClipChildren() &&
if (!DoesClipChildrenInBothAxes() &&
!(IsXULCollapsed() && (IsXULBoxFrame() || ::IsXULBoxWrapped(this)))) {
nsLayoutUtils::UnionChildOverflow(this, aOverflowAreas);
}
@ -9021,7 +9037,8 @@ static nsRect UnionBorderBoxes(
}
const nsStyleDisplay* disp = aFrame->StyleDisplay();
LayoutFrameType fType = aFrame->Type();
if (aFrame->ShouldApplyOverflowClipping(disp) ||
auto overflowClipAxes = aFrame->ShouldApplyOverflowClipping(disp);
if (overflowClipAxes == nsIFrame::PhysicalAxes::Both ||
fType == LayoutFrameType::Scroll ||
fType == LayoutFrameType::ListControl ||
fType == LayoutFrameType::SVGOuterSVG) {
@ -9092,6 +9109,15 @@ static nsRect UnionBorderBoxes(
}
}
if (overflowClipAxes & nsIFrame::PhysicalAxes::Vertical) {
u.y = bounds.y;
u.height = bounds.height;
}
if (overflowClipAxes & nsIFrame::PhysicalAxes::Horizontal) {
u.x = bounds.x;
u.width = bounds.width;
}
return u;
}
@ -9237,12 +9263,12 @@ bool nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
// changed.
SetSize(aNewSize, false);
const bool applyOverflowClipping = ShouldApplyOverflowClipping(disp);
const auto overflowClipAxes = ShouldApplyOverflowClipping(disp);
if (ChildrenHavePerspective(disp) && sizeChanged) {
RecomputePerspectiveChildrenOverflow(this);
if (!applyOverflowClipping) {
if (overflowClipAxes != PhysicalAxes::Both) {
aOverflowAreas.SetAllTo(bounds);
DebugOnly<bool> ok = ComputeCustomOverflow(aOverflowAreas);
@ -9271,16 +9297,25 @@ bool nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
"Computed overflow area must contain frame bounds");
}
// If we clip our children, clear accumulated overflow area. The
// children are actually clipped to the padding-box, but since the
// overflow area should include the entire border-box, just set it to
// the border-box here.
NS_ASSERTION((disp->mOverflowY == StyleOverflow::Clip) ==
(disp->mOverflowX == StyleOverflow::Clip),
"If one overflow is clip, the other should be too");
if (applyOverflowClipping) {
// The contents are actually clipped to the padding area
aOverflowAreas.SetAllTo(bounds);
// If we clip our children, clear accumulated overflow area in the affected
// dimension(s). The children are actually clipped to the padding-box, but
// since the overflow area should include the entire border-box, just set it
// to the border-box size here.
if (overflowClipAxes != PhysicalAxes::None) {
nsRect& ink = aOverflowAreas.InkOverflow();
nsRect& scrollable = aOverflowAreas.ScrollableOverflow();
if (overflowClipAxes & PhysicalAxes::Vertical) {
ink.y = bounds.y;
scrollable.y = bounds.y;
ink.height = bounds.height;
scrollable.height = bounds.height;
}
if (overflowClipAxes & PhysicalAxes::Horizontal) {
ink.x = bounds.x;
scrollable.x = bounds.x;
ink.width = bounds.width;
scrollable.width = bounds.width;
}
}
// Overflow area must always include the frame's top-left and bottom-right,
@ -11020,7 +11055,8 @@ void nsIFrame::UpdateVisibleDescendantsState() {
}
}
bool nsIFrame::ShouldApplyOverflowClipping(const nsStyleDisplay* aDisp) const {
nsIFrame::PhysicalAxes nsIFrame::ShouldApplyOverflowClipping(
const nsStyleDisplay* aDisp) const {
MOZ_ASSERT(aDisp == StyleDisplay(), "Wrong display struct");
// 'contain:paint', which we handle as 'overflow:clip' here. Except for
@ -11030,7 +11066,7 @@ bool nsIFrame::ShouldApplyOverflowClipping(const nsStyleDisplay* aDisp) const {
// (e.g. because it forms a fixed-pos containing block).
if (aDisp->IsContainPaint() && !IsScrollFrame() &&
IsFrameOfType(eSupportsContainLayoutAndPaint)) {
return true;
return PhysicalAxes::Both;
}
// and overflow:hidden that we should interpret as clip
@ -11045,35 +11081,48 @@ bool nsIFrame::ShouldApplyOverflowClipping(const nsStyleDisplay* aDisp) const {
case LayoutFrameType::SVGInnerSVG:
case LayoutFrameType::SVGSymbol:
case LayoutFrameType::SVGForeignObject:
return true;
return PhysicalAxes::Both;
default:
if (IsFrameOfType(nsIFrame::eReplacedContainsBlock)) {
// It has an anonymous scroll frame that handles any overflow
// except TextInput.
return type != LayoutFrameType::TextInput;
if (type == mozilla::LayoutFrameType::TextInput) {
// It has an anonymous scroll frame that handles any overflow.
return PhysicalAxes::None;
}
return PhysicalAxes::Both;
}
}
}
// clip overflow:clip, except for nsListControlFrame,
// which is an nsHTMLScrollFrame.
if (MOZ_UNLIKELY(aDisp->mOverflowX == StyleOverflow::Clip &&
// clip overflow:clip, except for nsListControlFrame which is
// an nsHTMLScrollFrame sub-class.
if (MOZ_UNLIKELY((aDisp->mOverflowX == mozilla::StyleOverflow::Clip ||
aDisp->mOverflowY == mozilla::StyleOverflow::Clip) &&
!IsListControlFrame())) {
// FIXME: we could use GetViewportScrollStylesOverrideElement() here instead
// if that worked correctly in a print context. (see bug 1654667)
const auto* element = Element::FromNodeOrNull(GetContent());
if (!element ||
!PresContext()->ElementWouldPropagateScrollStyles(*element)) {
return true;
uint8_t axes = uint8_t(PhysicalAxes::None);
if (aDisp->mOverflowX == mozilla::StyleOverflow::Clip) {
axes |= uint8_t(PhysicalAxes::Horizontal);
}
if (aDisp->mOverflowY == mozilla::StyleOverflow::Clip) {
axes |= uint8_t(PhysicalAxes::Vertical);
}
return PhysicalAxes(axes);
}
}
if (HasAnyStateBits(NS_FRAME_SVG_LAYOUT)) {
return false;
return PhysicalAxes::None;
}
// If we're paginated and a block, and have NS_BLOCK_CLIP_PAGINATED_OVERFLOW
// set, then we want to clip our overflow.
return HasAnyStateBits(NS_BLOCK_CLIP_PAGINATED_OVERFLOW) &&
PresContext()->IsPaginated() && IsBlockFrame();
bool clip = HasAnyStateBits(NS_BLOCK_CLIP_PAGINATED_OVERFLOW) &&
PresContext()->IsPaginated() && IsBlockFrame();
return clip ? PhysicalAxes::Both : PhysicalAxes::None;
}
// Box layout debugging

Просмотреть файл

@ -2956,10 +2956,18 @@ class nsIFrame : public nsQueryFrame {
*/
virtual void UnionChildOverflow(nsOverflowAreas& aOverflowAreas);
// Represents zero or more physical axes.
enum class PhysicalAxes : uint8_t {
None = 0x0,
Horizontal = 0x1,
Vertical = 0x2,
Both = Horizontal | Vertical,
};
/**
* Returns true if this frame should apply overflow clipping.
*/
bool ShouldApplyOverflowClipping(const nsStyleDisplay* aDisp) const;
PhysicalAxes ShouldApplyOverflowClipping(const nsStyleDisplay* aDisp) const;
/**
* Helper method used by block reflow to identify runs of text so
@ -4254,7 +4262,7 @@ class nsIFrame : public nsQueryFrame {
* Returns true if this box clips its children, e.g., if this box is an
* scrollbox.
*/
virtual bool DoesClipChildren();
virtual bool DoesClipChildrenInBothAxes();
// We compute and store the HTML content's overflow area. So don't
// try to compute it in the box code.
@ -5381,6 +5389,7 @@ class nsIFrame : public nsQueryFrame {
#endif
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsIFrame::PhysicalAxes)
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(nsIFrame::ReflowChildFlags)
//----------------------------------------------------------------------

Просмотреть файл

@ -12,6 +12,7 @@
#define nsIScrollFrame_h___
#include "nsCoord.h"
#include "mozilla/dom/WindowBinding.h" // for mozilla::dom::ScrollBehavior
#include "mozilla/Maybe.h"
#include "mozilla/ScrollOrigin.h"
#include "mozilla/ScrollStyles.h"

Просмотреть файл

@ -35,11 +35,11 @@
<img width="400px" height="10px" src="data:image/gif;base64,R0lGODlhAQABAIABAAD/AP///ywAAAAAAQABAAACAkQBADs=">
</div>
</div>
<div class="outer">
<div class="clip"><div class="outer">
<div class="inner">
<img width="400px" height="10px" src="data:image/gif;base64,R0lGODlhAQABAIABAAD/AP///ywAAAAAAQABAAACAkQBADs=">
</div>
</div>
</div></div>
<div class="clip"><div class="outer">
<div class="inner">
<img width="400px" height="10px" src="data:image/gif;base64,R0lGODlhAQABAIABAAD/AP///ywAAAAAAQABAAACAkQBADs=">
@ -66,11 +66,11 @@
<img width="400px" height="10px" src="data:image/gif;base64,R0lGODlhAQABAIABAAD/AP///ywAAAAAAQABAAACAkQBADs=">
</div>
</div>
<div class="outer">
<div class="clip"><div class="outer">
<div class="inner">
<img width="400px" height="10px" src="data:image/gif;base64,R0lGODlhAQABAIABAAD/AP///ywAAAAAAQABAAACAkQBADs=">
</div>
</div>
</div></div>
<div class="clip"><div class="outer">
<div class="inner">
<img width="400px" height="10px" src="data:image/gif;base64,R0lGODlhAQABAIABAAD/AP///ywAAAAAAQABAAACAkQBADs=">

Просмотреть файл

@ -33,7 +33,7 @@
</div>
<div class="outer">
<div class="inner" style="overflow-y:clip;">
<img width="400px" height="10px" src="data:image/gif;base64,R0lGODlhAQABAIABAAD/AP///ywAAAAAAQABAAACAkQBADs=">
<img width="296px" height="10px" src="data:image/gif;base64,R0lGODlhAQABAIABAAD/AP///ywAAAAAAQABAAACAkQBADs=">
</div>
</div>
<div class="outer">
@ -64,7 +64,7 @@
</div>
<div class="outer" style="overflow-y:clip;">
<div class="inner">
<img width="400px" height="10px" src="data:image/gif;base64,R0lGODlhAQABAIABAAD/AP///ywAAAAAAQABAAACAkQBADs=">
<img width="296px" height="10px" src="data:image/gif;base64,R0lGODlhAQABAIABAAD/AP///ywAAAAAAQABAAACAkQBADs=">
</div>
</div>
<div class="outer" style="overflow:hidden;">

Просмотреть файл

@ -1504,8 +1504,8 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay {
}
bool IsScrollableOverflow() const {
// mOverflowX and mOverflowY always match when one of them is
// Visible or Clip.
// Visible and Clip can be combined but not with other values,
// so checking mOverflowX is enough.
return mOverflowX != mozilla::StyleOverflow::Visible &&
mOverflowX != mozilla::StyleOverflow::Clip;
}

Просмотреть файл

@ -1926,7 +1926,8 @@ void nsTableFrame::Reflow(nsPresContext* aPresContext,
// make sure the table overflow area does include the table rect.
nsRect tableRect(0, 0, aDesiredSize.Width(), aDesiredSize.Height());
if (!ShouldApplyOverflowClipping(aReflowInput.mStyleDisplay)) {
if (ShouldApplyOverflowClipping(aReflowInput.mStyleDisplay) !=
PhysicalAxes::Both) {
// collapsed border may leak out
LogicalMargin bcMargin = GetExcludedOuterBCBorder(wm);
tableRect.Inflate(bcMargin.GetPhysicalMargin(wm));
@ -2001,7 +2002,7 @@ void nsTableFrame::FixupPositionedTableParts(nsPresContext* aPresContext,
bool nsTableFrame::ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas) {
// As above in Reflow, make sure the table overflow area includes the table
// rect, and check for collapsed borders leaking out.
if (!ShouldApplyOverflowClipping(StyleDisplay())) {
if (ShouldApplyOverflowClipping(StyleDisplay()) != PhysicalAxes::Both) {
nsRect bounds(nsPoint(0, 0), GetSize());
WritingMode wm = GetWritingMode();
LogicalMargin bcMargin = GetExcludedOuterBCBorder(wm);

Просмотреть файл

@ -255,13 +255,10 @@ nsresult nsIFrame::XULLayout(nsBoxLayoutState& aState) {
return NS_OK;
}
bool nsIFrame::DoesClipChildren() {
bool nsIFrame::DoesClipChildrenInBothAxes() {
const nsStyleDisplay* display = StyleDisplay();
NS_ASSERTION(
(display->mOverflowY == StyleOverflow::Clip) ==
(display->mOverflowX == StyleOverflow::Clip),
"If one overflow is clip, the other should be too");
return display->mOverflowX == StyleOverflow::Clip;
return display->mOverflowX == StyleOverflow::Clip &&
display->mOverflowY == StyleOverflow::Clip;
}
nsresult nsIFrame::SyncXULLayout(nsBoxLayoutState& aBoxLayoutState) {
@ -290,7 +287,7 @@ nsresult nsIFrame::SyncXULLayout(nsBoxLayoutState& aBoxLayoutState) {
} else {
nsRect rect(nsPoint(0, 0), GetSize());
nsOverflowAreas overflowAreas(rect, rect);
if (!DoesClipChildren() && !IsXULCollapsed()) {
if (!DoesClipChildrenInBothAxes() && !IsXULCollapsed()) {
// See if our child frames caused us to overflow after being laid
// out. If so, store the overflow area. This normally can't happen
// in XUL, but it can happen with the CSS 'outline' property and

Просмотреть файл

@ -97,7 +97,7 @@ class nsScrollbarFrame final : public nsBoxFrame,
* scrollframe by setting its height or width to zero, that will
* hide the children too.
*/
virtual bool DoesClipChildren() override { return true; }
virtual bool DoesClipChildrenInBothAxes() override { return true; }
virtual nsresult GetXULMargin(nsMargin& aMargin) override;

Просмотреть файл

@ -469,48 +469,22 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
}
/// CSS3 overflow-x and overflow-y require some fixup as well in some
/// cases.
///
/// overflow: clip and overflow: visible are meaningful only when used in
/// both dimensions.
/// CSS overflow-x and overflow-y require some fixup as well in some cases.
/// https://drafts.csswg.org/css-overflow-3/#overflow-properties
/// "Computed value: as specified, except with `visible`/`clip` computing to
/// `auto`/`hidden` (respectively) if one of `overflow-x` or `overflow-y` is
/// neither `visible` nor `clip`."
fn adjust_for_overflow(&mut self) {
let original_overflow_x = self.style.get_box().clone_overflow_x();
let original_overflow_y = self.style.get_box().clone_overflow_y();
let mut overflow_x = original_overflow_x;
let mut overflow_y = original_overflow_y;
let overflow_x = self.style.get_box().clone_overflow_x();
let overflow_y = self.style.get_box().clone_overflow_y();
if overflow_x == overflow_y {
return;
return; // optimization for the common case
}
// If 'visible' is specified but doesn't match the other dimension,
// it turns into 'auto'.
if overflow_x == Overflow::Visible {
overflow_x = Overflow::Auto;
}
if overflow_y == Overflow::Visible {
overflow_y = Overflow::Auto;
}
#[cfg(feature = "gecko")]
{
// overflow: clip is deprecated, so convert to hidden if it's
// specified in only one dimension.
if overflow_x == Overflow::Clip {
overflow_x = Overflow::Hidden;
}
if overflow_y == Overflow::Clip {
overflow_y = Overflow::Hidden;
}
}
if overflow_x != original_overflow_x || overflow_y != original_overflow_y {
if overflow_x.is_scrollable() != overflow_y.is_scrollable() {
let box_style = self.style.mutate_box();
box_style.set_overflow_x(overflow_x);
box_style.set_overflow_y(overflow_y);
box_style.set_overflow_x(overflow_x.to_scrollable());
box_style.set_overflow_y(overflow_y.to_scrollable());
}
}

Просмотреть файл

@ -0,0 +1,3 @@
[clip-003.html]
expected:
if os == "mac": FAIL # 3rd and 5th grid container fails on macOS 10.14 by rendering scrollbars in both axes. However, the same build succeeds when I load the test locally on a 10.15.3 MacBook

Просмотреть файл

@ -1,31 +0,0 @@
[overflow-computed.html]
[Property overflow value 'clip clip']
expected: FAIL
[Property overflow value 'clip auto']
expected: FAIL
[Property overflow value 'auto clip']
expected: FAIL
[Property overflow value 'hidden clip']
expected: FAIL
[Property overflow value 'scroll clip']
expected: FAIL
[Property overflow value 'clip']
expected: FAIL
[Property overflow value 'clip hidden']
expected: FAIL
[Property overflow-y value 'clip']
expected: FAIL
[Property overflow value 'clip scroll']
expected: FAIL
[Property overflow-block value 'clip']
expected: FAIL

Просмотреть файл

@ -1,13 +0,0 @@
[overflow-valid.html]
[e.style['overflow'\] = "clip" should set the property value]
expected: FAIL
[e.style['overflow-y'\] = "clip" should set the property value]
expected: FAIL
[e.style['overflow'\] = "clip clip" should set the property value]
expected: FAIL
[e.style['overflow-block'\] = "clip" should set the property value]
expected: FAIL

Просмотреть файл

@ -0,0 +1,35 @@
<!doctype html>
<meta charset="utf-8">
<title>Reference: overflow: clip can be combined with overflow: visible</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<style>
.outer {
width: 50px;
height: 50px;
margin-left: 100px;
margin-top: 100px;
background: black;
}
.inner {
position: relative;
background: blue;
height: 100px;
width: 100px;
opacity: 0.5;
}
</style>
<!-- there should be no overflow -->
<div class="outer">
<div class="inner" style="width:50px; height:50px;"></div>
</div>
<!-- there should be overflow in the vertical dimension, but not horizontally -->
<div class="outer">
<div class="inner" style="top:-20px; width:50px"></div>
</div>
<!-- there should be overflow in the horizontal dimension, but not vertically -->
<div class="outer">
<div class="inner" style="left:-40px; height:50px"></div>
</div>

Просмотреть файл

@ -0,0 +1,39 @@
<!doctype html>
<meta charset="utf-8">
<title>CSS Test: overflow:clip can be combined with overflow:visible</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<link rel="help" href="https://drafts.csswg.org/css-overflow/#valdef-overflow-clip">
<link rel="match" href="clip-002-ref.html">
<style>
.outer {
width: 50px;
height: 50px;
margin-left: 100px;
margin-top: 100px;
background: black;
}
.inner {
position: relative;
top: -20px;
left: -40px;
background: blue;
height: 100px;
width: 100px;
opacity: 0.5;
}
</style>
<!-- there should be no overflow -->
<div class="outer" style="overflow:clip">
<div class="inner"></div>
</div>
<!-- there should be overflow in the vertical dimension, but not horizontally -->
<div class="outer" style="overflow-x:clip">
<div class="inner"></div>
</div>
<!-- there should be overflow in the horizontal dimension, but not vertically -->
<div class="outer" style="overflow-y:clip">
<div class="inner"></div>
</div>

Просмотреть файл

@ -0,0 +1,61 @@
<!doctype html>
<meta charset="utf-8">
<title>Reference: overflow:clip can be combined with overflow:visible</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<style>
.wrapper {
margin-left: 30px;
margin-bottom: 20px;
width: 50px;
height: 50px;
}
.outer {
width: 50px;
height: 50px;
background: black;
}
.inner {
position: relative;
top: -10px;
left: -10px;
height: 100px;
width: 100px;
background: blue;
opacity: 0.5;
}
</style>
<!-- there should be no scrollbars -->
<div class="wrapper" style="overflow: hidden">
<div class="outer">
<div class="inner"></div>
</div>
</div>
<!-- there should be no white areas inside the outline -->
<div class="wrapper" style="outline: solid">
<div class="outer">
<div class="inner" style="left:0; width:50px"></div>
</div>
</div>
<!-- there should be a vertical scrollbar, but not a horizontal one -->
<div class="wrapper" style="overflow: hidden scroll; margin-top:50px">
<div class="outer">
<div class="inner" style="width:1px"></div>
</div>
</div>
<!-- there should be no white areas inside the outline -->
<div class="wrapper" style="outline: solid">
<div class="outer">
<div class="inner" style="top:0; height:50px"></div>
</div>
</div>
<!-- there should be horizontal scrollbar, but not a vertical one -->
<div class="wrapper" style="overflow: scroll hidden">
<div class="outer">
<div class="inner" style="height:1px"></div>
</div>
</div>

Просмотреть файл

@ -0,0 +1,63 @@
<!doctype html>
<meta charset="utf-8">
<title>CSS Test: overflow:clip can be combined with overflow:visible</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<link rel="help" href="https://drafts.csswg.org/css-overflow/#valdef-overflow-clip">
<link rel="match" href="clip-003-ref.html">
<style>
.wrapper {
margin-left: 30px;
margin-bottom: 20px;
width: 50px;
height: 50px;
}
.outer {
width: 50px;
height: 50px;
background: black;
}
.inner {
position: relative;
top: -10px;
left: -10px;
height: 100px;
width: 100px;
background: blue;
opacity: 0.5;
}
</style>
<!-- there should be no scrollbars -->
<div class="wrapper" style="overflow: auto">
<div class="outer" style="overflow:clip; outline:solid red">
<div class="inner"></div>
</div>
</div>
<!-- there should be no white areas inside the outline -->
<div class="wrapper" style="outline: solid">
<div class="outer" style="overflow-x:clip">
<div class="inner"></div>
</div>
</div>
<!-- there should be a vertical scrollbar, but not a horizontal one -->
<div class="wrapper" style="overflow: auto; margin-top:50px">
<div class="outer" style="overflow-x:clip">
<div class="inner" style="width:1px"></div>
</div>
</div>
<!-- there should be no white areas inside the outline -->
<div class="wrapper" style="outline: solid">
<div class="outer" style="overflow-y:clip">
<div class="inner"></div>
</div>
</div>
<!-- there should be horizontal scrollbar, but not a vertical one -->
<div class="wrapper" style="overflow: auto">
<div class="outer" style="overflow-y:clip">
<div class="inner" style="height:1px"></div>
</div>
</div>

Просмотреть файл

@ -0,0 +1,35 @@
<!doctype html>
<meta charset="utf-8">
<title>Reference: overflow: clip can be combined with overflow: visible</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<style>
.outer {
width: 50px;
height: 50px;
margin-left: 100px;
margin-top: 100px;
background: black;
}
.inner {
position: relative;
background: blue;
height: 100px;
width: 100px;
opacity: 0.5;
}
</style>
<!-- there should be no overflow -->
<div class="outer">
<div class="inner" style="width:50px; height:50px;"></div>
</div>
<!-- there should be overflow in the vertical dimension, but not horizontally -->
<div class="outer">
<div class="inner" style="top:-10px; width:50px"></div>
</div>
<!-- there should be overflow in the horizontal dimension, but not vertically -->
<div class="outer">
<div class="inner" style="left:-30px; height:50px"></div>
</div>

Просмотреть файл

@ -0,0 +1,40 @@
<!doctype html>
<meta charset="utf-8">
<title>CSS Test: overflow:clip can be combined with overflow:visible</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<link rel="help" href="https://drafts.csswg.org/css-overflow/#valdef-overflow-clip">
<link rel="match" href="clip-004-ref.html">
<style>
.outer {
width: 30px;
height: 30px;
padding: 10px;
margin-left: 100px;
margin-top: 100px;
background: black;
}
.inner {
position: relative;
top: -20px;
left: -40px;
background: blue;
height: 100px;
width: 100px;
opacity: 0.5;
}
</style>
<!-- there should be no overflow -->
<div class="outer" style="overflow:clip">
<div class="inner"></div>
</div>
<!-- there should be overflow in the vertical dimension, but not horizontally -->
<div class="outer" style="overflow-x:clip">
<div class="inner"></div>
</div>
<!-- there should be overflow in the horizontal dimension, but not vertically -->
<div class="outer" style="overflow-y:clip">
<div class="inner"></div>
</div>

Просмотреть файл

@ -0,0 +1,36 @@
<!doctype html>
<meta charset="utf-8">
<title>Reference: overflow:clip doesn't affect the box' own outline</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<style>
.outer {
width: 50px;
height: 50px;
margin-left: 100px;
margin-top: 100px;
background: black;
outline: 2px solid grey;
}
.inner {
position: relative;
background: blue;
height: 100px;
width: 100px;
opacity: 0.5;
}
</style>
<!-- there should be no overflow -->
<div class="outer">
<div class="inner" style="width:50px; height:50px;"></div>
</div>
<!-- there should be overflow in the vertical dimension, but not horizontally -->
<div class="outer">
<div class="inner" style="top:-10px; width:50px"></div>
</div>
<!-- there should be overflow in the horizontal dimension, but not vertically -->
<div class="outer">
<div class="inner" style="left:-30px; height:50px"></div>
</div>

Просмотреть файл

@ -0,0 +1,41 @@
<!doctype html>
<meta charset="utf-8">
<title>CSS Test: overflow:clip doesn't affect the box' own outline</title>
<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1531609">
<link rel="help" href="https://drafts.csswg.org/css-overflow/#valdef-overflow-clip">
<link rel="match" href="clip-005-ref.html">
<style>
.outer {
width: 30px;
height: 30px;
padding: 10px;
margin-left: 100px;
margin-top: 100px;
background: black;
outline: 2px solid grey;
}
.inner {
position: relative;
top: -20px;
left: -40px;
background: blue;
height: 100px;
width: 100px;
opacity: 0.5;
}
</style>
<!-- there should be no overflow -->
<div class="outer" style="overflow:clip">
<div class="inner"></div>
</div>
<!-- there should be overflow in the vertical dimension, but not horizontally -->
<div class="outer" style="overflow-x:clip">
<div class="inner"></div>
</div>
<!-- there should be overflow in the horizontal dimension, but not vertically -->
<div class="outer" style="overflow-y:clip">
<div class="inner"></div>
</div>

Просмотреть файл

@ -25,6 +25,7 @@ test_computed_value("overflow", 'clip auto', 'hidden auto');
test_computed_value("overflow", 'clip clip', 'clip');
test_computed_value("overflow", 'clip hidden', 'hidden');
test_computed_value("overflow", 'clip scroll', 'hidden scroll')
test_computed_value("overflow", 'clip visible', 'clip visible')
test_computed_value("overflow", 'hidden clip', 'hidden');
test_computed_value("overflow", 'hidden visible', 'hidden auto');
test_computed_value("overflow", 'scroll auto');
@ -33,6 +34,7 @@ test_computed_value("overflow", 'scroll visible', 'scroll auto');
test_computed_value("overflow", 'visible auto', 'auto');
test_computed_value("overflow", 'visible hidden', 'auto hidden');
test_computed_value("overflow", 'visible scroll', 'auto scroll');
test_computed_value("overflow", 'visible clip', 'visible clip');
test_computed_value("overflow", 'visible visible', 'visible');