1 /*
  2  * Copyright (c) 2003, 2021, 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 sun.print;
 27 
 28 import java.io.Serial;
 29 import java.util.ArrayList;
 30 import java.util.Map;
 31 import java.util.HashMap;
 32 import java.util.Objects;
 33 
 34 import javax.print.attribute.EnumSyntax;
 35 import javax.print.attribute.standard.Media;
 36 import javax.print.attribute.standard.MediaSize;
 37 import javax.print.attribute.standard.MediaSizeName;
 38 import javax.print.attribute.Size2DSyntax;
 39 
 40 class CustomMediaSizeName extends MediaSizeName {
 41     private static ArrayList<String> customStringTable = new ArrayList<>();
 42     private static ArrayList<MediaSizeName> customEnumTable = new ArrayList<>();
 43     private static Map<SizeNameChoiceItem, CustomMediaSizeName> customMap = new HashMap<>();
 44     private String choiceName;
 45     private MediaSizeName mediaName;
 46 
 47     private CustomMediaSizeName(int x) {
 48         super(x);
 49 
 50     }
 51 
 52     private static synchronized int nextValue(String name) {
 53       customStringTable.add(name);
 54 
 55       return (customStringTable.size()-1);
 56     }
 57 
 58     public CustomMediaSizeName(String name) {
 59         super(nextValue(name));
 60         customEnumTable.add(this);
 61         choiceName = null;
 62         mediaName = null;
 63     }
 64 
 65     public CustomMediaSizeName(String name, String choice,
 66                                float width, float length) {
 67         super(nextValue(name));
 68         choiceName = choice;
 69         customEnumTable.add(this);
 70         mediaName = null;
 71         try {
 72             mediaName = MediaSize.findMedia(width, length,
 73                                             MediaSize.INCH);
 74         } catch (IllegalArgumentException iae) {
 75         }
 76         // The public API method finds a closest match even if it not
 77         // all that close. Here we want to be sure its *really* close.
 78         if (mediaName != null) {
 79             MediaSize sz = MediaSize.getMediaSizeForName(mediaName);
 80             if (sz == null) {
 81                 mediaName = null;
 82             } else {
 83                 float w = sz.getX(MediaSize.INCH);
 84                 float h = sz.getY(MediaSize.INCH);
 85                 float dw = Math.abs(w - width);
 86                 float dh = Math.abs(h - length);
 87                 if (dw > 0.1 || dh > 0.1) {
 88                     mediaName = null;
 89                 }
 90             }
 91         }
 92     }
 93 
 94     /**
 95      * Use serialVersionUID from JDK 1.5 for interoperability.
 96      */
 97     @Serial
 98     private static final long serialVersionUID = 7412807582228043717L;
 99 
100     /**
101      * Returns the command string for this media.
102      */
103     public String getChoiceName() {
104         return choiceName;
105     }
106 
107 
108     /**
109      * Returns matching standard MediaSizeName.
110      */
111     public MediaSizeName getStandardMedia() {
112         return mediaName;
113     }
114 
115 
116     // moved from RasterPrinterJob
117     /**
118      * Returns closest matching MediaSizeName among given array of Media
119      */
120     public static MediaSizeName findMedia(Media[] media, float x, float y,
121                                           int units) {
122 
123 
124         if (x <= 0.0f || y <= 0.0f || units < 1) {
125             throw new IllegalArgumentException("args must be +ve values");
126         }
127 
128         if (media == null || media.length == 0) {
129             throw new IllegalArgumentException("args must have valid array of media");
130         }
131 
132         int size =0;
133         MediaSizeName[] msn = new MediaSizeName[media.length];
134         for (int i=0; i<media.length; i++) {
135             if (media[i] instanceof MediaSizeName) {
136                 msn[size++] = (MediaSizeName)media[i];
137             }
138         }
139 
140         if (size == 0) {
141             return null;
142         }
143 
144         int match = 0;
145 
146         double ls = x * x + y * y;
147         double tmp_ls;
148         float []dim;
149         float diffx = x;
150         float diffy = y;
151 
152         for (int i=0; i < size ; i++) {
153             MediaSize mediaSize = MediaSize.getMediaSizeForName(msn[i]);
154             if (mediaSize == null) {
155                 continue;
156             }
157             dim = mediaSize.getSize(units);
158             if (x == dim[0] && y == dim[1]) {
159                 match = i;
160                 break;
161             } else {
162                 diffx = x - dim[0];
163                 diffy = y - dim[1];
164                 tmp_ls = diffx * diffx + diffy * diffy;
165                 if (tmp_ls < ls) {
166                     ls = tmp_ls;
167                     match = i;
168                 }
169             }
170         }
171 
172         return msn[match];
173     }
174 
175     /**
176      * Returns the string table for super class MediaSizeName.
177      */
178     public  Media[] getSuperEnumTable() {
179         return (Media[])super.getEnumValueTable();
180     }
181 
182 
183     /**
184      * Returns the string table for class CustomMediaSizeName.
185      */
186     protected String[] getStringTable() {
187       String[] nameTable = new String[customStringTable.size()];
188       return customStringTable.toArray(nameTable);
189     }
190 
191     /**
192      * Returns the enumeration value table for class CustomMediaSizeName.
193      */
194     protected EnumSyntax[] getEnumValueTable() {
195       MediaSizeName[] enumTable = new MediaSizeName[customEnumTable.size()];
196       return customEnumTable.toArray(enumTable);
197     }
198 
199     public static CustomMediaSizeName create(String name, String choice,
200                                              float width, float length) {
201         SizeNameChoiceItem key = new SizeNameChoiceItem(name, choice, width, length);
202         CustomMediaSizeName value = customMap.get(key);
203         if (value == null) {
204             value = new CustomMediaSizeName(name, choice, width, length);
205             customMap.put(key, value);
206 
207             // add this new custom media size name to MediaSize array
208             if ((width > 0.0) && (length > 0.0)) {
209                 try {
210                     new MediaSize(width, length, Size2DSyntax.INCH, value);
211                 } catch (IllegalArgumentException e) {
212                         /* PDF printer in Linux for Ledger paper causes
213                         "IllegalArgumentException: X dimension > Y dimension".
214                         We rotate based on IPP spec. */
215                     new MediaSize(length, width, Size2DSyntax.INCH, value);
216                 }
217             }
218         }
219         return value;
220     }
221 
222     private static class SizeNameChoiceItem {
223 
224         private final String name;
225         private final String choice;
226         private final float width;
227         private final float length;
228 
229         public SizeNameChoiceItem(String name, String choice, float width, float length) {
230             this.name = name;
231             this.choice = choice;
232             this.width = width;
233             this.length = length;
234         }
235 
236         public boolean equals(Object object) {
237             if (this == object) return true;
238             if (object == null || getClass() != object.getClass()) return false;
239             SizeNameChoiceItem that = (SizeNameChoiceItem) object;
240             return Objects.equals(this.name, that.name)
241                     && Objects.equals(this.choice, that.choice) &&
242                     Float.compare(this.width, that.width) == 0 &&
243                     Float.compare(this.length, that.length) == 0;
244         }
245 
246         public int hashCode() {
247             return Objects.hash(name, choice, width, length);
248         }
249     }
250 }