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.
5 #include "ppapi/utility/graphics/paint_manager.h"
7 #include "ppapi/c/pp_errors.h"
8 #include "ppapi/cpp/instance.h"
9 #include "ppapi/cpp/logging.h"
10 #include "ppapi/cpp/module.h"
14 PaintManager::PaintManager()
17 is_always_opaque_(false),
18 callback_factory_(NULL
),
19 manual_callback_pending_(false),
20 flush_pending_(false),
21 has_pending_resize_(false) {
22 // Set the callback object outside of the initializer list to avoid a
23 // compiler warning about using "this" in an initializer list.
24 callback_factory_
.Initialize(this);
27 PaintManager::PaintManager(Instance
* instance
,
29 bool is_always_opaque
)
30 : instance_(instance
),
32 is_always_opaque_(is_always_opaque
),
33 callback_factory_(NULL
),
34 manual_callback_pending_(false),
35 flush_pending_(false),
36 has_pending_resize_(false) {
37 // Set the callback object outside of the initializer list to avoid a
38 // compiler warning about using "this" in an initializer list.
39 callback_factory_
.Initialize(this);
41 // You can not use a NULL client pointer.
45 PaintManager::~PaintManager() {
48 void PaintManager::Initialize(Instance
* instance
,
50 bool is_always_opaque
) {
51 PP_DCHECK(!instance_
&& !client_
); // Can't initialize twice.
54 is_always_opaque_
= is_always_opaque
;
57 void PaintManager::SetSize(const Size
& new_size
) {
58 if (GetEffectiveSize() == new_size
)
61 has_pending_resize_
= true;
62 pending_size_
= new_size
;
67 void PaintManager::Invalidate() {
68 // You must call SetSize before using.
69 PP_DCHECK(!graphics_
.is_null() || has_pending_resize_
);
71 EnsureCallbackPending();
72 aggregator_
.InvalidateRect(Rect(GetEffectiveSize()));
75 void PaintManager::InvalidateRect(const Rect
& rect
) {
76 // You must call SetSize before using.
77 PP_DCHECK(!graphics_
.is_null() || has_pending_resize_
);
79 // Clip the rect to the device area.
80 Rect clipped_rect
= rect
.Intersect(Rect(GetEffectiveSize()));
81 if (clipped_rect
.IsEmpty())
82 return; // Nothing to do.
84 EnsureCallbackPending();
85 aggregator_
.InvalidateRect(clipped_rect
);
88 void PaintManager::ScrollRect(const Rect
& clip_rect
, const Point
& amount
) {
89 // You must call SetSize before using.
90 PP_DCHECK(!graphics_
.is_null() || has_pending_resize_
);
92 EnsureCallbackPending();
93 aggregator_
.ScrollRect(clip_rect
, amount
);
96 Size
PaintManager::GetEffectiveSize() const {
97 return has_pending_resize_
? pending_size_
: graphics_
.size();
100 void PaintManager::EnsureCallbackPending() {
101 // The best way for us to do the next update is to get a notification that
102 // a previous one has completed. So if we're already waiting for one, we
103 // don't have to do anything differently now.
107 // If no flush is pending, we need to do a manual call to get back to the
108 // main thread. We may have one already pending, or we may need to schedule.
109 if (manual_callback_pending_
)
112 Module::Get()->core()->CallOnMainThread(
114 callback_factory_
.NewCallback(&PaintManager::OnManualCallbackComplete
),
116 manual_callback_pending_
= true;
119 void PaintManager::DoPaint() {
120 PP_DCHECK(aggregator_
.HasPendingUpdate());
122 // Make a copy of the pending update and clear the pending update flag before
123 // actually painting. A plugin might cause invalidates in its Paint code, and
124 // we want those to go to the *next* paint.
125 PaintAggregator::PaintUpdate update
= aggregator_
.GetPendingUpdate();
126 aggregator_
.ClearPendingUpdate();
128 // Apply any pending resize. Setting the graphics to this class must happen
129 // before asking the plugin to paint in case it requests the Graphics2D during
130 // painting. However, the bind must not happen until afterward since we don't
131 // want to have an unpainted device bound. The needs_binding flag tells us
132 // whether to do this later.
133 bool needs_binding
= false;
134 if (has_pending_resize_
) {
135 graphics_
= Graphics2D(instance_
, pending_size_
, is_always_opaque_
);
136 needs_binding
= true;
138 // Since we're binding a new one, all of the callbacks have been canceled.
139 manual_callback_pending_
= false;
140 flush_pending_
= false;
141 callback_factory_
.CancelAll();
143 // This must be cleared before calling into the plugin since it may do
144 // additional invalidation or sizing operations.
145 has_pending_resize_
= false;
146 pending_size_
= Size();
149 // Apply any scroll before asking the client to paint.
150 if (update
.has_scroll
)
151 graphics_
.Scroll(update
.scroll_rect
, update
.scroll_delta
);
153 if (client_
->OnPaint(graphics_
, update
.paint_rects
, update
.paint_bounds
)) {
154 // Something was painted, schedule a flush.
155 int32_t result
= graphics_
.Flush(
156 callback_factory_
.NewOptionalCallback(&PaintManager::OnFlushComplete
));
158 // If you trigger this assertion, then your plugin has called Flush()
159 // manually. When using the PaintManager, you should not call Flush, it
160 // will handle that for you because it needs to know when it can do the
161 // next paint by implementing the flush callback.
163 // Another possible cause of this assertion is re-using devices. If you
164 // use one device, swap it with another, then swap it back, we won't know
165 // that we've already scheduled a Flush on the first device. It's best to
166 // not re-use devices in this way.
167 PP_DCHECK(result
!= PP_ERROR_INPROGRESS
);
169 if (result
== PP_OK_COMPLETIONPENDING
) {
170 flush_pending_
= true;
172 PP_DCHECK(result
== PP_OK
); // Catch all other errors in debug mode.
177 instance_
->BindGraphics(graphics_
);
180 void PaintManager::OnFlushComplete(int32_t result
) {
181 PP_DCHECK(flush_pending_
);
182 flush_pending_
= false;
184 // Theoretically this shouldn't fail unless we've made an error, but don't
185 // want to call into the client code to do more painting if something bad
190 // If more paints were enqueued while we were waiting for the flush to
191 // complete, execute them now.
192 if (aggregator_
.HasPendingUpdate())
196 void PaintManager::OnManualCallbackComplete(int32_t) {
197 PP_DCHECK(manual_callback_pending_
);
198 manual_callback_pending_
= false;
200 // Just because we have a manual callback doesn't mean there are actually any
201 // invalid regions. Even though we only schedule this callback when something
202 // is pending, a Flush callback could have come in before this callback was
203 // executed and that could have cleared the queue.
204 if (aggregator_
.HasPendingUpdate() && !flush_pending_
)