root/ppapi/utility/graphics/paint_manager.h

/* [<][>][^][v][top][bottom][index][help] */

INCLUDED FROM


// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef PPAPI_UTILITY_GRAPHICS_PAINT_MANAGER_H_
#define PPAPI_UTILITY_GRAPHICS_PAINT_MANAGER_H_

#include <vector>

#include "ppapi/cpp/graphics_2d.h"
#include "ppapi/utility/completion_callback_factory.h"
#include "ppapi/utility/graphics/paint_aggregator.h"

/// @file
/// This file defines the API to convert the "plugin push" model of painting
/// in PPAPI to a paint request at a later time.

namespace pp {

class Graphics2D;
class Instance;
class Point;
class Rect;

/// This class converts the "instance push" model of painting in PPAPI to a
/// paint request at a later time. Usage is that you call Invalidate and
/// Scroll, and implement the Client interface. Your OnPaint handler will
/// then get called with coalesced paint events.
///
/// This class is basically a <code>PaintAggregator</code> that groups updates,
/// plus management of callbacks for scheduling paints.
///
/// <strong>Example:</strong>
///
/// <code>
///
///  class MyClass : public pp::Instance, public PaintManager::Client {
///   public:
///    MyClass() {
///      paint_manager_.Initialize(this, this, false);
///    }
///
///    void ViewChanged(const pp::Rect& position, const pp::Rect& clip) {
///      paint_manager_.SetSize(position.size());
///    }
///
///    void DoSomething() {
///      // This function does something like respond to an event that causes
///      // the screen to need updating.
///      paint_manager_.InvalidateRect(some_rect);
///    }
///
///    // Implementation of PaintManager::Client
///    virtual bool OnPaint(pp::Graphics2D& device,
///                         const pp::PaintUpdate& update) {
///      // If our app needed scrolling, we would apply that first here.
///
///      // Then we would either repaint the area returned by GetPaintBounds or
///      // iterate through all the paint_rects.
///
///      // The caller will call Flush() for us, so don't do that here.
///      return true;
///    }
///
///   private:
///    pp::PaintManager paint_manager_;
///  };
/// </code>
class PaintManager {
 public:
  class Client {
   public:
    /// OnPaint() paints the given invalid area of the instance to the given
    /// graphics device. Returns true if anything was painted.
    ///
    /// You are given the list of rects to paint in <code>paint_rects</code>,
    /// and the union of all of these rects in <code>paint_bounds</code>. You
    /// only have to paint the area inside each of the
    /// <code>paint_rects</code>, but can paint more if you want (some apps may
    /// just want to paint the union).
    ///
    /// Do not call Flush() on the graphics device, this will be done
    /// automatically if you return true from this function since the
    /// <code>PaintManager</code> needs to handle the callback.
    ///
    /// It is legal for you to cause invalidates inside of Paint which will
    /// then get executed as soon as the Flush for this update has completed.
    /// However, this is not very nice to the host system since it will spin the
    /// CPU, possibly updating much faster than necessary. It is best to have a
    /// 1/60 second timer to do an invalidate instead. This will limit your
    /// animation to the slower of 60Hz or "however fast Flush can complete."
    ///
    /// @param[in] graphics A <code>Graphics2D</code> to be painted.
    /// @param[in] paint_rects A list of rects to paint.
    /// @param[in] paint_bounds A union of the rects to paint.
    ///
    /// @return true if successful, otherwise false.
    virtual bool OnPaint(Graphics2D& graphics,
                         const std::vector<Rect>& paint_rects,
                         const Rect& paint_bounds) = 0;

   protected:
    // You shouldn't be doing deleting through this interface.
    virtual ~Client() {}
  };

  /// Default constructor for creating an is_null() <code>PaintManager</code>
  /// object. If you use this version of the constructor, you must call
  /// Initialize() below.
  PaintManager();

  /// A constructor to create a new <code>PaintManager</code> with an instance
  /// and client.
  ///
  /// <strong>Note:</strong> You will need to call SetSize() before this class
  /// will do anything. Normally you do this from the <code>ViewChanged</code>
  /// method of your instance.
  ///
  /// @param instance The instance using this paint manager to do its
  /// painting. Painting will automatically go to this instance and you don't
  /// have to manually bind any device context (this is all handled by the
  /// paint manager).
  ///
  /// @param client A non-owning pointer and must remain valid (normally the
  /// object implementing the Client interface will own the paint manager).
  ///
  /// @param is_always_opaque A flag passed to the device contexts that this
  /// class creates. Set this to true if your instance always draws an opaque
  /// image to the device. This is used as a hint to the browser that it does
  /// not need to do alpha blending, which speeds up painting. If you generate
  /// non-opqaue pixels or aren't sure, set this to false for more general
  /// blending.
  ///
  /// If you set is_always_opaque, your alpha channel should always be set to
  /// 0xFF or there may be painting artifacts. Being opaque will allow the
  /// browser to do a memcpy rather than a blend to paint the plugin, and this
  /// means your alpha values will get set on the page backing store. If these
  /// values are incorrect, it could mess up future blending. If you aren't
  /// sure, it is always correct to specify that it it not opaque.
  PaintManager(Instance* instance, Client* client, bool is_always_opaque);

