Skip to content
Permalink
Browse files
[ContentChangeObserver] Add support for observing implicit transitions
https://bugs.webkit.org/show_bug.cgi?id=195914
<rdar://problem/49091959>

Reviewed by Simon Fraser.

This patch is in preparation for observing elements with property "left" implicit transitions.

This is not a continuous tracking, we are only interested in the start and the end state.
The idea here is to register hidden elements only and check if they become visible by
the end of the transition (and ignore if the transition gets "canceled").

* page/animation/AnimationBase.h:
* page/animation/ImplicitAnimation.cpp:
(WebCore::ImplicitAnimation::ImplicitAnimation):
(WebCore::ImplicitAnimation::~ImplicitAnimation):
(WebCore::ImplicitAnimation::clear):
(WebCore::ImplicitAnimation::onAnimationEnd):
* page/animation/ImplicitAnimation.h:
* page/ios/ContentChangeObserver.cpp:
(WebCore::ContentChangeObserver::didAddTransition):
(WebCore::ContentChangeObserver::removeTransitionIfNeeded):
(WebCore::ContentChangeObserver::didFinishTransition):
(WebCore::ContentChangeObserver::didRemoveTransition):
(WebCore::ContentChangeObserver::didInstallDOMTimer):
* page/ios/ContentChangeObserver.h:
(WebCore::ContentChangeObserver::isObservingTransitions const):
(WebCore::ContentChangeObserver::isObservedPropertyForTransition const):

Canonical link: https://commits.webkit.org/210368@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@243304 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
alanbujtas committed Mar 21, 2019
1 parent b2384e3 commit f2ce40ceeaf054a477d4797b4524655ffde27b83
Showing 6 changed files with 114 additions and 2 deletions.
@@ -1,3 +1,34 @@
2019-03-21 Zalan Bujtas <zalan@apple.com>

[ContentChangeObserver] Add support for observing implicit transitions
https://bugs.webkit.org/show_bug.cgi?id=195914
<rdar://problem/49091959>

Reviewed by Simon Fraser.

This patch is in preparation for observing elements with property "left" implicit transitions.

This is not a continuous tracking, we are only interested in the start and the end state.
The idea here is to register hidden elements only and check if they become visible by
the end of the transition (and ignore if the transition gets "canceled").

* page/animation/AnimationBase.h:
* page/animation/ImplicitAnimation.cpp:
(WebCore::ImplicitAnimation::ImplicitAnimation):
(WebCore::ImplicitAnimation::~ImplicitAnimation):
(WebCore::ImplicitAnimation::clear):
(WebCore::ImplicitAnimation::onAnimationEnd):
* page/animation/ImplicitAnimation.h:
* page/ios/ContentChangeObserver.cpp:
(WebCore::ContentChangeObserver::didAddTransition):
(WebCore::ContentChangeObserver::removeTransitionIfNeeded):
(WebCore::ContentChangeObserver::didFinishTransition):
(WebCore::ContentChangeObserver::didRemoveTransition):
(WebCore::ContentChangeObserver::didInstallDOMTimer):
* page/ios/ContentChangeObserver.h:
(WebCore::ContentChangeObserver::isObservingTransitions const):
(WebCore::ContentChangeObserver::isObservedPropertyForTransition const):

2019-03-21 Devin Rousso <drousso@apple.com>

Web Inspector: Page: lazily create the agent
@@ -61,7 +61,7 @@ class AnimationBase : public RefCounted<AnimationBase>
Element* element() const { return m_element.get(); }
const RenderStyle& currentStyle() const override;
RenderElement* renderer() const override;
void clear();
virtual void clear();

double duration() const;

