Unreviewed, roll out http://trac.webkit.org/changeset/187972.
[WebKit-https.git] / Source / WebCore / platform / graphics / DisplayRefreshMonitor.cpp
index f89103f..f23808c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2014 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -13,7 +13,7 @@
  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
  * 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
  */
 
 #include "config.h"
+#include "DisplayRefreshMonitor.h"
 
 #if USE(REQUEST_ANIMATION_FRAME_DISPLAY_MONITOR)
 
-#include "DisplayRefreshMonitor.h"
-
-#include <wtf/CurrentTime.h>
+#include "DisplayRefreshMonitorClient.h"
+#include "DisplayRefreshMonitorIOS.h"
+#include "DisplayRefreshMonitorMac.h"
+#include "DisplayRefreshMonitorManager.h"
 
 namespace WebCore {
 
-DisplayRefreshMonitorClient::DisplayRefreshMonitorClient()
-    : m_scheduled(false)
-    , m_displayIDIsSet(false)
+RefPtr<DisplayRefreshMonitor> DisplayRefreshMonitor::createDefaultDisplayRefreshMonitor(PlatformDisplayID displayID)
 {
+#if PLATFORM(MAC)
+    return DisplayRefreshMonitorMac::create(displayID);
+#endif
+#if PLATFORM(IOS)
+    return DisplayRefreshMonitorIOS::create(displayID);
+#endif
+    return nullptr;
 }
 
-DisplayRefreshMonitorClient::~DisplayRefreshMonitorClient()
-{
-    DisplayRefreshMonitorManager::sharedManager()->unregisterClient(this);
-}
-
-void DisplayRefreshMonitorClient::fireDisplayRefreshIfNeeded(double timestamp)
+RefPtr<DisplayRefreshMonitor> DisplayRefreshMonitor::create(DisplayRefreshMonitorClient& client)
 {
-    if (m_scheduled) {
-        m_scheduled = false;
-        displayRefreshFired(timestamp);
-    }
+    return client.createDisplayRefreshMonitor(client.displayID());
 }
 
 DisplayRefreshMonitor::DisplayRefreshMonitor(PlatformDisplayID displayID)
-    : m_timestamp(0)
+    : m_monotonicAnimationStartTime(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
+    , m_clientsToBeNotified(nullptr)
+{
+}
+
+DisplayRefreshMonitor::~DisplayRefreshMonitor()
 {
 }
 
@@ -74,126 +72,60 @@ void DisplayRefreshMonitor::handleDisplayRefreshedNotificationOnMainThread(void*
     monitor->displayDidRefresh();
 }
 
-void DisplayRefreshMonitor::addClient(DisplayRefreshMonitorClient* client)
+void DisplayRefreshMonitor::addClient(DisplayRefreshMonitorClient& client)
 {
-    m_clients.add(client);
+    m_clients.add(&client);
 }
 
-bool DisplayRefreshMonitor::removeClient(DisplayRefreshMonitorClient* 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;
+    if (m_clientsToBeNotified)
+        m_clientsToBeNotified->remove(&client);
+    return m_clients.remove(&client);
 }
 
 void DisplayRefreshMonitor::displayDidRefresh()
 {
-    double timestamp;
+    double monotonicAnimationStartTime;
+
     {
         MutexLocker lock(m_mutex);
-         if (!m_scheduled)
+        if (!m_scheduled)
             ++m_unscheduledFireCount;
         else
             m_unscheduledFireCount = 0;
 
         m_scheduled = false;
-        timestamp = m_timestamp;
+        monotonicAnimationStartTime = m_monotonicAnimationStartTime;
     }
 
     // The call back can cause all our clients to be unregistered, so we need to protect
     // against deletion until the end of the method.
-    RefPtr<DisplayRefreshMonitor> protector(this);
-    
-    Vector<DisplayRefreshMonitorClient*> clients;
-    copyToVector(m_clients, clients);
-    for (size_t i = 0; i < clients.size(); ++i)
-        clients[i]->fireDisplayRefreshIfNeeded(timestamp);
+    Ref<DisplayRefreshMonitor> protect(*this);
+
+    // Copy the hash table and remove clients from it one by one so we don't notify
+    // any client twice, but can respond to removal of clients during the delivery process.
+    HashSet<DisplayRefreshMonitorClient*> clientsToBeNotified = m_clients;
+    m_clientsToBeNotified = &clientsToBeNotified;
+    while (!clientsToBeNotified.isEmpty()) {
+        DisplayRefreshMonitorClient* client = clientsToBeNotified.takeAny();
+        client->fireDisplayRefreshIfNeeded(monotonicAnimationStartTime);
+
+        // This checks if this function was reentered. In that case, stop iterating
+        // since it's not safe to use the set any more.
+        if (m_clientsToBeNotified != &clientsToBeNotified)
+            break;
+    }
+
+    if (m_clientsToBeNotified == &clientsToBeNotified)
+        m_clientsToBeNotified = nullptr;
 
     {
         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->value.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->value.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);
+    DisplayRefreshMonitorManager::sharedManager().displayDidRefresh(*this);
 }
 
 }