15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/utility/graphics/paint_manager.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/c/pp_errors.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/instance.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/logging.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/module.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace pp { 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PaintManager::PaintManager() 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : instance_(NULL), 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_(NULL), 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_always_opaque_(false), 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_factory_(NULL), 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manual_callback_pending_(false), 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flush_pending_(false), 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) has_pending_resize_(false) { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the callback object outside of the initializer list to avoid a 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // compiler warning about using "this" in an initializer list. 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_factory_.Initialize(this); 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PaintManager::PaintManager(Instance* instance, 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Client* client, 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_always_opaque) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : instance_(instance), 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_(client), 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_always_opaque_(is_always_opaque), 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_factory_(NULL), 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manual_callback_pending_(false), 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flush_pending_(false), 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) has_pending_resize_(false) { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Set the callback object outside of the initializer list to avoid a 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // compiler warning about using "this" in an initializer list. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_factory_.Initialize(this); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // You can not use a NULL client pointer. 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(client); 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PaintManager::~PaintManager() { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PaintManager::Initialize(Instance* instance, 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Client* client, 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_always_opaque) { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(!instance_ && !client_); // Can't initialize twice. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) instance_ = instance; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) client_ = client; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_always_opaque_ = is_always_opaque; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PaintManager::SetSize(const Size& new_size) { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (GetEffectiveSize() == new_size) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) has_pending_resize_ = true; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_size_ = new_size; 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Invalidate(); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PaintManager::Invalidate() { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // You must call SetSize before using. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(!graphics_.is_null() || has_pending_resize_); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureCallbackPending(); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) aggregator_.InvalidateRect(Rect(GetEffectiveSize())); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PaintManager::InvalidateRect(const Rect& rect) { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // You must call SetSize before using. 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(!graphics_.is_null() || has_pending_resize_); 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Clip the rect to the device area. 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Rect clipped_rect = rect.Intersect(Rect(GetEffectiveSize())); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (clipped_rect.IsEmpty()) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; // Nothing to do. 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureCallbackPending(); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) aggregator_.InvalidateRect(clipped_rect); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PaintManager::ScrollRect(const Rect& clip_rect, const Point& amount) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // You must call SetSize before using. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(!graphics_.is_null() || has_pending_resize_); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnsureCallbackPending(); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) aggregator_.ScrollRect(clip_rect, amount); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Size PaintManager::GetEffectiveSize() const { 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return has_pending_resize_ ? pending_size_ : graphics_.size(); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PaintManager::EnsureCallbackPending() { 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The best way for us to do the next update is to get a notification that 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a previous one has completed. So if we're already waiting for one, we 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // don't have to do anything differently now. 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (flush_pending_) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If no flush is pending, we need to do a manual call to get back to the 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // main thread. We may have one already pending, or we may need to schedule. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (manual_callback_pending_) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Module::Get()->core()->CallOnMainThread( 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_factory_.NewCallback(&PaintManager::OnManualCallbackComplete), 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manual_callback_pending_ = true; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PaintManager::DoPaint() { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(aggregator_.HasPendingUpdate()); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make a copy of the pending update and clear the pending update flag before 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // actually painting. A plugin might cause invalidates in its Paint code, and 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we want those to go to the *next* paint. 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PaintAggregator::PaintUpdate update = aggregator_.GetPendingUpdate(); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) aggregator_.ClearPendingUpdate(); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Apply any pending resize. Setting the graphics to this class must happen 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // before asking the plugin to paint in case it requests the Graphics2D during 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // painting. However, the bind must not happen until afterward since we don't 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // want to have an unpainted device bound. The needs_binding flag tells us 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // whether to do this later. 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool needs_binding = false; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (has_pending_resize_) { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) graphics_ = Graphics2D(instance_, pending_size_, is_always_opaque_); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) needs_binding = true; 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since we're binding a new one, all of the callbacks have been canceled. 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manual_callback_pending_ = false; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flush_pending_ = false; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_factory_.CancelAll(); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This must be cleared before calling into the plugin since it may do 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // additional invalidation or sizing operations. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) has_pending_resize_ = false; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pending_size_ = Size(); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Apply any scroll before asking the client to paint. 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (update.has_scroll) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) graphics_.Scroll(update.scroll_rect, update.scroll_delta); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (client_->OnPaint(graphics_, update.paint_rects, update.paint_bounds)) { 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Something was painted, schedule a flush. 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32_t result = graphics_.Flush( 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callback_factory_.NewOptionalCallback(&PaintManager::OnFlushComplete)); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If you trigger this assertion, then your plugin has called Flush() 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // manually. When using the PaintManager, you should not call Flush, it 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will handle that for you because it needs to know when it can do the 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // next paint by implementing the flush callback. 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Another possible cause of this assertion is re-using devices. If you 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // use one device, swap it with another, then swap it back, we won't know 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that we've already scheduled a Flush on the first device. It's best to 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // not re-use devices in this way. 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(result != PP_ERROR_INPROGRESS); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result == PP_OK_COMPLETIONPENDING) { 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flush_pending_ = true; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(result == PP_OK); // Catch all other errors in debug mode. 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (needs_binding) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) instance_->BindGraphics(graphics_); 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PaintManager::OnFlushComplete(int32_t result) { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(flush_pending_); 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flush_pending_ = false; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Theoretically this shouldn't fail unless we've made an error, but don't 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // want to call into the client code to do more painting if something bad 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // did happen. 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (result != PP_OK) 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If more paints were enqueued while we were waiting for the flush to 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // complete, execute them now. 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (aggregator_.HasPendingUpdate()) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoPaint(); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void PaintManager::OnManualCallbackComplete(int32_t) { 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(manual_callback_pending_); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) manual_callback_pending_ = false; 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Just because we have a manual callback doesn't mean there are actually any 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // invalid regions. Even though we only schedule this callback when something 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is pending, a Flush callback could have come in before this callback was 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // executed and that could have cleared the queue. 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (aggregator_.HasPendingUpdate() && !flush_pending_) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoPaint(); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace pp 210