// Copyright 2015 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. #ifndef UI_ACCELERATED_WIDGET_MAC_WINDOW_RESIZE_HELPER_MAC_H_ #define UI_ACCELERATED_WIDGET_MAC_WINDOW_RESIZE_HELPER_MAC_H_ #include "base/lazy_instance.h" #include "base/memory/ref_counted.h" #include "ui/accelerated_widget_mac/accelerated_widget_mac_export.h" namespace base { class SingleThreadTaskRunner; class TimeDelta; class WaitableEvent; } namespace ui { // WindowResizeHelperMac is used to make resize appear smooth. That is to // say, make sure that the window size and the size of the contents being drawn // in that window are resized in lock-step. This is accomplished by waiting // inside AppKit drawing routines on the UI thread for the compositor to produce // a frame of same size as the NSView that hosts an AcceleratedWidgetMac. When a // resize occurs, the view controller can wait for a frame of the correct size // by calling WindowResizeHelperMac::WaitForSingleTaskToRun() until a timeout // occurs, or the corresponding AcceleratedWidgetMac has a renderer frame of the // same size as its NSView. // // By posting tasks to the custom task_runner(), other threads indicate tasks // that are required to pick up a new frame. In the ordinary run of things these // would be posted to the |target_task_runner|; the UI thread given as an // argument to Init(). Posting instead to task_runner() will cause the tasks to // be posted to the UI thread (as usual), and will also enqueue them into a // queue which will be read and run in WaitForSingleTaskToRun(), potentially // before the task posted to the UI thread is run. Some care is taken (see // WrappedTask) to make sure that the messages are only executed once. // // This is further complicated because, in order for a frame to appear, it is // also necessary to run tasks posted by the ui::Compositor. To accomplish this, // the task_runner() that WindowResizeHelperMac provides can be used to // construct a ui::Compositor. When the Compositor posts tasks to it, they are // enqueued in the aforementioned queue, which may be pumped by // WindowResizeHelperMac::WaitForSingleTaskToRun(). class ACCELERATED_WIDGET_MAC_EXPORT WindowResizeHelperMac { public: static WindowResizeHelperMac* Get(); WindowResizeHelperMac(const WindowResizeHelperMac&) = delete; WindowResizeHelperMac& operator=(const WindowResizeHelperMac&) = delete; // Initializes the pumpable task_runner(), providing it with the task runner // for UI thread tasks. task_runner() will be null before Init() is called, // and WaitForSingleTaskToRun() will immediately return false. void Init( const scoped_refptr& target_task_runner); // Because this class is global, many tests may want to do this setup // repeatedly, so need some way to uninitialize as well. void ShutdownForTests(); scoped_refptr task_runner() const; // UI THREAD ONLY ----------------------------------------------------------- // Waits at most |max_delay| for a task to run. Returns true if a task ran, // false if no task ran. bool WaitForSingleTaskToRun(const base::TimeDelta& max_delay); private: friend struct base::LazyInstanceTraitsBase; WindowResizeHelperMac(); ~WindowResizeHelperMac(); // This helper is needed to create a ScopedAllowWait inside the scope of a // class where it is allowed. static void EventTimedWait(base::WaitableEvent* event, base::TimeDelta delay); // The task runner to which the helper will post tasks. This also maintains // the task queue and does the actual work for WaitForSingleTaskToRun. scoped_refptr task_runner_; }; } // namespace ui #endif // UI_ACCELERATED_WIDGET_MAC_WINDOW_RESIZE_HELPER_MAC_H_