From a57cdd05c5e6dc946da9a5967d518f0c3395309b Mon Sep 17 00:00:00 2001 From: David Shin <dshin@mozilla.com> Date: Tue, 13 Dec 2022 15:23:35 +0000 Subject: [PATCH] Bug 1800907 - Do not `UnionRect` empty rects in `OverflowAreas::Union*`. r=jwatt Previously, when current overflow area has one axis at zero size, calling `OverflowAreas::Union*` with a rect with both axes at zero would overwrite the axis with non-zero size. Differential Revision: https://phabricator.services.mozilla.com/D162245 --- layout/generic/ReflowOutput.cpp | 27 ++++++++- .../scrollable-overflow-zero-one-axis.html | 59 +++++++++++++++++++ 2 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 testing/web-platform/tests/css/css-overflow/scrollable-overflow-zero-one-axis.html diff --git a/layout/generic/ReflowOutput.cpp b/layout/generic/ReflowOutput.cpp index d54684809a371..a0312dffda947 100644 --- a/layout/generic/ReflowOutput.cpp +++ b/layout/generic/ReflowOutput.cpp @@ -11,6 +11,19 @@ namespace mozilla { +static bool IsValidOverflowRect(const nsRect& aRect) { + // `IsEmpty` in the context of `nsRect` means "width OR height is zero." + // However, in the context of overflow, the rect having one axis as zero is + // NOT considered empty. + if (MOZ_LIKELY(!aRect.IsEmpty())) { + return true; + } + + // Be defensive and consider rects with any negative size as invalid. + return !aRect.IsEqualEdges(nsRect()) && aRect.Width() >= 0 && + aRect.Height() >= 0; +} + /* static */ nsRect OverflowAreas::GetOverflowClipRect(const nsRect& aRectToClip, const nsRect& aBounds, @@ -40,12 +53,20 @@ void OverflowAreas::ApplyOverflowClippingOnRect(nsRect& aOverflowRect, } void OverflowAreas::UnionWith(const OverflowAreas& aOther) { - InkOverflow().UnionRect(InkOverflow(), aOther.InkOverflow()); - ScrollableOverflow().UnionRect(ScrollableOverflow(), - aOther.ScrollableOverflow()); + if (IsValidOverflowRect(aOther.InkOverflow())) { + InkOverflow().UnionRect(InkOverflow(), aOther.InkOverflow()); + } + if (IsValidOverflowRect(aOther.ScrollableOverflow())) { + ScrollableOverflow().UnionRect(ScrollableOverflow(), + aOther.ScrollableOverflow()); + } } void OverflowAreas::UnionAllWith(const nsRect& aRect) { + if (!IsValidOverflowRect(aRect)) { + // Same as `UnionWith()` - avoid losing information. + return; + } InkOverflow().UnionRect(InkOverflow(), aRect); ScrollableOverflow().UnionRect(ScrollableOverflow(), aRect); } diff --git a/testing/web-platform/tests/css/css-overflow/scrollable-overflow-zero-one-axis.html b/testing/web-platform/tests/css/css-overflow/scrollable-overflow-zero-one-axis.html new file mode 100644 index 0000000000000..1986a8d48b98f --- /dev/null +++ b/testing/web-platform/tests/css/css-overflow/scrollable-overflow-zero-one-axis.html @@ -0,0 +1,59 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Overflow: Scroll Length Calculated Correctly When One Axis Has Zero Length</title> +<link rel="author" title="David Shin" href="mailto:dshin@mozilla.com"> +<link rel="author" title="Mozilla" href="http://www.mozilla.org/"> +<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#scrollable"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1800907"> +<style> +.scroll { + overflow: scroll; +} + +.zero-h { + width: 100px; + height: 0px; +} + +.zero-w { + width: 0; + height: 100px; +} + +.flex-row { + display: flex; +} + +.flex-col { + display: flex; + flex-direction: column; +} + +.grid { + display: grid; +} +</style> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/resources/check-layout-th.js"></script> +<body onload="checkLayout('.scroll')"> +<div class="scroll zero-h" data-expected-scroll-height="100"> + <div class="zero-w"></div> +</div> +<div class="scroll zero-w" data-expected-scroll-width="100"> + <div class="zero-h"></div> +</div> + +<div class="scroll zero-h flex-row" data-expected-scroll-height="100"> + <div class="zero-w"></div> +</div> +<div class="scroll zero-w flex-col" data-expected-scroll-width="100"> + <div class="zero-h"></div> +</div> + +<div class="scroll zero-h grid" data-expected-scroll-height="100"> + <div class="zero-w"></div> +</div> +<div class="scroll zero-w grid" data-expected-scroll-width="100"> + <div class="zero-h"></div> +</div> -- GitLab