blob: 3d567e19afdb4fc56ba60bbbdb5211aa526f3aa8 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/observer/ResizeObserver.h"
#include "core/dom/Element.h"
#include "core/frame/FrameView.h"
#include "core/observer/ResizeObservation.h"
#include "core/observer/ResizeObserverCallback.h"
#include "core/observer/ResizeObserverController.h"
#include "core/observer/ResizeObserverEntry.h"
namespace blink {
ResizeObserver* ResizeObserver::create(Document& document, ResizeObserverCallback* callback)
{
return new ResizeObserver(callback, document);
}
ResizeObserver::ResizeObserver(ResizeObserverCallback* callback, Document& document)
: m_callback(callback)
, m_skippedObservations(false)
, m_elementSizeChanged(false)
{
m_controller = &document.ensureResizeObserverController();
m_controller->addObserver(*this);
}
void ResizeObserver::observe(Element* target)
{
auto& observerMap = target->ensureResizeObserverData();
if (observerMap.contains(this))
return; // Already registered.
auto observation = new ResizeObservation(target, this);
m_observations.add(observation);
observerMap.set(this, observation);
if (FrameView* frameView = target->document().view())
frameView->scheduleAnimation();
}
void ResizeObserver::unobserve(Element* target)
{
auto observerMap = target ? target->resizeObserverData() : nullptr;
if (!observerMap)
return;
auto observation = observerMap->find(this);
if (observation != observerMap->end()) {
m_observations.remove((*observation).value);
observerMap->remove(observation);
}
}
void ResizeObserver::disconnect()
{
ObservationList observations;
m_observations.swap(observations);
for (auto& observation : observations) {
Element* target = (*observation).target();
if (target)
target->ensureResizeObserverData().remove(this);
}
clearObservations();
}
size_t ResizeObserver::gatherObservations(size_t deeperThan)
{
DCHECK(m_activeObservations.isEmpty());
size_t minObservedDepth = ResizeObserverController::kDepthBottom;
if (!m_elementSizeChanged)
return minObservedDepth;
for (auto& observation : m_observations) {
if (!observation->observationSizeOutOfSync())
continue;
auto depth = observation->targetDepth();
if (depth > deeperThan) {
m_activeObservations.append(*observation);
minObservedDepth = std::min(minObservedDepth, depth);
} else {
m_skippedObservations = true;
}
}
return minObservedDepth;
}
void ResizeObserver::deliverObservations()
{
// We can only clear this flag after all observations have been
// broadcast.
m_elementSizeChanged = m_skippedObservations;
if (m_activeObservations.size() == 0)
return;
HeapVector<Member<ResizeObserverEntry>> entries;
for (auto& observation : m_activeObservations) {
auto entry = new ResizeObserverEntry(observation->target());
entries.append(entry);
observation->setObservationSize(entry->contentSize());
}
m_callback->handleEvent(entries, this);
clearObservations();
}
void ResizeObserver::clearObservations()
{
m_activeObservations.clear();
m_skippedObservations = false;
}
void ResizeObserver::elementSizeChanged()
{
m_elementSizeChanged = true;
if (m_controller)
m_controller->observerChanged();
}
DEFINE_TRACE(ResizeObserver)
{
visitor->trace(m_callback);
visitor->trace(m_observations);
visitor->trace(m_activeObservations);
visitor->trace(m_controller);
}
} // namespace blink