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 }