Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(411)

Unified Diff: Source/WebCore/page/IntersectionObserver.cpp

Issue 349730043: WIP - wip
Patch Set: . Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/WebCore/page/IntersectionObserver.cpp
diff --git a/Source/WebCore/page/IntersectionObserver.cpp b/Source/WebCore/page/IntersectionObserver.cpp
index 07fa8a889c4845b29a1d7a823b2665c5ffae56c4..12cf01260dc711104b3524d2b1a502132204b3f5 100644
--- a/Source/WebCore/page/IntersectionObserver.cpp
+++ b/Source/WebCore/page/IntersectionObserver.cpp
@@ -28,41 +28,152 @@
#if ENABLE(INTERSECTION_OBSERVER)
#include "IntersectionObserver.h"
+#include "CSSParser.h"
+#include "CSSPropertyParser.h"
+#include "CSSTokenizer.h"
+#include "DOMWindow.h"
#include "Element.h"
+#include "ExceptionCode.h"
#include "IntersectionObserverCallback.h"
#include "IntersectionObserverEntry.h"
+#include "Logging.h"
+#include "StyleResolver.h"
+#include <wtf/text/TextStream.h>
#include <wtf/Vector.h>
+#include <algorithm>
+#include <functional>
namespace WebCore {
-IntersectionObserver::IntersectionObserver(Ref<IntersectionObserverCallback>&& callback, Init&& init)
- : m_root(init.root)
+namespace {
+
+bool isThresholdWithinRange(double threshold) {
+ return threshold >= 0.0 && threshold <= 1.0;
+}
+
+} // namespace
+
+ExceptionOr<Ref<IntersectionObserver>> IntersectionObserver::create(Document& document, Ref<IntersectionObserverCallback>&& callback, IntersectionObserver::Init&& init)
+{
+ CSSParserContext context(HTMLStandardMode);
+ CSSTokenizer tokenizer(init.rootMargin);
+ ParsedPropertyVector properties;
+ bool important = false;
+ if (!CSSPropertyParser::parseValue(CSSPropertyMargin, important, tokenizer.tokenRange(), context, properties, StyleRule::Style)) {
+ return Exception { SyntaxError, "Failed to construct 'IntersectionObserver': rootMargin must be specified in pixels or percent." };
+ }
+ StyleResolver resolver(document);
+ resolver.state().setStyle(RenderStyle::createPtr());
+ StringBuilder builder;
+ for (auto& prop : properties) {
+ if (!builder.isEmpty()) {
+ builder.append(" ");
+ }
+ builder.append(prop.value()->cssText());
+ resolver.applyPropertyToCurrentStyle(prop.id(), prop.value());
+ }
+ init.rootMargin = builder.toString();
+ LengthBox marginBox(Length(resolver.style()->marginTop()),
+ Length(resolver.style()->marginRight()),
+ Length(resolver.style()->marginBottom()),
+ Length(resolver.style()->marginLeft()));
+
+ bool foundOutOfRangeThreshold = false;
+ if (WTF::holds_alternative<double>(init.threshold))
+ foundOutOfRangeThreshold = !isThresholdWithinRange(WTF::get<double>(init.threshold));
+ else {
+ for (auto& threshold : WTF::get<Vector<double>>(init.threshold))
+ foundOutOfRangeThreshold |= !isThresholdWithinRange(threshold);
+ }
+ if (foundOutOfRangeThreshold) {
+ 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), WTFMove(init), WTFMove(marginBox)));
+}
+
+// FIXME: need to stop observing if the root is deleted.
+IntersectionObserver::IntersectionObserver(Document& document, Ref<IntersectionObserverCallback>&& callback, Init&& init, LengthBox&& marginBox)
+ : m_document(document)
+ , m_root(init.root)
, m_rootMargin(WTFMove(init.rootMargin))
, m_callback(WTFMove(callback))
+ , m_marginBox(marginBox)
{
if (WTF::holds_alternative<double>(init.threshold))
m_thresholds.append(WTF::get<double>(init.threshold));
else
m_thresholds = WTF::get<Vector<double>>(WTFMove(init.threshold));
+ std::sort(m_thresholds.begin(), m_thresholds.end(), std::less<double>());
+}
+
+IntersectionObserver::~IntersectionObserver()
+{
+ disconnect();
}
-void IntersectionObserver::observe(Element&)
+ExceptionOr<void> IntersectionObserver::observe(Element& element)
{
+ if (&element.document() != &m_document) {
+ m_document.domWindow()->printErrorMessage("IntersectionObserver.observe() on an element from another document is not allowed.");
+ return Exception { WrongDocumentError };
+ }
+
+ element.startObservingIntersections(*this);
+ return { };
}
-void IntersectionObserver::unobserve(Element&)
+void IntersectionObserver::unobserve(Element& element)
{
+ if (&element.document() != &m_document)
+ return;
+
+ element.endObservingIntersections(*this);
}
void IntersectionObserver::disconnect()
{
+ for (auto* target : m_observationTargets)
+ unobserve(*target);
}
-Vector<RefPtr<IntersectionObserverEntry>> IntersectionObserver::takeRecords()
+Vector<Ref<IntersectionObserverEntry>> IntersectionObserver::takeRecords()
{
- return { };
+ return WTFMove(m_queuedEntries);
}
+void IntersectionObserver::addObservationTarget(Element& element)
+{
+ ASSERT(!m_observationTargets.contains(&element));
+ m_observationTargets.append(&element);
+}
+
+void IntersectionObserver::removeObservationTarget(Element& element)
+{
+ m_observationTargets.removeFirst(&element);
+}
+
+bool IntersectionObserver::hasObservationTarget(Element& element) const
+{
+ return m_observationTargets.contains(&element);
+}
+
+void IntersectionObserver::appendQueuedEntry(Ref<IntersectionObserverEntry>&& entry)
+{
+ LOG_WITH_STREAM(IntersectionObserver, stream << " adding queued entry " << entry.get());
+
+ m_queuedEntries.append(WTFMove(entry));
+}
+
+void IntersectionObserver::notify()
+{
+ if (m_queuedEntries.isEmpty())
+ return;
+
+ LOG(IntersectionObserver, "IntersectionObserver %p callback(): %lu records", this, m_queuedEntries.size());
+
+ m_callback->handleEvent(takeRecords(), *this);
+}
} // namespace WebCore

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b