Index: content/browser/renderer_host/render_widget_resize_helper.cc |
diff --git a/content/browser/renderer_host/render_widget_resize_helper.cc b/content/browser/renderer_host/render_widget_resize_helper.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..f5e6ff5317f3301c27d90ea16231a87362fdf2d3 |
--- /dev/null |
+++ b/content/browser/renderer_host/render_widget_resize_helper.cc |
@@ -0,0 +1,166 @@ |
+// Copyright 2014 The Chromium 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 "content/browser/renderer_host/render_widget_resize_helper.h" |
+ |
+#include "content/browser/gpu/gpu_process_host_ui_shim.h" |
+#include "content/browser/renderer_host/render_process_host_impl.h" |
+#include "content/public/browser/browser_thread.h" |
+ |
+namespace content { |
+namespace { |
+base::LazyInstance<RenderWidgetResizeHelper> g_render_widget_task_runner = |
+ LAZY_INSTANCE_INITIALIZER; |
+} // namespace |
+ |
+// A wrapper for IPCs and tasks that we may potentially execute in |
+// WaitForSingleTaskToRun. Because these tasks are sent to two places to run, |
+// we to wrap them in this structure and track whether or not they have run |
+// yet, to avoid running them twice. |
+class RenderWidgetResizeHelper::EnqueuedTask { |
+ public: |
+ enum Type { |
+ RENDERER_IPC, |
+ GPU_IPC, |
+ }; |
+ EnqueuedTask(Type type, int process_id, const IPC::Message& m); |
+ ~EnqueuedTask(); |
+ void Run(); |
+ void InvalidateHelper(); |
+ |
+ private: |
+ Type type_; |
+ int process_id_; |
+ IPC::Message message_; |
+ bool has_run_; |
+ RenderWidgetResizeHelper* helper_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(EnqueuedTask); |
+}; |
+ |
+RenderWidgetResizeHelper::EnqueuedTask::EnqueuedTask( |
+ Type type, |
+ int process_id, |
+ const IPC::Message& m) |
+ : type_(type), |
+ process_id_(process_id), |
+ message_(m), |
+ has_run_(false), |
+ helper_(RenderWidgetResizeHelper::Get()) { |
+} |
+ |
+RenderWidgetResizeHelper::EnqueuedTask::~EnqueuedTask() { |
+} |
+ |
+void RenderWidgetResizeHelper::EnqueuedTask::Run() { |
+ if (has_run_) |
+ return; |
+ |
+ if (helper_) |
+ helper_->WillRunEnqueuedTask(this); |
+ has_run_ = true; |
+ |
+ switch (type_) { |
+ case RENDERER_IPC: { |
+ RenderProcessHost* host = RenderProcessHost::FromID(process_id_); |
+ if (host) |
+ host->OnMessageReceived(message_); |
+ break; |
+ } |
+ case GPU_IPC: { |
+ GpuProcessHostUIShim* host = GpuProcessHostUIShim::FromID(process_id_); |
+ if (host) |
+ host->OnMessageReceived(message_); |
+ break; |
+ } |
+ } |
+} |
+ |
+void RenderWidgetResizeHelper::EnqueuedTask::InvalidateHelper() { |
+ helper_ = NULL; |
+} |
+ |
+// static |
+RenderWidgetResizeHelper* RenderWidgetResizeHelper::Get() { |
+ return g_render_widget_task_runner.Pointer(); |
+} |
+ |
+bool RenderWidgetResizeHelper::WaitForSingleTaskToRun( |
+ const base::TimeDelta& max_delay) { |
+ base::TimeTicks time_start = base::TimeTicks::Now(); |
+ |
+ for (;;) { |
+ // Peek at the message from the front of the queue. Running it will remove |
+ // it from the queue. |
+ EnqueuedTask* task = NULL; |
+ { |
+ base::AutoLock lock(task_queue_lock_); |
+ if (!task_queue_.empty()) |
+ task = task_queue_.front(); |
+ } |
+ |
+ if (task) { |
+ task->Run(); |
+ return true; |
+ } |
+ |
+ // Calculate the maximum amount of time that we are willing to sleep. |
+ base::TimeDelta max_sleep_time = |
+ max_delay - (base::TimeTicks::Now() - time_start); |
+ if (max_sleep_time <= base::TimeDelta::FromMilliseconds(0)) |
+ break; |
+ |
+ base::ThreadRestrictions::ScopedAllowWait allow_wait; |
+ event_.TimedWait(max_sleep_time); |
+ } |
+ |
+ return false; |
+} |
+ |
+void RenderWidgetResizeHelper::PostEnqueuedTask(EnqueuedTask* task) { |
+ { |
+ base::AutoLock lock(task_queue_lock_); |
+ task_queue_.push_back(task); |
+ } |
+ |
+ // Notify anyone waiting on the UI thread that there is a new entry in the |
+ // task map. If they don't find the entry they are looking for, then they |
+ // will just continue waiting. |
+ event_.Signal(); |
+ |
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
+ base::Bind(&EnqueuedTask::Run, base::Owned(task))); |
+} |
+ |
+void RenderWidgetResizeHelper::WillRunEnqueuedTask(EnqueuedTask* task) { |
+ base::AutoLock lock(task_queue_lock_); |
+ DCHECK(task_queue_.front() == task); |
+ task_queue_.pop_front(); |
+} |
+ |
+void RenderWidgetResizeHelper::PostRendererProcessMsg( |
+ int render_process_id, const IPC::Message& msg) { |
+ PostEnqueuedTask(new EnqueuedTask( |
+ EnqueuedTask::RENDERER_IPC, render_process_id, msg)); |
+} |
+ |
+void RenderWidgetResizeHelper::PostGpuProcessMsg( |
+ int gpu_host_id, const IPC::Message& msg) { |
+ PostEnqueuedTask(new EnqueuedTask(EnqueuedTask::GPU_IPC, gpu_host_id, msg)); |
+} |
+ |
+RenderWidgetResizeHelper::RenderWidgetResizeHelper() |
+ : event_(false /* auto-reset */, false /* initially signalled */) {} |
+ |
+RenderWidgetResizeHelper::~RenderWidgetResizeHelper() { |
+ // Ensure that any tasks that outlive this do not reach back into it. |
+ for (EnqueuedTaskQueue::iterator it = task_queue_.begin(); |
+ it != task_queue_.end(); ++it) { |
+ EnqueuedTask* task = *it; |
+ task->InvalidateHelper(); |
+ } |
+} |
+ |
+} // namespace content |
+ |