Home | History | Annotate | Download | only in pdf
      1 // Copyright (c) 2010 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 PDF_PAINT_MANAGER_H_
      6 #define PDF_PAINT_MANAGER_H_
      7 
      8 #include <vector>
      9 
     10 #include "pdf/paint_aggregator.h"
     11 #include "ppapi/cpp/graphics_2d.h"
     12 #include "ppapi/utility/completion_callback_factory.h"
     13 
     14 namespace pp {
     15 class Graphics2D;
     16 class Instance;
     17 class Point;
     18 class Rect;
     19 };
     20 
     21 // Custom PaintManager for the PDF plugin.  This is branched from the Pepper
     22 // version.  The difference is that this supports progressive rendering of dirty
     23 // rects, where multiple calls to the rendering engine are needed.  It also
     24 // supports having higher-priority rects flushing right away, i.e. the
     25 // scrollbars.
     26 //
     27 // The client's OnPaint
     28 class PaintManager {
     29  public:
     30   // Like PaintAggregator's version, but allows the plugin to tell us whether
     31   // it should be flushed to the screen immediately or when the rest of the
     32   // plugin viewport is ready.
     33   struct ReadyRect {
     34     pp::Point offset;
     35     pp::Rect rect;
     36     pp::ImageData image_data;
     37     bool flush_now;
     38 
     39     ReadyRect(const pp::Rect& r, const pp::ImageData& i, bool f)
     40         : rect(r), image_data(i), flush_now(f) {}
     41 
     42     operator PaintAggregator::ReadyRect() const {
     43       PaintAggregator::ReadyRect rv;
     44       rv.offset = offset;
     45       rv.rect = rect;
     46       rv.image_data = image_data;
     47       return rv;
     48     }
     49   };
     50   class Client {
     51    public:
     52     // Paints the given invalid area of the plugin to the given graphics
     53     // device. Returns true if anything was painted.
     54     //
     55     // You are given the list of rects to paint in |paint_rects|.  You can
     56     // combine painting into less rectangles if it's more efficient.  When a
     57     // rect is painted, information about that paint should be inserted into
     58     // |ready|.  Otherwise if a paint needs more work, add the rect to
     59     // |pending|.  If |pending| is not empty, your OnPaint function will get
     60     // called again.  Once OnPaint is called and it returns no pending rects,
     61     // all the previously ready rects will be flushed on screen.  The exception
     62     // is for ready rects that have |flush_now| set to true.  These will be
     63     // flushed right away.
     64     //
     65     // Do not call Flush() on the graphics device, this will be done
     66     // automatically if you return true from this function since the
     67     // PaintManager needs to handle the callback.
     68     //
     69     // Calling Invalidate/Scroll is not allowed while inside an OnPaint
     70     virtual void OnPaint(const std::vector<pp::Rect>& paint_rects,
     71                          std::vector<ReadyRect>* ready,
     72                          std::vector<pp::Rect>* pending) = 0;
     73    protected:
     74     // You shouldn't be doing deleting through this interface.
     75     virtual ~Client() {}
     76   };
     77 
     78   // The instance is the plugin instance using this paint manager to do its
     79   // painting. Painting will automatically go to this instance and you don't
     80   // have to manually bind any device context (this is all handled by the
     81   // paint manager).
     82   //
     83   // The Client is a non-owning pointer and must remain valid (normally the
     84   // object implementing the Client interface will own the paint manager).
     85   //
     86   // The is_always_opaque flag will be passed to the device contexts that this
     87   // class creates. Set this to true if your plugin always draws an opaque
     88   // image to the device. This is used as a hint to the browser that it does
     89   // not need to do alpha blending, which speeds up painting. If you generate
     90   // non-opqaue pixels or aren't sure, set this to false for more general
     91   // blending.
     92   //
     93   // If you set is_always_opaque, your alpha channel should always be set to
     94   // 0xFF or there may be painting artifacts. Being opaque will allow the
     95   // browser to do a memcpy rather than a blend to paint the plugin, and this
     96   // means your alpha values will get set on the page backing store. If these
     97   // values are incorrect, it could mess up future blending. If you aren't
     98   // sure, it is always correct to specify that it it not opaque.
     99   //
    100   // You will need to call SetSize before this class will do anything. Normally
    101   // you do this from the ViewChanged method of your plugin instance.
    102   PaintManager(pp::Instance* instance, Client* client, bool is_always_opaque);
    103 
    104   ~PaintManager();
    105 
    106   // Returns the size of the graphics context to allocate for a given plugin
    107   // size. We may allocated a slightly larger buffer than required so that we
    108   // don't have to resize the context when scrollbars appear/dissapear due to
    109   // zooming (which can result in flickering).
    110   static pp::Size GetNewContextSize(const pp::Size& current_context_size,
    111                                     const pp::Size& plugin_size);
    112 
    113   // You must call this function before using if you use the 0-arg constructor.
    114   // See the constructor for what these arguments mean.
    115   void Initialize(pp::Instance* instance, Client* client,
    116                   bool is_always_opaque);
    117 
    118   // Sets the size of the plugin. If the size is the same as the previous call,
    119   // this will be a NOP. If the size has changed, a new device will be
    120   // allocated to the given size and a paint to that device will be scheduled.
    121   //
    122   // This is intended to be called from ViewChanged with the size of the
    123   // plugin. Since it tracks the old size and only allocates when the size
    124   // changes, you can always call this function without worrying about whether
    125   // the size changed or ViewChanged is called for another reason (like the
    126   // position changed).
    127   void SetSize(const pp::Size& new_size, float new_device_scale);
    128 
    129   // Invalidate the entire plugin.
    130   void Invalidate();
    131 
    132   // Invalidate the given rect.
    133   void InvalidateRect(const pp::Rect& rect);
    134 
    135   // The given rect should be scrolled by the given amounts.
    136   void ScrollRect(const pp::Rect& clip_rect, const pp::Point& amount);
    137 
    138   // Returns the size of the graphics context for the next paint operation.
    139   // This is the pending size if a resize is pending (the plugin has called
    140   // SetSize but we haven't actually painted it yet), or the current size of
    141   // no resize is pending.
    142   pp::Size GetEffectiveSize() const;
    143   float GetEffectiveDeviceScale() const;
    144 
    145  private:
    146   // Disallow copy and assign (these are unimplemented).
    147   PaintManager(const PaintManager&);
    148   PaintManager& operator=(const PaintManager&);
    149 
    150   // Makes sure there is a callback that will trigger a paint at a later time.
    151   // This will be either a Flush callback telling us we're allowed to generate
    152   // more data, or, if there's no flush callback pending, a manual call back
    153   // to the message loop via ExecuteOnMainThread.
    154   void EnsureCallbackPending();
    155 
    156   // Does the client paint and executes a Flush if necessary.
    157   void DoPaint();
    158 
    159   // Callback for asynchronous completion of Flush.
    160   void OnFlushComplete(int32_t);
    161 
    162   // Callback for manual scheduling of paints when there is no flush callback
    163   // pending.
    164   void OnManualCallbackComplete(int32_t);
    165 
    166   pp::Instance* instance_;
    167 
    168   // Non-owning pointer. See the constructor.
    169   Client* client_;
    170 
    171   bool is_always_opaque_;
    172 
    173   pp::CompletionCallbackFactory<PaintManager> callback_factory_;
    174 
    175   // This graphics device will be is_null() if no graphics has been manually
    176   // set yet.
    177   pp::Graphics2D graphics_;
    178 
    179   PaintAggregator aggregator_;
    180 
    181   // See comment for EnsureCallbackPending for more on how these work.
    182   bool manual_callback_pending_;
    183   bool flush_pending_;
    184 
    185   // When we get a resize, we don't bind right away (see SetSize). The
    186   // has_pending_resize_ tells us that we need to do a resize for the next
    187   // paint operation. When true, the new size is in pending_size_.
    188   bool has_pending_resize_;
    189   bool graphics_need_to_be_bound_;
    190   pp::Size pending_size_;
    191   pp::Size plugin_size_;
    192   float pending_device_scale_;
    193   float device_scale_;
    194 
    195   // True iff we're in the middle of a paint.
    196   bool in_paint_;
    197 
    198   // True if we haven't painted the plugin viewport yet.
    199   bool first_paint_;
    200 
    201   // True when the view size just changed and we're waiting for a paint.
    202   bool view_size_changed_waiting_for_paint_;
    203 };
    204 
    205 #endif  // PDF_PAINT_MANAGER_H_
    206