blob: fbddd9fceaef1496a49f7bb8b3ffc52d62273430 [file] [log] [blame]
// Copyright (c) 2011 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_CPP_PAINT_MANAGER_H_
#define PPAPI_CPP_PAINT_MANAGER_H_
#include <vector>
#include "ppapi/cpp/completion_callback.h"
#include "ppapi/cpp/graphics_2d.h"
#include "ppapi/cpp/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);
// 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_CPP_PAINT_MANAGER_H_