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