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