DisplayRefreshMonitor.cpp [plain text]
#include "config.h"
#if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
#include "DisplayRefreshMonitor.h"
#include <wtf/CurrentTime.h>
namespace WebCore {
DisplayRefreshMonitorClient::DisplayRefreshMonitorClient()
: m_scheduled(false)
, m_displayIDIsSet(false)
{
}
DisplayRefreshMonitorClient::~DisplayRefreshMonitorClient()
{
DisplayRefreshMonitorManager::sharedManager()->unregisterClient(this);
}
void DisplayRefreshMonitorClient::fireDisplayRefreshIfNeeded(double timestamp)
{
if (m_scheduled) {
m_scheduled = false;
displayRefreshFired(timestamp);
}
}
DisplayRefreshMonitor::DisplayRefreshMonitor(PlatformDisplayID displayID)
: m_timestamp(0)
, m_active(true)
, m_scheduled(false)
, m_previousFrameDone(true)
, m_unscheduledFireCount(0)
, m_displayID(displayID)
#if PLATFORM(MAC)
, m_displayLink(0)
#endif
#if PLATFORM(BLACKBERRY)
, m_animationClient(0)
#endif
{
}
void DisplayRefreshMonitor::handleDisplayRefreshedNotificationOnMainThread(void* data)
{
DisplayRefreshMonitor* monitor = static_cast<DisplayRefreshMonitor*>(data);
monitor->displayDidRefresh();
}
void DisplayRefreshMonitor::addClient(DisplayRefreshMonitorClient* client)
{
m_clients.add(client);
}
bool DisplayRefreshMonitor::removeClient(DisplayRefreshMonitorClient* client)
{
DisplayRefreshMonitorClientSet::iterator it = m_clients.find(client);
if (it != m_clients.end()) {
m_clients.remove(it);
return true;
}
return false;
}
void DisplayRefreshMonitor::displayDidRefresh()
{
double timestamp;
{
MutexLocker lock(m_mutex);
if (!m_scheduled)
++m_unscheduledFireCount;
else
m_unscheduledFireCount = 0;
m_scheduled = false;
timestamp = m_timestamp;
}
RefPtr<DisplayRefreshMonitor> protector(this);
Vector<DisplayRefreshMonitorClient*> clients;
copyToVector(m_clients, clients);
for (size_t i = 0; i < clients.size(); ++i)
clients[i]->fireDisplayRefreshIfNeeded(timestamp);
{
MutexLocker lock(m_mutex);
m_previousFrameDone = true;
}
DisplayRefreshMonitorManager::sharedManager()->displayDidRefresh(this);
}
DisplayRefreshMonitorManager* DisplayRefreshMonitorManager::sharedManager()
{
DEFINE_STATIC_LOCAL(DisplayRefreshMonitorManager, manager, ());
return &manager;
}
DisplayRefreshMonitor* DisplayRefreshMonitorManager::ensureMonitorForClient(DisplayRefreshMonitorClient* client)
{
DisplayRefreshMonitorMap::iterator it = m_monitors.find(client->m_displayID);
if (it == m_monitors.end()) {
RefPtr<DisplayRefreshMonitor> monitor = DisplayRefreshMonitor::create(client->m_displayID);
monitor->addClient(client);
DisplayRefreshMonitor* result = monitor.get();
m_monitors.add(client->m_displayID, monitor.release());
return result;
}
return it->second.get();
}
void DisplayRefreshMonitorManager::registerClient(DisplayRefreshMonitorClient* client)
{
if (!client->m_displayIDIsSet)
return;
ensureMonitorForClient(client);
}
void DisplayRefreshMonitorManager::unregisterClient(DisplayRefreshMonitorClient* client)
{
if (!client->m_displayIDIsSet)
return;
DisplayRefreshMonitorMap::iterator it = m_monitors.find(client->m_displayID);
if (it == m_monitors.end())
return;
DisplayRefreshMonitor* monitor = it->second.get();
if (monitor->removeClient(client)) {
if (!monitor->hasClients())
m_monitors.remove(it);
}
}
bool DisplayRefreshMonitorManager::scheduleAnimation(DisplayRefreshMonitorClient* client)
{
if (!client->m_displayIDIsSet)
return false;
DisplayRefreshMonitor* monitor = ensureMonitorForClient(client);
client->m_scheduled = true;
return monitor->requestRefreshCallback();
}
void DisplayRefreshMonitorManager::displayDidRefresh(DisplayRefreshMonitor* monitor)
{
if (monitor->shouldBeTerminated()) {
DisplayRefreshMonitorMap::iterator it = m_monitors.find(monitor->displayID());
ASSERT(it != m_monitors.end());
m_monitors.remove(it);
}
}
void DisplayRefreshMonitorManager::windowScreenDidChange(PlatformDisplayID displayID, DisplayRefreshMonitorClient* client)
{
if (client->m_displayIDIsSet && client->m_displayID == displayID)
return;
unregisterClient(client);
client->setDisplayID(displayID);
registerClient(client);
if (client->m_scheduled)
scheduleAnimation(client);
}
}
#endif // USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)