  /// Destructor.
  ~PaintManager();

  /// Initialize() must be called if you are using the 0-arg constructor.
  ///
  /// @param instance The instance using this paint manager to do its
  /// painting. Painting will automatically go to this instance and you don't
  /// have to manually bind any device context (this is all handled by the
  /// paint manager).
  /// @param client A non-owning pointer and must remain valid (normally the
  /// object implementing the Client interface will own the paint manager).
  /// @param is_always_opaque A flag passed to the device contexts that this
  /// class creates. Set this to true if your instance always draws an opaque
  /// image to the device. This is used as a hint to the browser that it does
  /// not need to do alpha blending, which speeds up painting. If you generate
  /// non-opqaue pixels or aren't sure, set this to false for more general
  /// blending.
  ///
  /// If you set <code>is_always_opaque</code>, your alpha channel should
  /// always be set to <code>0xFF</code> or there may be painting artifacts.
  /// Being opaque will allow the browser to do a memcpy rather than a blend
  /// to paint the plugin, and this means your alpha values will get set on the
  /// page backing store. If these values are incorrect, it could mess up
  /// future blending. If you aren't sure, it is always correct to specify that
  /// it it not opaque.
  void Initialize(Instance* instance, Client* client, bool is_always_opaque);

  /// Setter function setting the max ratio of paint rect area to scroll rect
  /// area that we will tolerate before downgrading the scroll into a repaint.
  ///
  /// If the combined area of paint rects contained within the scroll
  /// rect grows too large, then we might as well just treat
  /// the scroll rect as a paint rect.
  ///
  /// @param[in] area The max ratio of paint rect area to scroll rect area that
  /// we will tolerate before downgrading the scroll into a repaint.
  void set_max_redundant_paint_to_scroll_area(float area) {
    aggregator_.set_max_redundant_paint_to_scroll_area(area);
  }

  /// Setter function for setting the maximum number of paint rects. If we
  /// exceed this limit, then we'll start combining paint rects (refer to
  /// CombinePaintRects() for further information). This limiting can be
  /// important since there is typically some overhead in deciding what to
  /// paint. If your module is fast at doing these computations, raise this
  /// threshold, if your module is slow, lower it (probably requires some
  /// tuning to find the right value).
  ///
  /// @param[in] max_rects The maximum number of paint rects.
  void set_max_paint_rects(size_t max_rects) {
    aggregator_.set_max_paint_rects(max_rects);
  }

  /// SetSize() sets the size of the instance. 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 function is intended to be called from <code>ViewChanged</code> with
  /// the size of the instance. 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).
  ///
  /// @param new_size The new size for the instance.
  void SetSize(const Size& new_size);

  /// This function provides access to the underlying device in case you need
  /// it. If you have done a SetSize(), note that the graphics context won't be
  /// updated until right before the next call to OnPaint().
  ///
  /// <strong>Note:</strong> If you call Flush on this device the paint manager
  /// will get very confused, don't do this!
  const Graphics2D& graphics() const { return graphics_; }

  /// This function provides access to the underlying device in case you need
  /// it. If you have done a SetSize(), note that the graphics context won't be
  /// updated until right before the next call to OnPaint().
  ///
  /// <strong>Note:</strong> If you call Flush on this device the paint manager
  /// will get very confused, don't do this!
  Graphics2D& graphics() { return graphics_; }

  /// Invalidate() invalidate the entire instance.
  void Invalidate();

  /// InvalidateRect() Invalidate the provided rect.
  ///
  /// @param[in] rect The <code>Rect</code> to be invalidated.
  void InvalidateRect(const Rect& rect);

  /// ScrollRect() scrolls the provided <code>clip_rect</code> by the
  /// <code>amount</code> argument.
  ///
  /// @param clip_rect The clip rectangle to scroll.
  /// @param amount The amount to scroll <code>clip_rect</code>.
  void ScrollRect(const Rect& clip_rect, const Point& amount);

  /// GetEffectiveSize() returns the size of the graphics context for the
  /// next paint operation. This is the pending size if a resize is pending
  /// (the instance has called SetSize() but we haven't actually painted it
  /// yet), or the current size of no resize is pending.
  ///
  /// @return The effective size.
  Size GetEffectiveSize() const;

 private:
  // Disallow copy and assign (these are unimplemented).
  PaintManager(const PaintManager&);
  PaintManager& operator=(const PaintManager&);

  // 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();

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

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

  Instance* instance_;

  // Non-owning pointer. See the constructor.
  Client* client_;

  bool is_always_opaque_;

  CompletionCallbackFactory<PaintManager> callback_factory_;

  // This graphics device will be is_null() if no graphics has been manually
  // set yet.
  Graphics2D graphics_;

  PaintAggregator aggregator_;

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

  // When we get a resize, we don't bind 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_;
  Size pending_size_;
};

}  // namespace pp

#endif  // PPAPI_UTILITY_GRAPHICS_PAINT_MANAGER_H_

/* [<][>][^][v][top][bottom][index][help] */