• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 namespace pp {
19 
20 class Graphics2D;
21 class Instance;
22 class Point;
23 class 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>
69 class 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.
~Client()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.
set_max_redundant_paint_to_scroll_area(float area)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.
set_max_paint_rects(size_t max_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!
graphics()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!
graphics()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