1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192

pdf / paint_manager.h [blame]

// Copyright 2010 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef PDF_PAINT_MANAGER_H_
#define PDF_PAINT_MANAGER_H_

#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "pdf/paint_aggregator.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "ui/gfx/geometry/size.h"

class SkImage;
class SkSurface;

namespace gfx {
class Point;
class Rect;
class Vector2d;
class Vector2dF;
}  // namespace gfx

namespace chrome_pdf {

// Custom PaintManager for the PDF plugin.  This is branched from the Pepper
// version.  The difference is that this supports progressive rendering of dirty
// rects, where multiple calls to the rendering engine are needed.  It also
// supports having higher-priority rects flushing right away, i.e. the
// scrollbars.
//
// The client's OnPaint
class PaintManager {
 public:
  class Client {
   public:
    // Invalidates the entire plugin container, scheduling a repaint.
    virtual void InvalidatePluginContainer() = 0;

    // Paints the given invalid area of the plugin to the given graphics
    // device. Returns true if anything was painted.
    //
    // You are given the list of rects to paint in `paint_rects`.  You can
    // combine painting into less rectangles if it's more efficient.  When a
    // rect is painted, information about that paint should be inserted into
    // `ready`.  Otherwise if a paint needs more work, add the rect to
    // `pending`.  If `pending` is not empty, your OnPaint function will get
    // called again.  Once OnPaint is called and it returns no pending rects,
    // all the previously ready rects will be flushed on screen.  The exception
    // is for ready rects that have `flush_now` set to true.  These will be
    // flushed right away.
    //
    // Do not call Flush() on the graphics device, this will be done
    // automatically if you return true from this function since the
    // PaintManager needs to handle the callback.
    //
    // Calling Invalidate/Scroll is not allowed while inside an OnPaint
    virtual void OnPaint(const std::vector<gfx::Rect>& paint_rects,
                         std::vector<PaintReadyRect>& ready,
                         std::vector<gfx::Rect>& pending) = 0;

    // Updates the client with the latest snapshot created by `Flush()`.
    virtual void UpdateSnapshot(sk_sp<SkImage> snapshot) = 0;

    // Updates the client with the latest output scale.
    virtual void UpdateScale(float scale) = 0;

    // Updates the client with the latest output layer transform.
    virtual void UpdateLayerTransform(float scale,
                                      const gfx::Vector2dF& translate) = 0;

   protected:
    // You shouldn't delete through this interface.
    ~Client() = default;
  };

  // The Client is a non-owning pointer and must remain valid (normally the
  // object implementing the Client interface will own the paint manager).
  //
  // You will need to call SetSize() before this class will do anything.
  // Normally you do this from UpdateGeometryOnViewChanged() of your plugin
  // instance.
  explicit PaintManager(Client* client);
  PaintManager(const PaintManager&) = delete;
  PaintManager& operator=(const PaintManager&) = delete;
  ~PaintManager();

  // Returns the size of the graphics context to allocate for a given plugin
  // size. We may allocated a slightly larger buffer than required so that we
  // don't have to resize the context when scrollbars appear/dissapear due to
  // zooming (which can result in flickering).
  static gfx::Size GetNewContextSize(const gfx::Size& current_context_size,
                                     const gfx::Size& plugin_size);

  // Sets the size of the plugin. If the size is the same as the previous call,
  // this will be a NOP. If the size has changed, a new device will be
  // allocated to the given size and a paint to that device will be scheduled.
  //
  // This is intended to be called from ViewChanged with the size of the
  // plugin. Since it tracks the old size and only allocates when the size
  // changes, you can always call this function without worrying about whether
  // the size changed or ViewChanged is called for another reason (like the
  // position changed).
  void SetSize(const gfx::Size& new_size, float new_device_scale);

  // Invalidate the entire plugin.
  void Invalidate();

  // Invalidate the given rect.
  void InvalidateRect(const gfx::Rect& rect);

  // The given rect should be scrolled by the given amounts.
  void ScrollRect(const gfx::Rect& clip_rect, const gfx::Vector2d& amount);

  // Returns the size of the graphics context for the next paint operation.
  // This is the pending size if a resize is pending (the plugin has called
  // SetSize but we haven't actually painted it yet), or the current size of
  // no resize is pending.
  gfx::Size GetEffectiveSize() const;
  float GetEffectiveDeviceScale() const;

  // Set the transform for the graphics layer.
  // If `schedule_flush` is true, it ensures a flush will be scheduled for
  // this change. If `schedule_flush` is false, then the change will not take
  // effect until another change causes a flush.
  void SetTransform(float scale,
                    const gfx::Point& origin,
                    const gfx::Vector2d& translate,
                    bool schedule_flush);
  // Resets any transform for the graphics layer.
  // This does not schedule a flush.
  void ClearTransform();

 private:
  // Makes sure there is a callback that will trigger a paint at a later time.
  // This will be either a Flush callback telling us we're allowed to generate
  // more data, or, if there's no flush callback pending, a manual call back
  // to the message loop via ExecuteOnMainThread.
  void EnsureCallbackPending();

  // Does the client paint and executes a Flush if necessary.
  void DoPaint();

  // Executes a Flush.
  void Flush();

  // Callback for asynchronous completion of Flush.
  void OnFlushComplete();

  // Callback for manual scheduling of paints when there is no flush callback
  // pending.
  void OnManualCallbackComplete();

  // Non-owning pointer. See the constructor.
  const raw_ptr<Client> client_;

  // Backing Skia surface.
  sk_sp<SkSurface> surface_;

  PaintAggregator aggregator_;

  // See comment for EnsureCallbackPending for more on how these work.
  bool manual_callback_pending_ = false;
  bool flush_pending_ = false;
  bool flush_requested_ = false;

  // When we get a resize, we don't do so right away (see `SetSize()`). The
  // `has_pending_resize_` tells us that we need to do a resize for the next
  // paint operation. When true, the new size is in `pending_size_`.
  bool has_pending_resize_ = false;
  gfx::Size pending_size_;
  gfx::Size plugin_size_;
  float pending_device_scale_ = 1.0f;
  float device_scale_ = 1.0f;

  // True iff we're in the middle of a paint.
  bool in_paint_ = false;

  // True if we haven't painted the plugin viewport yet.
  bool first_paint_ = true;

  // True when the view size just changed and we're waiting for a paint.
  bool view_size_changed_waiting_for_paint_ = false;

  base::WeakPtrFactory<PaintManager> weak_factory_{this};
};

}  // namespace chrome_pdf

#endif  // PDF_PAINT_MANAGER_H_