1/*
2 * Copyright (c) 2000, 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 */
25package javax.print.attribute.standard;
26
27import javax.print.DocFlavor;
28import javax.print.attribute.Attribute;
29import javax.print.attribute.AttributeSet;
30import javax.print.attribute.DocAttribute;
31import javax.print.attribute.PrintJobAttribute;
32import javax.print.attribute.PrintRequestAttribute;
33
34/**
35 * Class MediaPrintableArea is a printing attribute used to distinguish
36 * the printable and non-printable areas of media.
37 * <p>
38 * The printable area is specified to be a rectangle, within the overall
39 * dimensions of a media.
40 * <p>
41 * Most printers cannot print on the entire surface of the media, due
42 * to printer hardware limitations. This class can be used to query
43 * the acceptable values for a supposed print job, and to request an area
44 * within the constraints of the printable area to be used in a print job.
45 * <p>
46 * To query for the printable area, a client must supply a suitable context.
47 * Without specifying at the very least the size of the media being used
48 * no meaningful value for printable area can be obtained.
49 * <p>
50 * The attribute is not described in terms of the distance from the edge
51 * of the paper, in part to emphasise that this attribute is not independent
52 * of a particular media, but must be described within the context of a
53 * choice of other attributes. Additionally it is usually more convenient
54 * for a client to use the printable area.
55 * <p>
56 * The hardware's minimum margins is not just a property of the printer,
57 * but may be a function of the media size, orientation, media type, and
58 * any specified finishings.
59 * {@code PrintService} provides the method to query the supported
60 * values of an attribute in a suitable context :
61 * See  {@link javax.print.PrintService#getSupportedAttributeValues(Class,DocFlavor, AttributeSet) PrintService.getSupportedAttributeValues()}
62 * <p>
63 * The rectangular printable area is defined thus:
64 * The (x,y) origin is positioned at the top-left of the paper in portrait
65 * mode regardless of the orientation specified in the requesting context.
66 * For example a printable area for A4 paper in portrait or landscape
67 * orientation will have height {@literal >} width.
68 * <p>
69 * A printable area attribute's values are stored
70 * internally as integers in units of micrometers (&#181;m), where 1 micrometer
71 * = 10<SUP>-6</SUP> meter = 1/1000 millimeter = 1/25400 inch. This permits
72 * dimensions to be represented exactly to a precision of 1/1000 mm (= 1
73 * &#181;m) or 1/100 inch (= 254 &#181;m). If fractional inches are expressed in
74
75 * negative powers of two, this permits dimensions to be represented exactly to
76 * a precision of 1/8 inch (= 3175 &#181;m) but not 1/16 inch (because 1/16 inch
77
78 * does not equal an integral number of &#181;m).
79 * <p>
80 * <B>IPP Compatibility:</B> MediaPrintableArea is not an IPP attribute.
81 */
82
83public final class MediaPrintableArea
84      implements DocAttribute, PrintRequestAttribute, PrintJobAttribute {
85
86    private int x, y, w, h;
87    private int units;
88
89    private static final long serialVersionUID = -1597171464050795793L;
90
91    /**
92     * Value to indicate units of inches (in). It is actually the conversion
93     * factor by which to multiply inches to yield &#181;m (25400).
94     */
95    public static final int INCH = 25400;
96
97    /**
98     * Value to indicate units of millimeters (mm). It is actually the
99     * conversion factor by which to multiply mm to yield &#181;m (1000).
100     */
101    public static final int MM = 1000;
102
103    /**
104      * Constructs a MediaPrintableArea object from floating point values.
105      * @param x      printable x
106      * @param y      printable y
107      * @param w      printable width
108      * @param h      printable height
109      * @param units  in which the values are expressed.
110      *
111      * @exception  IllegalArgumentException
112      *     Thrown if {@code x < 0} or {@code y < 0}
113      *     or {@code w <= 0} or {@code h <= 0} or
114      *     {@code units < 1}.
115      */
116    public MediaPrintableArea(float x, float y, float w, float h, int units) {
117        if ((x < 0.0) || (y < 0.0) || (w <= 0.0) || (h <= 0.0) ||
118            (units < 1)) {
119            throw new IllegalArgumentException("0 or negative value argument");
120        }
121
122        this.x = (int) (x * units + 0.5f);
123        this.y = (int) (y * units + 0.5f);
124        this.w = (int) (w * units + 0.5f);
125        this.h = (int) (h * units + 0.5f);
126
127    }
128
129    /**
130      * Constructs a MediaPrintableArea object from integer values.
131      * @param x      printable x
132      * @param y      printable y
133      * @param w      printable width
134      * @param h      printable height
135      * @param units  in which the values are expressed.
136      *
137      * @exception  IllegalArgumentException
138      *     Thrown if {@code x < 0} or {@code y < 0}
139      *     or {@code w <= 0} or {@code h <= 0} or
140      *     {@code units < 1}.
141      */
142    public MediaPrintableArea(int x, int y, int w, int h, int units) {
143        if ((x < 0) || (y < 0) || (w <= 0) || (h <= 0) ||
144            (units < 1)) {
145            throw new IllegalArgumentException("0 or negative value argument");
146        }
147        this.x = x * units;
148        this.y = y * units;
149        this.w = w * units;
150        this.h = h * units;
151
152    }
153
154    /**
155     * Get the printable area as an array of 4 values in the order
156     * x, y, w, h. The values returned are in the given units.
157     * @param  units
158     *     Unit conversion factor, e.g. {@link #INCH INCH} or
159     *     {@link #MM MM}.
160     *
161     * @return printable area as array of x, y, w, h in the specified units.
162     *
163     * @exception  IllegalArgumentException
164     *     (unchecked exception) Thrown if {@code units < 1}.
165     */
166    public float[] getPrintableArea(int units) {
167        return new float[] { getX(units), getY(units),
168                             getWidth(units), getHeight(units) };
169    }
170
171    /**
172     * Get the x location of the origin of the printable area in the
173     * specified units.
174     * @param  units
175     *     Unit conversion factor, e.g. {@link #INCH INCH} or
176     *     {@link #MM MM}.
177     *
178     * @return  x location of the origin of the printable area in the
179     * specified units.
180     *
181     * @exception  IllegalArgumentException
182     *     (unchecked exception) Thrown if {@code units < 1}.
183     */
184     public float getX(int units) {
185        return convertFromMicrometers(x, units);
186     }
187
188    /**
189     * Get the y location of the origin of the printable area in the
190     * specified units.
191     * @param  units
192     *     Unit conversion factor, e.g. {@link #INCH INCH} or
193     *     {@link #MM MM}.
194     *
195     * @return  y location of the origin of the printable area in the
196     * specified units.
197     *
198     * @exception  IllegalArgumentException
199     *     (unchecked exception) Thrown if {@code units < 1}.
200     */
201     public float getY(int units) {
202        return convertFromMicrometers(y, units);
203     }
204
205    /**
206     * Get the width of the printable area in the specified units.
207     * @param  units
208     *     Unit conversion factor, e.g. {@link #INCH INCH} or
209     *     {@link #MM MM}.
210     *
211     * @return  width of the printable area in the specified units.
212     *
213     * @exception  IllegalArgumentException
214     *     (unchecked exception) Thrown if {@code units < 1}.
215     */
216     public float getWidth(int units) {
217        return convertFromMicrometers(w, units);
218     }
219
220    /**
221     * Get the height of the printable area in the specified units.
222     * @param  units
223     *     Unit conversion factor, e.g. {@link #INCH INCH} or
224     *     {@link #MM MM}.
225     *
226     * @return  height of the printable area in the specified units.
227     *
228     * @exception  IllegalArgumentException
229     *     (unchecked exception) Thrown if {@code units < 1}.
230     */
231     public float getHeight(int units) {
232        return convertFromMicrometers(h, units);
233     }
234
235    /**
236     * Returns whether this media margins attribute is equivalent to the passed
237     * in object.
238     * To be equivalent, all of the following conditions must be true:
239     * <OL TYPE=1>
240     * <LI>
241     * {@code object} is not null.
242     * <LI>
243     * {@code object} is an instance of class MediaPrintableArea.
244     * <LI>
245     * The origin and dimensions are the same.
246     * </OL>
247     *
248     * @param  object  Object to compare to.
249     *
250     * @return  True if {@code object} is equivalent to this media margins
251     *          attribute, false otherwise.
252     */
253    public boolean equals(Object object) {
254        boolean ret = false;
255        if (object instanceof MediaPrintableArea) {
256           MediaPrintableArea mm = (MediaPrintableArea)object;
257           if (x == mm.x &&  y == mm.y && w == mm.w && h == mm.h) {
258               ret = true;
259           }
260        }
261        return ret;
262    }
263
264    /**
265     * Get the printing attribute class which is to be used as the "category"
266     * for this printing attribute value.
267     * <P>
268     * For class MediaPrintableArea, the category is
269     * class MediaPrintableArea itself.
270     *
271     * @return  Printing attribute class (category), an instance of class
272     *          {@link java.lang.Class java.lang.Class}.
273     */
274    public final Class<? extends Attribute> getCategory() {
275        return MediaPrintableArea.class;
276    }
277
278    /**
279     * Get the name of the category of which this attribute value is an
280     * instance.
281     * <P>
282     * For class MediaPrintableArea,
283     * the category name is {@code "media-printable-area"}.
284     * <p>This is not an IPP V1.1 attribute.
285     *
286     * @return  Attribute category name.
287     */
288    public final String getName() {
289        return "media-printable-area";
290    }
291
292    /**
293     * Returns a string version of this rectangular size attribute in the
294     * given units.
295     *
296     * @param  units
297     *     Unit conversion factor, e.g. {@link #INCH INCH} or
298     *     {@link #MM MM}.
299     * @param  unitsName
300     *     Units name string, e.g. {@code "in"} or {@code "mm"}. If
301     *     null, no units name is appended to the result.
302     *
303     * @return  String version of this two-dimensional size attribute.
304     *
305     * @exception  IllegalArgumentException
306     *     (unchecked exception) Thrown if {@code units < 1}.
307     */
308    public String toString(int units, String unitsName) {
309        if (unitsName == null) {
310            unitsName = "";
311        }
312        float []vals = getPrintableArea(units);
313        String str = "("+vals[0]+","+vals[1]+")->("+vals[2]+","+vals[3]+")";
314        return str + unitsName;
315    }
316
317    /**
318     * Returns a string version of this rectangular size attribute in mm.
319     */
320    public String toString() {
321        return(toString(MM, "mm"));
322    }
323
324    /**
325     * Returns a hash code value for this attribute.
326     */
327    public int hashCode() {
328        return x + 37*y + 43*w + 47*h;
329    }
330
331    private static float convertFromMicrometers(int x, int units) {
332        if (units < 1) {
333            throw new IllegalArgumentException("units is < 1");
334        }
335        return ((float)x) / ((float)units);
336    }
337}
338