blob: 9c58f226880927ab51d36b448f6f80ff2275da5f [file] [log] [blame]
/*
* Copyright (C) 2021 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#if ENABLE(MOMENTUM_EVENT_DISPATCHER)
#define ENABLE_MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING 0
#include "DisplayLinkObserverID.h"
#include "ScrollingAccelerationCurve.h"
#include "WebWheelEvent.h"
#include <WebCore/FloatSize.h>
#include <WebCore/PageIdentifier.h>
#include <WebCore/RectEdges.h>
#include <memory>
#include <wtf/Deque.h>
#include <wtf/MonotonicTime.h>
#include <wtf/Noncopyable.h>
namespace WebCore {
struct DisplayUpdate;
using FramesPerSecond = unsigned;
using PlatformDisplayID = uint32_t;
}
namespace WebKit {
class EventDispatcher;
class MomentumEventDispatcher {
WTF_MAKE_NONCOPYABLE(MomentumEventDispatcher);
WTF_MAKE_FAST_ALLOCATED;
public:
MomentumEventDispatcher(EventDispatcher&);
~MomentumEventDispatcher();
bool handleWheelEvent(WebCore::PageIdentifier, const WebWheelEvent&, WebCore::RectEdges<bool> rubberBandableEdges);
void setScrollingAccelerationCurve(WebCore::PageIdentifier, std::optional<ScrollingAccelerationCurve>);
void displayWasRefreshed(WebCore::PlatformDisplayID, const WebCore::DisplayUpdate&);
void pageScreenDidChange(WebCore::PageIdentifier, WebCore::PlatformDisplayID, std::optional<unsigned> nominalFramesPerSecond);
private:
void didStartMomentumPhase(WebCore::PageIdentifier, const WebWheelEvent&);
void didEndMomentumPhase();
bool eventShouldStartSyntheticMomentumPhase(WebCore::PageIdentifier, const WebWheelEvent&) const;
void startDisplayLink();
void stopDisplayLink();
struct DisplayProperties {
WebCore::PlatformDisplayID displayID;
WebCore::FramesPerSecond nominalFrameRate;
};
std::optional<DisplayProperties> displayProperties(WebCore::PageIdentifier) const;
void dispatchSyntheticMomentumEvent(WebWheelEvent::Phase, WebCore::FloatSize delta);
void buildOffsetTableWithInitialDelta(WebCore::FloatSize);
void equalizeTailGaps();
// Once consumed, this delta *must* be dispatched in an event.
std::optional<WebCore::FloatSize> consumeDeltaForCurrentTime();
WebCore::FloatSize offsetAtTime(Seconds);
std::pair<WebCore::FloatSize, WebCore::FloatSize> computeNextDelta(WebCore::FloatSize currentUnacceleratedDelta);
void didReceiveScrollEventWithInterval(WebCore::FloatSize, Seconds);
void didReceiveScrollEvent(const WebWheelEvent&);
#if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
void pushLogEntry(uint32_t generatedPhase, uint32_t eventPhase);
void flushLog();
WebCore::FloatSize m_lastActivePhaseDelta;
struct LogEntry {
MonotonicTime time;
float totalGeneratedOffset { 0 };
float totalEventOffset { 0 };
uint32_t generatedPhase { 0 };
uint32_t eventPhase { 0 };
};
LogEntry m_currentLogState;
Vector<LogEntry> m_log;
#endif
struct Delta {
float rawPlatformDelta;
Seconds frameInterval;
};
static constexpr unsigned deltaHistoryQueueSize = 9;
typedef Deque<Delta, deltaHistoryQueueSize> HistoricalDeltas;
HistoricalDeltas m_deltaHistoryX;
HistoricalDeltas m_deltaHistoryY;
std::optional<WallTime> m_lastScrollTimestamp;
std::optional<WebWheelEvent> m_lastIncomingEvent;
WebCore::RectEdges<bool> m_lastRubberBandableEdges;
bool m_isInOverriddenPlatformMomentumGesture { false };
struct {
bool active { false };
WebCore::PageIdentifier pageIdentifier;
std::optional<ScrollingAccelerationCurve> accelerationCurve;
std::optional<WebWheelEvent> initiatingEvent;
WebCore::FloatSize currentOffset;
MonotonicTime startTime;
Vector<WebCore::FloatSize> offsetTable; // Always at 60Hz intervals.
Vector<WebCore::FloatSize> tailDeltaTable; // Always at event dispatch intervals.
Seconds tailStartDelay;
unsigned currentTailDeltaIndex { 0 };
WebCore::FramesPerSecond displayNominalFrameRate { 0 };
#if ENABLE(MOMENTUM_EVENT_DISPATCHER_TEMPORARY_LOGGING)
WebCore::FloatSize accumulatedEventOffset;
bool didLogInitialQueueState { false };
#endif
#if ENABLE(MOMENTUM_EVENT_DISPATCHER_PREMATURE_ROUNDING)
WebCore::FloatSize carryOffset;
#endif
} m_currentGesture;
DisplayLinkObserverID m_observerID;
HashMap<WebCore::PageIdentifier, DisplayProperties> m_displayProperties;
HashMap<WebCore::PageIdentifier, std::optional<ScrollingAccelerationCurve>> m_accelerationCurves;
EventDispatcher& m_dispatcher;
};
} // namespace WebKit
#endif