@@ -32,6 +32,9 @@
#include "CSSAnimationControllerPrivate.h"
#include "CSSPropertyAnimation.h"
#include "CompositeAnimation.h"
#if PLATFORM(IOS_FAMILY)
#include "ContentChangeObserver.h"
#endif
#include "EventNames.h"
#include "GeometryUtilities.h"
#include "KeyframeAnimation.h"
@@ -46,11 +49,18 @@ ImplicitAnimation::ImplicitAnimation(const Animation& transition, CSSPropertyID
, m_transitionProperty(transition.property())
, m_animatingProperty(animatingProperty)
{
#if PLATFORM(IOS_FAMILY)
element.document().contentChangeObserver().didAddTransition(element, transition);
#endif
ASSERT(animatingProperty != CSSPropertyInvalid);
}

ImplicitAnimation::~ImplicitAnimation()
{
#if PLATFORM(IOS_FAMILY)
if (auto* element = this->element())
element->document().contentChangeObserver().didRemoveTransition(*element, m_animatingProperty);
#endif
// // Make sure to tell the renderer that we are ending. This will make sure any accelerated animations are removed.
if (!postActive())
endAnimation();
@@ -158,6 +168,15 @@ void ImplicitAnimation::pauseAnimation(double timeOffset)
setNeedsStyleRecalc(element());
}

void ImplicitAnimation::clear()
{
#if PLATFORM(IOS_FAMILY)
if (auto* element = this->element())
element->document().contentChangeObserver().didRemoveTransition(*element, m_animatingProperty);
#endif
AnimationBase::clear();
}

void ImplicitAnimation::endAnimation(bool)
{
if (auto* renderer = this->renderer())
@@ -166,6 +185,10 @@ void ImplicitAnimation::endAnimation(bool)

void ImplicitAnimation::onAnimationEnd(double elapsedTime)
{
#if PLATFORM(IOS_FAMILY)
if (auto* element = this->element())
element->document().contentChangeObserver().didFinishTransition(*element, m_animatingProperty);
#endif
// If we have a keyframe animation on this property, this transition is being overridden. The keyframe
// animation keeps an unanimated style in case a transition starts while the keyframe animation is
// running. But now that the transition has completed, we need to update this style with its new
@@ -79,6 +79,8 @@ class ImplicitAnimation : public AnimationBase {

const RenderStyle& unanimatedStyle() const override { return *m_fromStyle; }

void clear() override;

protected:
bool shouldSendEventForListener(Document::ListenerType) const;
bool sendTransitionEvent(const AtomicString&, double elapsedTime);
@@ -39,6 +39,9 @@

namespace WebCore {

static const Seconds maximumDelayForTimers { 300_ms };
static const Seconds maximumDelayForTransitions { 300_ms };

ContentChangeObserver::ContentChangeObserver(Document& document)
: m_document(document)
, m_contentObservationTimer([this] { completeDurationBasedContentObservation(); })
@@ -81,13 +84,54 @@ void ContentChangeObserver::completeDurationBasedContentObservation()
adjustObservedState(Event::EndedFixedObservationTimeWindow);
}

void ContentChangeObserver::didAddTransition(const Element& element, const Animation& transition)
{
if (!m_document.settings().contentChangeObserverEnabled())
return;
if (hasVisibleChangeState())
return;
if (!isObservingTransitions())
return;
if (!transition.isDurationSet() || !transition.isPropertySet())
return;
if (!isObservedPropertyForTransition(transition.property()))
return;
auto transitionEnd = Seconds { transition.duration() + std::max<double>(0, transition.isDelaySet() ? transition.delay() : 0) };
if (transitionEnd > maximumDelayForTransitions)
return;
LOG_WITH_STREAM(ContentObservation, stream << "didAddTransition: transition created on " << &element << " (" << transitionEnd.milliseconds() << "ms).");

m_elementsWithTransition.add(&element);
// FIXME: report state change.
}

void ContentChangeObserver::didFinishTransition(const Element& element, CSSPropertyID propertyID)
{
if (!isObservedPropertyForTransition(propertyID))
return;
if (!m_elementsWithTransition.take(&element))
return;
LOG_WITH_STREAM(ContentObservation, stream << "didFinishTransition: transition finished (" << &element << ").");
// FIXME: report state change.
}

void ContentChangeObserver::didRemoveTransition(const Element& element, CSSPropertyID propertyID)
{
if (!isObservedPropertyForTransition(propertyID))
return;
if (!m_elementsWithTransition.take(&element))
return;
LOG_WITH_STREAM(ContentObservation, stream << "didRemoveTransition: transition got interrupted (" << &element << ").");
// FIXME: report state change.
}

void ContentChangeObserver::didInstallDOMTimer(const DOMTimer& timer, Seconds timeout, bool singleShot)
{
if (!m_document.settings().contentChangeObserverEnabled())
return;
if (m_document.activeDOMObjectsAreSuspended())
return;
if (timeout > 300_ms || !singleShot)
if (timeout > maximumDelayForTimers || !singleShot)
return;
if (!isObservingDOMTimerScheduling())
return;
@@ -30,9 +30,11 @@
#include "PlatformEvent.h"
#include "Timer.h"
#include "WKContentObservation.h"
#include <wtf/HashSet.h>

namespace WebCore {

class Animation;
class DOMTimer;
class Document;
class Element;
@@ -46,6 +48,11 @@ class ContentChangeObserver {

void didInstallDOMTimer(const DOMTimer&, Seconds timeout, bool singleShot);
void didRemoveDOMTimer(const DOMTimer&);

void didAddTransition(const Element&, const Animation&);
void didFinishTransition(const Element&, CSSPropertyID);
void didRemoveTransition(const Element&, CSSPropertyID);

WEBCORE_EXPORT void willNotProceedWithClick();
WEBCORE_EXPORT static void didRecognizeLongPress(Frame& mainFrame);
WEBCORE_EXPORT static void didPreventDefaultForEvent(Frame& mainFrame);
@@ -114,6 +121,8 @@ class ContentChangeObserver {

void setShouldObserveDOMTimerScheduling(bool observe) { m_isObservingDOMTimerScheduling = observe; }
bool isObservingDOMTimerScheduling() const { return m_isObservingDOMTimerScheduling; }
bool isObservingTransitions() const { return m_isObservingTransitions; }
bool isObservedPropertyForTransition(CSSPropertyID propertyId) const { return propertyId == CSSPropertyLeft; }
void domTimerExecuteDidStart(const DOMTimer&);
void domTimerExecuteDidFinish(const DOMTimer&);
void registerDOMTimer(const DOMTimer& timer) { m_DOMTimerList.add(&timer); }
@@ -167,13 +176,16 @@ class ContentChangeObserver {
Document& m_document;
Timer m_contentObservationTimer;
HashSet<const DOMTimer*> m_DOMTimerList;
// FIXME: Move over to WeakHashSet when it starts supporting const.
HashSet<const Element*> m_elementsWithTransition;
bool m_touchEventIsBeingDispatched { false };
bool m_isWaitingForStyleRecalc { false };
bool m_isInObservedStyleRecalc { false };
bool m_isObservingDOMTimerScheduling { false };
bool m_observedDomTimerIsBeingExecuted { false };
bool m_mouseMovedEventIsBeingDispatched { false };
bool m_isBetweenTouchEndAndMouseMoved { false };
bool m_isObservingTransitions { false };
};

inline void ContentChangeObserver::setHasNoChangeState()

0 comments on commit f2ce40c

Please sign in to comment.