1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-09 17:44:56 +09:00

LibWeb: Implement Element::check_visibility

This commit is contained in:
Edwin Hoksberg 2024-06-24 22:48:27 +02:00 committed by Tim Ledbetter
parent 4a2d5bcf89
commit 5f154ba372
Notes: github-actions[bot] 2024-07-20 08:15:46 +00:00
5 changed files with 148 additions and 1 deletions

View file

@ -0,0 +1,8 @@
display-none visible: false
content-visibility-parent visible: true
content-visibility-child visible: false
opacity-hidden visible: false
opacity-visible visible: true
visibility-hidden visible: false
visibility-visible visible: true
content-visibility-auto-hidden visible: true

View file

@ -0,0 +1,71 @@
<!DOCTYPE html>
<style>
.display-none {
display: none;
}
.content-visibility-parent {
content-visibility: hidden;
}
.opacity-hidden {
opacity: 0;
}
.opacity-visible {
opacity: 0.1;
}
.visibility-hidden {
visibility: hidden;
}
.visibility-visible {
visibility: visible;
}
.content-visibility-auto-hidden {
content-visibility: auto;
}
</style>
<div class="display-none"></div>
<div class="content-visibility-parent">
<div class="content-visibility-child"></div>
</div>
<div class="opacity-hidden"></div>
<div class="opacity-visible"></div>
<div class="visibility-hidden"></div>
<div class="visibility-visible"></div>
<div class="content-visibility-auto-hidden"></div>
<script src="../include.js"></script>
<script>
test(() => {
const displayNone = document.querySelector('.display-none');
println("display-none visible: " + displayNone.checkVisibility());
const contentVisibilityParent = document.querySelector('.content-visibility-parent');
println("content-visibility-parent visible: " + contentVisibilityParent.checkVisibility());
const contentVisibilityChild = document.querySelector('.content-visibility-child');
println("content-visibility-child visible: " + contentVisibilityChild.checkVisibility());
const opacityHidden = document.querySelector('.opacity-hidden');
println("opacity-hidden visible: " + opacityHidden.checkVisibility({opacityProperty: true}));
const opacityVisible = document.querySelector('.opacity-visible');
println("opacity-visible visible: " + opacityVisible.checkVisibility({opacityProperty: true}));
const visibilityHidden = document.querySelector('.visibility-hidden');
println("visibility-hidden visible: " + visibilityHidden.checkVisibility({visibilityProperty: true}));
const visibilityVisible = document.querySelector('.visibility-visible');
println("visibility-visible visible: " + visibilityVisible.checkVisibility({visibilityProperty: true}));
const contentVisibilityAutoHidden = document.querySelector('.content-visibility-auto-hidden');
println("content-visibility-auto-hidden visible: " + contentVisibilityAutoHidden.checkVisibility({contentVisibilityAuto: true}));
});
</script>

View file

@ -2344,6 +2344,54 @@ void Element::scroll_by(HTML::ScrollToOptions options)
scroll(options);
}
// https://drafts.csswg.org/cssom-view-1/#dom-element-checkvisibility
bool Element::check_visibility(Optional<CheckVisibilityOptions> options)
{
// NOTE: Ensure that layout is up-to-date before looking at metrics.
document().update_layout();
// 1. If this does not have an associated box, return false.
if (!paintable_box())
return false;
// 2. If an ancestor of this in the flat tree has content-visibility: hidden, return false.
for (auto* element = parent_element(); element; element = element->parent_element()) {
if (element->computed_css_values()->content_visibility() == CSS::ContentVisibility::Hidden)
return false;
}
// AD-HOC: Since the rest of the steps use the options, we can return early if we haven't been given any options.
if (!options.has_value())
return true;
// 3. If either the opacityProperty or the checkOpacity dictionary members of options are true, and this, or an ancestor of this in the flat tree, has a computed opacity value of 0, return false.
if (options->opacity_property || options->check_opacity) {
for (auto* element = this; element; element = element->parent_element()) {
if (element->computed_css_values()->opacity() == 0.0f)
return false;
}
}
// 4. If either the visibilityProperty or the checkVisibilityCSS dictionary members of options are true, and this is invisible, return false.
if (options->visibility_property || options->check_visibility_css) {
if (computed_css_values()->visibility() == CSS::Visibility::Hidden)
return false;
}
// 5. If the contentVisibilityAuto dictionary member of options is true and an ancestor of this in the flat tree skips its contents due to content-visibility: auto, return false.
// FIXME: Currently we do not skip any content if content-visibility is auto: https://drafts.csswg.org/css-contain-2/#proximity-to-the-viewport
auto const skipped_contents_due_to_content_visibility_auto = false;
if (options->content_visibility_auto && skipped_contents_due_to_content_visibility_auto) {
for (auto* element = this; element; element = element->parent_element()) {
if (element->computed_css_values()->content_visibility() == CSS::ContentVisibility::Auto)
return false;
}
}
// 6. Return true.
return true;
}
bool Element::id_reference_exists(String const& id_reference) const
{
return document().get_element_by_id(id_reference);

View file

@ -48,6 +48,15 @@ struct ScrollIntoViewOptions : public HTML::ScrollOptions {
Bindings::ScrollLogicalPosition inline_ { Bindings::ScrollLogicalPosition::Nearest };
};
// https://drafts.csswg.org/cssom-view-1/#dictdef-checkvisibilityoptions
struct CheckVisibilityOptions {
bool check_opacity = false;
bool check_visibility_css = false;
bool content_visibility_auto = false;
bool opacity_property = false;
bool visibility_property = false;
};
// https://html.spec.whatwg.org/multipage/custom-elements.html#upgrade-reaction
// An upgrade reaction, which will upgrade the custom element and contains a custom element definition; or
struct CustomElementUpgradeReaction {
@ -354,6 +363,8 @@ public:
void scroll_by(HTML::ScrollToOptions);
void scroll_by(double x, double y);
bool check_visibility(Optional<CheckVisibilityOptions>);
void register_intersection_observer(Badge<IntersectionObserver::IntersectionObserver>, IntersectionObserver::IntersectionObserverRegistration);
void unregister_intersection_observer(Badge<IntersectionObserver::IntersectionObserver>, JS::NonnullGCPtr<IntersectionObserver::IntersectionObserver>);
IntersectionObserver::IntersectionObserverRegistration& get_intersection_observer_registration(Badge<DOM::Document>, IntersectionObserver::IntersectionObserver const&);

View file

@ -20,6 +20,15 @@ dictionary ScrollIntoViewOptions : ScrollOptions {
ScrollLogicalPosition inline = "nearest";
};
// https://drafts.csswg.org/cssom-view-1/#dictdef-checkvisibilityoptions
dictionary CheckVisibilityOptions {
boolean checkOpacity = false;
boolean checkVisibilityCSS = false;
boolean contentVisibilityAuto = false;
boolean opacityProperty = false;
boolean visibilityProperty = false;
};
// https://dom.spec.whatwg.org/#element
[Exposed=Window]
interface Element : Node {
@ -74,7 +83,7 @@ interface Element : Node {
DOMRectList getClientRects();
DOMRect getBoundingClientRect();
[FIXME] boolean checkVisibility(optional CheckVisibilityOptions options = {});
boolean checkVisibility(optional CheckVisibilityOptions options = {});
undefined scrollIntoView(optional (boolean or ScrollIntoViewOptions) arg = {});
undefined scroll(optional ScrollToOptions options = {});