1 /*
2 * Copyright (c) 1995, 2017, 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 java.awt;
27
28 import java.awt.geom.Rectangle2D;
29 import java.beans.Transient;
30
31 /**
32 * A {@code Rectangle} specifies an area in a coordinate space that is
33 * enclosed by the {@code Rectangle} object's upper-left point
34 * {@code (x,y)}
35 * in the coordinate space, its width, and its height.
36 * <p>
37 * A {@code Rectangle} object's {@code width} and
38 * {@code height} are {@code public} fields. The constructors
39 * that create a {@code Rectangle}, and the methods that can modify
40 * one, do not prevent setting a negative value for width or height.
41 * <p>
42 * <a id="Empty">
43 * A {@code Rectangle} whose width or height is exactly zero has location
44 * along those axes with zero dimension, but is otherwise considered empty.</a>
45 * The {@link #isEmpty} method will return true for such a {@code Rectangle}.
46 * Methods which test if an empty {@code Rectangle} contains or intersects
47 * a point or rectangle will always return false if either dimension is zero.
48 * Methods which combine such a {@code Rectangle} with a point or rectangle
49 * will include the location of the {@code Rectangle} on that axis in the
50 * result as if the {@link #add(Point)} method were being called.
51 * <p>
52 * <a id="NonExistent">
53 * A {@code Rectangle} whose width or height is negative has neither
54 * location nor dimension along those axes with negative dimensions.
55 * Such a {@code Rectangle} is treated as non-existent along those axes.
56 * Such a {@code Rectangle} is also empty with respect to containment
57 * calculations and methods which test if it contains or intersects a
58 * point or rectangle will always return false.
59 * Methods which combine such a {@code Rectangle} with a point or rectangle
60 * will ignore the {@code Rectangle} entirely in generating the result.
61 * If two {@code Rectangle} objects are combined and each has a negative
62 * dimension, the result will have at least one negative dimension.
63 * </a>
64 * <p>
65 * Methods which affect only the location of a {@code Rectangle} will
66 * operate on its location regardless of whether or not it has a negative
67 * or zero dimension along either axis.
68 * <p>
69 * Note that a {@code Rectangle} constructed with the default no-argument
70 * constructor will have dimensions of {@code 0x0} and therefore be empty.
71 * That {@code Rectangle} will still have a location of {@code (0,0)} and
72 * will contribute that location to the union and add operations.
73 * Code attempting to accumulate the bounds of a set of points should
74 * therefore initially construct the {@code Rectangle} with a specifically
75 * negative width and height or it should use the first point in the set
76 * to construct the {@code Rectangle}.
77 * For example:
78 * <pre>{@code
79 * Rectangle bounds = new Rectangle(0, 0, -1, -1);
80 * for (int i = 0; i < points.length; i++) {
81 * bounds.add(points[i]);
82 * }
83 * }</pre>
84 * or if we know that the points array contains at least one point:
85 * <pre>{@code
86 * Rectangle bounds = new Rectangle(points[0]);
87 * for (int i = 1; i < points.length; i++) {
88 * bounds.add(points[i]);
89 * }
90 * }</pre>
91 * <p>
92 * This class uses 32-bit integers to store its location and dimensions.
93 * Frequently operations may produce a result that exceeds the range of
94 * a 32-bit integer.
95 * The methods will calculate their results in a way that avoids any
96 * 32-bit overflow for intermediate results and then choose the best
97 * representation to store the final results back into the 32-bit fields
98 * which hold the location and dimensions.
99 * The location of the result will be stored into the {@link #x} and
100 * {@link #y} fields by clipping the true result to the nearest 32-bit value.
101 * The values stored into the {@link #width} and {@link #height} dimension
102 * fields will be chosen as the 32-bit values that encompass the largest
103 * part of the true result as possible.
104 * Generally this means that the dimension will be clipped independently
105 * to the range of 32-bit integers except that if the location had to be
106 * moved to store it into its pair of 32-bit fields then the dimensions
107 * will be adjusted relative to the "best representation" of the location.
108 * If the true result had a negative dimension and was therefore
109 * non-existent along one or both axes, the stored dimensions will be
110 * negative numbers in those axes.
111 * If the true result had a location that could be represented within
112 * the range of 32-bit integers, but zero dimension along one or both
113 * axes, then the stored dimensions will be zero in those axes.
114 *
115 * @author Sami Shaio
116 * @since 1.0
117 */
118 public class Rectangle extends Rectangle2D
119 implements Shape, java.io.Serializable
120 {
121
122 /**
123 * The X coordinate of the upper-left corner of the {@code Rectangle}.
124 *
125 * @serial
126 * @see #setLocation(int, int)
127 * @see #getLocation()
128 * @since 1.0
129 */
130 public int x;
131
132 /**
133 * The Y coordinate of the upper-left corner of the {@code Rectangle}.
134 *
135 * @serial
136 * @see #setLocation(int, int)
137 * @see #getLocation()
138 * @since 1.0
139 */
140 public int y;
141
142 /**
143 * The width of the {@code Rectangle}.
144 * @serial
145 * @see #setSize(int, int)
146 * @see #getSize()
147 * @since 1.0
148 */
149 public int width;
150
151 /**
152 * The height of the {@code Rectangle}.
153 *
154 * @serial
155 * @see #setSize(int, int)
156 * @see #getSize()
157 * @since 1.0
158 */
159 public int height;
160
161 /*
162 * JDK 1.1 serialVersionUID
163 */
164 private static final long serialVersionUID = -4345857070255674764L;
165
166 /**
167 * Initialize JNI field and method IDs
168 */
169 private static native void initIDs();
170
171 static {
172 /* ensure that the necessary native libraries are loaded */
173 Toolkit.loadLibraries();
174 if (!GraphicsEnvironment.isHeadless()) {
175 initIDs();
176 }
177 }
178
179 /**
180 * Constructs a new {@code Rectangle} whose upper-left corner
181 * is at (0, 0) in the coordinate space, and whose width and
182 * height are both zero.
183 */
184 public Rectangle() {
185 this(0, 0, 0, 0);
186 }
187
188 /**
189 * Constructs a new {@code Rectangle}, initialized to match
190 * the values of the specified {@code Rectangle}.
191 * @param r the {@code Rectangle} from which to copy initial values
192 * to a newly constructed {@code Rectangle}
193 * @since 1.1
194 */
195 public Rectangle(Rectangle r) {
196 this(r.x, r.y, r.width, r.height);
197 }
198
199 /**
200 * Constructs a new {@code Rectangle} whose upper-left corner is
201 * specified as
202 * {@code (x,y)} and whose width and height
203 * are specified by the arguments of the same name.
204 * @param x the specified X coordinate
205 * @param y the specified Y coordinate
206 * @param width the width of the {@code Rectangle}
207 * @param height the height of the {@code Rectangle}
208 * @since 1.0
209 */
210 public Rectangle(int x, int y, int width, int height) {
211 this.x = x;
212 this.y = y;
213 this.width = width;
214 this.height = height;
215 }
216
217 /**
218 * Constructs a new {@code Rectangle} whose upper-left corner
219 * is at (0, 0) in the coordinate space, and whose width and
220 * height are specified by the arguments of the same name.
221 * @param width the width of the {@code Rectangle}
222 * @param height the height of the {@code Rectangle}
223 */
224 public Rectangle(int width, int height) {
225 this(0, 0, width, height);
226 }
227
228 /**
229 * Constructs a new {@code Rectangle} whose upper-left corner is
230 * specified by the {@link Point} argument, and
231 * whose width and height are specified by the
232 * {@link Dimension} argument.
233 * @param p a {@code Point} that is the upper-left corner of
234 * the {@code Rectangle}
235 * @param d a {@code Dimension}, representing the
236 * width and height of the {@code Rectangle}
237 */
238 public Rectangle(Point p, Dimension d) {
239 this(p.x, p.y, d.width, d.height);
240 }
241
242 /**
243 * Constructs a new {@code Rectangle} whose upper-left corner is the
244 * specified {@code Point}, and whose width and height are both zero.
245 * @param p a {@code Point} that is the top left corner
246 * of the {@code Rectangle}
247 */
248 public Rectangle(Point p) {
249 this(p.x, p.y, 0, 0);
250 }
251
252 /**
253 * Constructs a new {@code Rectangle} whose top left corner is
254 * (0, 0) and whose width and height are specified
255 * by the {@code Dimension} argument.
256 * @param d a {@code Dimension}, specifying width and height
257 */
258 public Rectangle(Dimension d) {
259 this(0, 0, d.width, d.height);
260 }
261
262 /**
263 * Returns the X coordinate of the bounding {@code Rectangle} in
264 * {@code double} precision.
265 * @return the X coordinate of the bounding {@code Rectangle}.
266 */
267 public double getX() {
268 return x;
269 }
270
271 /**
272 * Returns the Y coordinate of the bounding {@code Rectangle} in
273 * {@code double} precision.
274 * @return the Y coordinate of the bounding {@code Rectangle}.
275 */
276 public double getY() {
277 return y;
278 }
279
280 /**
281 * Returns the width of the bounding {@code Rectangle} in
282 * {@code double} precision.
283 * @return the width of the bounding {@code Rectangle}.
284 */
285 public double getWidth() {
286 return width;
287 }
288
289 /**
290 * Returns the height of the bounding {@code Rectangle} in
291 * {@code double} precision.
292 * @return the height of the bounding {@code Rectangle}.
293 */
294 public double getHeight() {
295 return height;
296 }
297
298 /**
299 * Gets the bounding {@code Rectangle} of this {@code Rectangle}.
300 * <p>
301 * This method is included for completeness, to parallel the
302 * {@code getBounds} method of
303 * {@link Component}.
304 * @return a new {@code Rectangle}, equal to the
305 * bounding {@code Rectangle} for this {@code Rectangle}.
306 * @see java.awt.Component#getBounds
307 * @see #setBounds(Rectangle)
308 * @see #setBounds(int, int, int, int)
309 * @since 1.1
310 */
311 @Transient
312 public Rectangle getBounds() {
313 return new Rectangle(x, y, width, height);
314 }
315
316 /**
317 * {@inheritDoc}
318 * @since 1.2
319 */
320 public Rectangle2D getBounds2D() {
321 return new Rectangle(x, y, width, height);
322 }
323
324 /**
325 * Sets the bounding {@code Rectangle} of this {@code Rectangle}
326 * to match the specified {@code Rectangle}.
327 * <p>
328 * This method is included for completeness, to parallel the
329 * {@code setBounds} method of {@code Component}.
330 * @param r the specified {@code Rectangle}
331 * @see #getBounds
332 * @see java.awt.Component#setBounds(java.awt.Rectangle)
333 * @since 1.1
334 */
335 public void setBounds(Rectangle r) {
336 setBounds(r.x, r.y, r.width, r.height);
337 }
338
339 /**
340 * Sets the bounding {@code Rectangle} of this
341 * {@code Rectangle} to the specified
342 * {@code x}, {@code y}, {@code width},
343 * and {@code height}.
344 * <p>
345 * This method is included for completeness, to parallel the
346 * {@code setBounds} method of {@code Component}.
347 * @param x the new X coordinate for the upper-left
348 * corner of this {@code Rectangle}
349 * @param y the new Y coordinate for the upper-left
350 * corner of this {@code Rectangle}
351 * @param width the new width for this {@code Rectangle}
352 * @param height the new height for this {@code Rectangle}
353 * @see #getBounds
354 * @see java.awt.Component#setBounds(int, int, int, int)
355 * @since 1.1
356 */
357 public void setBounds(int x, int y, int width, int height) {
358 reshape(x, y, width, height);
359 }
360
361 /**
362 * Sets the bounds of this {@code Rectangle} to the integer bounds
363 * which encompass the specified {@code x}, {@code y}, {@code width},
364 * and {@code height}.
365 * If the parameters specify a {@code Rectangle} that exceeds the
366 * maximum range of integers, the result will be the best
367 * representation of the specified {@code Rectangle} intersected
368 * with the maximum integer bounds.
369 * @param x the X coordinate of the upper-left corner of
370 * the specified rectangle
371 * @param y the Y coordinate of the upper-left corner of
372 * the specified rectangle
373 * @param width the width of the specified rectangle
374 * @param height the new height of the specified rectangle
375 */
376 public void setRect(double x, double y, double width, double height) {
377 int newx, newy, neww, newh;
378
379 if (x > 2.0 * Integer.MAX_VALUE) {
380 // Too far in positive X direction to represent...
381 // We cannot even reach the left side of the specified
382 // rectangle even with both x & width set to MAX_VALUE.
383 // The intersection with the "maximal integer rectangle"
384 // is non-existent so we should use a width < 0.
385 // REMIND: Should we try to determine a more "meaningful"
386 // adjusted value for neww than just "-1"?
387 newx = Integer.MAX_VALUE;
388 neww = -1;
389 } else {
390 newx = clip(x, false);
391 if (width >= 0) width += x-newx;
392 neww = clip(width, width >= 0);
393 }
394
395 if (y > 2.0 * Integer.MAX_VALUE) {
396 // Too far in positive Y direction to represent...
397 newy = Integer.MAX_VALUE;
398 newh = -1;
399 } else {
400 newy = clip(y, false);
401 if (height >= 0) height += y-newy;
402 newh = clip(height, height >= 0);
403 }
404
405 reshape(newx, newy, neww, newh);
406 }
407 // Return best integer representation for v, clipped to integer
408 // range and floor-ed or ceiling-ed, depending on the boolean.
409 private static int clip(double v, boolean doceil) {
410 if (v <= Integer.MIN_VALUE) {
411 return Integer.MIN_VALUE;
412 }
413 if (v >= Integer.MAX_VALUE) {
414 return Integer.MAX_VALUE;
415 }
416 return (int) (doceil ? Math.ceil(v) : Math.floor(v));
417 }
418
419 /**
420 * Sets the bounding {@code Rectangle} of this
421 * {@code Rectangle} to the specified
422 * {@code x}, {@code y}, {@code width},
423 * and {@code height}.
424 *
425 * @param x the new X coordinate for the upper-left
426 * corner of this {@code Rectangle}
427 * @param y the new Y coordinate for the upper-left
428 * corner of this {@code Rectangle}
429 * @param width the new width for this {@code Rectangle}
430 * @param height the new height for this {@code Rectangle}
431 * @deprecated As of JDK version 1.1,
432 * replaced by {@code setBounds(int, int, int, int)}.
433 */
434 @Deprecated
435 public void reshape(int x, int y, int width, int height) {
436 this.x = x;
437 this.y = y;
438 this.width = width;
439 this.height = height;
440 }
441
442 /**
443 * Returns the location of this {@code Rectangle}.
444 * <p>
445 * This method is included for completeness, to parallel the
446 * {@code getLocation} method of {@code Component}.
447 * @return the {@code Point} that is the upper-left corner of
448 * this {@code Rectangle}.
449 * @see java.awt.Component#getLocation
450 * @see #setLocation(Point)
451 * @see #setLocation(int, int)
452 * @since 1.1
453 */
454 public Point getLocation() {
455 return new Point(x, y);
456 }
457
458 /**
459 * Moves this {@code Rectangle} to the specified location.
460 * <p>
461 * This method is included for completeness, to parallel the
462 * {@code setLocation} method of {@code Component}.
463 * @param p the {@code Point} specifying the new location
464 * for this {@code Rectangle}
465 * @see java.awt.Component#setLocation(java.awt.Point)
466 * @see #getLocation
467 * @since 1.1
468 */
469 public void setLocation(Point p) {
470 setLocation(p.x, p.y);
471 }
472
473 /**
474 * Moves this {@code Rectangle} to the specified location.
475 * <p>
476 * This method is included for completeness, to parallel the
477 * {@code setLocation} method of {@code Component}.
478 * @param x the X coordinate of the new location
479 * @param y the Y coordinate of the new location
480 * @see #getLocation
481 * @see java.awt.Component#setLocation(int, int)
482 * @since 1.1
483 */
484 public void setLocation(int x, int y) {
485 move(x, y);
486 }
487
488 /**
489 * Moves this {@code Rectangle} to the specified location.
490 *
491 * @param x the X coordinate of the new location
492 * @param y the Y coordinate of the new location
493 * @deprecated As of JDK version 1.1,
494 * replaced by {@code setLocation(int, int)}.
495 */
496 @Deprecated
497 public void move(int x, int y) {
498 this.x = x;
499 this.y = y;
500 }
501
502 /**
503 * Translates this {@code Rectangle} the indicated distance,
504 * to the right along the X coordinate axis, and
505 * downward along the Y coordinate axis.
506 * @param dx the distance to move this {@code Rectangle}
507 * along the X axis
508 * @param dy the distance to move this {@code Rectangle}
509 * along the Y axis
510 * @see java.awt.Rectangle#setLocation(int, int)
511 * @see java.awt.Rectangle#setLocation(java.awt.Point)
512 */
513 public void translate(int dx, int dy) {
514 int oldv = this.x;
515 int newv = oldv + dx;
516 if (dx < 0) {
517 // moving leftward
518 if (newv > oldv) {
519 // negative overflow
520 // Only adjust width if it was valid (>= 0).
521 if (width >= 0) {
522 // The right edge is now conceptually at
523 // newv+width, but we may move newv to prevent
524 // overflow. But we want the right edge to
525 // remain at its new location in spite of the
526 // clipping. Think of the following adjustment
527 // conceptually the same as:
528 // width += newv; newv = MIN_VALUE; width -= newv;
529 width += newv - Integer.MIN_VALUE;
530 // width may go negative if the right edge went past
531 // MIN_VALUE, but it cannot overflow since it cannot
532 // have moved more than MIN_VALUE and any non-negative
533 // number + MIN_VALUE does not overflow.
534 }
535 newv = Integer.MIN_VALUE;
536 }
537 } else {
538 // moving rightward (or staying still)
539 if (newv < oldv) {
540 // positive overflow
541 if (width >= 0) {
542 // Conceptually the same as:
543 // width += newv; newv = MAX_VALUE; width -= newv;
544 width += newv - Integer.MAX_VALUE;
545 // With large widths and large displacements
546 // we may overflow so we need to check it.
547 if (width < 0) width = Integer.MAX_VALUE;
548 }
549 newv = Integer.MAX_VALUE;
550 }
551 }
552 this.x = newv;
553
554 oldv = this.y;
555 newv = oldv + dy;
556 if (dy < 0) {
557 // moving upward
558 if (newv > oldv) {
559 // negative overflow
560 if (height >= 0) {
561 height += newv - Integer.MIN_VALUE;
562 // See above comment about no overflow in this case
563 }
564 newv = Integer.MIN_VALUE;
565 }
566 } else {
567 // moving downward (or staying still)
568 if (newv < oldv) {
569 // positive overflow
570 if (height >= 0) {
571 height += newv - Integer.MAX_VALUE;
572 if (height < 0) height = Integer.MAX_VALUE;
573 }
574 newv = Integer.MAX_VALUE;
575 }
576 }
577 this.y = newv;
578 }
579
580 /**
581 * Gets the size of this {@code Rectangle}, represented by
582 * the returned {@code Dimension}.
583 * <p>
584 * This method is included for completeness, to parallel the
585 * {@code getSize} method of {@code Component}.
586 * @return a {@code Dimension}, representing the size of
587 * this {@code Rectangle}.
588 * @see java.awt.Component#getSize
589 * @see #setSize(Dimension)
590 * @see #setSize(int, int)
591 * @since 1.1
592 */
593 public Dimension getSize() {
594 return new Dimension(width, height);
595 }
596
597 /**
598 * Sets the size of this {@code Rectangle} to match the
599 * specified {@code Dimension}.
600 * <p>
601 * This method is included for completeness, to parallel the
602 * {@code setSize} method of {@code Component}.
603 * @param d the new size for the {@code Dimension} object
604 * @see java.awt.Component#setSize(java.awt.Dimension)
605 * @see #getSize
606 * @since 1.1
607 */
608 public void setSize(Dimension d) {
609 setSize(d.width, d.height);
610 }
611
612 /**
613 * Sets the size of this {@code Rectangle} to the specified
614 * width and height.
615 * <p>
616 * This method is included for completeness, to parallel the
617 * {@code setSize} method of {@code Component}.
618 * @param width the new width for this {@code Rectangle}
619 * @param height the new height for this {@code Rectangle}
620 * @see java.awt.Component#setSize(int, int)
621 * @see #getSize
622 * @since 1.1
623 */
624 public void setSize(int width, int height) {
625 resize(width, height);
626 }
627
628 /**
629 * Sets the size of this {@code Rectangle} to the specified
630 * width and height.
631 *
632 * @param width the new width for this {@code Rectangle}
633 * @param height the new height for this {@code Rectangle}
634 * @deprecated As of JDK version 1.1,
635 * replaced by {@code setSize(int, int)}.
636 */
637 @Deprecated
638 public void resize(int width, int height) {
639 this.width = width;
640 this.height = height;
641 }
642
643 /**
644 * Checks whether or not this {@code Rectangle} contains the
645 * specified {@code Point}.
646 * @param p the {@code Point} to test
647 * @return {@code true} if the specified {@code Point}
648 * is inside this {@code Rectangle};
649 * {@code false} otherwise.
650 * @since 1.1
651 */
652 public boolean contains(Point p) {
653 return contains(p.x, p.y);
654 }
655
656 /**
657 * Checks whether or not this {@code Rectangle} contains the
658 * point at the specified location {@code (x,y)}.
659 *
660 * @param x the specified X coordinate
661 * @param y the specified Y coordinate
662 * @return {@code true} if the point
663 * {@code (x,y)} is inside this
664 * {@code Rectangle};
665 * {@code false} otherwise.
666 * @since 1.1
667 */
668 public boolean contains(int x, int y) {
669 return inside(x, y);
670 }
671
672 /**
673 * Checks whether or not this {@code Rectangle} entirely contains
674 * the specified {@code Rectangle}.
675 *
676 * @param r the specified {@code Rectangle}
677 * @return {@code true} if the {@code Rectangle}
678 * is contained entirely inside this {@code Rectangle};
679 * {@code false} otherwise
680 * @since 1.2
681 */
682 public boolean contains(Rectangle r) {
683 return contains(r.x, r.y, r.width, r.height);
684 }
685
686 /**
687 * Checks whether this {@code Rectangle} entirely contains
688 * the {@code Rectangle}
689 * at the specified location {@code (X,Y)} with the
690 * specified dimensions {@code (W,H)}.
691 * @param X the specified X coordinate
692 * @param Y the specified Y coordinate
693 * @param W the width of the {@code Rectangle}
694 * @param H the height of the {@code Rectangle}
695 * @return {@code true} if the {@code Rectangle} specified by
696 * {@code (X, Y, W, H)}
697 * is entirely enclosed inside this {@code Rectangle};
698 * {@code false} otherwise.
699 * @since 1.1
700 */
701 public boolean contains(int X, int Y, int W, int H) {
702 int w = this.width;
703 int h = this.height;
704 if ((w | h | W | H) < 0) {
705 // At least one of the dimensions is negative...
706 return false;
707 }
708 // Note: if any dimension is zero, tests below must return false...
709 int x = this.x;
710 int y = this.y;
711 if (X < x || Y < y) {
712 return false;
713 }
714 w += x;
715 W += X;
716 if (W <= X) {
717 // X+W overflowed or W was zero, return false if...
718 // either original w or W was zero or
719 // x+w did not overflow or
720 // the overflowed x+w is smaller than the overflowed X+W
721 if (w >= x || W > w) return false;
722 } else {
723 // X+W did not overflow and W was not zero, return false if...
724 // original w was zero or
725 // x+w did not overflow and x+w is smaller than X+W
726 if (w >= x && W > w) return false;
727 }
728 h += y;
729 H += Y;
730 if (H <= Y) {
731 if (h >= y || H > h) return false;
732 } else {
733 if (h >= y && H > h) return false;
734 }
735 return true;
736 }
737
738 /**
739 * Checks whether or not this {@code Rectangle} contains the
740 * point at the specified location {@code (X,Y)}.
741 *
742 * @param X the specified X coordinate
743 * @param Y the specified Y coordinate
744 * @return {@code true} if the point
745 * {@code (X,Y)} is inside this
746 * {@code Rectangle};
747 * {@code false} otherwise.
748 * @deprecated As of JDK version 1.1,
749 * replaced by {@code contains(int, int)}.
750 */
751 @Deprecated
752 public boolean inside(int X, int Y) {
753 int w = this.width;
754 int h = this.height;
755 if ((w | h) < 0) {
756 // At least one of the dimensions is negative...
757 return false;
758 }
759 // Note: if either dimension is zero, tests below must return false...
760 int x = this.x;
761 int y = this.y;
762 if (X < x || Y < y) {
763 return false;
764 }
765 w += x;
766 h += y;
767 // overflow || intersect
768 return ((w < x || w > X) &&
769 (h < y || h > Y));
770 }
771
772 /**
773 * Determines whether or not this {@code Rectangle} and the specified
774 * {@code Rectangle} intersect. Two rectangles intersect if
775 * their intersection is nonempty.
776 *
777 * @param r the specified {@code Rectangle}
778 * @return {@code true} if the specified {@code Rectangle}
779 * and this {@code Rectangle} intersect;
780 * {@code false} otherwise.
781 */
782 public boolean intersects(Rectangle r) {
783 int tw = this.width;
784 int th = this.height;
785 int rw = r.width;
786 int rh = r.height;
787 if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) {
788 return false;
789 }
790 int tx = this.x;
791 int ty = this.y;
792 int rx = r.x;
793 int ry = r.y;
794 rw += rx;
795 rh += ry;
796 tw += tx;
797 th += ty;
798 // overflow || intersect
799 return ((rw < rx || rw > tx) &&
800 (rh < ry || rh > ty) &&
801 (tw < tx || tw > rx) &&
802 (th < ty || th > ry));
803 }
804
805 /**
806 * Computes the intersection of this {@code Rectangle} with the
807 * specified {@code Rectangle}. Returns a new {@code Rectangle}
808 * that represents the intersection of the two rectangles.
809 * If the two rectangles do not intersect, the result will be
810 * an empty rectangle.
811 *
812 * @param r the specified {@code Rectangle}
813 * @return the largest {@code Rectangle} contained in both the
814 * specified {@code Rectangle} and in
815 * this {@code Rectangle}; or if the rectangles
816 * do not intersect, an empty rectangle.
817 */
818 public Rectangle intersection(Rectangle r) {
819 int tx1 = this.x;
820 int ty1 = this.y;
821 int rx1 = r.x;
822 int ry1 = r.y;
823 long tx2 = tx1; tx2 += this.width;
824 long ty2 = ty1; ty2 += this.height;
825 long rx2 = rx1; rx2 += r.width;
826 long ry2 = ry1; ry2 += r.height;
827 if (tx1 < rx1) tx1 = rx1;
828 if (ty1 < ry1) ty1 = ry1;
829 if (tx2 > rx2) tx2 = rx2;
830 if (ty2 > ry2) ty2 = ry2;
831 tx2 -= tx1;
832 ty2 -= ty1;
833 // tx2,ty2 will never overflow (they will never be
834 // larger than the smallest of the two source w,h)
835 // they might underflow, though...
836 if (tx2 < Integer.MIN_VALUE) tx2 = Integer.MIN_VALUE;
837 if (ty2 < Integer.MIN_VALUE) ty2 = Integer.MIN_VALUE;
838 return new Rectangle(tx1, ty1, (int) tx2, (int) ty2);
839 }
840
841 /**
842 * Computes the union of this {@code Rectangle} with the
843 * specified {@code Rectangle}. Returns a new
844 * {@code Rectangle} that
845 * represents the union of the two rectangles.
846 * <p>
847 * If either {@code Rectangle} has any dimension less than zero
848 * the rules for <a href=#NonExistent>non-existent</a> rectangles
849 * apply.
850 * If only one has a dimension less than zero, then the result
851 * will be a copy of the other {@code Rectangle}.
852 * If both have dimension less than zero, then the result will
853 * have at least one dimension less than zero.
854 * <p>
855 * If the resulting {@code Rectangle} would have a dimension
856 * too large to be expressed as an {@code int}, the result
857 * will have a dimension of {@code Integer.MAX_VALUE} along
858 * that dimension.
859 * @param r the specified {@code Rectangle}
860 * @return the smallest {@code Rectangle} containing both
861 * the specified {@code Rectangle} and this
862 * {@code Rectangle}.
863 */
864 public Rectangle union(Rectangle r) {
865 long tx2 = this.width;
866 long ty2 = this.height;
867 if ((tx2 | ty2) < 0) {
868 // This rectangle has negative dimensions...
869 // If r has non-negative dimensions then it is the answer.
870 // If r is non-existent (has a negative dimension), then both
871 // are non-existent and we can return any non-existent rectangle
872 // as an answer. Thus, returning r meets that criterion.
873 // Either way, r is our answer.
874 return new Rectangle(r);
875 }
876 long rx2 = r.width;
877 long ry2 = r.height;
878 if ((rx2 | ry2) < 0) {
879 return new Rectangle(this);
880 }
881 int tx1 = this.x;
882 int ty1 = this.y;
883 tx2 += tx1;
884 ty2 += ty1;
885 int rx1 = r.x;
886 int ry1 = r.y;
887 rx2 += rx1;
888 ry2 += ry1;
889 if (tx1 > rx1) tx1 = rx1;
890 if (ty1 > ry1) ty1 = ry1;
891 if (tx2 < rx2) tx2 = rx2;
892 if (ty2 < ry2) ty2 = ry2;
893 tx2 -= tx1;
894 ty2 -= ty1;
895 // tx2,ty2 will never underflow since both original rectangles
896 // were already proven to be non-empty
897 // they might overflow, though...
898 if (tx2 > Integer.MAX_VALUE) tx2 = Integer.MAX_VALUE;
899 if (ty2 > Integer.MAX_VALUE) ty2 = Integer.MAX_VALUE;
900 return new Rectangle(tx1, ty1, (int) tx2, (int) ty2);
901 }
902
903 /**
904 * Adds a point, specified by the integer arguments {@code newx,newy}
905 * to the bounds of this {@code Rectangle}.
906 * <p>
907 * If this {@code Rectangle} has any dimension less than zero,
908 * the rules for <a href=#NonExistent>non-existent</a>
909 * rectangles apply.
910 * In that case, the new bounds of this {@code Rectangle} will
911 * have a location equal to the specified coordinates and
912 * width and height equal to zero.
913 * <p>
914 * After adding a point, a call to {@code contains} with the
915 * added point as an argument does not necessarily return
916 * {@code true}. The {@code contains} method does not
917 * return {@code true} for points on the right or bottom
918 * edges of a {@code Rectangle}. Therefore, if the added point
919 * falls on the right or bottom edge of the enlarged
920 * {@code Rectangle}, {@code contains} returns
921 * {@code false} for that point.
922 * If the specified point must be contained within the new
923 * {@code Rectangle}, a 1x1 rectangle should be added instead:
924 * <pre>
925 * r.add(newx, newy, 1, 1);
926 * </pre>
927 * @param newx the X coordinate of the new point
928 * @param newy the Y coordinate of the new point
929 */
930 public void add(int newx, int newy) {
931 if ((width | height) < 0) {
932 this.x = newx;
933 this.y = newy;
934 this.width = this.height = 0;
935 return;
936 }
937 int x1 = this.x;
938 int y1 = this.y;
939 long x2 = this.width;
940 long y2 = this.height;
941 x2 += x1;
942 y2 += y1;
943 if (x1 > newx) x1 = newx;
944 if (y1 > newy) y1 = newy;
945 if (x2 < newx) x2 = newx;
946 if (y2 < newy) y2 = newy;
947 x2 -= x1;
948 y2 -= y1;
949 if (x2 > Integer.MAX_VALUE) x2 = Integer.MAX_VALUE;
950 if (y2 > Integer.MAX_VALUE) y2 = Integer.MAX_VALUE;
951 reshape(x1, y1, (int) x2, (int) y2);
952 }
953
954 /**
955 * Adds the specified {@code Point} to the bounds of this
956 * {@code Rectangle}.
957 * <p>
958 * If this {@code Rectangle} has any dimension less than zero,
959 * the rules for <a href=#NonExistent>non-existent</a>
960 * rectangles apply.
961 * In that case, the new bounds of this {@code Rectangle} will
962 * have a location equal to the coordinates of the specified
963 * {@code Point} and width and height equal to zero.
964 * <p>
965 * After adding a {@code Point}, a call to {@code contains}
966 * with the added {@code Point} as an argument does not
967 * necessarily return {@code true}. The {@code contains}
968 * method does not return {@code true} for points on the right
969 * or bottom edges of a {@code Rectangle}. Therefore if the added
970 * {@code Point} falls on the right or bottom edge of the
971 * enlarged {@code Rectangle}, {@code contains} returns
972 * {@code false} for that {@code Point}.
973 * If the specified point must be contained within the new
974 * {@code Rectangle}, a 1x1 rectangle should be added instead:
975 * <pre>
976 * r.add(pt.x, pt.y, 1, 1);
977 * </pre>
978 * @param pt the new {@code Point} to add to this
979 * {@code Rectangle}
980 */
981 public void add(Point pt) {
982 add(pt.x, pt.y);
983 }
984
985 /**
986 * Adds a {@code Rectangle} to this {@code Rectangle}.
987 * The resulting {@code Rectangle} is the union of the two
988 * rectangles.
989 * <p>
990 * If either {@code Rectangle} has any dimension less than 0, the
991 * result will have the dimensions of the other {@code Rectangle}.
992 * If both {@code Rectangle}s have at least one dimension less
993 * than 0, the result will have at least one dimension less than 0.
994 * <p>
995 * If either {@code Rectangle} has one or both dimensions equal
996 * to 0, the result along those axes with 0 dimensions will be
997 * equivalent to the results obtained by adding the corresponding
998 * origin coordinate to the result rectangle along that axis,
999 * similar to the operation of the {@link #add(Point)} method,
1000 * but contribute no further dimension beyond that.
1001 * <p>
1002 * If the resulting {@code Rectangle} would have a dimension
1003 * too large to be expressed as an {@code int}, the result
1004 * will have a dimension of {@code Integer.MAX_VALUE} along
1005 * that dimension.
1006 * @param r the specified {@code Rectangle}
1007 */
1008 public void add(Rectangle r) {
1009 long tx2 = this.width;
1010 long ty2 = this.height;
1011 if ((tx2 | ty2) < 0) {
1012 reshape(r.x, r.y, r.width, r.height);
1013 }
1014 long rx2 = r.width;
1015 long ry2 = r.height;
1016 if ((rx2 | ry2) < 0) {
1017 return;
1018 }
1019 int tx1 = this.x;
1020 int ty1 = this.y;
1021 tx2 += tx1;
1022 ty2 += ty1;
1023 int rx1 = r.x;
1024 int ry1 = r.y;
1025 rx2 += rx1;
1026 ry2 += ry1;
1027 if (tx1 > rx1) tx1 = rx1;
1028 if (ty1 > ry1) ty1 = ry1;
1029 if (tx2 < rx2) tx2 = rx2;
1030 if (ty2 < ry2) ty2 = ry2;
1031 tx2 -= tx1;
1032 ty2 -= ty1;
1033 // tx2,ty2 will never underflow since both original
1034 // rectangles were non-empty
1035 // they might overflow, though...
1036 if (tx2 > Integer.MAX_VALUE) tx2 = Integer.MAX_VALUE;
1037 if (ty2 > Integer.MAX_VALUE) ty2 = Integer.MAX_VALUE;
1038 reshape(tx1, ty1, (int) tx2, (int) ty2);
1039 }
1040
1041 /**
1042 * Resizes the {@code Rectangle} both horizontally and vertically.
1043 * <p>
1044 * This method modifies the {@code Rectangle} so that it is
1045 * {@code h} units larger on both the left and right side,
1046 * and {@code v} units larger at both the top and bottom.
1047 * <p>
1048 * The new {@code Rectangle} has {@code (x - h, y - v)}
1049 * as its upper-left corner,
1050 * width of {@code (width + 2h)},
1051 * and a height of {@code (height + 2v)}.
1052 * <p>
1053 * If negative values are supplied for {@code h} and
1054 * {@code v}, the size of the {@code Rectangle}
1055 * decreases accordingly.
1056 * The {@code grow} method will check for integer overflow
1057 * and underflow, but does not check whether the resulting
1058 * values of {@code width} and {@code height} grow
1059 * from negative to non-negative or shrink from non-negative
1060 * to negative.
1061 * @param h the horizontal expansion
1062 * @param v the vertical expansion
1063 */
1064 public void grow(int h, int v) {
1065 long x0 = this.x;
1066 long y0 = this.y;
1067 long x1 = this.width;
1068 long y1 = this.height;
1069 x1 += x0;
1070 y1 += y0;
1071
1072 x0 -= h;
1073 y0 -= v;
1074 x1 += h;
1075 y1 += v;
1076
1077 if (x1 < x0) {
1078 // Non-existent in X direction
1079 // Final width must remain negative so subtract x0 before
1080 // it is clipped so that we avoid the risk that the clipping
1081 // of x0 will reverse the ordering of x0 and x1.
1082 x1 -= x0;
1083 if (x1 < Integer.MIN_VALUE) x1 = Integer.MIN_VALUE;
1084 if (x0 < Integer.MIN_VALUE) x0 = Integer.MIN_VALUE;
1085 else if (x0 > Integer.MAX_VALUE) x0 = Integer.MAX_VALUE;
1086 } else { // (x1 >= x0)
1087 // Clip x0 before we subtract it from x1 in case the clipping
1088 // affects the representable area of the rectangle.
1089 if (x0 < Integer.MIN_VALUE) x0 = Integer.MIN_VALUE;
1090 else if (x0 > Integer.MAX_VALUE) x0 = Integer.MAX_VALUE;
1091 x1 -= x0;
1092 // The only way x1 can be negative now is if we clipped
1093 // x0 against MIN and x1 is less than MIN - in which case
1094 // we want to leave the width negative since the result
1095 // did not intersect the representable area.
1096 if (x1 < Integer.MIN_VALUE) x1 = Integer.MIN_VALUE;
1097 else if (x1 > Integer.MAX_VALUE) x1 = Integer.MAX_VALUE;
1098 }
1099
1100 if (y1 < y0) {
1101 // Non-existent in Y direction
1102 y1 -= y0;
1103 if (y1 < Integer.MIN_VALUE) y1 = Integer.MIN_VALUE;
1104 if (y0 < Integer.MIN_VALUE) y0 = Integer.MIN_VALUE;
1105 else if (y0 > Integer.MAX_VALUE) y0 = Integer.MAX_VALUE;
1106 } else { // (y1 >= y0)
1107 if (y0 < Integer.MIN_VALUE) y0 = Integer.MIN_VALUE;
1108 else if (y0 > Integer.MAX_VALUE) y0 = Integer.MAX_VALUE;
1109 y1 -= y0;
1110 if (y1 < Integer.MIN_VALUE) y1 = Integer.MIN_VALUE;
1111 else if (y1 > Integer.MAX_VALUE) y1 = Integer.MAX_VALUE;
1112 }
1113
1114 reshape((int) x0, (int) y0, (int) x1, (int) y1);
1115 }
1116
1117 /**
1118 * {@inheritDoc}
1119 * @since 1.2
1120 */
1121 public boolean isEmpty() {
1122 return (width <= 0) || (height <= 0);
1123 }
1124
1125 /**
1126 * {@inheritDoc}
1127 * @since 1.2
1128 */
1129 public int outcode(double x, double y) {
1130 /*
1131 * Note on casts to double below. If the arithmetic of
1132 * x+w or y+h is done in int, then we may get integer
1133 * overflow. By converting to double before the addition
1134 * we force the addition to be carried out in double to
1135 * avoid overflow in the comparison.
1136 *
1137 * See bug 4320890 for problems that this can cause.
1138 */
1139 int out = 0;
1140 if (this.width <= 0) {
1141 out |= OUT_LEFT | OUT_RIGHT;
1142 } else if (x < this.x) {
1143 out |= OUT_LEFT;
1144 } else if (x > this.x + (double) this.width) {
1145 out |= OUT_RIGHT;
1146 }
1147 if (this.height <= 0) {
1148 out |= OUT_TOP | OUT_BOTTOM;
1149 } else if (y < this.y) {
1150 out |= OUT_TOP;
1151 } else if (y > this.y + (double) this.height) {
1152 out |= OUT_BOTTOM;
1153 }
1154 return out;
1155 }
1156
1157 /**
1158 * {@inheritDoc}
1159 * @since 1.2
1160 */
1161 public Rectangle2D createIntersection(Rectangle2D r) {
1162 if (r instanceof Rectangle) {
1163 return intersection((Rectangle) r);
1164 }
1165 Rectangle2D dest = new Rectangle2D.Double();
1166 Rectangle2D.intersect(this, r, dest);
1167 return dest;
1168 }
1169
1170 /**
1171 * {@inheritDoc}
1172 * @since 1.2
1173 */
1174 public Rectangle2D createUnion(Rectangle2D r) {
1175 if (r instanceof Rectangle) {
1176 return union((Rectangle) r);
1177 }
1178 Rectangle2D dest = new Rectangle2D.Double();
1179 Rectangle2D.union(this, r, dest);
1180 return dest;
1181 }
1182
1183 /**
1184 * Checks whether two rectangles are equal.
1185 * <p>
1186 * The result is {@code true} if and only if the argument is not
1187 * {@code null} and is a {@code Rectangle} object that has the
1188 * same upper-left corner, width, and height as
1189 * this {@code Rectangle}.
1190 * @param obj the {@code Object} to compare with
1191 * this {@code Rectangle}
1192 * @return {@code true} if the objects are equal;
1193 * {@code false} otherwise.
1194 */
1195 public boolean equals(Object obj) {
1196 if (obj instanceof Rectangle) {
1197 Rectangle r = (Rectangle)obj;
1198 return ((x == r.x) &&
1199 (y == r.y) &&
1200 (width == r.width) &&
1201 (height == r.height));
1202 }
1203 return super.equals(obj);
1204 }
1205
1206 /**
1207 * Returns a {@code String} representing this
1208 * {@code Rectangle} and its values.
1209 * @return a {@code String} representing this
1210 * {@code Rectangle} object's coordinate and size values.
1211 */
1212 public String toString() {
1213 return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]";
1214 }
1215 }
1216