Don't create unneeded layers for scrollbar-gutter: force
This CL prevents the creation of unnecessary layers for elements
that use scrollbar-gutter's "force" keyword.
Now those layers are created only when the element's style uses
custom scrollbars, because a PaintLayerScrollableArea is required
in order to calculate their thickness.
When the element uses default scrollbars, their thickness can be
obtained directly from the page's scrollbar theme.
Bug: 710214
Change-Id: Ia319e5601745247189be58da8b1e992a34a17c99
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2738895
Reviewed-by: Philip Rogers <pdr@chromium.org>
Commit-Queue: Felipe Erias <felipeerias@igalia.com>
Cr-Commit-Position: refs/heads/master@{#864254}
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index dfb4b7b..df80e37 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -1489,8 +1489,7 @@
LayoutBox* Element::GetLayoutBoxForScrolling() const {
LayoutBox* box = GetLayoutBox();
- if (!box || (!box->IsScrollContainer() &&
- !box->StyleRef().IsScrollbarGutterForce())) {
+ if (!box || !box->IsScrollContainer()) {
return nullptr;
}
return box;
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index d0c6adc4..0e75300 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -90,6 +90,7 @@
#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.h"
#include "third_party/blink/renderer/core/layout/shapes/shape_outside_info.h"
#include "third_party/blink/renderer/core/page/autoscroll_controller.h"
+#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
#include "third_party/blink/renderer/core/paint/background_image_geometry.h"
@@ -99,6 +100,7 @@
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/paint/rounded_border_geometry.h"
+#include "third_party/blink/renderer/core/style/computed_style_base_constants.h"
#include "third_party/blink/renderer/core/style/shadow_list.h"
#include "third_party/blink/renderer/platform/geometry/double_rect.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
@@ -366,6 +368,30 @@
}
}
+int HypotheticalScrollbarThickness(const LayoutBox& box,
+ ScrollbarOrientation scrollbar_orientation,
+ bool should_include_overlay_thickness) {
+ box.CheckIsNotDestroyed();
+
+ if (PaintLayerScrollableArea* scrollable_area = box.GetScrollableArea()) {
+ return scrollable_area->HypotheticalScrollbarThickness(
+ scrollbar_orientation, should_include_overlay_thickness);
+ } else {
+ Page* page = box.GetFrame()->GetPage();
+ ScrollbarTheme& theme = page->GetScrollbarTheme();
+
+ if (theme.UsesOverlayScrollbars() && !should_include_overlay_thickness) {
+ return 0;
+ } else {
+ ChromeClient& chrome_client = page->GetChromeClient();
+ Document& document = box.GetDocument();
+ float scale_from_dip =
+ chrome_client.WindowToViewportScalar(document.GetFrame(), 1.0f);
+ return theme.ScrollbarThickness(scale_from_dip);
+ }
+ }
+}
+
} // namespace
BoxLayoutExtraInput::BoxLayoutExtraInput(LayoutBox& box) : box(box) {
@@ -416,7 +442,8 @@
if (HasNonVisibleOverflow())
return kOverflowClipPaintLayer;
- if (StyleRef().IsScrollbarGutterForce())
+ if (StyleRef().IsScrollbarGutterForce() &&
+ StyleRef().HasPseudoElementStyle(kPseudoIdScrollbar))
return kNormalPaintLayer;
return kNoPaintLayer;
@@ -1000,8 +1027,14 @@
LayoutUnit LayoutBox::ScrollWidth() const {
NOT_DESTROYED();
- if (IsScrollContainer() || StyleRef().IsScrollbarGutterForce())
+ if (IsScrollContainer())
return GetScrollableArea()->ScrollWidth();
+ if (StyleRef().IsScrollbarGutterForce()) {
+ if (auto* scrollable_area = GetScrollableArea())
+ return scrollable_area->ScrollWidth();
+ else
+ return PhysicalLayoutOverflowRect().Width();
+ }
// For objects with visible overflow, this matches IE.
// FIXME: Need to work right with writing modes.
if (StyleRef().IsLeftToRightDirection())
@@ -1012,8 +1045,14 @@
LayoutUnit LayoutBox::ScrollHeight() const {
NOT_DESTROYED();
- if (IsScrollContainer() || StyleRef().IsScrollbarGutterForce())
+ if (IsScrollContainer())
return GetScrollableArea()->ScrollHeight();
+ if (StyleRef().IsScrollbarGutterForce()) {
+ if (auto* scrollable_area = GetScrollableArea())
+ return scrollable_area->ScrollHeight();
+ else
+ return PhysicalLayoutOverflowRect().Height();
+ }
// For objects with visible overflow, this matches IE.
// FIXME: Need to work right with writing modes.
return std::max(ClientHeight(), LayoutOverflowRect().MaxY() - BorderTop());
@@ -1584,14 +1623,11 @@
NOT_DESTROYED();
NGPhysicalBoxStrut scrollbars;
PaintLayerScrollableArea* scrollable_area = GetScrollableArea();
- if (!scrollable_area)
- return scrollbars;
if (include_scrollbar_gutter == kIncludeScrollbarGutter &&
HasScrollbarGutters(kVerticalScrollbar)) {
- LayoutUnit gutter_size =
- LayoutUnit(scrollable_area->HypotheticalScrollbarThickness(
- kVerticalScrollbar, /* should_include_overlay_thickness */ true));
+ LayoutUnit gutter_size = LayoutUnit(HypotheticalScrollbarThickness(
+ *this, kVerticalScrollbar, /* include_overlay_thickness */ true));
if (ShouldPlaceVerticalScrollbarOnLeft()) {
scrollbars.left = gutter_size;
if (StyleRef().IsScrollbarGutterBoth())
@@ -1601,23 +1637,25 @@
if (StyleRef().IsScrollbarGutterBoth())
scrollbars.left = gutter_size;
}
- } else if (ShouldPlaceVerticalScrollbarOnLeft()) {
- scrollbars.left = LayoutUnit(scrollable_area->VerticalScrollbarWidth(
- overlay_scrollbar_clip_behavior));
- } else {
- scrollbars.right = LayoutUnit(scrollable_area->VerticalScrollbarWidth(
- overlay_scrollbar_clip_behavior));
+ } else if (scrollable_area) {
+ if (ShouldPlaceVerticalScrollbarOnLeft()) {
+ scrollbars.left = LayoutUnit(scrollable_area->VerticalScrollbarWidth(
+ overlay_scrollbar_clip_behavior));
+ } else {
+ scrollbars.right = LayoutUnit(scrollable_area->VerticalScrollbarWidth(
+ overlay_scrollbar_clip_behavior));
+ }
}
if (include_scrollbar_gutter == kIncludeScrollbarGutter &&
HasScrollbarGutters(kHorizontalScrollbar)) {
- LayoutUnit gutter_size =
- LayoutUnit(scrollable_area->HypotheticalScrollbarThickness(
- kHorizontalScrollbar, /* should_include_overlay_thickness */ true));
+ LayoutUnit gutter_size = LayoutUnit(
+ HypotheticalScrollbarThickness(*this, kHorizontalScrollbar,
+ /* include_overlay_thickness */ true));
scrollbars.bottom = gutter_size;
if (StyleRef().IsScrollbarGutterBoth())
scrollbars.top = gutter_size;
- } else {
+ } else if (scrollable_area) {
scrollbars.bottom = LayoutUnit(scrollable_area->HorizontalScrollbarHeight(
overlay_scrollbar_clip_behavior));
}
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 2f9146d..a8ecd5fb 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -1683,10 +1683,12 @@
// PaintLayerScrollableArea.
if (GetLayoutBox()->CanResize())
return true;
- // When scrollbar-gutter is "force" we need a PaintLayerScrollableArea
- // in order to calculate the size of scrollbar gutters.
- if (GetLayoutObject().StyleRef().IsScrollbarGutterForce())
+ // With custom scrollbars, we need a PaintLayerScrollableArea
+ // so we can calculate the size of scrollbar gutters.
+ if (GetLayoutObject().StyleRef().IsScrollbarGutterForce() &&
+ GetLayoutObject().StyleRef().HasPseudoElementStyle(kPseudoIdScrollbar)) {
return true;
+ }
return false;
}
diff --git a/third_party/blink/web_tests/compositing/overflow/overflow-scrollbar-gutter-layers-expected.txt b/third_party/blink/web_tests/compositing/overflow/overflow-scrollbar-gutter-layers-expected.txt
new file mode 100644
index 0000000..c543542
--- /dev/null
+++ b/third_party/blink/web_tests/compositing/overflow/overflow-scrollbar-gutter-layers-expected.txt
@@ -0,0 +1,11 @@
+{
+ "layers": [
+ {
+ "name": "Scrolling Contents Layer",
+ "bounds": [800, 600],
+ "contentsOpaque": true,
+ "backgroundColor": "#FFFFFF"
+ }
+ ]
+}
+
diff --git a/third_party/blink/web_tests/compositing/overflow/overflow-scrollbar-gutter-layers.html b/third_party/blink/web_tests/compositing/overflow/overflow-scrollbar-gutter-layers.html
new file mode 100644
index 0000000..ccf5a15
--- /dev/null
+++ b/third_party/blink/web_tests/compositing/overflow/overflow-scrollbar-gutter-layers.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<style>
+ body {
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+ .container {
+ width: 100px;
+ height: 100px;
+ margin: 5px;
+ background-color: green;
+ border: solid;
+ }
+
+ .content {
+ width: 100%;
+ height: 105px;
+ background-color: orange;
+ }
+
+ /* overflow */
+ .container.visible { overflow: visible; }
+ .container.hidden { overflow-y: hidden; }
+ .container.clip { overflow: clip; }
+
+ /* scrollbar-gutter */
+ .stable { scrollbar-gutter: stable; }
+ .stable_both { scrollbar-gutter: stable both; }
+ .stable_force { scrollbar-gutter: stable force; }
+ .stable_both_force { scrollbar-gutter: stable both force; }
+ .always { scrollbar-gutter: always; }
+ .always_both { scrollbar-gutter: always both; }
+ .always_force { scrollbar-gutter: always force; }
+ .always_both_force { scrollbar-gutter: always both force; }
+
+</style>
+<pre id="layerTree"></pre>
+<!-- These elements should not create new layers. -->
+<div class="container visible stable_force">
+ <div class="content"></div>
+</div>
+<div class="container visible stable_both_force">
+ <div class="content"></div>
+</div>
+<div class="container visible always_force">
+ <div class="content"></div>
+</div>
+<div class="container visible always_both_force">
+ <div class="content"></div>
+</div>
+<div class="container hidden stable_force">
+ <div class="content"></div>
+</div>
+<div class="container hidden stable_both_force">
+ <div class="content"></div>
+</div>
+<div class="container hidden always_force">
+ <div class="content"></div>
+</div>
+<div class="container hidden always_both_force">
+ <div class="content"></div>
+</div>
+<div class="container clip stable_force">
+ <div class="content"></div>
+</div>
+<div class="container clip stable_both_force">
+ <div class="content"></div>
+</div>
+<div class="container clip always_force">
+ <div class="content"></div>
+</div>
+<div class="container clip always_both_force">
+ <div class="content"></div>
+</div>
+<script>
+ if (window.testRunner) {
+ testRunner.dumpAsText();
+ document.getElementById("layerTree").innerText = internals.layerTreeAsText(document);
+ }
+</script>
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/compositing/overflow/overflow-scrollbar-gutter-layers-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/compositing/overflow/overflow-scrollbar-gutter-layers-expected.txt
new file mode 100644
index 0000000..82c7392
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/compositing/overflow/overflow-scrollbar-gutter-layers-expected.txt
@@ -0,0 +1,11 @@
+{
+ "layers": [
+ {
+ "name": "Scrolling background of LayoutView #document",
+ "bounds": [800, 600],
+ "contentsOpaque": true,
+ "backgroundColor": "#FFFFFF"
+ }
+ ]
+}
+