Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/classes/sun/awt/RepaintArea.java
41152 views
1
/*
2
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.awt;
27
28
import java.awt.Component;
29
import java.awt.Graphics;
30
import java.awt.Rectangle;
31
import java.awt.event.PaintEvent;
32
33
/**
34
* The {@code RepaintArea} is a geometric construct created for the
35
* purpose of holding the geometry of several coalesced paint events.
36
* This geometry is accessed synchronously, although it is written such
37
* that painting may still be executed asynchronously.
38
*
39
* @author Eric Hawkes
40
* @since 1.3
41
*/
42
public class RepaintArea {
43
44
/**
45
* Maximum ratio of bounding rectangle to benefit for which
46
* both the vertical and horizontal unions are repainted.
47
* For smaller ratios the whole bounding rectangle is repainted.
48
* @see #paint
49
*/
50
private static final int MAX_BENEFIT_RATIO = 4;
51
52
private static final int HORIZONTAL = 0;
53
private static final int VERTICAL = 1;
54
private static final int UPDATE = 2;
55
56
private static final int RECT_COUNT = UPDATE + 1;
57
58
private Rectangle[] paintRects = new Rectangle[RECT_COUNT];
59
60
61
/**
62
* Constructs a new {@code RepaintArea}
63
* @since 1.3
64
*/
65
public RepaintArea() {
66
}
67
68
/**
69
* Constructs a new {@code RepaintArea} initialized to match
70
* the values of the specified RepaintArea.
71
*
72
* @param ra the {@code RepaintArea} from which to copy initial
73
* values to a newly constructed RepaintArea
74
* @since 1.3
75
*/
76
private RepaintArea(RepaintArea ra) {
77
// This constructor is private because it should only be called
78
// from the cloneAndReset method
79
for (int i = 0; i < RECT_COUNT; i++) {
80
paintRects[i] = ra.paintRects[i];
81
}
82
}
83
84
/**
85
* Adds a {@code Rectangle} to this {@code RepaintArea}.
86
* PAINT Rectangles are divided into mostly vertical and mostly horizontal.
87
* Each group is unioned together.
88
* UPDATE Rectangles are unioned.
89
*
90
* @param r the specified {@code Rectangle}
91
* @param id possible values PaintEvent.UPDATE or PaintEvent.PAINT
92
* @since 1.3
93
*/
94
public synchronized void add(Rectangle r, int id) {
95
// Make sure this new rectangle has positive dimensions
96
if (r.isEmpty()) {
97
return;
98
}
99
int addTo = UPDATE;
100
if (id == PaintEvent.PAINT) {
101
addTo = (r.width > r.height) ? HORIZONTAL : VERTICAL;
102
}
103
if (paintRects[addTo] != null) {
104
paintRects[addTo].add(r);
105
} else {
106
paintRects[addTo] = new Rectangle(r);
107
}
108
}
109
110
111
/**
112
* Creates a new {@code RepaintArea} with the same geometry as this
113
* RepaintArea, then removes all of the geometry from this
114
* RepaintArea and restores it to an empty RepaintArea.
115
*
116
* @return ra a new {@code RepaintArea} having the same geometry as
117
* this RepaintArea.
118
* @since 1.3
119
*/
120
private synchronized RepaintArea cloneAndReset() {
121
RepaintArea ra = new RepaintArea(this);
122
for (int i = 0; i < RECT_COUNT; i++) {
123
paintRects[i] = null;
124
}
125
return ra;
126
}
127
128
public boolean isEmpty() {
129
for (int i = 0; i < RECT_COUNT; i++) {
130
if (paintRects[i] != null) {
131
return false;
132
}
133
}
134
return true;
135
}
136
137
/**
138
* Constrains the size of the repaint area to the passed in bounds.
139
*/
140
public synchronized void constrain(int x, int y, int w, int h) {
141
for (int i = 0; i < RECT_COUNT; i++) {
142
Rectangle rect = paintRects[i];
143
if (rect != null) {
144
if (rect.x < x) {
145
rect.width -= (x - rect.x);
146
rect.x = x;
147
}
148
if (rect.y < y) {
149
rect.height -= (y - rect.y);
150
rect.y = y;
151
}
152
int xDelta = rect.x + rect.width - x - w;
153
if (xDelta > 0) {
154
rect.width -= xDelta;
155
}
156
int yDelta = rect.y + rect.height - y - h;
157
if (yDelta > 0) {
158
rect.height -= yDelta;
159
}
160
if (rect.width <= 0 || rect.height <= 0) {
161
paintRects[i] = null;
162
}
163
}
164
}
165
}
166
167
/**
168
* Marks the passed in region as not needing to be painted. It's possible
169
* this will do nothing.
170
*/
171
public synchronized void subtract(int x, int y, int w, int h) {
172
Rectangle subtract = new Rectangle(x, y, w, h);
173
for (int i = 0; i < RECT_COUNT; i++) {
174
if (subtract(paintRects[i], subtract)) {
175
if (paintRects[i] != null && paintRects[i].isEmpty()) {
176
paintRects[i] = null;
177
}
178
}
179
}
180
}
181
182
/**
183
* Invokes paint and update on target Component with optimal
184
* rectangular clip region.
185
* If PAINT bounding rectangle is less than
186
* MAX_BENEFIT_RATIO times the benefit, then the vertical and horizontal unions are
187
* painted separately. Otherwise the entire bounding rectangle is painted.
188
*
189
* @param target Component to {@code paint} or {@code update}
190
* @since 1.4
191
*/
192
public void paint(Object target, boolean shouldClearRectBeforePaint) {
193
Component comp = (Component)target;
194
195
if (isEmpty()) {
196
return;
197
}
198
199
if (!comp.isVisible()) {
200
return;
201
}
202
203
RepaintArea ra = this.cloneAndReset();
204
205
if (!subtract(ra.paintRects[VERTICAL], ra.paintRects[HORIZONTAL])) {
206
subtract(ra.paintRects[HORIZONTAL], ra.paintRects[VERTICAL]);
207
}
208
209
if (ra.paintRects[HORIZONTAL] != null && ra.paintRects[VERTICAL] != null) {
210
Rectangle paintRect = ra.paintRects[HORIZONTAL].union(ra.paintRects[VERTICAL]);
211
int square = paintRect.width * paintRect.height;
212
int benefit = square - ra.paintRects[HORIZONTAL].width
213
* ra.paintRects[HORIZONTAL].height - ra.paintRects[VERTICAL].width
214
* ra.paintRects[VERTICAL].height;
215
// if benefit is comparable with bounding box
216
if (MAX_BENEFIT_RATIO * benefit < square) {
217
ra.paintRects[HORIZONTAL] = paintRect;
218
ra.paintRects[VERTICAL] = null;
219
}
220
}
221
for (int i = 0; i < paintRects.length; i++) {
222
if (ra.paintRects[i] != null
223
&& !ra.paintRects[i].isEmpty())
224
{
225
// Should use separate Graphics for each paint() call,
226
// since paint() can change Graphics state for next call.
227
Graphics g = comp.getGraphics();
228
if (g != null) {
229
try {
230
g.setClip(ra.paintRects[i]);
231
if (i == UPDATE) {
232
updateComponent(comp, g);
233
} else {
234
if (shouldClearRectBeforePaint) {
235
g.clearRect( ra.paintRects[i].x,
236
ra.paintRects[i].y,
237
ra.paintRects[i].width,
238
ra.paintRects[i].height);
239
}
240
paintComponent(comp, g);
241
}
242
} finally {
243
g.dispose();
244
}
245
}
246
}
247
}
248
}
249
250
/**
251
* Calls {@code Component.update(Graphics)} with given Graphics.
252
*/
253
protected void updateComponent(Component comp, Graphics g) {
254
if (comp != null) {
255
comp.update(g);
256
}
257
}
258
259
/**
260
* Calls {@code Component.paint(Graphics)} with given Graphics.
261
*/
262
protected void paintComponent(Component comp, Graphics g) {
263
if (comp != null) {
264
comp.paint(g);
265
}
266
}
267
268
/**
269
* Subtracts subtr from rect. If the result is rectangle
270
* changes rect and returns true. Otherwise false.
271
*/
272
static boolean subtract(Rectangle rect, Rectangle subtr) {
273
if (rect == null || subtr == null) {
274
return true;
275
}
276
Rectangle common = rect.intersection(subtr);
277
if (common.isEmpty()) {
278
return true;
279
}
280
if (rect.x == common.x && rect.y == common.y) {
281
if (rect.width == common.width) {
282
rect.y += common.height;
283
rect.height -= common.height;
284
return true;
285
} else
286
if (rect.height == common.height) {
287
rect.x += common.width;
288
rect.width -= common.width;
289
return true;
290
}
291
} else
292
if (rect.x + rect.width == common.x + common.width
293
&& rect.y + rect.height == common.y + common.height)
294
{
295
if (rect.width == common.width) {
296
rect.height -= common.height;
297
return true;
298
} else
299
if (rect.height == common.height) {
300
rect.width -= common.width;
301
return true;
302
}
303
}
304
return false;
305
}
306
307
public String toString() {
308
return super.toString() + "[ horizontal=" + paintRects[0] +
309
" vertical=" + paintRects[1] +
310
" update=" + paintRects[2] + "]";
311
}
312
}
313
314