1 | // Aseprite UI Library |
2 | // Copyright (C) 2018-2022 Igara Studio S.A. |
3 | // Copyright (C) 2001-2016 David Capello |
4 | // |
5 | // This file is released under the terms of the MIT license. |
6 | // Read LICENSE.txt for more information. |
7 | |
8 | #ifdef HAVE_CONFIG_H |
9 | #include "config.h" |
10 | #endif |
11 | |
12 | #include "ui/overlay.h" |
13 | |
14 | #include "os/surface.h" |
15 | #include "os/system.h" |
16 | #include "ui/display.h" |
17 | |
18 | namespace ui { |
19 | |
20 | Overlay::Overlay(Display* display, |
21 | const os::SurfaceRef& overlaySurface, |
22 | const gfx::Point& pos, |
23 | ZOrder zorder) |
24 | : m_display(display) |
25 | , m_surface(overlaySurface) |
26 | , m_overlap(nullptr) |
27 | , m_captured(nullptr) |
28 | , m_pos(pos) |
29 | , m_zorder(zorder) |
30 | { |
31 | } |
32 | |
33 | Overlay::~Overlay() |
34 | { |
35 | ASSERT(!m_captured); |
36 | |
37 | if (m_surface) { |
38 | if (m_display) |
39 | m_display->invalidateRect(bounds()); |
40 | m_surface.reset(); |
41 | } |
42 | |
43 | if (m_overlap) |
44 | m_overlap.reset(); |
45 | } |
46 | |
47 | os::SurfaceRef Overlay::setSurface(const os::SurfaceRef& newSurface) |
48 | { |
49 | os::SurfaceRef oldSurface = m_surface; |
50 | m_surface = newSurface; |
51 | return oldSurface; |
52 | } |
53 | |
54 | gfx::Rect Overlay::bounds() const |
55 | { |
56 | if (m_surface) |
57 | return gfx::Rect(m_pos.x, m_pos.y, m_surface->width(), m_surface->height()); |
58 | else |
59 | return gfx::Rect(0, 0, 0, 0); |
60 | } |
61 | |
62 | void Overlay::drawOverlay() |
63 | { |
64 | if (!m_surface || |
65 | !m_captured) |
66 | return; |
67 | |
68 | os::SurfaceLock lock(m_surface.get()); |
69 | m_captured->drawRgbaSurface(m_surface.get(), m_pos.x, m_pos.y); |
70 | |
71 | m_display->dirtyRect( |
72 | gfx::Rect(m_pos.x, m_pos.y, |
73 | m_surface->width(), |
74 | m_surface->height())); |
75 | } |
76 | |
77 | void Overlay::moveOverlay(const gfx::Point& newPos) |
78 | { |
79 | if (m_captured) |
80 | restoreOverlappedArea(gfx::Rect()); |
81 | |
82 | m_pos = newPos; |
83 | } |
84 | |
85 | void Overlay::captureOverlappedArea() |
86 | { |
87 | if (!m_surface || |
88 | m_captured) |
89 | return; |
90 | |
91 | os::Surface* displaySurface = m_display->surface(); |
92 | os::SurfaceLock lockDisplaySurface(displaySurface); |
93 | |
94 | if (!m_overlap) { |
95 | // Use the same color space for the overlay as in the screen |
96 | m_overlap = os::instance()->makeSurface(m_surface->width(), |
97 | m_surface->height(), |
98 | displaySurface->colorSpace()); |
99 | } |
100 | |
101 | os::SurfaceLock lock(m_overlap.get()); |
102 | displaySurface->blitTo(m_overlap.get(), m_pos.x, m_pos.y, 0, 0, |
103 | m_overlap->width(), m_overlap->height()); |
104 | // TODO uncomment and test this when GPU support is added |
105 | //m_overlap->setImmutable(); |
106 | |
107 | m_captured = base::AddRef(displaySurface); |
108 | } |
109 | |
110 | void Overlay::restoreOverlappedArea(const gfx::Rect& restoreBounds) |
111 | { |
112 | if (!m_surface || |
113 | !m_overlap || |
114 | !m_captured) |
115 | return; |
116 | |
117 | if (!restoreBounds.isEmpty() && |
118 | !restoreBounds.intersects(bounds())) |
119 | return; |
120 | |
121 | os::SurfaceLock lock(m_overlap.get()); |
122 | m_overlap->blitTo(m_captured.get(), 0, 0, m_pos.x, m_pos.y, |
123 | m_overlap->width(), m_overlap->height()); |
124 | |
125 | m_display->dirtyRect(bounds()); |
126 | m_captured = nullptr; |
127 | } |
128 | |
129 | } |
130 | |