1 /*
   2  * Copyright (c) 2000, 2013, 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 
  27 package javax.print.attribute;
  28 
  29 import java.io.Serializable;
  30 
  31 /**
  32  * Class Size2DSyntax is an abstract base class providing the common
  33  * implementation of all attributes denoting a size in two dimensions.
  34  * <P>
  35  * A two-dimensional size attribute's value consists of two items, the X
  36  * dimension and the Y dimension. A two-dimensional size attribute may be
  37  * constructed by supplying the two values and indicating the units in which the
  38  * values are measured. Methods are provided to return a two-dimensional size
  39  * attribute's values, indicating the units in which the values are to be
  40  * returned. The two most common size units are inches (in) and millimeters
  41  * (mm), and exported constants {@link #INCH INCH} and {@link #MM
  42  * MM} are provided for indicating those units.
  43  * <P>
  44  * Once constructed, a two-dimensional size attribute's value is immutable.
  45  * <P>
  46  * <B>Design</B>
  47  * <P>
  48  * A two-dimensional size attribute's X and Y dimension values are stored
  49  * internally as integers in units of micrometers (µm), where 1 micrometer
  50  * = 10<SUP>-6</SUP> meter = 1/1000 millimeter = 1/25400 inch. This permits
  51  * dimensions to be represented exactly to a precision of 1/1000 mm (= 1
  52  * µm) or 1/100 inch (= 254 µm). If fractional inches are expressed in
  53  * negative powers of two, this permits dimensions to be represented exactly to
  54  * a precision of 1/8 inch (= 3175 µm) but not 1/16 inch (because 1/16 inch
  55  * does not equal an integral number of µm).
  56  * <P>
  57  * Storing the dimensions internally in common units of µm lets two size
  58  * attributes be compared without regard to the units in which they were
  59  * created; for example, 8.5 in will compare equal to 215.9 mm, as they both are
  60  * stored as 215900 µm. For example, a lookup service can
  61  * match resolution attributes based on equality of their serialized
  62  * representations regardless of the units in which they were created. Using
  63  * integers for internal storage allows precise equality comparisons to be done,
  64  * which would not be guaranteed if an internal floating point representation
  65  * were used. Note that if you're looking for U.S. letter sized media in metric
  66  * units, you have to search for a media size of 215.9 x 279.4 mm; rounding off
  67  * to an integral 216 x 279 mm will not match.
  68  * <P>
  69  * The exported constant {@link #INCH INCH} is actually the
  70  * conversion factor by which to multiply a value in inches to get the value in
  71  * µm. Likewise, the exported constant {@link #MM MM} is the
  72  * conversion factor by which to multiply a value in mm to get the value in
  73  * µm. A client can specify a resolution value in units other than inches
  74  * or mm by supplying its own conversion factor. However, since the internal
  75  * units of µm was chosen with supporting only the external units of inch
  76  * and mm in mind, there is no guarantee that the conversion factor for the
  77  * client's units will be an exact integer. If the conversion factor isn't an
  78  * exact integer, resolution values in the client's units won't be stored
  79  * precisely.
  80  * <P>
  81  *
  82  * @author  Alan Kaminsky
  83  */
  84 public abstract class Size2DSyntax implements Serializable, Cloneable {
  85 
  86     private static final long serialVersionUID = 5584439964938660530L;
  87 
  88     /**
  89      * X dimension in units of micrometers (µm).
  90      * @serial
  91      */
  92     private int x;
  93 
  94     /**
  95      * Y dimension in units of micrometers (µm).
  96      * @serial
  97      */
  98     private int y;
  99 
 100     /**
 101      * Value to indicate units of inches (in). It is actually the conversion
 102      * factor by which to multiply inches to yield µm (25400).
 103      */
 104     public static final int INCH = 25400;
 105 
 106     /**
 107      * Value to indicate units of millimeters (mm). It is actually the
 108      * conversion factor by which to multiply mm to yield µm (1000).
 109      */
 110     public static final int MM = 1000;
 111 
 112 
 113     /**
 114      * Construct a new two-dimensional size attribute from the given
 115      * floating-point values.
 116      *
 117      * @param  x  X dimension.
 118      * @param  y  Y dimension.
 119      * @param  units
 120      *     Unit conversion factor, e.g. {@link #INCH INCH} or
 121      *     {@link #MM MM}.
 122      *
 123      * @exception  IllegalArgumentException
 124      *     (Unchecked exception) Thrown if {@code x < 0} or {@code y < 0} or
 125      *     {@code units < 1}.
 126      */
 127     protected Size2DSyntax(float x, float y, int units) {
 128         if (x < 0.0f) {
 129             throw new IllegalArgumentException("x < 0");
 130         }
 131         if (y < 0.0f) {
 132             throw new IllegalArgumentException("y < 0");
 133         }
 134         if (units < 1) {
 135             throw new IllegalArgumentException("units < 1");
 136         }
 137         this.x = (int) (x * units + 0.5f);
 138         this.y = (int) (y * units + 0.5f);
 139     }
 140 
 141     /**
 142      * Construct a new two-dimensional size attribute from the given integer
 143      * values.
 144      *
 145      * @param  x  X dimension.
 146      * @param  y  Y dimension.
 147      * @param  units
 148      *     Unit conversion factor, e.g. {@link #INCH INCH} or
 149      *     {@link #MM MM}.
 150      *
 151      * @exception  IllegalArgumentException
 152      *   (Unchecked exception) Thrown if {@code x < 0} or {@code y < 0}
 153      *    or {@code units < 1}.
 154      */
 155     protected Size2DSyntax(int x, int y, int units) {
 156         if (x < 0) {
 157             throw new IllegalArgumentException("x < 0");
 158         }
 159         if (y < 0) {
 160             throw new IllegalArgumentException("y < 0");
 161         }
 162         if (units < 1) {
 163             throw new IllegalArgumentException("units < 1");
 164         }
 165         this.x = x * units;
 166         this.y = y * units;
 167     }
 168 
 169     /**
 170      * Convert a value from micrometers to some other units. The result is
 171      * returned as a floating-point number.
 172      *
 173      * @param  x
 174      *     Value (micrometers) to convert.
 175      * @param  units
 176      *     Unit conversion factor, e.g. {@link #INCH <CODE>INCH</CODE>} or
 177      *     {@link #MM <CODE>MM</CODE>}.
 178      *
 179      * @return  The value of <CODE>x</CODE> converted to the desired units.
 180      *
 181      * @exception  IllegalArgumentException
 182      *     (unchecked exception) Thrown if <CODE>units</CODE> < 1.
 183      */
 184     private static float convertFromMicrometers(int x, int units) {
 185         if (units < 1) {
 186             throw new IllegalArgumentException("units is < 1");
 187         }
 188         return ((float)x) / ((float)units);
 189     }
 190 
 191     /**
 192      * Get this two-dimensional size attribute's dimensions in the given units
 193      * as floating-point values.
 194      *
 195      * @param  units
 196      *     Unit conversion factor, e.g. {@link #INCH INCH} or {@link #MM MM}.
 197      *
 198      * @return  A two-element array with the X dimension at index 0 and the Y
 199      *          dimension at index 1.
 200      *
 201      * @exception  IllegalArgumentException
 202      *     (unchecked exception) Thrown if {@code units < 1}.
 203      */
 204     public float[] getSize(int units) {
 205         return new float[] {getX(units), getY(units)};
 206     }
 207 
 208     /**
 209      * Returns this two-dimensional size attribute's X dimension in the given
 210      * units as a floating-point value.
 211      *
 212      * @param  units
 213      *     Unit conversion factor, e.g. {@link #INCH INCH} or {@link #MM MM}.
 214      *
 215      * @return  X dimension.
 216      *
 217      * @exception  IllegalArgumentException
 218      *     (unchecked exception) Thrown if {@code units < 1}.
 219      */
 220     public float getX(int units) {
 221         return convertFromMicrometers(x, units);
 222     }
 223 
 224     /**
 225      * Returns this two-dimensional size attribute's Y dimension in the given
 226      * units as a floating-point value.
 227      *
 228      * @param  units
 229      *     Unit conversion factor, e.g. {@link #INCH INCH} or {@link #MM MM}.
 230      *
 231      * @return  Y dimension.
 232      *
 233      * @exception  IllegalArgumentException
 234      *     (unchecked exception) Thrown if {@code units < 1}.
 235      */
 236     public float getY(int units) {
 237         return convertFromMicrometers(y, units);
 238     }
 239 
 240     /**
 241      * Returns a string version of this two-dimensional size attribute in the
 242      * given units. The string takes the form <CODE>"<I>X</I>x<I>Y</I>
 243      * <I>U</I>"</CODE>, where <I>X</I> is the X dimension, <I>Y</I> is the Y
 244      * dimension, and <I>U</I> is the units name. The values are displayed in
 245      * floating point.
 246      *
 247      * @param  units
 248      *     Unit conversion factor, e.g. {@link #INCH INCH} or {@link #MM MM}.
 249      *
 250      * @param  unitsName
 251      *     Units name string, e.g. {@code in} or {@code mm}. If
 252      *     null, no units name is appended to the result.
 253      *
 254      * @return  String version of this two-dimensional size attribute.
 255      *
 256      * @exception  IllegalArgumentException
 257      *     (unchecked exception) Thrown if {@code units < 1}.
 258      */
 259     public String toString(int units, String unitsName) {
 260         StringBuffer result = new StringBuffer();
 261         result.append(getX (units));
 262         result.append('x');
 263         result.append(getY (units));
 264         if (unitsName != null) {
 265             result.append(' ');
 266             result.append(unitsName);
 267         }
 268         return result.toString();
 269     }
 270 
 271     /**
 272      * Returns whether this two-dimensional size attribute is equivalent to the
 273      * passed in object. To be equivalent, all of the following conditions must
 274      * be true:
 275      * <OL TYPE=1>
 276      * <LI>
 277      * <CODE>object</CODE> is not null.
 278      * <LI>
 279      * <CODE>object</CODE> is an instance of class Size2DSyntax.
 280      * <LI>
 281      * This attribute's X dimension is equal to <CODE>object</CODE>'s X
 282      * dimension.
 283      * <LI>
 284      * This attribute's Y dimension is equal to <CODE>object</CODE>'s Y
 285      * dimension.
 286      * </OL>
 287      *
 288      * @param  object  Object to compare to.
 289      *
 290      * @return  True if <CODE>object</CODE> is equivalent to this
 291      *          two-dimensional size attribute, false otherwise.
 292      */
 293     public boolean equals(Object object) {
 294         return(object != null &&
 295                object instanceof Size2DSyntax &&
 296                this.x == ((Size2DSyntax) object).x &&
 297                this.y == ((Size2DSyntax) object).y);
 298     }
 299 
 300     /**
 301      * Returns a hash code value for this two-dimensional size attribute.
 302      */
 303     public int hashCode() {
 304         return (((x & 0x0000FFFF)      ) |
 305                 ((y & 0x0000FFFF) << 16));
 306     }
 307 
 308     /**
 309      * Returns a string version of this two-dimensional size attribute. The
 310      * string takes the form <CODE>"<I>X</I>x<I>Y</I> um"</CODE>, where
 311      * <I>X</I> is the X dimension and <I>Y</I> is the Y dimension.
 312      * The values are reported in the internal units of micrometers.
 313      */
 314     public String toString() {
 315         StringBuffer result = new StringBuffer();
 316         result.append(x);
 317         result.append('x');
 318         result.append(y);
 319         result.append(" um");
 320         return result.toString();
 321     }
 322 
 323     /**
 324      * Returns this two-dimensional size attribute's X dimension in units of
 325      * micrometers (µm). (For use in a subclass.)
 326      *
 327      * @return  X dimension (µm).
 328      */
 329     protected int getXMicrometers(){
 330         return x;
 331     }
 332 
 333     /**
 334      * Returns this two-dimensional size attribute's Y dimension in units of
 335      * micrometers (µm). (For use in a subclass.)
 336      *
 337      * @return  Y dimension (µm).
 338      */
 339     protected int getYMicrometers() {
 340         return y;
 341     }
 342 
 343 }