Diff
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (257975 => 257976)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2020-03-06 11:11:40 UTC (rev 257975)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2020-03-06 11:53:49 UTC (rev 257976)
@@ -1,3 +1,13 @@
+2020-03-06 Frederic Wang <[email protected]>
+
+ [intersection-observer] Accept a Document as an explicit root
+ https://bugs.webkit.org/show_bug.cgi?id=208047
+
+ Reviewed by Simon Fraser.
+
+ * web-platform-tests/intersection-observer/document-scrolling-element-root-expected.txt:
+ Update expectation now that the test passes.
+
2020-03-02 Rob Buis <[email protected]>
Fix behavior of pings regarding Origin header
Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/document-scrolling-element-root-expected.txt (257975 => 257976)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/document-scrolling-element-root-expected.txt 2020-03-06 11:11:40 UTC (rev 257975)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/intersection-observer/document-scrolling-element-root-expected.txt 2020-03-06 11:53:49 UTC (rev 257976)
@@ -1,3 +1,4 @@
-FAIL Observer with explicit root which is the document. Type error
+PASS Observer with explicit root which is the document.
+PASS First rAF.
Modified: trunk/Source/WebCore/ChangeLog (257975 => 257976)
--- trunk/Source/WebCore/ChangeLog 2020-03-06 11:11:40 UTC (rev 257975)
+++ trunk/Source/WebCore/ChangeLog 2020-03-06 11:53:49 UTC (rev 257976)
@@ -1,3 +1,57 @@
+2020-03-06 Frederic Wang <[email protected]>
+
+ [intersection-observer] Accept a Document as an explicit root
+ https://bugs.webkit.org/show_bug.cgi?id=208047
+
+ Reviewed by Simon Fraser.
+
+ This patch introduces a recent enhancement to the Intersection Observer specification: the
+ root initialization parameter can be explicitly be set to a Document. The typical use case
+ is when document is an iframe. See https://github.com/w3c/IntersectionObserver/issues/372
+
+ This patch also updates the way Element's intersection observer data is handled so that it is
+ more consistent with the explicit Document root case introduced here.
+
+ Test: imported/w3c/web-platform-tests/intersection-observer/document-scrolling-element-root.html
+
+ * dom/Document.cpp:
+ (WebCore::Document::~Document): Notify observers about our desctruction.
+ (WebCore::Document::updateIntersectionObservations): Use new method name. This does not
+ require null-check because ensureIntersectionObserverData() has been called in
+ IntersectionObserver::observe().
+ (WebCore::Document::ensureIntersectionObserverData): Return reference to intersection
+ observer data for this document, creating one if it does not exist.
+ * dom/Document.h: Add new intersection observer data, used for documents that are explicit
+ intersection observer roots.
+ (WebCore::Document::intersectionObserverDataIfExists): Return pointer to intersection
+ observer data or null if it does not exist.
+ * dom/Element.cpp:
+ (WebCore::Element::didMoveToNewDocument): Use new method name.
+ (WebCore::Element::disconnectFromIntersectionObservers): Ditto and null-check weak refs.
+ (WebCore::Element::intersectionObserverDataIfExists): Rename method to match Document's one
+ and be more explicit that it will be null if it does not exist.
+ (WebCore::Element::intersectionObserverData): Renamed.
+ * dom/Element.h: Renamed.
+ * html/LazyLoadImageObserver.cpp:
+ (WebCore::LazyLoadImageObserver::intersectionObserver): Initialize with a WTF::Optional
+ after API change.
+ * page/IntersectionObserver.cpp:
+ (WebCore::IntersectionObserver::create): Pass a Node* root, which can be null (implicit
+ root), Document* or Element* (explicit roots). This is determined from init.root.
+ (WebCore::IntersectionObserver::IntersectionObserver): Handle the case of explicit Document
+ root.
+ (WebCore::IntersectionObserver::~IntersectionObserver): Ditto and update method name for
+ the explicit Element case. Note that in both explicit root cases the corresponding
+ ensureIntersectionObserverData() method had been called in the constructor so they can
+ be safely deferenced.
+ (WebCore::IntersectionObserver::removeTargetRegistration): Use new method name.
+ * page/IntersectionObserver.h: Update comment and code now that explicit root is a Node* and
+ IntersectionObserver::Init::root is either an Element or a Document or null.
+ (WebCore::IntersectionObserver::root const): Ditto.
+ (): Deleted.
+ * page/IntersectionObserver.idl: Update IDL to match the spec IntersectionObserver::root
+ is a nullable Node and IntersectionObserverInit::root a nullable Element or Document.
+
2020-03-06 Yusuke Suzuki <[email protected]>
Put all generated JSCells in WebCore into IsoSubspace
Modified: trunk/Source/WebCore/dom/Document.cpp (257975 => 257976)
--- trunk/Source/WebCore/dom/Document.cpp 2020-03-06 11:11:40 UTC (rev 257975)
+++ trunk/Source/WebCore/dom/Document.cpp 2020-03-06 11:53:49 UTC (rev 257976)
@@ -635,6 +635,18 @@
if (m_logger)
m_logger->removeObserver(*this);
+#if ENABLE(INTERSECTION_OBSERVER)
+ if (m_intersectionObserverData) {
+ for (const auto& observer : m_intersectionObserverData->observers) {
+ if (observer)
+ observer->rootDestroyed();
+ }
+ m_intersectionObserverData->observers.clear();
+ // Document cannot be a target.
+ ASSERT(m_intersectionObserverData->registrations.isEmpty());
+ }
+#endif
+
ASSERT(allDocumentsMap().contains(m_identifier));
allDocumentsMap().remove(m_identifier);
// We need to remove from the contexts map very early in the destructor so that calling postTask() on this Document from another thread is safe.
@@ -7574,7 +7586,7 @@
if (!observer->createTimestamp(timestamp))
continue;
for (Element* target : observer->observationTargets()) {
- auto& targetRegistrations = target->intersectionObserverData()->registrations;
+ auto& targetRegistrations = target->intersectionObserverDataIfExists()->registrations;
auto index = targetRegistrations.findMatching([observer](auto& registration) {
return registration.observer.get() == observer;
});
@@ -7661,6 +7673,13 @@
m_intersectionObserversInitialUpdateTimer.startOneShot(intersectionObserversInitialUpdateDelay);
}
+IntersectionObserverData& Document::ensureIntersectionObserverData()
+{
+ if (!m_intersectionObserverData)
+ m_intersectionObserverData = makeUnique<IntersectionObserverData>();
+ return *m_intersectionObserverData;
+}
+
#endif
#if ENABLE(RESIZE_OBSERVER)
Modified: trunk/Source/WebCore/dom/Document.h (257975 => 257976)
--- trunk/Source/WebCore/dom/Document.h 2020-03-06 11:11:40 UTC (rev 257975)
+++ trunk/Source/WebCore/dom/Document.h 2020-03-06 11:53:49 UTC (rev 257976)
@@ -252,6 +252,7 @@
#if ENABLE(INTERSECTION_OBSERVER)
class IntersectionObserver;
+struct IntersectionObserverData;
#endif
#if ENABLE(RESIZE_OBSERVER)
@@ -1389,6 +1390,8 @@
unsigned numberOfIntersectionObservers() const { return m_intersectionObservers.size(); }
void updateIntersectionObservations();
void scheduleInitialIntersectionObservationUpdate();
+ IntersectionObserverData& ensureIntersectionObserverData();
+ IntersectionObserverData* intersectionObserverDataIfExists() { return m_intersectionObserverData.get(); }
#endif
#if ENABLE(RESIZE_OBSERVER)
@@ -1823,6 +1826,8 @@
Vector<WeakPtr<IntersectionObserver>> m_intersectionObserversWithPendingNotifications;
Timer m_intersectionObserversNotifyTimer;
Timer m_intersectionObserversInitialUpdateTimer;
+ // This is only non-null when this document is an explicit root.
+ std::unique_ptr<IntersectionObserverData> m_intersectionObserverData;
#endif
#if ENABLE(RESIZE_OBSERVER)
Modified: trunk/Source/WebCore/dom/Element.cpp (257975 => 257976)
--- trunk/Source/WebCore/dom/Element.cpp 2020-03-06 11:11:40 UTC (rev 257975)
+++ trunk/Source/WebCore/dom/Element.cpp 2020-03-06 11:53:49 UTC (rev 257976)
@@ -2065,7 +2065,7 @@
CustomElementReactionQueue::enqueueAdoptedCallbackIfNeeded(*this, oldDocument, newDocument);
#if ENABLE(INTERSECTION_OBSERVER)
- if (auto* observerData = intersectionObserverData()) {
+ if (auto* observerData = intersectionObserverDataIfExists()) {
for (const auto& observer : observerData->observers) {
if (observer->hasObservationTargets()) {
oldDocument.removeIntersectionObserver(*observer);
@@ -3724,16 +3724,20 @@
void Element::disconnectFromIntersectionObservers()
{
- auto* observerData = intersectionObserverData();
+ auto* observerData = intersectionObserverDataIfExists();
if (!observerData)
return;
- for (const auto& registration : observerData->registrations)
- registration.observer->targetDestroyed(*this);
+ for (const auto& registration : observerData->registrations) {
+ if (registration.observer)
+ registration.observer->targetDestroyed(*this);
+ }
observerData->registrations.clear();
- for (const auto& observer : observerData->observers)
- observer->rootDestroyed();
+ for (const auto& observer : observerData->observers) {
+ if (observer)
+ observer->rootDestroyed();
+ }
observerData->observers.clear();
}
@@ -3745,7 +3749,7 @@
return *rareData.intersectionObserverData();
}
-IntersectionObserverData* Element::intersectionObserverData()
+IntersectionObserverData* Element::intersectionObserverDataIfExists()
{
return hasRareData() ? elementRareData()->intersectionObserverData() : nullptr;
}
Modified: trunk/Source/WebCore/dom/Element.h (257975 => 257976)
--- trunk/Source/WebCore/dom/Element.h 2020-03-06 11:11:40 UTC (rev 257975)
+++ trunk/Source/WebCore/dom/Element.h 2020-03-06 11:53:49 UTC (rev 257976)
@@ -591,7 +591,7 @@
#if ENABLE(INTERSECTION_OBSERVER)
IntersectionObserverData& ensureIntersectionObserverData();
- IntersectionObserverData* intersectionObserverData();
+ IntersectionObserverData* intersectionObserverDataIfExists();
#endif
#if ENABLE(RESIZE_OBSERVER)
Modified: trunk/Source/WebCore/html/LazyLoadImageObserver.cpp (257975 => 257976)
--- trunk/Source/WebCore/html/LazyLoadImageObserver.cpp 2020-03-06 11:11:40 UTC (rev 257975)
+++ trunk/Source/WebCore/html/LazyLoadImageObserver.cpp 2020-03-06 11:53:49 UTC (rev 257976)
@@ -85,7 +85,7 @@
{
if (!m_lazyLoadIntersectionObserver) {
auto callback = LazyImageLoadIntersectionObserverCallback::create(document);
- IntersectionObserver::Init options { nullptr, emptyString(), { } };
+ IntersectionObserver::Init options { WTF::nullopt, emptyString(), { } };
auto observer = IntersectionObserver::create(document, WTFMove(callback), WTFMove(options));
if (observer.hasException())
return nullptr;
Modified: trunk/Source/WebCore/page/IntersectionObserver.cpp (257975 => 257976)
--- trunk/Source/WebCore/page/IntersectionObserver.cpp 2020-03-06 11:11:40 UTC (rev 257975)
+++ trunk/Source/WebCore/page/IntersectionObserver.cpp 2020-03-06 11:53:49 UTC (rev 257976)
@@ -86,6 +86,15 @@
ExceptionOr<Ref<IntersectionObserver>> IntersectionObserver::create(Document& document, Ref<IntersectionObserverCallback>&& callback, IntersectionObserver::Init&& init)
{
+ Node* root = nullptr;
+ if (init.root) {
+ WTF::switchOn(*init.root, [&root] (RefPtr<Element> element) {
+ root = element.get();
+ }, [&root] (RefPtr<Document> document) {
+ root = document.get();
+ });
+ }
+
auto rootMarginOrException = parseRootMargin(init.rootMargin);
if (rootMarginOrException.hasException())
return rootMarginOrException.releaseException();
@@ -103,10 +112,10 @@
return Exception { RangeError, "Failed to construct 'IntersectionObserver': all thresholds must lie in the range [0.0, 1.0]." };
}
- return adoptRef(*new IntersectionObserver(document, WTFMove(callback), init.root, rootMarginOrException.releaseReturnValue(), WTFMove(thresholds)));
+ return adoptRef(*new IntersectionObserver(document, WTFMove(callback), root, rootMarginOrException.releaseReturnValue(), WTFMove(thresholds)));
}
-IntersectionObserver::IntersectionObserver(Document& document, Ref<IntersectionObserverCallback>&& callback, Element* root, LengthBox&& parsedRootMargin, Vector<double>&& thresholds)
+IntersectionObserver::IntersectionObserver(Document& document, Ref<IntersectionObserverCallback>&& callback, Node* root, LengthBox&& parsedRootMargin, Vector<double>&& thresholds)
: ActiveDOMObject(callback->scriptExecutionContext())
, m_root(root)
, m_rootMargin(WTFMove(parsedRootMargin))
@@ -113,9 +122,13 @@
, m_thresholds(WTFMove(thresholds))
, m_callback(WTFMove(callback))
{
- if (m_root) {
- auto& observerData = m_root->ensureIntersectionObserverData();
+ if (is<Document>(m_root)) {
+ auto& observerData = downcast<Document>(*m_root).ensureIntersectionObserverData();
observerData.observers.append(makeWeakPtr(this));
+ } else if (m_root) {
+ ASSERT(is<Element>(m_root));
+ auto& observerData = downcast<Element>(*m_root).ensureIntersectionObserverData();
+ observerData.observers.append(makeWeakPtr(this));
} else if (auto* frame = document.frame())
m_implicitRootDocument = makeWeakPtr(frame->mainFrame().document());
@@ -125,8 +138,12 @@
IntersectionObserver::~IntersectionObserver()
{
- if (m_root)
- m_root->intersectionObserverData()->observers.removeFirst(this);
+ if (is<Document>(m_root)) {
+ downcast<Document>(*m_root).intersectionObserverDataIfExists()->observers.removeFirst(this);
+ } else if (m_root) {
+ ASSERT(is<Element>(m_root));
+ downcast<Element>(*m_root).intersectionObserverDataIfExists()->observers.removeFirst(this);
+ }
disconnect();
}
@@ -201,7 +218,7 @@
bool IntersectionObserver::removeTargetRegistration(Element& target)
{
- auto* observerData = target.intersectionObserverData();
+ auto* observerData = target.intersectionObserverDataIfExists();
if (!observerData)
return false;
Modified: trunk/Source/WebCore/page/IntersectionObserver.h (257975 => 257976)
--- trunk/Source/WebCore/page/IntersectionObserver.h 2020-03-06 11:11:40 UTC (rev 257975)
+++ trunk/Source/WebCore/page/IntersectionObserver.h 2020-03-06 11:53:49 UTC (rev 257976)
@@ -41,6 +41,7 @@
class Document;
class Element;
+class Node;
struct IntersectionObserverRegistration {
WeakPtr<IntersectionObserver> observer;
@@ -50,12 +51,12 @@
struct IntersectionObserverData {
WTF_MAKE_STRUCT_FAST_ALLOCATED;
- // IntersectionObservers for which the element that owns this IntersectionObserverData is the root.
+ // IntersectionObservers for which the node that owns this IntersectionObserverData is the root.
// An IntersectionObserver is only owned by a _javascript_ wrapper. ActiveDOMObject::hasPendingActivity
// is overridden to keep this wrapper alive while the observer has ongoing observations.
Vector<WeakPtr<IntersectionObserver>> observers;
- // IntersectionObserverRegistrations for which the element that owns this IntersectionObserverData is the target.
+ // IntersectionObserverRegistrations for which the node that owns this IntersectionObserverData is the target.
Vector<IntersectionObserverRegistration> registrations;
};
@@ -62,7 +63,7 @@
class IntersectionObserver : public RefCounted<IntersectionObserver>, public ActiveDOMObject, public CanMakeWeakPtr<IntersectionObserver> {
public:
struct Init {
- Element* root { nullptr };
+ Optional<Variant<RefPtr<Element>, RefPtr<Document>>> root;
String rootMargin;
Variant<double, Vector<double>> threshold;
};
@@ -73,7 +74,7 @@
Document* trackingDocument() const { return m_root ? &m_root->document() : m_implicitRootDocument.get(); }
- Element* root() const { return m_root; }
+ Node* root() const { return m_root; }
String rootMargin() const;
const LengthBox& rootMarginBox() const { return m_rootMargin; }
const Vector<double>& thresholds() const { return m_thresholds; }
@@ -104,13 +105,13 @@
void stop() override;
private:
- IntersectionObserver(Document&, Ref<IntersectionObserverCallback>&&, Element* root, LengthBox&& parsedRootMargin, Vector<double>&& thresholds);
+ IntersectionObserver(Document&, Ref<IntersectionObserverCallback>&&, Node* root, LengthBox&& parsedRootMargin, Vector<double>&& thresholds);
bool removeTargetRegistration(Element&);
void removeAllTargets();
WeakPtr<Document> m_implicitRootDocument;
- Element* m_root;
+ Node* m_root;
LengthBox m_rootMargin;
Vector<double> m_thresholds;
RefPtr<IntersectionObserverCallback> m_callback;
Modified: trunk/Source/WebCore/page/IntersectionObserver.idl (257975 => 257976)
--- trunk/Source/WebCore/page/IntersectionObserver.idl 2020-03-06 11:11:40 UTC (rev 257975)
+++ trunk/Source/WebCore/page/IntersectionObserver.idl 2020-03-06 11:53:49 UTC (rev 257976)
@@ -33,7 +33,7 @@
Constructor(IntersectionObserverCallback callback, optional IntersectionObserverInit options),
EnabledAtRuntime=IntersectionObserver
] interface IntersectionObserver {
- readonly attribute Element? root;
+ readonly attribute Node? root;
readonly attribute DOMString rootMargin;
readonly attribute sequence<double> thresholds;
@@ -48,7 +48,7 @@
EnabledBySetting=IntersectionObserver
]
dictionary IntersectionObserverInit {
- Element? root = null;
+ (Element or Document)? root = null;
DOMString rootMargin = "0px";
(double or sequence<double>) threshold = 0.0;
};