1 /* 2 * Copyright (c) 1995, 2008, 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</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 }