1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef PPAPI_UTILITY_GRAPHICS_PAINT_MANAGER_H_
6#define PPAPI_UTILITY_GRAPHICS_PAINT_MANAGER_H_
7
8#include <vector>
9
10#include "ppapi/cpp/graphics_2d.h"
11#include "ppapi/utility/completion_callback_factory.h"
12#include "ppapi/utility/graphics/paint_aggregator.h"
13
14/// @file
15/// This file defines the API to convert the "plugin push" model of painting
16/// in PPAPI to a paint request at a later time.
17
18namespace pp {
19
20class Graphics2D;
21class Instance;
22class Point;
23class Rect;
24
25/// This class converts the "instance push" model of painting in PPAPI to a
26/// paint request at a later time. Usage is that you call Invalidate and
27/// Scroll, and implement the Client interface. Your OnPaint handler will
28/// then get called with coalesced paint events.
29///
30/// This class is basically a <code>PaintAggregator</code> that groups updates,
31/// plus management of callbacks for scheduling paints.
32///
33/// <strong>Example:</strong>
34///
35/// <code>
36///
37///  class MyClass : public pp::Instance, public PaintManager::Client {
38///   public:
39///    MyClass() {
40///      paint_manager_.Initialize(this, this, false);
41///    }
42///
43///    void ViewChanged(const pp::Rect& position, const pp::Rect& clip) {
44///      paint_manager_.SetSize(position.size());
45///    }
46///
47///    void DoSomething() {
48///      // This function does something like respond to an event that causes
49///      // the screen to need updating.
50///      paint_manager_.InvalidateRect(some_rect);
51///    }
52///
53///    // Implementation of PaintManager::Client
54///    virtual bool OnPaint(pp::Graphics2D& device,
55///                         const pp::PaintUpdate& update) {
56///      // If our app needed scrolling, we would apply that first here.
57///
58///      // Then we would either repaint the area returned by GetPaintBounds or
59///      // iterate through all the paint_rects.
60///
61///      // The caller will call Flush() for us, so don't do that here.
62///      return true;
63///    }
64///
65///   private:
66///    pp::PaintManager paint_manager_;
67///  };
68/// </code>
69class PaintManager {
70 public:
71  class Client {
72   public:
73    /// OnPaint() paints the given invalid area of the instance to the given
74    /// graphics device. Returns true if anything was painted.
75    ///
76    /// You are given the list of rects to paint in <code>paint_rects</code>,
77    /// and the union of all of these rects in <code>paint_bounds</code>. You
78    /// only have to paint the area inside each of the
79    /// <code>paint_rects</code>, but can paint more if you want (some apps may
80    /// just want to paint the union).
81    ///
82    /// Do not call Flush() on the graphics device, this will be done
83    /// automatically if you return true from this function since the
84    /// <code>PaintManager</code> needs to handle the callback.
85    ///
86    /// It is legal for you to cause invalidates inside of Paint which will
87    /// then get executed as soon as the Flush for this update has completed.
88    /// However, this is not very nice to the host system since it will spin the
89    /// CPU, possibly updating much faster than necessary. It is best to have a
90    /// 1/60 second timer to do an invalidate instead. This will limit your
91    /// animation to the slower of 60Hz or "however fast Flush can complete."
92    ///
93    /// @param[in] graphics A <code>Graphics2D</code> to be painted.
94    /// @param[in] paint_rects A list of rects to paint.
95    /// @param[in] paint_bounds A union of the rects to paint.
96    ///
97    /// @return true if successful, otherwise false.
98    virtual bool OnPaint(Graphics2D& graphics,
99                         const std::vector<Rect>& paint_rects,
100                         const Rect& paint_bounds) = 0;
101
102   protected:
103    // You shouldn't be doing deleting through this interface.
104    virtual ~Client() {}
105  };
106
107  /// Default constructor for creating an is_null() <code>PaintManager</code>
108  /// object. If you use this version of the constructor, you must call
109  /// Initialize() below.
110  PaintManager();
111
112  /// A constructor to create a new <code>PaintManager</code> with an instance
113  /// and client.
114  ///
115  /// <strong>Note:</strong> You will need to call SetSize() before this class
116  /// will do anything. Normally you do this from the <code>ViewChanged</code>
117  /// method of your instance.
118  ///
119  /// @param instance The instance using this paint manager to do its
120  /// painting. Painting will automatically go to this instance and you don't
121  /// have to manually bind any device context (this is all handled by the
122  /// paint manager).
123  ///
124  /// @param client A non-owning pointer and must remain valid (normally the
125  /// object implementing the Client interface will own the paint manager).
126  ///
127  /// @param is_always_opaque A flag passed to the device contexts that this
128  /// class creates. Set this to true if your instance always draws an opaque
129  /// image to the device. This is used as a hint to the browser that it does
130  /// not need to do alpha blending, which speeds up painting. If you generate
131  /// non-opqaue pixels or aren't sure, set this to false for more general
132  /// blending.
133  ///
134  /// If you set is_always_opaque, your alpha channel should always be set to
135  /// 0xFF or there may be painting artifacts. Being opaque will allow the
136  /// browser to do a memcpy rather than a blend to paint the plugin, and this
137  /// means your alpha values will get set on the page backing store. If these
138  /// values are incorrect, it could mess up future blending. If you aren't
139  /// sure, it is always correct to specify that it it not opaque.
140  PaintManager(Instance* instance, Client* client, bool is_always_opaque);
141
142  /// Destructor.
143  ~PaintManager();
144
145  /// Initialize() must be called if you are using the 0-arg constructor.
146  ///
147  /// @param instance The instance using this paint manager to do its
148  /// painting. Painting will automatically go to this instance and you don't
149  /// have to manually bind any device context (this is all handled by the
150  /// paint manager).
151  /// @param client A non-owning pointer and must remain valid (normally the
152  /// object implementing the Client interface will own the paint manager).
153  /// @param is_always_opaque A flag passed to the device contexts that this
154  /// class creates. Set this to true if your instance always draws an opaque
155  /// image to the device. This is used as a hint to the browser that it does
156  /// not need to do alpha blending, which speeds up painting. If you generate
157  /// non-opqaue pixels or aren't sure, set this to false for more general
158  /// blending.
159  ///
160  /// If you set <code>is_always_opaque</code>, your alpha channel should
161  /// always be set to <code>0xFF</code> or there may be painting artifacts.
162  /// Being opaque will allow the browser to do a memcpy rather than a blend
163  /// to paint the plugin, and this means your alpha values will get set on the
164  /// page backing store. If these values are incorrect, it could mess up
165  /// future blending. If you aren't sure, it is always correct to specify that
166  /// it it not opaque.
167  void Initialize(Instance* instance, Client* client, bool is_always_opaque);
168
169  /// Setter function setting the max ratio of paint rect area to scroll rect
170  /// area that we will tolerate before downgrading the scroll into a repaint.
171  ///
172  /// If the combined area of paint rects contained within the scroll
173  /// rect grows too large, then we might as well just treat
174  /// the scroll rect as a paint rect.
175  ///
176  /// @param[in] area The max ratio of paint rect area to scroll rect area that
177  /// we will tolerate before downgrading the scroll into a repaint.
178  void set_max_redundant_paint_to_scroll_area(float area) {
179    aggregator_.set_max_redundant_paint_to_scroll_area(area);
180  }
181
182  /// Setter function for setting the maximum number of paint rects. If we
183  /// exceed this limit, then we'll start combining paint rects (refer to
184  /// CombinePaintRects() for further information). This limiting can be
185  /// important since there is typically some overhead in deciding what to
186  /// paint. If your module is fast at doing these computations, raise this
187  /// threshold, if your module is slow, lower it (probably requires some
188  /// tuning to find the right value).
189  ///
190  /// @param[in] max_rects The maximum number of paint rects.
191  void set_max_paint_rects(size_t max_rects) {
192    aggregator_.set_max_paint_rects(max_rects);
193  }
194
195  /// SetSize() sets the size of the instance. If the size is the same as the
196  /// previous call, this will be a NOP. If the size has changed, a new device
197  /// will be allocated to the given size and a paint to that device will be
198  /// scheduled.
199  ///
200  /// This function is intended to be called from <code>ViewChanged</code> with
201  /// the size of the instance. Since it tracks the old size and only allocates
202  /// when the size changes, you can always call this function without worrying
203  /// about whether the size changed or ViewChanged() is called for another
204  /// reason (like the position changed).
205  ///
206  /// @param new_size The new size for the instance.
207  void SetSize(const Size& new_size);
208
209  /// This function provides access to the underlying device in case you need
210  /// it. If you have done a SetSize(), note that the graphics context won't be
211  /// updated until right before the next call to OnPaint().
212  ///
213  /// <strong>Note:</strong> If you call Flush on this device the paint manager
214  /// will get very confused, don't do this!
215  const Graphics2D& graphics() const { return graphics_; }
216
217  /// This function provides access to the underlying device in case you need
218  /// it. If you have done a SetSize(), note that the graphics context won't be
219  /// updated until right before the next call to OnPaint().
220  ///
221  /// <strong>Note:</strong> If you call Flush on this device the paint manager
222  /// will get very confused, don't do this!
223  Graphics2D& graphics() { return graphics_; }
224
225  /// Invalidate() invalidate the entire instance.
226  void Invalidate();
227
228  /// InvalidateRect() Invalidate the provided rect.
229  ///
230  /// @param[in] rect The <code>Rect</code> to be invalidated.
231  void InvalidateRect(const Rect& rect);
232
233  /// ScrollRect() scrolls the provided <code>clip_rect</code> by the
234  /// <code>amount</code> argument.
235  ///
236  /// @param clip_rect The clip rectangle to scroll.
237  /// @param amount The amount to scroll <code>clip_rect</code>.
238  void ScrollRect(const Rect& clip_rect, const Point& amount);
239
240  /// GetEffectiveSize() returns the size of the graphics context for the
241  /// next paint operation. This is the pending size if a resize is pending
242  /// (the instance has called SetSize() but we haven't actually painted it
243  /// yet), or the current size of no resize is pending.
244  ///
245  /// @return The effective size.
246  Size GetEffectiveSize() const;
247
248 private:
249  // Disallow copy and assign (these are unimplemented).
250  PaintManager(const PaintManager&);
251  PaintManager& operator=(const PaintManager&);
252
253  // Makes sure there is a callback that will trigger a paint at a later time.
254  // This will be either a Flush callback telling us we're allowed to generate
255  // more data, or, if there's no flush callback pending, a manual call back
256  // to the message loop via ExecuteOnMainThread.
257  void EnsureCallbackPending();
258
259  // Does the client paint and executes a Flush if necessary.
260  void DoPaint();
261
262  // Callback for asynchronous completion of Flush.
263  void OnFlushComplete(int32_t result);
264
265  // Callback for manual scheduling of paints when there is no flush callback
266  // pending.
267  void OnManualCallbackComplete(int32_t);
268
269  Instance* instance_;
270
271  // Non-owning pointer. See the constructor.
272  Client* client_;
273
274  bool is_always_opaque_;
275
276  CompletionCallbackFactory<PaintManager> callback_factory_;
277
278  // This graphics device will be is_null() if no graphics has been manually
279  // set yet.
280  Graphics2D graphics_;
281
282  PaintAggregator aggregator_;
283
284  // See comment for EnsureCallbackPending for more on how these work.
285  bool manual_callback_pending_;
286  bool flush_pending_;
287
288  // When we get a resize, we don't bind right away (see SetSize). The
289  // has_pending_resize_ tells us that we need to do a resize for the next
290  // paint operation. When true, the new size is in pending_size_.
291  bool has_pending_resize_;
292  Size pending_size_;
293};
294
295}  // namespace pp
296
297#endif  // PPAPI_UTILITY_GRAPHICS_PAINT_MANAGER_H_
298