mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-13 11:39:43 +00:00
LibWeb: Fix getBoundingClientRect() for elements with "position: sticky"
Use offset from ScrollFrame which is an actual value a box is shifted by while painting. Also change `update_paint_and_hit_testing_properties_if_needed()` to refresh scroll frames state, because `getBoundingClientRect()` now depends on them. Fixes wrong file tree sidebar location and excessive layout invalidations caused by some miscalculation on JS-side when wrong bounding client rect is provided on Github PR pages like https://github.com/LadybirdBrowser/ladybird/pull/1232/files
This commit is contained in:
parent
d1bea9c2a4
commit
20f68106a7
Notes:
github-actions[bot]
2024-09-02 11:11:13 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: 20f68106a7
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1241
4 changed files with 64 additions and 6 deletions
|
@ -0,0 +1 @@
|
||||||
|
Sticky Element Bounding Client Rect: top=50, left=10, width=500, height=57
|
|
@ -0,0 +1,47 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#scrollable {
|
||||||
|
width: 300px;
|
||||||
|
height: 200px;
|
||||||
|
overflow: auto;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner-content {
|
||||||
|
width: 500px;
|
||||||
|
height: 800px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #f06;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sticky-element {
|
||||||
|
position: sticky;
|
||||||
|
top: 50px;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #4caf50;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div id="scrollable">
|
||||||
|
<div id="inner-content">
|
||||||
|
<div id="sticky-element">Sticky Element</div>
|
||||||
|
<div style="height: 600px"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="include.js"></script>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
const stickyElement = document.getElementById("sticky-element");
|
||||||
|
const boundingRect = stickyElement.getBoundingClientRect();
|
||||||
|
|
||||||
|
const result = document.createElement("p");
|
||||||
|
result.textContent = `Bounding Client Rect: top=${boundingRect.top}, left=${boundingRect.left}, width=${boundingRect.width}, height=${boundingRect.height}`;
|
||||||
|
document.body.appendChild(result);
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -1291,12 +1291,17 @@ void Document::update_animated_style_if_needed()
|
||||||
|
|
||||||
void Document::update_paint_and_hit_testing_properties_if_needed()
|
void Document::update_paint_and_hit_testing_properties_if_needed()
|
||||||
{
|
{
|
||||||
|
if (auto* paintable = this->paintable()) {
|
||||||
|
paintable->refresh_scroll_state();
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_needs_to_resolve_paint_only_properties)
|
if (!m_needs_to_resolve_paint_only_properties)
|
||||||
return;
|
return;
|
||||||
m_needs_to_resolve_paint_only_properties = false;
|
m_needs_to_resolve_paint_only_properties = false;
|
||||||
if (auto* paintable = this->paintable())
|
if (auto* paintable = this->paintable()) {
|
||||||
paintable->resolve_paint_only_properties();
|
paintable->resolve_paint_only_properties();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Document::set_normal_link_color(Color color)
|
void Document::set_normal_link_color(Color color)
|
||||||
{
|
{
|
||||||
|
|
|
@ -974,7 +974,6 @@ JS::NonnullGCPtr<Geometry::DOMRectList> Element::get_client_rects() const
|
||||||
// or inline-table include both the table box and the caption box, if any, but not the anonymous container box.
|
// or inline-table include both the table box and the caption box, if any, but not the anonymous container box.
|
||||||
// FIXME: - Replace each anonymous block box with its child box(es) and repeat this until no anonymous block boxes
|
// FIXME: - Replace each anonymous block box with its child box(es) and repeat this until no anonymous block boxes
|
||||||
// are left in the final list.
|
// are left in the final list.
|
||||||
auto viewport_offset = navigable->viewport_scroll_offset();
|
|
||||||
|
|
||||||
// NOTE: Make sure CSS transforms are resolved before it is used to calculate the rect position.
|
// NOTE: Make sure CSS transforms are resolved before it is used to calculate the rect position.
|
||||||
const_cast<Document&>(document()).update_paint_and_hit_testing_properties_if_needed();
|
const_cast<Document&>(document()).update_paint_and_hit_testing_properties_if_needed();
|
||||||
|
@ -988,21 +987,27 @@ JS::NonnullGCPtr<Geometry::DOMRectList> Element::get_client_rects() const
|
||||||
transform = Gfx::extract_2d_affine_transform(paintable_box->transform());
|
transform = Gfx::extract_2d_affine_transform(paintable_box->transform());
|
||||||
for (auto const* containing_block = paintable->containing_block(); !containing_block->is_viewport(); containing_block = containing_block->containing_block()) {
|
for (auto const* containing_block = paintable->containing_block(); !containing_block->is_viewport(); containing_block = containing_block->containing_block()) {
|
||||||
transform = Gfx::extract_2d_affine_transform(containing_block->transform()).multiply(transform);
|
transform = Gfx::extract_2d_affine_transform(containing_block->transform()).multiply(transform);
|
||||||
scroll_offset.translate_by(containing_block->scroll_offset());
|
}
|
||||||
|
|
||||||
|
if (auto enclosing_scroll_offset = paintable_box->enclosing_scroll_frame(); enclosing_scroll_offset) {
|
||||||
|
scroll_offset.translate_by(-enclosing_scroll_offset->cumulative_offset());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto absolute_rect = paintable_box->absolute_border_box_rect();
|
auto absolute_rect = paintable_box->absolute_border_box_rect();
|
||||||
auto transformed_rect = transform.map(absolute_rect.translated(-paintable_box->transform_origin()).to_type<float>())
|
auto transformed_rect = transform.map(absolute_rect.translated(-paintable_box->transform_origin()).to_type<float>())
|
||||||
.to_type<CSSPixels>()
|
.to_type<CSSPixels>()
|
||||||
.translated(paintable_box->transform_origin())
|
.translated(paintable_box->transform_origin())
|
||||||
.translated(-scroll_offset)
|
.translated(-scroll_offset);
|
||||||
.translated(-viewport_offset);
|
|
||||||
rects.append(Geometry::DOMRect::create(realm(), transformed_rect.to_type<float>()));
|
rects.append(Geometry::DOMRect::create(realm(), transformed_rect.to_type<float>()));
|
||||||
} else if (paintable && is<Painting::InlinePaintable>(*paintable)) {
|
} else if (paintable && is<Painting::InlinePaintable>(*paintable)) {
|
||||||
auto const& inline_paintable = static_cast<Painting::InlinePaintable const&>(*paintable);
|
auto const& inline_paintable = static_cast<Painting::InlinePaintable const&>(*paintable);
|
||||||
|
|
||||||
|
if (auto enclosing_scroll_offset = inline_paintable.enclosing_scroll_frame(); enclosing_scroll_offset) {
|
||||||
|
scroll_offset.translate_by(-enclosing_scroll_offset->cumulative_offset());
|
||||||
|
}
|
||||||
|
|
||||||
auto absolute_rect = inline_paintable.bounding_rect();
|
auto absolute_rect = inline_paintable.bounding_rect();
|
||||||
absolute_rect.translate_by(-scroll_offset);
|
absolute_rect.translate_by(-scroll_offset);
|
||||||
absolute_rect.translate_by(-viewport_offset);
|
|
||||||
rects.append(Geometry::DOMRect::create(realm(), transform.map(absolute_rect.to_type<float>())));
|
rects.append(Geometry::DOMRect::create(realm(), transform.map(absolute_rect.to_type<float>())));
|
||||||
} else if (paintable) {
|
} else if (paintable) {
|
||||||
dbgln("FIXME: Failed to get client rects for element ({})", debug_description());
|
dbgln("FIXME: Failed to get client rects for element ({})", debug_description());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue