Commit 77b67445 authored by David Bokan's avatar David Bokan Committed by Commit Bot

Elements with fixed bottom and top stick to top

When an element is position: fixed and specifies a value for bottom, we
want it to stick to the bottom of the viewport as the URL bar hides (and
the renderer is moved up). However, we missed the special case where
both top and bottom are specified. We can't resize the element in real
time but it's more intuitive to have the element stick to the screen
top.

This also exposed an issue in how we raster the area exposed by the URL
bar. Since we don't resize the viewport layers until the finger is
lifted, the raster code needs to adjust the visible rect by the amount
the URL bar is hidden. This was done by always adding the entire top
controls height in the pending tree. This was guarded by an ANDROID
ifdef which meant the test added here didn't get its benefit and
produced unrastered tiles. I removed the ifdef (URL bar hiding is now
also available on ChromeOS) and improved the expansion to make it more
exactly match the amount of extra visible area.

Bug: 846322
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I02700e08e8254a64405c3adb1a7a123b65468f44
Reviewed-on: https://chromium-review.googlesource.com/1235123
Commit-Queue: David Bokan <bokan@chromium.org>
Reviewed-by: default avatarStefan Zager <szager@chromium.org>
Reviewed-by: default avatarvmpstr <vmpstr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#594515}
parent 09a02c72
......@@ -718,26 +718,29 @@ void PictureLayerImpl::UpdateViewportRectForTilePriorityInContentSpace() {
}
viewport_rect_for_tile_priority_in_content_space_ =
visible_rect_in_content_space;
#if defined(OS_ANDROID)
// On android, if we're in a scrolling gesture, the pending tree does not
// reflect the fact that we may be hiding the top or bottom controls. Thus,
// it would believe that the viewport is smaller than it actually is which
// can cause activation flickering issues. So, if we're in this situation
// adjust the visible rect by the top/bottom controls height. This isn't
// ideal since we're not always in this case, but since we should be
// prioritizing the active tree anyway, it doesn't cause any serious issues.
// https://crbug.com/794456.
if (layer_tree_impl()->IsPendingTree() &&
layer_tree_impl()->IsActivelyScrolling()) {
float total_controls_height = layer_tree_impl()->top_controls_height() +
layer_tree_impl()->bottom_controls_height();
viewport_rect_for_tile_priority_in_content_space_.Inset(
0, // left
0, // top,
0, // right,
-total_controls_height); // bottom
float total_controls_height = layer_tree_impl()->top_controls_height() +
layer_tree_impl()->bottom_controls_height();
if (total_controls_height) {
// If sliding top controls are being used, the pending tree does not
// reflect the fact that we may be hiding the top or bottom controls. Thus,
// it would believe that the viewport is smaller than it actually is which
// can cause activation flickering issues. So, if we're in this situation
// adjust the visible rect by the amount the controls are expanded beyond
// the current viewport size (this is also called the "bounds delta" in
// LayerImpl and LTHI::UpdateViewportContainerBounds().
if (layer_tree_impl()->IsPendingTree() &&
layer_tree_impl()->browser_controls_shrink_blink_size()) {
float hidden_ratio =
1.f - layer_tree_impl()->CurrentBrowserControlsShownRatio();
viewport_rect_for_tile_priority_in_content_space_.Inset(
0, // left
0, // top,
0, // right,
std::ceilf(-total_controls_height * hidden_ratio)); // bottom
}
}
#endif
}
PictureLayerImpl* PictureLayerImpl::GetPendingOrActiveTwinLayer() const {
......
<!DOCTYPE html>
<meta name="viewport" content="width=device-width, user-scalable=no" />
<script>
// NOTE: It is important that this test be run with the Android viewport
// flags turned on.
if (window.internals) {
internals.settings.setHideScrollbars(true);
}
</script>
<style>
html, body {
height: 100%;
width: 100%;
margin: 0;
background-color: palegreen;
}
#bottom {
position: fixed;
right: 0px;
width: 200px;
top: 0px;
height: 500px;
background-color: coral;
}
</style>
Test passes if the orange bar's top edge is at the top of the screen.
<div id="bottom"></div>
<!DOCTYPE html>
<meta name="viewport" content="width=device-width, user-scalable=no" />
<script>
// NOTE: It is important that this test be run with the Android viewport
// flags turned on.
// Set the browser controls to be 100px and start off showing. Bring them in
// fully without causing a resize. i.e. as if the user dragged them into view
// but hasn't lifted their finger.
// This test verifies that a position: fixed element that has both |top| and
// |bottom| properties set sticks to the top of the screen, rather than the
// bottom.
if (window.internals) {
internals.setBrowserControlsShownRatio(1);
internals.setBrowserControlsState(100, 0, true);
internals.setBrowserControlsShownRatio(0);
internals.settings.setHideScrollbars(true);
}
</script>
<style>
html, body {
height: 100%;
width: 100%;
margin: 0;
}
#cover {
width: 100%;
/* Must be scrollable to force fixed elements to get a transform node. */
height: 200%;
background-color: palegreen;
}
#bottom {
position: fixed;
right: 0px;
width: 200px;
top: 0px;
bottom: 0px;
background-color: coral;
}
</style>
<div id="cover">
Test passes if the orange bar's top edge is at the top of the screen.
</div>
<div id="bottom"></div>
......@@ -837,7 +837,6 @@ void ChromeClientImpl::SetBrowserControlsState(float top_height,
void ChromeClientImpl::SetBrowserControlsShownRatio(float ratio) {
web_view_->GetBrowserControls().SetShownRatio(ratio);
web_view_->DidUpdateBrowserControls();
}
bool ChromeClientImpl::ShouldOpenModalDialogDuringPageDismissal(
......
......@@ -309,7 +309,7 @@ static cc::LayerPositionConstraint ComputePositionConstraint(
if (layer->GetLayoutObject().Style()->GetPosition() == EPosition::kFixed) {
const LayoutObject& fixed_position_object = layer->GetLayoutObject();
bool fixed_to_right = !fixed_position_object.Style()->Right().IsAuto();
bool fixed_to_bottom = !fixed_position_object.Style()->Bottom().IsAuto();
bool fixed_to_bottom = fixed_position_object.Style()->IsFixedToBottom();
cc::LayerPositionConstraint constraint;
constraint.set_is_fixed_position(true);
constraint.set_is_fixed_to_right_edge(fixed_to_right);
......
......@@ -377,7 +377,7 @@ void FragmentPaintPropertyTreeBuilder::UpdatePaintOffsetTranslation(
state.affected_by_outer_viewport_bounds_delta =
object_.StyleRef().GetPosition() == EPosition::kFixed &&
!object_.StyleRef().Bottom().IsAuto();
object_.StyleRef().IsFixedToBottom();
if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled())
......
......@@ -381,6 +381,10 @@ class ComputedStyle : public ComputedStyleBase,
return static_cast<EFillBox>(BackgroundInternal().Clip());
}
// Returns true if the Element should stick to the viewport bottom as the URL
// bar hides.
bool IsFixedToBottom() const { return !Bottom().IsAuto() && Top().IsAuto(); }
// Border properties.
// border-image-slice
const LengthBox& BorderImageSlices() const {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment