| // Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights |
| // reserved. Use of this source code is governed by a BSD-style license that can |
| // be found in the LICENSE file. |
| |
| #include "libcef/browser/browser_message_loop.h" |
| #include "libcef/browser/context.h" |
| #include "libcef/common/content_client.h" |
| |
| #include "base/memory/ptr_util.h" |
| #include "base/message_loop/message_pump.h" |
| #include "base/message_loop/message_pump_for_ui.h" |
| |
| #if defined(OS_MACOSX) |
| #include "base/mac/scoped_nsautorelease_pool.h" |
| #include "base/message_loop/message_pump_mac.h" |
| #endif |
| |
| #include "content/public/browser/browser_thread.h" |
| |
| namespace { |
| |
| // MessagePump implementation that delegates to OnScheduleMessagePumpWork() for |
| // scheduling. |
| class MessagePumpExternal : public base::MessagePumpForUI { |
| public: |
| MessagePumpExternal(float max_time_slice, |
| CefRefPtr<CefBrowserProcessHandler> handler) |
| : max_time_slice_(max_time_slice), handler_(handler) {} |
| |
| void Run(Delegate* delegate) override { |
| base::TimeTicks start = base::TimeTicks::Now(); |
| while (true) { |
| #if defined(OS_MACOSX) |
| base::mac::ScopedNSAutoreleasePool autorelease_pool; |
| #endif |
| |
| base::TimeTicks next_run_time; // is_null() |
| const bool has_more_work = DirectRunWork(delegate, &next_run_time); |
| if (!has_more_work) |
| break; |
| |
| if (next_run_time.is_null()) { |
| // We have more work that should run immediately. |
| next_run_time = base::TimeTicks::Now(); |
| } |
| |
| const base::TimeDelta& delta = next_run_time - start; |
| if (delta.InSecondsF() > max_time_slice_) |
| break; |
| } |
| } |
| |
| void Quit() override {} |
| |
| void ScheduleWork() override { handler_->OnScheduleMessagePumpWork(0); } |
| |
| void ScheduleDelayedWork(const base::TimeTicks& delayed_work_time) override { |
| const base::TimeDelta& delta = delayed_work_time - base::TimeTicks::Now(); |
| handler_->OnScheduleMessagePumpWork(delta.InMilliseconds()); |
| } |
| |
| private: |
| static bool DirectRunWork(Delegate* delegate, |
| base::TimeTicks* next_run_time) { |
| bool more_immediate_work = false; |
| bool more_idle_work = false; |
| bool more_delayed_work = false; |
| |
| Delegate::NextWorkInfo next_work_info = delegate->DoWork(); |
| |
| // is_immediate() returns true if the next task is ready right away. |
| more_immediate_work = next_work_info.is_immediate(); |
| if (!more_immediate_work) { |
| // DoIdleWork() returns true if idle work was all done. |
| more_idle_work = !delegate->DoIdleWork(); |
| |
| // Check the next PendingTask's |delayed_run_time|. |
| // is_max() returns true if there are no more immediate nor delayed tasks. |
| more_delayed_work = !next_work_info.delayed_run_time.is_max(); |
| if (more_delayed_work && !more_idle_work) { |
| // The only remaining work that we know about is the PendingTask. |
| // Consider the run time for that task in the time slice calculation. |
| *next_run_time = next_work_info.delayed_run_time; |
| } |
| } |
| |
| return more_immediate_work || more_idle_work || more_delayed_work; |
| } |
| |
| const float max_time_slice_; |
| CefRefPtr<CefBrowserProcessHandler> handler_; |
| }; |
| |
| CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() { |
| CefRefPtr<CefApp> app = CefContentClient::Get()->application(); |
| if (app) |
| return app->GetBrowserProcessHandler(); |
| return nullptr; |
| } |
| |
| std::unique_ptr<base::MessagePump> MessagePumpFactoryForUI() { |
| if (!content::BrowserThread::IsThreadInitialized( |
| content::BrowserThread::UI) || |
| content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { |
| CefRefPtr<CefBrowserProcessHandler> handler = GetBrowserProcessHandler(); |
| if (handler) |
| return std::make_unique<MessagePumpExternal>(0.01f, handler); |
| } |
| |
| #if defined(OS_MACOSX) |
| return base::MessagePumpMac::Create(); |
| #else |
| return std::make_unique<base::MessagePumpForUI>(); |
| #endif |
| } |
| |
| } // namespace |
| |
| void InitMessagePumpFactoryForUI() { |
| const CefSettings& settings = CefContext::Get()->settings(); |
| if (settings.external_message_pump) { |
| base::MessagePump::OverrideMessagePumpForUIFactory(MessagePumpFactoryForUI); |
| } |
| } |