1 /*
   2  * Copyright (c) 2007, 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 org.jemmy;
  27 
  28 
  29 import java.io.Serializable;
  30 
  31 
  32 /**
  33  * Replacement for java.awt.Rectangle
  34  * @author Alexander Kouznetsov <mrkam@mail.ru>
  35  */
  36 public class Rectangle implements Serializable {
  37 
  38     /**
  39      * The X coordinate of the upper-left corner of the <code>Rectangle</code>.
  40      *
  41      * @serial
  42      * @see #setLocation(int, int)
  43      * @see #getLocation()
  44      */
  45     public int x;
  46 
  47     /**
  48      * The Y coordinate of the upper-left corner of the <code>Rectangle</code>.
  49      *
  50      * @serial
  51      * @see #setLocation(int, int)
  52      * @see #getLocation()
  53      */
  54     public int y;
  55 
  56     /**
  57      * The width of the <code>Rectangle</code>.
  58      * @serial
  59      * @see #setSize(int, int)
  60      * @see #getSize()
  61      */
  62     public int width;
  63 
  64     /**
  65      * The height of the <code>Rectangle</code>.
  66      *
  67      * @serial
  68      * @see #setSize(int, int)
  69      * @see #getSize()
  70      */
  71     public int height;
  72 
  73     /*
  74      * JDK 1.1 serialVersionUID
  75      */
  76     private static final long serialVersionUID = -4345857070255674764L;
  77 
  78 
  79     /**
  80      * Constructs a new <code>Rectangle</code> whose upper-left corner
  81      * is at (0,&nbsp;0) in the coordinate space, and whose width and
  82      * height are both zero.
  83      */
  84     public Rectangle() {
  85         this(0, 0, 0, 0);
  86     }
  87 
  88     /**
  89      * Constructs a new <code>Rectangle</code>, initialized to match
  90      * the values of the specified <code>Rectangle</code>.
  91      * @param r  the <code>Rectangle</code> from which to copy initial values
  92      *           to a newly constructed <code>Rectangle</code>
  93      */
  94     public Rectangle(Rectangle r) {
  95         this(r.x, r.y, r.width, r.height);
  96     }
  97 
  98     /**
  99      * Constructs a new <code>Rectangle</code> whose upper-left corner is
 100      * specified as
 101      * {@code (x,y)} and whose width and height
 102      * are specified by the arguments of the same name.
 103      * @param     x the specified X coordinate
 104      * @param     y the specified Y coordinate
 105      * @param     width    the width of the <code>Rectangle</code>
 106      * @param     height   the height of the <code>Rectangle</code>
 107      */
 108     public Rectangle(int x, int y, int width, int height) {
 109         this.x = x;
 110         this.y = y;
 111         this.width = width;
 112         this.height = height;
 113     }
 114 
 115     /**
 116      * Constructs a new <code>Rectangle</code> whose upper-left corner
 117      * is at (0,&nbsp;0) in the coordinate space, and whose width and
 118      * height are specified by the arguments of the same name.
 119      * @param width the width of the <code>Rectangle</code>
 120      * @param height the height of the <code>Rectangle</code>
 121      */
 122     public Rectangle(int width, int height) {
 123         this(0, 0, width, height);
 124     }
 125 
 126     /**
 127      * Constructs a new <code>Rectangle</code> whose upper-left corner is
 128      * specified by the {@link Point} argument, and
 129      * whose width and height are specified by the
 130      * {@link Dimension} argument.
 131      * @param p a <code>Point</code> that is the upper-left corner of
 132      * the <code>Rectangle</code>
 133      * @param d a <code>Dimension</code>, representing the
 134      * width and height of the <code>Rectangle</code>
 135      */
 136     public Rectangle(Point p, Dimension d) {
 137         this(p.x, p.y, d.width, d.height);
 138     }
 139 
 140     /**
 141      * Constructs a new <code>Rectangle</code> whose upper-left corner is the
 142      * specified <code>Point</code>, and whose width and height are both zero.
 143      * @param p a <code>Point</code> that is the top left corner
 144      * of the <code>Rectangle</code>
 145      */
 146     public Rectangle(Point p) {
 147         this(p.x, p.y, 0, 0);
 148     }
 149 
 150     /**
 151      * Constructs a new <code>Rectangle</code> whose top left corner is
 152      * (0,&nbsp;0) and whose width and height are specified
 153      * by the <code>Dimension</code> argument.
 154      * @param d a <code>Dimension</code>, specifying width and height
 155      */
 156     public Rectangle(Dimension d) {
 157         this(0, 0, d.width, d.height);
 158     }
 159 
 160     /**
 161      * Constructs a new <code>Rectangle</code> whose upper-left corner is
 162      * specified as {@code (x,y)} and whose width and height
 163      * are specified by the arguments of the same name. All {@code double}
 164      * values are rounded and stored as {@code int} values.
 165      * @param     x the specified X coordinate
 166      * @param     y the specified Y coordinate
 167      * @param     width    the width of the <code>Rectangle</code>
 168      * @param     height   the height of the <code>Rectangle</code>
 169      */
 170     public Rectangle(double x, double y, double width, double height) {
 171         this((int) Math.round(x), (int) Math.round(y),
 172                 (int) Math.round(width), (int) Math.round(height));
 173     }
 174 
 175     /**
 176      * Returns the X coordinate of the bounding <code>Rectangle</code> in
 177      * <code>double</code> precision.
 178      * @return the X coordinate of the bounding <code>Rectangle</code>.
 179      */
 180     public double getX() {
 181         return x;
 182     }
 183 
 184     /**
 185      * Returns the Y coordinate of the bounding <code>Rectangle</code> in
 186      * <code>double</code> precision.
 187      * @return the Y coordinate of the bounding <code>Rectangle</code>.
 188      */
 189     public double getY() {
 190         return y;
 191     }
 192 
 193     /**
 194      * Returns the width of the bounding <code>Rectangle</code> in
 195      * <code>double</code> precision.
 196      * @return the width of the bounding <code>Rectangle</code>.
 197      */
 198     public double getWidth() {
 199         return width;
 200     }
 201 
 202     /**
 203      * Returns the height of the bounding <code>Rectangle</code> in
 204      * <code>double</code> precision.
 205      * @return the height of the bounding <code>Rectangle</code>.
 206      */
 207     public double getHeight() {
 208         return height;
 209     }
 210 
 211     /**
 212      * Gets the bounding <code>Rectangle</code> of this <code>Rectangle</code>.
 213      * <p>
 214      * @return    a new <code>Rectangle</code>, equal to the
 215      * bounding <code>Rectangle</code> for this <code>Rectangle</code>.
 216      * @see       #setBounds(Rectangle)
 217      * @see       #setBounds(int, int, int, int)
 218      */
 219     public Rectangle getBounds() {
 220         return new Rectangle(x, y, width, height);
 221     }
 222 
 223     /**
 224      * Sets the bounding <code>Rectangle</code> of this <code>Rectangle</code>
 225      * to match the specified <code>Rectangle</code>.
 226      * <p>
 227      * @param r the specified <code>Rectangle</code>
 228      * @see       #getBounds
 229      */
 230     public void setBounds(Rectangle r) {
 231         setBounds(r.x, r.y, r.width, r.height);
 232     }
 233 
 234     /**
 235      * Sets the bounding <code>Rectangle</code> of this
 236      * <code>Rectangle</code> to the specified
 237      * <code>x</code>, <code>y</code>, <code>width</code>,
 238      * and <code>height</code>.
 239      * <p>
 240      * @param x the new X coordinate for the upper-left
 241      *                    corner of this <code>Rectangle</code>
 242      * @param y the new Y coordinate for the upper-left
 243      *                    corner of this <code>Rectangle</code>
 244      * @param width the new width for this <code>Rectangle</code>
 245      * @param height the new height for this <code>Rectangle</code>
 246      * @see       #getBounds
 247      */
 248     public void setBounds(int x, int y, int width, int height) {
 249         this.x = x;
 250         this.y = y;
 251         this.width = width;
 252         this.height = height;
 253     }
 254 
 255     /**
 256      * Sets the bounds of this {@code Rectangle} to the integer bounds
 257      * which encompass the specified {@code x}, {@code y}, {@code width},
 258      * and {@code height}.
 259      * If the parameters specify a {@code Rectangle} that exceeds the
 260      * maximum range of integers, the result will be the best
 261      * representation of the specified {@code Rectangle} intersected
 262      * with the maximum integer bounds.
 263      * @param x the X coordinate of the upper-left corner of
 264      *                  the specified rectangle
 265      * @param y the Y coordinate of the upper-left corner of
 266      *                  the specified rectangle
 267      * @param width the width of the specified rectangle
 268      * @param height the new height of the specified rectangle
 269      */
 270     public void setRect(double x, double y, double width, double height) {
 271         int newx, newy, neww, newh;
 272 
 273         if (x > 2.0 * Integer.MAX_VALUE) {
 274             // Too far in positive X direction to represent...
 275             // We cannot even reach the left side of the specified
 276             // rectangle even with both x & width set to MAX_VALUE.
 277             // The intersection with the "maximal integer rectangle"
 278             // is non-existant so we should use a width < 0.
 279             // REMIND: Should we try to determine a more "meaningful"
 280             // adjusted value for neww than just "-1"?
 281             newx = Integer.MAX_VALUE;
 282             neww = -1;
 283         } else {
 284             newx = clip(x, false);
 285             if (width >= 0) width += x-newx;
 286             neww = clip(width, width >= 0);
 287         }
 288 
 289         if (y > 2.0 * Integer.MAX_VALUE) {
 290             // Too far in positive Y direction to represent...
 291             newy = Integer.MAX_VALUE;
 292             newh = -1;
 293         } else {
 294             newy = clip(y, false);
 295             if (height >= 0) height += y-newy;
 296             newh = clip(height, height >= 0);
 297         }
 298 
 299         setBounds(newx, newy, neww, newh);
 300     }
 301     // Return best integer representation for v, clipped to integer
 302     // range and floor-ed or ceiling-ed, depending on the boolean.
 303     private static int clip(double v, boolean doceil) {
 304         if (v <= Integer.MIN_VALUE) {
 305             return Integer.MIN_VALUE;
 306         }
 307         if (v >= Integer.MAX_VALUE) {
 308             return Integer.MAX_VALUE;
 309         }
 310         return (int) (doceil ? Math.ceil(v) : Math.floor(v));
 311     }
 312 
 313     /**
 314      * Returns the location of this <code>Rectangle</code>.
 315      * <p>
 316      * @return the <code>Point</code> that is the upper-left corner of
 317      * this <code>Rectangle</code>.
 318      * @see       #setLocation(Point)
 319      * @see       #setLocation(int, int)
 320      */
 321     public Point getLocation() {
 322         return new Point(x, y);
 323     }
 324 
 325     /**
 326      * Moves this <code>Rectangle</code> to the specified location.
 327      * <p>
 328      * @param p the <code>Point</code> specifying the new location
 329      *                for this <code>Rectangle</code>
 330      * @see       #getLocation
 331      */
 332     public void setLocation(Point p) {
 333         setLocation(p.x, p.y);
 334     }
 335 
 336     /**
 337      * Moves this <code>Rectangle</code> to the specified location.
 338      * <p>
 339      * @param x the X coordinate of the new location
 340      * @param y the Y coordinate of the new location
 341      * @see       #getLocation
 342      */
 343     public void setLocation(int x, int y) {
 344         this.x = x;
 345         this.y = y;
 346     }
 347 
 348     /**
 349      * Translates this <code>Rectangle</code> the indicated distance,
 350      * to the right along the X coordinate axis, and
 351      * downward along the Y coordinate axis.
 352      * @param dx the distance to move this <code>Rectangle</code>
 353      *                 along the X axis
 354      * @param dy the distance to move this <code>Rectangle</code>
 355      *                 along the Y axis
 356      * @see       #setLocation(int, int)
 357      * @see       #setLocation(org.jemmy.Point)
 358      */
 359     public void translate(int dx, int dy) {
 360         int oldv = this.x;
 361         int newv = oldv + dx;
 362         if (dx < 0) {
 363             // moving leftward
 364             if (newv > oldv) {
 365                 // negative overflow
 366                 // Only adjust width if it was valid (>= 0).
 367                 if (width >= 0) {
 368                     // The right edge is now conceptually at
 369                     // newv+width, but we may move newv to prevent
 370                     // overflow.  But we want the right edge to
 371                     // remain at its new location in spite of the
 372                     // clipping.  Think of the following adjustment
 373                     // conceptually the same as:
 374                     // width += newv; newv = MIN_VALUE; width -= newv;
 375                     width += newv - Integer.MIN_VALUE;
 376                     // width may go negative if the right edge went past
 377                     // MIN_VALUE, but it cannot overflow since it cannot
 378                     // have moved more than MIN_VALUE and any non-negative
 379                     // number + MIN_VALUE does not overflow.
 380                 }
 381                 newv = Integer.MIN_VALUE;
 382             }
 383         } else {
 384             // moving rightward (or staying still)
 385             if (newv < oldv) {
 386                 // positive overflow
 387                 if (width >= 0) {
 388                     // Conceptually the same as:
 389                     // width += newv; newv = MAX_VALUE; width -= newv;
 390                     width += newv - Integer.MAX_VALUE;
 391                     // With large widths and large displacements
 392                     // we may overflow so we need to check it.
 393                     if (width < 0) width = Integer.MAX_VALUE;
 394                 }
 395                 newv = Integer.MAX_VALUE;
 396             }
 397         }
 398         this.x = newv;
 399 
 400         oldv = this.y;
 401         newv = oldv + dy;
 402         if (dy < 0) {
 403             // moving upward
 404             if (newv > oldv) {
 405                 // negative overflow
 406                 if (height >= 0) {
 407                     height += newv - Integer.MIN_VALUE;
 408                     // See above comment about no overflow in this case
 409                 }
 410                 newv = Integer.MIN_VALUE;
 411             }
 412         } else {
 413             // moving downward (or staying still)
 414             if (newv < oldv) {
 415                 // positive overflow
 416                 if (height >= 0) {
 417                     height += newv - Integer.MAX_VALUE;
 418                     if (height < 0) height = Integer.MAX_VALUE;
 419                 }
 420                 newv = Integer.MAX_VALUE;
 421             }
 422         }
 423         this.y = newv;
 424     }
 425 
 426     /**
 427      * Gets the size of this <code>Rectangle</code>, represented by
 428      * the returned <code>Dimension</code>.
 429      * <p>
 430      * @return a <code>Dimension</code>, representing the size of
 431      *            this <code>Rectangle</code>.
 432      * @see       #setSize(Dimension)
 433      * @see       #setSize(int, int)
 434      */
 435     public Dimension getSize() {
 436         return new Dimension(width, height);
 437     }
 438 
 439     /**
 440      * Sets the size of this <code>Rectangle</code> to match the
 441      * specified <code>Dimension</code>.
 442      * <p>
 443      * @param d the new size for the <code>Dimension</code> object
 444      * @see       #getSize
 445      */
 446     public void setSize(Dimension d) {
 447         setSize(d.width, d.height);
 448     }
 449 
 450     /**
 451      * Sets the size of this <code>Rectangle</code> to the specified
 452      * width and height.
 453      * <p>
 454      * @param width the new width for this <code>Rectangle</code>
 455      * @param height the new height for this <code>Rectangle</code>
 456      * @see       #getSize
 457      */
 458     public void setSize(int width, int height) {
 459         this.width = width;
 460         this.height = height;
 461     }
 462 
 463     /**
 464      * Checks whether or not this <code>Rectangle</code> contains the
 465      * specified <code>Point</code>.
 466      * @param p the <code>Point</code> to test
 467      * @return    <code>true</code> if the specified <code>Point</code>
 468      *            is inside this <code>Rectangle</code>;
 469      *            <code>false</code> otherwise.
 470      */
 471     public boolean contains(Point p) {
 472         return contains(p.x, p.y);
 473     }
 474 
 475     /**
 476      * Checks whether or not this <code>Rectangle</code> contains the
 477      * point at the specified location {@code (x,y)}.
 478      *
 479      * @param  x the specified X coordinate
 480      * @param  y the specified Y coordinate
 481      * @return    <code>true</code> if the point
 482      * {@code (x,y)} is inside this
 483      * <code>Rectangle</code>;
 484      * <code>false</code> otherwise.
 485      */
 486     public boolean contains(int x, int y) {
 487         return contains(x, y, 1, 1);
 488     }
 489 
 490     /**
 491      * Checks whether or not this <code>Rectangle</code> entirely contains
 492      * the specified <code>Rectangle</code>.
 493      *
 494      * @param     r   the specified <code>Rectangle</code>
 495      * @return    <code>true</code> if the <code>Rectangle</code>
 496      *            is contained entirely inside this <code>Rectangle</code>;
 497      *            <code>false</code> otherwise
 498      */
 499     public boolean contains(Rectangle r) {
 500         return contains(r.x, r.y, r.width, r.height);
 501     }
 502 
 503     /**
 504      * Checks whether this <code>Rectangle</code> entirely contains
 505      * the <code>Rectangle</code>
 506      * at the specified location {@code (X,Y)} with the
 507      * specified dimensions {@code (W,H)}.
 508      * @param     X the specified X coordinate
 509      * @param     Y the specified Y coordinate
 510      * @param     W   the width of the <code>Rectangle</code>
 511      * @param     H   the height of the <code>Rectangle</code>
 512      * @return    <code>true</code> if the <code>Rectangle</code> specified by
 513      *            {@code (X, Y, W, H)}
 514      *            is entirely enclosed inside this <code>Rectangle</code>;
 515      *            <code>false</code> otherwise.
 516      */
 517     public boolean contains(int X, int Y, int W, int H) {
 518         int w = this.width;
 519         int h = this.height;
 520         if ((w | h | W | H) < 0) {
 521             // At least one of the dimensions is negative...
 522             return false;
 523         }
 524         // Note: if any dimension is zero, tests below must return false...
 525         int xx = this.x;
 526         int yy = this.y;
 527         if (X < xx || Y < yy) {
 528             return false;
 529         }
 530         w += xx;
 531         W += X;
 532         if (W <= X) {
 533             // X+W overflowed or W was zero, return false if...
 534             // either original w or W was zero or
 535             // x+w did not overflow or
 536             // the overflowed x+w is smaller than the overflowed X+W
 537             if (w >= xx || W > w) return false;
 538         } else {
 539             // X+W did not overflow and W was not zero, return false if...
 540             // original w was zero or
 541             // x+w did not overflow and x+w is smaller than X+W
 542             if (w >= xx && W > w) return false;
 543         }
 544         h += yy;
 545         H += Y;
 546         if (H <= Y) {
 547             if (h >= yy || H > h) return false;
 548         } else {
 549             if (h >= yy && H > h) return false;
 550         }
 551         return true;
 552     }
 553 
 554     /**
 555      * Determines whether or not this <code>Rectangle</code> and the specified
 556      * <code>Rectangle</code> intersect. Two rectangles intersect if
 557      * their intersection is nonempty.
 558      *
 559      * @param r the specified <code>Rectangle</code>
 560      * @return    <code>true</code> if the specified <code>Rectangle</code>
 561      *            and this <code>Rectangle</code> intersect;
 562      *            <code>false</code> otherwise.
 563      */
 564     public boolean intersects(Rectangle r) {
 565         int tw = this.width;
 566         int th = this.height;
 567         int rw = r.width;
 568         int rh = r.height;
 569         if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) {
 570             return false;
 571         }
 572         int tx = this.x;
 573         int ty = this.y;
 574         int rx = r.x;
 575         int ry = r.y;
 576         rw += rx;
 577         rh += ry;
 578         tw += tx;
 579         th += ty;
 580         //      overflow || intersect
 581         return ((rw < rx || rw > tx) &&
 582             (rh < ry || rh > ty) &&
 583             (tw < tx || tw > rx) &&
 584             (th < ty || th > ry));
 585     }
 586 
 587     /**
 588      * Computes the intersection of this <code>Rectangle</code> with the
 589      * specified <code>Rectangle</code>. Returns a new <code>Rectangle</code>
 590      * that represents the intersection of the two rectangles.
 591      * If the two rectangles do not intersect, the result will be
 592      * an empty rectangle.
 593      *
 594      * @param     r   the specified <code>Rectangle</code>
 595      * @return    the largest <code>Rectangle</code> contained in both the
 596      *            specified <code>Rectangle</code> and in
 597      * this <code>Rectangle</code>; or if the rectangles
 598      * do not intersect, an empty rectangle.
 599      */
 600     public Rectangle intersection(Rectangle r) {
 601         int tx1 = this.x;
 602         int ty1 = this.y;
 603         int rx1 = r.x;
 604         int ry1 = r.y;
 605         long tx2 = tx1; tx2 += this.width;
 606         long ty2 = ty1; ty2 += this.height;
 607         long rx2 = rx1; rx2 += r.width;
 608         long ry2 = ry1; ry2 += r.height;
 609         if (tx1 < rx1) tx1 = rx1;
 610         if (ty1 < ry1) ty1 = ry1;
 611         if (tx2 > rx2) tx2 = rx2;
 612         if (ty2 > ry2) ty2 = ry2;
 613         tx2 -= tx1;
 614         ty2 -= ty1;
 615         // tx2,ty2 will never overflow (they will never be
 616         // larger than the smallest of the two source w,h)
 617         // they might underflow, though...
 618         if (tx2 < Integer.MIN_VALUE) tx2 = Integer.MIN_VALUE;
 619         if (ty2 < Integer.MIN_VALUE) ty2 = Integer.MIN_VALUE;
 620         return new Rectangle(tx1, ty1, (int) tx2, (int) ty2);
 621     }
 622 
 623     /**
 624      * Computes the union of this <code>Rectangle</code> with the
 625      * specified <code>Rectangle</code>. Returns a new
 626      * <code>Rectangle</code> that
 627      * represents the union of the two rectangles.
 628      * <p>
 629      * If either {@code Rectangle} has any dimension less than zero
 630      * the rules for <a href=#NonExistant>non-existant</a> rectangles
 631      * apply.
 632      * If only one has a dimension less than zero, then the result
 633      * will be a copy of the other {@code Rectangle}.
 634      * If both have dimension less than zero, then the result will
 635      * have at least one dimension less than zero.
 636      * <p>
 637      * If the resulting {@code Rectangle} would have a dimension
 638      * too large to be expressed as an {@code int}, the result
 639      * will have a dimension of {@code Integer.MAX_VALUE} along
 640      * that dimension.
 641      * @param r the specified <code>Rectangle</code>
 642      * @return    the smallest <code>Rectangle</code> containing both
 643      * the specified <code>Rectangle</code> and this
 644      * <code>Rectangle</code>.
 645      */
 646     public Rectangle union(Rectangle r) {
 647         long tx2 = this.width;
 648         long ty2 = this.height;
 649         if ((tx2 | ty2) < 0) {
 650             // This rectangle has negative dimensions...
 651             // If r has non-negative dimensions then it is the answer.
 652             // If r is non-existant (has a negative dimension), then both
 653             // are non-existant and we can return any non-existant rectangle
 654             // as an answer.  Thus, returning r meets that criterion.
 655             // Either way, r is our answer.
 656             return new Rectangle(r);
 657         }
 658         long rx2 = r.width;
 659         long ry2 = r.height;
 660         if ((rx2 | ry2) < 0) {
 661             return new Rectangle(this);
 662         }
 663         int tx1 = this.x;
 664         int ty1 = this.y;
 665         tx2 += tx1;
 666         ty2 += ty1;
 667         int rx1 = r.x;
 668         int ry1 = r.y;
 669         rx2 += rx1;
 670         ry2 += ry1;
 671         if (tx1 > rx1) tx1 = rx1;
 672         if (ty1 > ry1) ty1 = ry1;
 673         if (tx2 < rx2) tx2 = rx2;
 674         if (ty2 < ry2) ty2 = ry2;
 675         tx2 -= tx1;
 676         ty2 -= ty1;
 677         // tx2,ty2 will never underflow since both original rectangles
 678         // were already proven to be non-empty
 679         // they might overflow, though...
 680         if (tx2 > Integer.MAX_VALUE) tx2 = Integer.MAX_VALUE;
 681         if (ty2 > Integer.MAX_VALUE) ty2 = Integer.MAX_VALUE;
 682         return new Rectangle(tx1, ty1, (int) tx2, (int) ty2);
 683     }
 684 
 685     /**
 686      * Adds a point, specified by the integer arguments {@code newx,newy}
 687      * to the bounds of this {@code Rectangle}.
 688      * <p>
 689      * If this {@code Rectangle} has any dimension less than zero,
 690      * the rules for <a href=#NonExistant>non-existant</a>
 691      * rectangles apply.
 692      * In that case, the new bounds of this {@code Rectangle} will
 693      * have a location equal to the specified coordinates and
 694      * width and height equal to zero.
 695      * <p>
 696      * After adding a point, a call to <code>contains</code> with the
 697      * added point as an argument does not necessarily return
 698      * <code>true</code>. The <code>contains</code> method does not
 699      * return <code>true</code> for points on the right or bottom
 700      * edges of a <code>Rectangle</code>. Therefore, if the added point
 701      * falls on the right or bottom edge of the enlarged
 702      * <code>Rectangle</code>, <code>contains</code> returns
 703      * <code>false</code> for that point.
 704      * If the specified point must be contained within the new
 705      * {@code Rectangle}, a 1x1 rectangle should be added instead:
 706      * <pre>
 707      *     r.add(newx, newy, 1, 1);
 708      * </pre>
 709      * @param newx the X coordinate of the new point
 710      * @param newy the Y coordinate of the new point
 711      */
 712     public void add(int newx, int newy) {
 713         if ((width | height) < 0) {
 714             this.x = newx;
 715             this.y = newy;
 716             this.width = this.height = 0;
 717             return;
 718         }
 719         int x1 = this.x;
 720         int y1 = this.y;
 721         long x2 = this.width;
 722         long y2 = this.height;
 723         x2 += x1;
 724         y2 += y1;
 725         if (x1 > newx) x1 = newx;
 726         if (y1 > newy) y1 = newy;
 727         if (x2 < newx) x2 = newx;
 728         if (y2 < newy) y2 = newy;
 729         x2 -= x1;
 730         y2 -= y1;
 731         if (x2 > Integer.MAX_VALUE) x2 = Integer.MAX_VALUE;
 732         if (y2 > Integer.MAX_VALUE) y2 = Integer.MAX_VALUE;
 733         setBounds(x1, y1, (int) x2, (int) y2);
 734     }
 735 
 736     /**
 737      * Adds the specified {@code Point} to the bounds of this
 738      * {@code Rectangle}.
 739      * <p>
 740      * If this {@code Rectangle} has any dimension less than zero,
 741      * the rules for <a href=#NonExistant>non-existant</a>
 742      * rectangles apply.
 743      * In that case, the new bounds of this {@code Rectangle} will
 744      * have a location equal to the coordinates of the specified
 745      * {@code Point} and width and height equal to zero.
 746      * <p>
 747      * After adding a <code>Point</code>, a call to <code>contains</code>
 748      * with the added <code>Point</code> as an argument does not
 749      * necessarily return <code>true</code>. The <code>contains</code>
 750      * method does not return <code>true</code> for points on the right
 751      * or bottom edges of a <code>Rectangle</code>. Therefore if the added
 752      * <code>Point</code> falls on the right or bottom edge of the
 753      * enlarged <code>Rectangle</code>, <code>contains</code> returns
 754      * <code>false</code> for that <code>Point</code>.
 755      * If the specified point must be contained within the new
 756      * {@code Rectangle}, a 1x1 rectangle should be added instead:
 757      * <pre>
 758      *     r.add(pt.x, pt.y, 1, 1);
 759      * </pre>
 760      * @param pt the new <code>Point</code> to add to this
 761      *           <code>Rectangle</code>
 762      */
 763     public void add(Point pt) {
 764         add(pt.x, pt.y);
 765     }
 766 
 767     /**
 768      * Adds a <code>Rectangle</code> to this <code>Rectangle</code>.
 769      * The resulting <code>Rectangle</code> is the union of the two
 770      * rectangles.
 771      * <p>
 772      * If either {@code Rectangle} has any dimension less than 0, the
 773      * result will have the dimensions of the other {@code Rectangle}.
 774      * If both {@code Rectangle}s have at least one dimension less
 775      * than 0, the result will have at least one dimension less than 0.
 776      * <p>
 777      * If either {@code Rectangle} has one or both dimensions equal
 778      * to 0, the result along those axes with 0 dimensions will be
 779      * equivalent to the results obtained by adding the corresponding
 780      * origin coordinate to the result rectangle along that axis,
 781      * similar to the operation of the {@link #add(Point)} method,
 782      * but contribute no further dimension beyond that.
 783      * <p>
 784      * If the resulting {@code Rectangle} would have a dimension
 785      * too large to be expressed as an {@code int}, the result
 786      * will have a dimension of {@code Integer.MAX_VALUE} along
 787      * that dimension.
 788      * @param  r the specified <code>Rectangle</code>
 789      */
 790     public void add(Rectangle r) {
 791         long tx2 = this.width;
 792         long ty2 = this.height;
 793         if ((tx2 | ty2) < 0) {
 794             setBounds(r.x, r.y, r.width, r.height);
 795         }
 796         long rx2 = r.width;
 797         long ry2 = r.height;
 798         if ((rx2 | ry2) < 0) {
 799             return;
 800         }
 801         int tx1 = this.x;
 802         int ty1 = this.y;
 803         tx2 += tx1;
 804         ty2 += ty1;
 805         int rx1 = r.x;
 806         int ry1 = r.y;
 807         rx2 += rx1;
 808         ry2 += ry1;
 809         if (tx1 > rx1) tx1 = rx1;
 810         if (ty1 > ry1) ty1 = ry1;
 811         if (tx2 < rx2) tx2 = rx2;
 812         if (ty2 < ry2) ty2 = ry2;
 813         tx2 -= tx1;
 814         ty2 -= ty1;
 815         // tx2,ty2 will never underflow since both original
 816         // rectangles were non-empty
 817         // they might overflow, though...
 818         if (tx2 > Integer.MAX_VALUE) tx2 = Integer.MAX_VALUE;
 819         if (ty2 > Integer.MAX_VALUE) ty2 = Integer.MAX_VALUE;
 820         setBounds(tx1, ty1, (int) tx2, (int) ty2);
 821     }
 822 
 823     /**
 824      * Resizes the <code>Rectangle</code> both horizontally and vertically.
 825      * <p>
 826      * This method modifies the <code>Rectangle</code> so that it is
 827      * <code>h</code> units larger on both the left and right side,
 828      * and <code>v</code> units larger at both the top and bottom.
 829      * <p>
 830      * The new <code>Rectangle</code> has {@code (x - h, y - v)}
 831      * as its upper-left corner,
 832      * width of {@code (width + 2h)},
 833      * and a height of {@code (height + 2v)}.
 834      * <p>
 835      * If negative values are supplied for <code>h</code> and
 836      * <code>v</code>, the size of the <code>Rectangle</code>
 837      * decreases accordingly.
 838      * The {@code grow} method will check for integer overflow
 839      * and underflow, but does not check whether the resulting
 840      * values of {@code width} and {@code height} grow
 841      * from negative to non-negative or shrink from non-negative
 842      * to negative.
 843      * @param h the horizontal expansion
 844      * @param v the vertical expansion
 845      */
 846     public void grow(int h, int v) {
 847         long x0 = this.x;
 848         long y0 = this.y;
 849         long x1 = this.width;
 850         long y1 = this.height;
 851         x1 += x0;
 852         y1 += y0;
 853 
 854         x0 -= h;
 855         y0 -= v;
 856         x1 += h;
 857         y1 += v;
 858 
 859         if (x1 < x0) {
 860             // Non-existant in X direction
 861             // Final width must remain negative so subtract x0 before
 862             // it is clipped so that we avoid the risk that the clipping
 863             // of x0 will reverse the ordering of x0 and x1.
 864             x1 -= x0;
 865             if (x1 < Integer.MIN_VALUE) x1 = Integer.MIN_VALUE;
 866             if (x0 < Integer.MIN_VALUE) x0 = Integer.MIN_VALUE;
 867             else if (x0 > Integer.MAX_VALUE) x0 = Integer.MAX_VALUE;
 868         } else { // (x1 >= x0)
 869             // Clip x0 before we subtract it from x1 in case the clipping
 870             // affects the representable area of the rectangle.
 871             if (x0 < Integer.MIN_VALUE) x0 = Integer.MIN_VALUE;
 872             else if (x0 > Integer.MAX_VALUE) x0 = Integer.MAX_VALUE;
 873             x1 -= x0;
 874             // The only way x1 can be negative now is if we clipped
 875             // x0 against MIN and x1 is less than MIN - in which case
 876             // we want to leave the width negative since the result
 877             // did not intersect the representable area.
 878             if (x1 < Integer.MIN_VALUE) x1 = Integer.MIN_VALUE;
 879             else if (x1 > Integer.MAX_VALUE) x1 = Integer.MAX_VALUE;
 880         }
 881 
 882         if (y1 < y0) {
 883             // Non-existant in Y direction
 884             y1 -= y0;
 885             if (y1 < Integer.MIN_VALUE) y1 = Integer.MIN_VALUE;
 886             if (y0 < Integer.MIN_VALUE) y0 = Integer.MIN_VALUE;
 887             else if (y0 > Integer.MAX_VALUE) y0 = Integer.MAX_VALUE;
 888         } else { // (y1 >= y0)
 889             if (y0 < Integer.MIN_VALUE) y0 = Integer.MIN_VALUE;
 890             else if (y0 > Integer.MAX_VALUE) y0 = Integer.MAX_VALUE;
 891             y1 -= y0;
 892             if (y1 < Integer.MIN_VALUE) y1 = Integer.MIN_VALUE;
 893             else if (y1 > Integer.MAX_VALUE) y1 = Integer.MAX_VALUE;
 894         }
 895 
 896         setBounds((int) x0, (int) y0, (int) x1, (int) y1);
 897     }
 898 
 899     /**
 900      * {@inheritDoc}
 901      * @return
 902      */
 903     public boolean isEmpty() {
 904         return (width <= 0) || (height <= 0);
 905     }
 906 
 907     /**
 908      * Checks whether two rectangles are equal.
 909      * <p>
 910      * The result is <code>true</code> if and only if the argument is not
 911      * <code>null</code> and is a <code>Rectangle</code> object that has the
 912      * same upper-left corner, width, and height as
 913      * this <code>Rectangle</code>.
 914      * @param obj the <code>Object</code> to compare with
 915      *                this <code>Rectangle</code>
 916      * @return    <code>true</code> if the objects are equal;
 917      *            <code>false</code> otherwise.
 918      */
 919     @Override
 920     public boolean equals(Object obj) {
 921         if (obj instanceof Rectangle) {
 922             Rectangle r = (Rectangle)obj;
 923             return ((x == r.x) &&
 924                 (y == r.y) &&
 925                 (width == r.width) &&
 926                 (height == r.height));
 927         }
 928         return super.equals(obj);
 929     }
 930 
 931     /**
 932      * {@inheritDoc }
 933      * @return
 934      */
 935     @Override
 936     public int hashCode() {
 937         int hash = 7;
 938         hash = 29 * hash + this.x;
 939         hash = 29 * hash + this.y;
 940         hash = 29 * hash + this.width;
 941         hash = 29 * hash + this.height;
 942         return hash;
 943     }
 944 
 945     /**
 946      * Returns a <code>String</code> representing this
 947      * <code>Rectangle</code> and its values.
 948      * @return a <code>String</code> representing this
 949      *               <code>Rectangle</code> object's coordinate and size values.
 950      */
 951     @Override
 952     public String toString() {
 953         return getClass().getName() + "[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]";
 954     }
 955 
 956     /**
 957      * Parses given string to restore Rectangle instance from the string.
 958      * String assumed to be previously created using
 959      * {@linkplain #toString() Rectangle.toString()} method.
 960      * @param str String to parse.
 961      * @return Recreated Rectangle instance.
 962      */
 963     public static Rectangle parseRectangle(String str) {
 964         if (str != null && str.startsWith(Rectangle.class.getName())) {
 965             try {
 966                 String[] t =
 967                         str.substring(Rectangle.class.getName().length() + 1)
 968                         .split("\\,|\\]");
 969                 Rectangle res = new Rectangle();
 970                 for(String pair : t) {
 971                     String[] p = pair.split("\\=");
 972                     String var = p[0];
 973                     int value = Integer.parseInt(p[1]);
 974                     res.getClass().getDeclaredField(var).setInt(res, value);
 975                 }
 976                 return res;
 977             } catch (Exception ex) {
 978                 throw new JemmyException(
 979                         "Failed to parse Rectangle '" + str + "'", ex);
 980             }
 981         }
 982         return null;
 983     }
 984 }