From 9b2889ef66d4cd140075515abf584ebbf5b1920c Mon Sep 17 00:00:00 2001 From: David Capello Date: Thu, 15 Nov 2018 15:42:50 -0300 Subject: [PATCH] Fix issue with overlays on macOS w/the new async painting (fix #1931) Fixed regression introduced in d20436f9570302e20484b51435276dc9bad94009. Now overlays are kept on the screen and the overlapped area is restored just in time when we have to re-paint some widget on that area. --- src/ui/LICENSE.txt | 1 + src/ui/manager.cpp | 7 ++++--- src/ui/overlay.cpp | 39 +++++++++++++++++++++++++------------- src/ui/overlay.h | 10 ++++++++-- src/ui/overlay_manager.cpp | 37 ++++++++++++++++++------------------ src/ui/overlay_manager.h | 7 ++++--- 6 files changed, 62 insertions(+), 39 deletions(-) diff --git a/src/ui/LICENSE.txt b/src/ui/LICENSE.txt index 3adbd711e..dcd0e290a 100644 --- a/src/ui/LICENSE.txt +++ b/src/ui/LICENSE.txt @@ -1,3 +1,4 @@ +Copyright (C) 2018 Igara Studio S.A. Copyright (c) 2001-2018 David Capello Permission is hereby granted, free of charge, to any person obtaining diff --git a/src/ui/manager.cpp b/src/ui/manager.cpp index 84879885a..595810546 100644 --- a/src/ui/manager.cpp +++ b/src/ui/manager.cpp @@ -243,7 +243,6 @@ void Manager::flipDisplay() update_cursor_overlay(); // Draw overlays. - overlays->captureOverlappedAreas(); overlays->drawOverlays(); // Flip dirty region. @@ -257,8 +256,6 @@ void Manager::flipDisplay() m_dirtyRegion.clear(); } - - overlays->restoreOverlappedAreas(); } bool Manager::generateMessages() @@ -1483,6 +1480,10 @@ bool Manager::sendMessageToWidget(Message* msg, Widget* widget) return false; PaintMessage* paintMsg = static_cast(msg); + + // Restore overlays in the region that we're going to paint. + OverlayManager::instance()->restoreOverlappedAreas(paintMsg->rect()); + os::Surface* surface = m_display->getSurface(); surface->saveClip(); diff --git a/src/ui/overlay.cpp b/src/ui/overlay.cpp index 2cc0f1788..7b91e3f00 100644 --- a/src/ui/overlay.cpp +++ b/src/ui/overlay.cpp @@ -1,4 +1,5 @@ // Aseprite UI Library +// Copyright (C) 2018 Igara Studio S.A. // Copyright (C) 2001-2016 David Capello // // This file is released under the terms of the MIT license. @@ -18,7 +19,8 @@ namespace ui { Overlay::Overlay(os::Surface* overlaySurface, const gfx::Point& pos, ZOrder zorder) : m_surface(overlaySurface) - , m_overlap(NULL) + , m_overlap(nullptr) + , m_captured(nullptr) , m_pos(pos) , m_zorder(zorder) { @@ -26,6 +28,8 @@ Overlay::Overlay(os::Surface* overlaySurface, const gfx::Point& pos, ZOrder zord Overlay::~Overlay() { + ASSERT(!m_captured); + if (m_surface) { Manager* manager = Manager::getDefault(); if (manager) @@ -54,13 +58,14 @@ gfx::Rect Overlay::bounds() const return gfx::Rect(0, 0, 0, 0); } -void Overlay::drawOverlay(os::Surface* screen) +void Overlay::drawOverlay() { - if (!m_surface) + if (!m_surface || + !m_captured) return; os::SurfaceLock lock(m_surface); - screen->drawRgbaSurface(m_surface, m_pos.x, m_pos.y); + m_captured->drawRgbaSurface(m_surface, m_pos.x, m_pos.y); Manager::getDefault()->dirtyRect( gfx::Rect(m_pos.x, m_pos.y, @@ -70,12 +75,16 @@ void Overlay::drawOverlay(os::Surface* screen) void Overlay::moveOverlay(const gfx::Point& newPos) { + if (m_captured) + restoreOverlappedArea(gfx::Rect()); + m_pos = newPos; } void Overlay::captureOverlappedArea(os::Surface* screen) { - if (!m_surface) + if (!m_surface || + m_captured) return; if (!m_overlap) { @@ -88,24 +97,28 @@ void Overlay::captureOverlappedArea(os::Surface* screen) os::SurfaceLock lock(m_overlap); screen->blitTo(m_overlap, m_pos.x, m_pos.y, 0, 0, m_overlap->width(), m_overlap->height()); + + m_captured = screen; } -void Overlay::restoreOverlappedArea(os::Surface* screen) +void Overlay::restoreOverlappedArea(const gfx::Rect& restoreBounds) { - if (!m_surface) + if (!m_surface || + !m_overlap || + !m_captured) return; - if (!m_overlap) + if (!restoreBounds.isEmpty() && + !restoreBounds.intersects(bounds())) return; os::SurfaceLock lock(m_overlap); - m_overlap->blitTo(screen, 0, 0, m_pos.x, m_pos.y, + m_overlap->blitTo(m_captured, 0, 0, m_pos.x, m_pos.y, m_overlap->width(), m_overlap->height()); - Manager::getDefault()->dirtyRect( - gfx::Rect(m_pos.x, m_pos.y, - m_overlap->width(), - m_overlap->height())); + Manager::getDefault()->dirtyRect(bounds()); + + m_captured = nullptr; } } diff --git a/src/ui/overlay.h b/src/ui/overlay.h index a9f48f649..afd14710b 100644 --- a/src/ui/overlay.h +++ b/src/ui/overlay.h @@ -1,4 +1,5 @@ // Aseprite UI Library +// Copyright (C) 2018 Igara Studio S.A. // Copyright (C) 2001-2016 David Capello // // This file is released under the terms of the MIT license. @@ -34,9 +35,9 @@ namespace ui { gfx::Rect bounds() const; void captureOverlappedArea(os::Surface* screen); - void restoreOverlappedArea(os::Surface* screen); + void restoreOverlappedArea(const gfx::Rect& restoreBounds); - void drawOverlay(os::Surface* screen); + void drawOverlay(); void moveOverlay(const gfx::Point& newPos); bool operator<(const Overlay& other) const { @@ -46,6 +47,11 @@ namespace ui { private: os::Surface* m_surface; os::Surface* m_overlap; + + // Surface where we captured the overlapped (m_overlap) + // region. It's nullptr if the overlay wasn't drawn yet. + os::Surface* m_captured; + gfx::Point m_pos; ZOrder m_zorder; }; diff --git a/src/ui/overlay_manager.cpp b/src/ui/overlay_manager.cpp index 03bb4c79a..e5f3d63ca 100644 --- a/src/ui/overlay_manager.cpp +++ b/src/ui/overlay_manager.cpp @@ -1,5 +1,6 @@ // Aseprite UI Library -// Copyright (C) 2001-2013, 2015, 2016 David Capello +// Copyright (C) 2018 Igara Studio S.A. +// Copyright (C) 2001-2016 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -53,46 +54,46 @@ void OverlayManager::addOverlay(Overlay* overlay) void OverlayManager::removeOverlay(Overlay* overlay) { + if (overlay) + overlay->restoreOverlappedArea(gfx::Rect()); + iterator it = std::find(begin(), end(), overlay); ASSERT(it != end()); if (it != end()) m_overlays.erase(it); } -void OverlayManager::captureOverlappedAreas() +void OverlayManager::restoreOverlappedAreas(const gfx::Rect& restoreBounds) { + if (m_overlays.empty()) + return; + + // TODO can we remove this? Manager* manager = Manager::getDefault(); if (!manager) return; - os::Surface* displaySurface = manager->getDisplay()->getSurface(); - os::SurfaceLock lock(displaySurface); for (Overlay* overlay : *this) - overlay->captureOverlappedArea(displaySurface); -} - -void OverlayManager::restoreOverlappedAreas() -{ - Manager* manager = Manager::getDefault(); - if (!manager) - return; - - os::Surface* displaySurface = manager->getDisplay()->getSurface(); - os::SurfaceLock lock(displaySurface); - for (Overlay* overlay : *this) - overlay->restoreOverlappedArea(displaySurface); + overlay->restoreOverlappedArea(restoreBounds); } void OverlayManager::drawOverlays() { + if (m_overlays.empty()) + return; + Manager* manager = Manager::getDefault(); if (!manager) return; os::Surface* displaySurface = manager->getDisplay()->getSurface(); os::SurfaceLock lock(displaySurface); + for (Overlay* overlay : *this) - overlay->drawOverlay(displaySurface); + overlay->captureOverlappedArea(displaySurface); + + for (Overlay* overlay : *this) + overlay->drawOverlay(); } } // namespace ui diff --git a/src/ui/overlay_manager.h b/src/ui/overlay_manager.h index 5ded2f697..bfeb73781 100644 --- a/src/ui/overlay_manager.h +++ b/src/ui/overlay_manager.h @@ -1,5 +1,6 @@ // Aseprite UI Library -// Copyright (C) 2001-2013, 2015 David Capello +// Copyright (C) 2018 Igara Studio S.A. +// Copyright (C) 2001-2015 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. @@ -8,6 +9,7 @@ #define UI_OVERLAY_MANAGER_H_INCLUDED #pragma once +#include "gfx/rect.h" #include "ui/base.h" #include @@ -30,9 +32,8 @@ namespace ui { void addOverlay(Overlay* overlay); void removeOverlay(Overlay* overlay); - void captureOverlappedAreas(); - void restoreOverlappedAreas(); void drawOverlays(); + void restoreOverlappedAreas(const gfx::Rect& bounds); private: static void destroyInstance();