]> git.sesse.net Git - casparcg/commitdiff
#375 Moved requestAnimationFrame/cancelAnimationFrame handling from C++ to Javascript...
authorHelge Norberg <helge.norberg@svt.se>
Mon, 9 Nov 2015 12:54:28 +0000 (13:54 +0100)
committerHelge Norberg <helge.norberg@svt.se>
Mon, 9 Nov 2015 12:54:28 +0000 (13:54 +0100)
modules/html/html.cpp
modules/html/html.h
modules/html/producer/html_producer.cpp

index c0147f495578179548416ffad13bae1847ee4d52..a52d6663a45a8cef75e4dc5c49d20bf9662fe4d6 100644 (file)
@@ -67,82 +67,6 @@ void caspar_log(
        }
 }
 
-class animation_handler : public CefV8Handler
-{
-private:
-       std::map<int, CefRefPtr<CefV8Value>>            callbacks_per_id_;
-       int                                                                                     current_callback_id_    = 0;
-       boost::timer                                                            since_start_timer_;
-public:
-       CefRefPtr<CefBrowser>                                           browser;
-       std::function<CefRefPtr<CefV8Context>()>        get_context;
-
-       bool Execute(
-                       const CefString& name,
-                       CefRefPtr<CefV8Value> object,
-                       const CefV8ValueList& arguments,
-                       CefRefPtr<CefV8Value>& retval,
-                       CefString& exception) override
-       {
-               if (!CefCurrentlyOn(TID_RENDERER))
-                       return false;
-
-               if (arguments.size() < 1)
-               {
-                       return false;
-               }
-
-               if (name == "requestAnimationFrame" && arguments.at(0)->IsFunction())
-               {
-                       callbacks_per_id_.insert(std::make_pair(++current_callback_id_, arguments.at(0)));
-
-                       if (browser)
-                               browser->SendProcessMessage(PID_BROWSER, CefProcessMessage::Create(
-                                       ANIMATION_FRAME_REQUESTED_MESSAGE_NAME));
-
-                       retval = CefV8Value::CreateInt(current_callback_id_);
-               }
-               else if (name == "cancelAnimationFrame" && arguments.at(0)->IsInt())
-               {
-                       callbacks_per_id_.erase(arguments.at(0)->GetIntValue());
-               }
-               else
-                       return false;
-
-               return true;
-       }
-
-       void tick()
-       {
-               if (!get_context)
-                       return;
-
-               auto context = get_context();
-
-               if (!context)
-                       return;
-
-               if (!CefCurrentlyOn(TID_RENDERER))
-                       return;
-
-               std::map<int, CefRefPtr<CefV8Value>> callbacks_per_id;
-               callbacks_per_id_.swap(callbacks_per_id);
-               current_callback_id_ = 0;
-
-               CefV8ValueList callback_args;
-               callback_args.push_back(CefV8Value::CreateDouble(
-                               since_start_timer_.elapsed() * 1000.0));
-
-               for (auto& callback : callbacks_per_id)
-               {
-                       callback.second->ExecuteFunctionWithContext(
-                                       context, callback.second, callback_args);
-               }
-       }
-
-       IMPLEMENT_REFCOUNTING(animation_handler);
-};
-
 class remove_handler : public CefV8Handler
 {
        CefRefPtr<CefBrowser> browser_;
@@ -174,26 +98,13 @@ public:
 
 class renderer_application : public CefApp, CefRenderProcessHandler
 {
-       std::vector<std::pair<CefRefPtr<animation_handler>, CefRefPtr<CefV8Context>>> contexts_per_handlers_;
-       //std::map<CefRefPtr<animation_handler>, CefRefPtr<CefV8Context>> contexts_per_handlers_;
+       std::vector<CefRefPtr<CefV8Context>> contexts_;
 public:
        CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override
        {
                return this;
        }
 
-       CefRefPtr<CefV8Context> get_context(
-                       const CefRefPtr<animation_handler>& handler)
-       {
-               for (auto& ctx : contexts_per_handlers_)
-               {
-                       if (ctx.first == handler)
-                               return ctx.second;
-               }
-
-               return nullptr;
-       }
-
        void OnContextCreated(
                        CefRefPtr<CefBrowser> browser,
                        CefRefPtr<CefFrame> frame,
@@ -203,37 +114,45 @@ public:
                                "context for frame "
                                + boost::lexical_cast<std::string>(frame->GetIdentifier())
                                + " created");
-
-               CefRefPtr<animation_handler> handler = new animation_handler;
-               contexts_per_handlers_.push_back(std::make_pair(handler, context));
-               auto handler_ptr = handler.get();
-
-               handler->browser = browser;
-               handler->get_context = [this, handler_ptr]
-               {
-                       return get_context(handler_ptr);
-               };
+               contexts_.push_back(context);
 
                auto window = context->GetGlobal();
 
-               window->SetValue(
-                               "requestAnimationFrame",
-                               CefV8Value::CreateFunction(
-                                               "requestAnimationFrame",
-                                               handler.get()),
-                               V8_PROPERTY_ATTRIBUTE_NONE);
-               window->SetValue(
-                               "cancelAnimationFrame",
-                               CefV8Value::CreateFunction(
-                                               "cancelAnimationFrame",
-                                               handler.get()),
-                               V8_PROPERTY_ATTRIBUTE_NONE);
                window->SetValue(
                                "remove",
                                CefV8Value::CreateFunction(
                                                "remove",
                                                new remove_handler(browser)),
                                V8_PROPERTY_ATTRIBUTE_NONE);
+
+               CefRefPtr<CefV8Value> ret;
+               CefRefPtr<CefV8Exception> exception;
+               bool injected = context->Eval(R"(
+                       var requestedAnimationFrames    = {};
+                       var currentAnimationFrameId             = 0;
+
+                       window.requestAnimationFrame = function(callback) {
+                               requestedAnimationFrames[++currentAnimationFrameId] = callback;
+                               return currentAnimationFrameId;
+                       }
+
+                       window.cancelAnimationFrame = function(animationFrameId) {
+                               delete requestedAnimationFrames[animationFrameId];
+                       }
+
+                       function tickAnimations() {
+                               var requestedFrames = requestedAnimationFrames;
+                               var timestamp = performance.now();
+                               requestedAnimationFrames = {};
+
+                               for (var animationFrameId in requestedFrames)
+                                       if (requestedFrames.hasOwnProperty(animationFrameId))
+                                               requestedFrames[animationFrameId](timestamp);
+                       }
+               )", ret, exception);
+
+               if (!injected)
+                       caspar_log(browser, boost::log::trivial::error, "Could not inject javascript animation code.");
        }
 
        void OnContextReleased(
@@ -242,14 +161,12 @@ public:
                        CefRefPtr<CefV8Context> context)
        {
                auto removed = boost::remove_if(
-                               contexts_per_handlers_, [&](const std::pair<
-                                               CefRefPtr<animation_handler>,
-                                               CefRefPtr<CefV8Context>>& c)
-               {
-                       return c.second->IsSame(context);
-               });
+                               contexts_, [&](const CefRefPtr<CefV8Context>& c)
+                               {
+                                       return c->IsSame(context);
+                               });
 
-               if (removed != contexts_per_handlers_.end())
+               if (removed != contexts_.end())
                        caspar_log(browser, boost::log::trivial::trace,
                                        "context for frame "
                                        + boost::lexical_cast<std::string>(frame->GetIdentifier())
@@ -263,7 +180,7 @@ public:
 
        void OnBrowserDestroyed(CefRefPtr<CefBrowser> browser) override
        {
-               contexts_per_handlers_.clear();
+               contexts_.clear();
        }
 
        bool OnProcessMessageReceived(
@@ -273,9 +190,11 @@ public:
        {
                if (message->GetName().ToString() == TICK_MESSAGE_NAME)
                {
-                       for (auto& handler : contexts_per_handlers_)
+                       for (auto& context : contexts_)
                        {
-                               handler.first->tick();
+                               CefRefPtr<CefV8Value> ret;
+                               CefRefPtr<CefV8Exception> exception;
+                               context->Eval("tickAnimations()", ret, exception);
                        }
 
                        return true;
index 5a192bc2f82c9f33e4fcfc319590df733415dcd5..75e8796d494b1c82f14b5ef8e6b688c687815042 100644 (file)
@@ -30,8 +30,6 @@
 namespace caspar { namespace html {
 
 const std::string TICK_MESSAGE_NAME = "CasparCGTick";
-const std::string ANIMATION_FRAME_REQUESTED_MESSAGE_NAME =
-               "CasparCGAnimationFrameRequested";
 const std::string REMOVE_MESSAGE_NAME = "CasparCGRemove";
 const std::string LOG_MESSAGE_NAME = "CasparCGLog";
 
index f911bc4ea92035a7a6e2f1f2895be162065b0d83..30d8ed06fb651da7009bff13328bd30c791e3ac0 100644 (file)
@@ -90,7 +90,6 @@ class html_client
        tbb::concurrent_queue<std::wstring>             javascript_before_load_;
        tbb::atomic<bool>                                               loaded_;
        tbb::atomic<bool>                                               removed_;
-       tbb::atomic<bool>                                               animation_frame_requested_;
        std::queue<core::draw_frame>                    frames_;
        mutable boost::mutex                                    frames_mutex_;
 
@@ -123,7 +122,6 @@ public:
 
                loaded_ = false;
                removed_ = false;
-               animation_frame_requested_ = false;
                executor_.begin_invoke([&]{ update(); });
        }
 
@@ -162,11 +160,6 @@ public:
 
        void close()
        {
-               if (!animation_frame_requested_)
-                       CASPAR_LOG(warning) << print()
-                                       << " window.requestAnimationFrame() never called. "
-                                       << "Animations might have been laggy";
-
                html::invoke([=]
                {
                        if (browser_ != nullptr)
@@ -289,15 +282,7 @@ private:
        {
                auto name = message->GetName().ToString();
 
-               if (name == ANIMATION_FRAME_REQUESTED_MESSAGE_NAME)
-               {
-                       CASPAR_LOG(trace)
-                                       << print() << L" Requested animation frame";
-                       animation_frame_requested_ = true;
-
-                       return true;
-               }
-               else if (name == REMOVE_MESSAGE_NAME)
+               if (name == REMOVE_MESSAGE_NAME)
                {
                        remove();