Home | History | Annotate | Download | only in graphics
      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.
    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