mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-04-18 09:50:27 +00:00
IntersectionObserver updates already iterate over each observer and its observation targets. We then looked the same target and observer pair up again through Element's registered observer list just to read and write previousThresholdIndex and previousIsIntersecting. Store that mutable state with the observer-side observation target instead. The element-side list now only keeps strong observer references for lifetime management and unobserve/disconnect. This deviates from the spec's storage model, so document the difference next to the preserved spec comments.
111 lines
4.4 KiB
C++
111 lines
4.4 KiB
C++
/*
|
|
* Copyright (c) 2021, Tim Flynn <trflynn89@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Optional.h>
|
|
#include <LibGC/Root.h>
|
|
#include <LibWeb/Bindings/PlatformObject.h>
|
|
#include <LibWeb/IntersectionObserver/IntersectionObserverEntry.h>
|
|
#include <LibWeb/PixelUnits.h>
|
|
|
|
namespace Web::IntersectionObserver {
|
|
|
|
using NullableIntersectionObserverRoot = Variant<GC::Root<DOM::Element>, GC::Root<DOM::Document>, Empty>;
|
|
|
|
struct ObservationTarget {
|
|
GC::Ref<DOM::Element> target;
|
|
Optional<size_t> previous_threshold_index;
|
|
bool previous_is_intersecting { false };
|
|
};
|
|
|
|
struct IntersectionObserverInit {
|
|
NullableIntersectionObserverRoot root { Empty {} };
|
|
String root_margin { "0px"_string };
|
|
String scroll_margin { "0px"_string };
|
|
Variant<double, Vector<double>> threshold { 0 };
|
|
long delay = 0;
|
|
bool track_visibility = false;
|
|
};
|
|
|
|
// https://w3c.github.io/IntersectionObserver/#intersection-observer-interface
|
|
class IntersectionObserver final : public Bindings::PlatformObject {
|
|
WEB_PLATFORM_OBJECT(IntersectionObserver, Bindings::PlatformObject);
|
|
GC_DECLARE_ALLOCATOR(IntersectionObserver);
|
|
|
|
public:
|
|
static constexpr bool OVERRIDES_FINALIZE = true;
|
|
|
|
static WebIDL::ExceptionOr<GC::Ref<IntersectionObserver>> construct_impl(JS::Realm&, GC::Ptr<WebIDL::CallbackType> callback, IntersectionObserverInit const& options = {});
|
|
|
|
virtual ~IntersectionObserver() override;
|
|
|
|
void observe(DOM::Element& target);
|
|
void unobserve(DOM::Element& target);
|
|
void disconnect();
|
|
Vector<GC::Root<IntersectionObserverEntry>> take_records();
|
|
|
|
Vector<ObservationTarget>& observation_targets() { return m_observation_targets; }
|
|
Vector<ObservationTarget> const& observation_targets() const { return m_observation_targets; }
|
|
|
|
NullableIntersectionObserverRoot root() const;
|
|
String root_margin() const;
|
|
String scroll_margin() const;
|
|
Vector<CSS::LengthPercentage> const& scroll_margin_values() const { return m_scroll_margin; }
|
|
Vector<double> const& thresholds() const { return m_thresholds; }
|
|
long delay() const { return m_delay; }
|
|
bool track_visibility() const { return m_track_visibility; }
|
|
|
|
Variant<GC::Root<DOM::Element>, GC::Root<DOM::Document>> intersection_root() const;
|
|
GC::Ref<DOM::Node> intersection_root_node() const;
|
|
bool is_implicit_root() const { return !m_root; }
|
|
CSSPixelRect root_intersection_rectangle() const;
|
|
|
|
void queue_entry(Badge<DOM::Document>, GC::Ref<IntersectionObserverEntry>);
|
|
|
|
WebIDL::CallbackType& callback() { return *m_callback; }
|
|
|
|
private:
|
|
explicit IntersectionObserver(JS::Realm&, GC::Ptr<WebIDL::CallbackType> callback, NullableIntersectionObserverRoot const& root, Vector<CSS::LengthPercentage> root_margin, Vector<CSS::LengthPercentage> scroll_margin, Vector<double>&& thresholds, double debug, bool track_visibility);
|
|
|
|
virtual void initialize(JS::Realm&) override;
|
|
virtual void visit_edges(JS::Cell::Visitor&) override;
|
|
virtual void finalize() override;
|
|
|
|
static Optional<Vector<CSS::LengthPercentage>> parse_a_margin(JS::Realm&, String);
|
|
|
|
// https://www.w3.org/TR/intersection-observer/#dom-intersectionobserver-callback-slot
|
|
GC::Ptr<WebIDL::CallbackType> m_callback;
|
|
|
|
// https://www.w3.org/TR/intersection-observer/#dom-intersectionobserver-root
|
|
GC::Ptr<DOM::Node> m_root;
|
|
|
|
// https://www.w3.org/TR/intersection-observer/#dom-intersectionobserver-rootmargin
|
|
Vector<CSS::LengthPercentage> m_root_margin;
|
|
|
|
// https://www.w3.org/TR/intersection-observer/#dom-intersectionobserver-scrollmargin
|
|
Vector<CSS::LengthPercentage> m_scroll_margin;
|
|
|
|
// https://www.w3.org/TR/intersection-observer/#dom-intersectionobserver-thresholds
|
|
Vector<double> m_thresholds;
|
|
|
|
// https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-delay
|
|
long m_delay;
|
|
|
|
// https://w3c.github.io/IntersectionObserver/#dom-intersectionobserver-trackvisibility
|
|
bool m_track_visibility;
|
|
|
|
// https://www.w3.org/TR/intersection-observer/#dom-intersectionobserver-queuedentries-slot
|
|
Vector<GC::Ref<IntersectionObserverEntry>> m_queued_entries;
|
|
|
|
// https://www.w3.org/TR/intersection-observer/#dom-intersectionobserver-observationtargets-slot
|
|
Vector<ObservationTarget> m_observation_targets;
|
|
|
|
// AD-HOC: This is the document where we've registered the IntersectionObserver.
|
|
GC::Weak<DOM::Document> m_document;
|
|
};
|
|
|
|
}
|