mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 05:47:35 +00:00
LibWeb: Implement getBoundingClientRect() for inline paintables
This fixes the issue that occurred when, after clicking an inline paintable page would always scroll to the top. The problem was that `scroll_an_element_into_view()` relies on `get_bounding_client_rect()` to produce the correct scroll position and for inline paintables we were always returning zero rect before this change.
This commit is contained in:
parent
874af6048f
commit
e464d484c4
5 changed files with 54 additions and 8 deletions
|
@ -1 +1,2 @@
|
||||||
{"x":8,"y":500,"width":784,"height":150,"top":500,"right":792,"bottom":650,"left":8}
|
inline {"x":8,"y":500,"width":784,"height":150,"top":500,"right":792,"bottom":650,"left":8}
|
||||||
|
{"x":8,"y":650,"width":41.296875,"height":17.46875,"top":650,"right":49.296875,"bottom":667.46875,"left":8}
|
|
@ -9,10 +9,16 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div id="box"></div>
|
<div id="box"></div>
|
||||||
|
<a id="inline">inline</a>
|
||||||
<script src="include.js"></script>
|
<script src="include.js"></script>
|
||||||
<script>
|
<script>
|
||||||
test(() => {
|
test(() => {
|
||||||
const rect = document.getElementById("box").getBoundingClientRect();
|
const rect = document.getElementById("box").getBoundingClientRect();
|
||||||
println(JSON.stringify(rect));
|
println(JSON.stringify(rect));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
const rect = document.getElementById("inline").getBoundingClientRect();
|
||||||
|
println(JSON.stringify(rect));
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
#include <LibWeb/Layout/Viewport.h>
|
#include <LibWeb/Layout/Viewport.h>
|
||||||
#include <LibWeb/Namespace.h>
|
#include <LibWeb/Namespace.h>
|
||||||
#include <LibWeb/Page/Page.h>
|
#include <LibWeb/Page/Page.h>
|
||||||
|
#include <LibWeb/Painting/InlinePaintable.h>
|
||||||
#include <LibWeb/Painting/PaintableBox.h>
|
#include <LibWeb/Painting/PaintableBox.h>
|
||||||
#include <LibWeb/WebIDL/AbstractOperations.h>
|
#include <LibWeb/WebIDL/AbstractOperations.h>
|
||||||
#include <LibWeb/WebIDL/DOMException.h>
|
#include <LibWeb/WebIDL/DOMException.h>
|
||||||
|
@ -834,16 +835,24 @@ JS::NonnullGCPtr<Geometry::DOMRect> Element::get_bounding_client_rect() const
|
||||||
{
|
{
|
||||||
// // NOTE: Ensure that layout is up-to-date before looking at metrics.
|
// // NOTE: Ensure that layout is up-to-date before looking at metrics.
|
||||||
const_cast<Document&>(document()).update_layout();
|
const_cast<Document&>(document()).update_layout();
|
||||||
|
|
||||||
// FIXME: Support inline layout nodes as well.
|
|
||||||
auto* paintable_box = this->paintable_box();
|
|
||||||
if (!paintable_box)
|
|
||||||
return Geometry::DOMRect::construct_impl(realm(), 0, 0, 0, 0).release_value_but_fixme_should_propagate_errors();
|
|
||||||
|
|
||||||
VERIFY(document().navigable());
|
VERIFY(document().navigable());
|
||||||
auto viewport_offset = document().navigable()->viewport_scroll_offset();
|
auto viewport_offset = document().navigable()->viewport_scroll_offset();
|
||||||
|
|
||||||
return Geometry::DOMRect::create(realm(), paintable_box->absolute_border_box_rect().translated(-viewport_offset.x(), -viewport_offset.y()).to_type<float>());
|
if (auto const* paintable_box = this->paintable_box()) {
|
||||||
|
auto absolute_rect = paintable_box->absolute_border_box_rect();
|
||||||
|
absolute_rect.translate_by(-viewport_offset.x(), -viewport_offset.y());
|
||||||
|
return Geometry::DOMRect::create(realm(), absolute_rect.to_type<float>());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto const* paintable = this->paintable(); is<Painting::InlinePaintable>(*paintable)) {
|
||||||
|
auto const& inline_paintable = static_cast<Painting::InlinePaintable const&>(*paintable);
|
||||||
|
auto absolute_rect = inline_paintable.bounding_rect();
|
||||||
|
absolute_rect.translate_by(-viewport_offset.x(), -viewport_offset.y());
|
||||||
|
return Geometry::DOMRect::create(realm(), absolute_rect.to_type<float>());
|
||||||
|
}
|
||||||
|
|
||||||
|
dbgln("FIXME: Failed to get bounding client rect for element ({})", debug_description());
|
||||||
|
return Geometry::DOMRect::construct_impl(realm(), 0, 0, 0, 0).release_value_but_fixme_should_propagate_errors();
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://drafts.csswg.org/cssom-view/#dom-element-getclientrects
|
// https://drafts.csswg.org/cssom-view/#dom-element-getclientrects
|
||||||
|
|
|
@ -173,4 +173,32 @@ void InlinePaintable::for_each_fragment(Callback callback) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSSPixelRect InlinePaintable::bounding_rect() const
|
||||||
|
{
|
||||||
|
auto top = CSSPixels::max();
|
||||||
|
auto left = CSSPixels::max();
|
||||||
|
auto right = CSSPixels::min();
|
||||||
|
auto bottom = CSSPixels::min();
|
||||||
|
auto has_fragments = false;
|
||||||
|
for_each_fragment([&](auto const& fragment, bool, bool) {
|
||||||
|
has_fragments = true;
|
||||||
|
auto fragment_absolute_rect = fragment.absolute_rect();
|
||||||
|
if (fragment_absolute_rect.top() < top)
|
||||||
|
top = fragment_absolute_rect.top();
|
||||||
|
if (fragment_absolute_rect.left() < left)
|
||||||
|
left = fragment_absolute_rect.left();
|
||||||
|
if (fragment_absolute_rect.right() > right)
|
||||||
|
right = fragment_absolute_rect.right();
|
||||||
|
if (fragment_absolute_rect.bottom() > bottom)
|
||||||
|
bottom = fragment_absolute_rect.bottom();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!has_fragments) {
|
||||||
|
// FIXME: This is adhoc, and we should return rect of empty fragment instead.
|
||||||
|
auto containing_block_position_in_absolute_coordinates = containing_block()->paintable_box()->absolute_position();
|
||||||
|
return { containing_block_position_in_absolute_coordinates, { 0, 0 } };
|
||||||
|
}
|
||||||
|
return { left, top, right - left, bottom - top };
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ public:
|
||||||
Layout::InlineNode const& layout_node() const;
|
Layout::InlineNode const& layout_node() const;
|
||||||
auto const& box_model() const { return layout_node().box_model(); }
|
auto const& box_model() const { return layout_node().box_model(); }
|
||||||
|
|
||||||
|
CSSPixelRect bounding_rect() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
InlinePaintable(Layout::InlineNode const&);
|
InlinePaintable(Layout::InlineNode const&);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue