001    /* RenderingHints.java --
002       Copyright (C) 2000, 2001, 2002, 2004, 2005  Free Software Foundation
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.awt;
040    
041    import java.util.Collection;
042    import java.util.Collections;
043    import java.util.HashMap;
044    import java.util.Iterator;
045    import java.util.Map;
046    import java.util.Set;
047    
048    /**
049     * A collection of (key, value) items that provide 'hints' for the
050     * {@link java.awt.Graphics2D} rendering pipeline.  Because these
051     * items are hints only, they may be ignored by a particular
052     * {@link java.awt.Graphics2D} implementation.
053     *
054     * @author Rolf W. Rasmussen (rolfwr@ii.uib.no)
055     * @author Eric Blake (ebb9@email.byu.edu)
056     */
057    public class RenderingHints
058      implements Map<Object,Object>, Cloneable
059    {
060      /**
061       * The base class used to represent keys.
062       */
063      public abstract static class Key
064      {
065        private final int key;
066    
067        /**
068         * Creates a new key.
069         *
070         * @param privateKey  the private key.
071         */
072        protected Key(int privateKey)
073        {
074          key = privateKey;
075        }
076    
077        /**
078         * Returns <code>true</code> if the specified value is compatible with
079         * this key, and <code>false</code> otherwise.
080         *
081         * @param value  the value (<code>null</code> permitted).
082         *
083         * @return A boolean.
084         */
085        public abstract boolean isCompatibleValue(Object value);
086    
087        /**
088         * Returns the private key for this instance.
089         *
090         * @return The private key.
091         */
092        protected final int intKey()
093        {
094          return key;
095        }
096    
097        /**
098         * Returns a hash code for the key.
099         *
100         * @return A hash code.
101         */
102        public final int hashCode()
103        {
104          return System.identityHashCode(this);
105        }
106    
107        /**
108         * Checks this key for equality with an arbitrary object.
109         *
110         * @param other  the object (<code>null</code> permitted)
111         *
112         * @return A boolean.
113         */
114        public final boolean equals(Object other)
115        {
116          return this == other;
117        }
118      } // class Key
119    
120      private static final class KeyImpl extends Key
121      {
122        final String description;
123        final Object v1;
124        final Object v2;
125        final Object v3;
126    
127        KeyImpl(int privateKey, String description,
128                Object v1, Object v2, Object v3)
129        {
130          super(privateKey);
131          this.description = description;
132          this.v1 = v1;
133          this.v2 = v2;
134          this.v3 = v3;
135        }
136    
137        /**
138         * Returns <code>true</code> if the specified value is compatible with
139         * this key, and <code>false</code> otherwise.
140         *
141         * @param value  the value (<code>null</code> permitted).
142         *
143         * @return A boolean.
144         */
145        public boolean isCompatibleValue(Object value)
146        {
147          return value == v1 || value == v2 || value == v3;
148        }
149    
150        /**
151         * Returns a string representation of the key.
152         *
153         * @return A string.
154         */
155        public String toString()
156        {
157          return description;
158        }
159      } // class KeyImpl
160    
161      private HashMap<Object,Object> hintMap = new HashMap<Object,Object>();
162    
163      /**
164       * A key for the 'antialiasing' hint.  Permitted values are:
165       * <p>
166       * <table>
167       * <tr>
168       *   <td>{@link #VALUE_ANTIALIAS_OFF}</td>
169       *   <td>Render without antialiasing (better speed).</td>
170       * </tr>
171       * <tr>
172       *   <td>{@link #VALUE_ANTIALIAS_ON}</td>
173       *   <td>Render with antialiasing (better quality).</td>
174       * </tr>
175       * <tr>
176       *   <td>{@link #VALUE_ANTIALIAS_DEFAULT}</td>
177       *   <td>Use the default value for antialiasing.</td>
178       * </tr>
179       * </table>
180       */
181      public static final Key KEY_ANTIALIASING;
182    
183      /**
184       * This value is for use with the {@link #KEY_ANTIALIASING} key.
185       */
186      public static final Object VALUE_ANTIALIAS_ON
187        = "Antialiased rendering mode";
188    
189      /**
190       * This value is for use with the {@link #KEY_ANTIALIASING} key.
191       */
192      public static final Object VALUE_ANTIALIAS_OFF
193        = "Nonantialiased rendering mode";
194    
195      /**
196       * This value is for use with the {@link #KEY_ANTIALIASING} key.
197       */
198      public static final Object VALUE_ANTIALIAS_DEFAULT
199        = "Default antialiasing rendering mode";
200    
201      /**
202       * A key for the 'rendering' hint.  Permitted values are:
203       * <p>
204       * <table>
205       * <tr>
206       *   <td>{@link #VALUE_RENDER_SPEED}</td>
207       *   <td>Prefer speed over quality when rendering.</td>
208       * </tr>
209       * <tr>
210       *   <td>{@link #VALUE_RENDER_QUALITY}</td>
211       *   <td>Prefer quality over speed when rendering.</td>
212       * </tr>
213       * <tr>
214       *   <td>{@link #VALUE_RENDER_DEFAULT}</td>
215       *   <td>Use the default value for quality vs. speed when rendering.</td>
216       * </tr>
217       * </table>
218       */
219      public static final Key KEY_RENDERING;
220    
221      /**
222       * This value is for use with the {@link #KEY_RENDERING} key.
223       */
224      public static final Object VALUE_RENDER_SPEED
225        = "Fastest rendering methods";
226    
227      /**
228       * This value is for use with the {@link #KEY_RENDERING} key.
229       */
230      public static final Object VALUE_RENDER_QUALITY
231        = "Highest quality rendering methods";
232    
233      /**
234       * This value is for use with the {@link #KEY_RENDERING} key.
235       */
236      public static final Object VALUE_RENDER_DEFAULT
237        = "Default rendering methods";
238    
239      /**
240       * A key for the 'dithering' hint.  Permitted values are:
241       * <p>
242       * <table>
243       * <tr>
244       *   <td>{@link #VALUE_DITHER_DISABLE}</td>
245       *   <td>Disable dithering.</td>
246       * </tr>
247       * <tr>
248       *   <td>{@link #VALUE_DITHER_ENABLE}</td>
249       *   <td>Enable dithering.</td>
250       * </tr>
251       * <tr>
252       *   <td>{@link #VALUE_DITHER_DEFAULT}</td>
253       *   <td>Use the default value for dithering.</td>
254       * </tr>
255       * </table>
256       */
257      public static final Key KEY_DITHERING;
258    
259      /**
260       * This value is for use with the {@link #KEY_DITHERING} key.
261       */
262      public static final Object VALUE_DITHER_DISABLE
263        = "Nondithered rendering mode";
264    
265      /**
266       * This value is for use with the {@link #KEY_DITHERING} key.
267       */
268      public static final Object VALUE_DITHER_ENABLE
269        = "Dithered rendering mode";
270    
271      /**
272       * This value is for use with the {@link #KEY_DITHERING} key.
273       */
274      public static final Object VALUE_DITHER_DEFAULT
275        = "Default dithering mode";
276    
277      /**
278       * A key for the 'text antialiasing' hint.  Permitted values are:
279       * <p>
280       * <table>
281       * <tr>
282       *   <td>{@link #VALUE_TEXT_ANTIALIAS_ON}</td>
283       *   <td>Render text with antialiasing (better quality usually).</td>
284       * </tr>
285       * <tr>
286       *   <td>{@link #VALUE_TEXT_ANTIALIAS_OFF}</td>
287       *   <td>Render test without antialiasing (better speed).</td>
288       * </tr>
289       * <tr>
290       *   <td>{@link #VALUE_TEXT_ANTIALIAS_DEFAULT}</td>
291       *   <td>Use the default value for text antialiasing.</td>
292       * </tr>
293       * </table>
294       */
295      public static final Key KEY_TEXT_ANTIALIASING;
296    
297      /**
298       * This value is for use with the {@link #KEY_TEXT_ANTIALIASING} key.
299       */
300      public static final Object VALUE_TEXT_ANTIALIAS_ON
301        = "Antialiased text mode";
302    
303      /**
304       * This value is for use with the {@link #KEY_TEXT_ANTIALIASING} key.
305       */
306      public static final Object VALUE_TEXT_ANTIALIAS_OFF
307        = "Nonantialiased text mode";
308    
309      /**
310       * This value is for use with the {@link #KEY_TEXT_ANTIALIASING} key.
311       */
312      public static final Object VALUE_TEXT_ANTIALIAS_DEFAULT
313        = "Default antialiasing text mode";
314    
315      /**
316       * A key for the 'fractional metrics' hint.  Permitted values are:
317       * <p>
318       * <table>
319       * <tr>
320       *   <td>{@link #VALUE_FRACTIONALMETRICS_OFF}</td>
321       *   <td>Render text with fractional metrics off.</td>
322       * </tr>
323       * <tr>
324       *   <td>{@link #VALUE_FRACTIONALMETRICS_ON}</td>
325       *   <td>Render text with fractional metrics on.</td>
326       * </tr>
327       * <tr>
328       *   <td>{@link #VALUE_FRACTIONALMETRICS_DEFAULT}</td>
329       *   <td>Use the default value for fractional metrics.</td>
330       * </tr>
331       * </table>
332       */
333      public static final Key KEY_FRACTIONALMETRICS;
334    
335      /**
336       * This value is for use with the {@link #KEY_FRACTIONALMETRICS} key.
337       */
338      public static final Object VALUE_FRACTIONALMETRICS_OFF
339        = "Integer text metrics mode";
340    
341      /**
342       * This value is for use with the {@link #KEY_FRACTIONALMETRICS} key.
343       */
344      public static final Object VALUE_FRACTIONALMETRICS_ON
345        = "Fractional text metrics mode";
346    
347      /**
348       * This value is for use with the {@link #KEY_FRACTIONALMETRICS} key.
349       */
350      public static final Object VALUE_FRACTIONALMETRICS_DEFAULT
351        = "Default fractional text metrics mode";
352    
353      /**
354       * A key for the 'interpolation' hint.  Permitted values are:
355       * <p>
356       * <table>
357       * <tr>
358       *   <td>{@link #VALUE_INTERPOLATION_NEAREST_NEIGHBOR}</td>
359       *   <td>Use nearest neighbour interpolation.</td>
360       * </tr>
361       * <tr>
362       *   <td>{@link #VALUE_INTERPOLATION_BILINEAR}</td>
363       *   <td>Use bilinear interpolation.</td>
364       * </tr>
365       * <tr>
366       *   <td>{@link #VALUE_INTERPOLATION_BICUBIC}</td>
367       *   <td>Use bicubic interpolation.</td>
368       * </tr>
369       * </table>
370       */
371      public static final Key KEY_INTERPOLATION;
372    
373      /**
374       * This value is for use with the {@link #KEY_INTERPOLATION} key.
375       */
376      public static final Object VALUE_INTERPOLATION_NEAREST_NEIGHBOR
377        = "Nearest Neighbor image interpolation mode";
378    
379      /**
380       * This value is for use with the {@link #KEY_INTERPOLATION} key.
381       */
382      public static final Object VALUE_INTERPOLATION_BILINEAR
383        = "Bilinear image interpolation mode";
384    
385      /**
386       * This value is for use with the {@link #KEY_INTERPOLATION} key.
387       */
388      public static final Object VALUE_INTERPOLATION_BICUBIC
389        = "Bicubic image interpolation mode";
390    
391      /**
392       * A key for the 'alpha interpolation' hint.  Permitted values are:
393       * <p>
394       * <table>
395       * <tr>
396       *   <td>{@link #VALUE_ALPHA_INTERPOLATION_SPEED}</td>
397       *   <td>Prefer speed over quality.</td>
398       * </tr>
399       * <tr>
400       *   <td>{@link #VALUE_ALPHA_INTERPOLATION_QUALITY}</td>
401       *   <td>Prefer quality over speed.</td>
402       * </tr>
403       * <tr>
404       *   <td>{@link #VALUE_ALPHA_INTERPOLATION_DEFAULT}</td>
405       *   <td>Use the default setting.</td>
406       * </tr>
407       * </table>
408       */
409      public static final Key KEY_ALPHA_INTERPOLATION;
410    
411      /**
412       * This value is for use with the {@link #KEY_ALPHA_INTERPOLATION} key.
413       */
414      public static final Object VALUE_ALPHA_INTERPOLATION_SPEED
415        = "Fastest alpha blending methods";
416    
417      /**
418       * This value is for use with the {@link #KEY_ALPHA_INTERPOLATION} key.
419       */
420      public static final Object VALUE_ALPHA_INTERPOLATION_QUALITY
421        = "Highest quality alpha blending methods";
422    
423      /**
424       * This value is for use with the {@link #KEY_ALPHA_INTERPOLATION} key.
425       */
426      public static final Object VALUE_ALPHA_INTERPOLATION_DEFAULT
427        = "Default alpha blending methods";
428    
429      /**
430       * A key for the 'color rendering' hint.  Permitted values are:
431       * <p>
432       * <table>
433       * <tr>
434       *   <td>{@link #VALUE_COLOR_RENDER_SPEED}</td>
435       *   <td>Prefer speed over quality.</td>
436       * </tr>
437       * <tr>
438       *   <td>{@link #VALUE_COLOR_RENDER_QUALITY}</td>
439       *   <td>Prefer quality over speed.</td>
440       * </tr>
441       * <tr>
442       *   <td>{@link #VALUE_COLOR_RENDER_DEFAULT}</td>
443       *   <td>Use the default setting.</td>
444       * </tr>
445       * </table>
446       */
447      public static final Key KEY_COLOR_RENDERING;
448    
449      /**
450       * This value is for use with the {@link #KEY_COLOR_RENDERING} key.
451       */
452      public static final Object VALUE_COLOR_RENDER_SPEED
453        = "Fastest color rendering mode";
454    
455      /**
456       * This value is for use with the {@link #KEY_COLOR_RENDERING} key.
457       */
458      public static final Object VALUE_COLOR_RENDER_QUALITY
459        = "Highest quality color rendering mode";
460    
461      /**
462       * This value is for use with the {@link #KEY_COLOR_RENDERING} key.
463       */
464      public static final Object VALUE_COLOR_RENDER_DEFAULT
465        = "Default color rendering mode";
466    
467      /**
468       * A key for the 'stroke control' hint.  Permitted values are:
469       * <p>
470       * <table>
471       * <tr>
472       *   <td>{@link #VALUE_STROKE_DEFAULT}</td>
473       *   <td>Use the default setting.</td>
474       * </tr>
475       * <tr>
476       *   <td>{@link #VALUE_STROKE_NORMALIZE}</td>
477       *   <td>XXX</td>
478       * </tr>
479       * <tr>
480       *   <td>{@link #VALUE_STROKE_PURE}</td>
481       *   <td>XXX</td>
482       * </tr>
483       * </table>
484       */
485      public static final Key KEY_STROKE_CONTROL;
486    
487      /**
488       * This value is for use with the {@link #KEY_STROKE_CONTROL} key.
489       */
490      public static final Object VALUE_STROKE_DEFAULT
491        = "Default stroke normalization";
492    
493      /**
494       * This value is for use with the {@link #KEY_STROKE_CONTROL} key.
495       */
496      public static final Object VALUE_STROKE_NORMALIZE
497        = "Normalize strokes for consistent rendering";
498    
499      /**
500       * This value is for use with the {@link #KEY_STROKE_CONTROL} key.
501       */
502      public static final Object VALUE_STROKE_PURE
503        = "Pure stroke conversion for accurate paths";
504    
505      static
506      {
507        KEY_ANTIALIASING = new KeyImpl(1, "Global antialiasing enable key",
508                                       VALUE_ANTIALIAS_ON,
509                                       VALUE_ANTIALIAS_OFF,
510                                       VALUE_ANTIALIAS_DEFAULT);
511        KEY_RENDERING = new KeyImpl(2, "Global rendering quality key",
512                                    VALUE_RENDER_SPEED,
513                                    VALUE_RENDER_QUALITY,
514                                    VALUE_RENDER_DEFAULT);
515        KEY_DITHERING = new KeyImpl(3, "Dithering quality key",
516                                    VALUE_DITHER_DISABLE,
517                                    VALUE_DITHER_ENABLE,
518                                    VALUE_DITHER_DEFAULT);
519        KEY_TEXT_ANTIALIASING
520          = new KeyImpl(4, "Text-specific antialiasing enable key",
521                        VALUE_TEXT_ANTIALIAS_ON,
522                        VALUE_TEXT_ANTIALIAS_OFF,
523                        VALUE_TEXT_ANTIALIAS_DEFAULT);
524        KEY_FRACTIONALMETRICS = new KeyImpl(5, "Fractional metrics enable key",
525                                            VALUE_FRACTIONALMETRICS_OFF,
526                                            VALUE_FRACTIONALMETRICS_ON,
527                                            VALUE_FRACTIONALMETRICS_DEFAULT);
528        KEY_INTERPOLATION = new KeyImpl(6, "Image interpolation method key",
529                                        VALUE_INTERPOLATION_NEAREST_NEIGHBOR,
530                                        VALUE_INTERPOLATION_BILINEAR,
531                                        VALUE_INTERPOLATION_BICUBIC);
532        KEY_ALPHA_INTERPOLATION
533          = new KeyImpl(7, "Alpha blending interpolation method key",
534                        VALUE_ALPHA_INTERPOLATION_SPEED,
535                        VALUE_ALPHA_INTERPOLATION_QUALITY,
536                        VALUE_ALPHA_INTERPOLATION_DEFAULT);
537        KEY_COLOR_RENDERING = new KeyImpl(8, "Color rendering quality key",
538                                          VALUE_COLOR_RENDER_SPEED,
539                                          VALUE_COLOR_RENDER_QUALITY,
540                                          VALUE_COLOR_RENDER_DEFAULT);
541        KEY_STROKE_CONTROL = new KeyImpl(9, "Stroke normalization control key",
542                                         VALUE_STROKE_DEFAULT,
543                                         VALUE_STROKE_NORMALIZE,
544                                         VALUE_STROKE_PURE);
545      }
546    
547      /**
548       * Creates a new collection of hints containing all the (key, value) pairs
549       * in the specified map.
550       *
551       * @param init  a map containing a collection of hints (<code>null</code>
552       *              permitted).
553       */
554      public RenderingHints(Map<Key,?> init)
555      {
556        if (init != null)
557          putAll(init);
558      }
559    
560      /**
561       * Creates a new collection containing a single (key, value) pair.
562       *
563       * @param key  the key.
564       * @param value  the value.
565       */
566      public RenderingHints(Key key, Object value)
567      {
568        put(key, value);
569      }
570    
571      /**
572       * Returns the number of hints in the collection.
573       *
574       * @return The number of hints.
575       */
576      public int size()
577      {
578        return hintMap.size();
579      }
580    
581      /**
582       * Returns <code>true</code> if there are no hints in the collection,
583       * and <code>false</code> otherwise.
584       *
585       * @return A boolean.
586       */
587      public boolean isEmpty()
588      {
589        return hintMap.isEmpty();
590      }
591    
592      /**
593       * Returns <code>true</code> if the collection of hints contains the
594       * specified key, and <code>false</code> otherwise.
595       *
596       * @param key  the key (<code>null</code> not permitted).
597       *
598       * @return A boolean.
599       *
600       * @throws NullPointerException if <code>key</code> is <code>null</code>.
601       * @throws ClassCastException if <code>key</code> is not a {@link Key}.
602       */
603      public boolean containsKey(Object key)
604      {
605        if (key == null)
606          throw new NullPointerException();
607        // don't remove the cast, it is necessary to throw the required exception
608        return hintMap.containsKey((Key) key);
609      }
610    
611      /**
612       * Returns <code>true</code> if the collection of hints contains the
613       * specified value, and <code>false</code> otherwise.
614       *
615       * @param value  the value.
616       *
617       * @return A boolean.
618       */
619      public boolean containsValue(Object value)
620      {
621        return hintMap.containsValue(value);
622      }
623    
624      /**
625       * Returns the value associated with the specified key, or <code>null</code>
626       * if there is no value defined for the key.
627       *
628       * @param key  the key (<code>null</code> permitted).
629       *
630       * @return The value (possibly <code>null</code>).
631       *
632       * @throws ClassCastException if <code>key</code> is not a {@link Key}.
633       *
634       * @see #containsKey(Object)
635       */
636      public Object get(Object key)
637      {
638        // don't remove the cast, it is necessary to throw the required exception
639        return hintMap.get((Key) key);
640      }
641    
642      /**
643       * Adds a (key, value) pair to the collection of hints (if the
644       * collection already contains the specified key, then the
645       * value is updated).
646       *
647       * @param key  the key.
648       * @param value  the value.
649       *
650       * @return  the previous value of the key or <code>null</code> if the key
651       * didn't have a value yet.
652       */
653      public Object put(Object key, Object value)
654      {
655        if (key == null || value == null)
656          throw new NullPointerException();
657        if (! ((Key) key).isCompatibleValue(value))
658          throw new IllegalArgumentException();
659        return hintMap.put(key, value);
660      }
661    
662      /**
663       * Adds all the hints from a collection to this collection.
664       *
665       * @param hints  the hint collection.
666       */
667      public void add(RenderingHints hints)
668      {
669        hintMap.putAll(hints);
670      }
671    
672      /**
673       * Clears all the hints from this collection.
674       */
675      public void clear()
676      {
677        hintMap.clear();
678      }
679    
680      /**
681       * Removes a hint from the collection.
682       *
683       * @param key  the key.
684       *
685       * @return The value that was associated with the key, or <code>null</code> if
686       *         the key was not part of the collection
687       *
688       * @throws ClassCastException if the key is not a subclass of
689       *         {@link RenderingHints.Key}.
690       */
691      public Object remove(Object key)
692      {
693        // don't remove the (Key) cast, it is necessary to throw the exception
694        // required by the spec
695        return hintMap.remove((Key) key);
696      }
697    
698      /**
699       * Adds a collection of (key, value) pairs to the collection.
700       *
701       * @param m  a map containing (key, value) items.
702       *
703       * @throws ClassCastException if the map contains a key that is not
704       *         a subclass of {@link RenderingHints.Key}.
705       * @throws IllegalArgumentException if the map contains a value that is
706       *         not compatible with its key.
707       */
708      public void putAll(Map<?,?> m)
709      {
710        // preprocess map to generate appropriate exceptions
711        Iterator iterator = m.keySet().iterator();
712        while (iterator.hasNext())
713          {
714            Key key = (Key) iterator.next();
715            if (!key.isCompatibleValue(m.get(key)))
716              throw new IllegalArgumentException();
717          }
718        // map is OK, update
719        hintMap.putAll(m);
720      }
721    
722      /**
723       * Returns a set containing the keys from this collection.
724       *
725       * @return A set of keys.
726       */
727      public Set<Object> keySet()
728      {
729        return hintMap.keySet();
730      }
731    
732      /**
733       * Returns a collection of the values from this hint collection.  The
734       * collection is backed by the <code>RenderingHints</code> instance,
735       * so updates to one will affect the other.
736       *
737       * @return A collection of values.
738       */
739      public Collection<Object> values()
740      {
741        return hintMap.values();
742      }
743    
744      /**
745       * Returns a set of entries from the collection.
746       *
747       * @return A set of entries.
748       */
749      public Set<Map.Entry<Object,Object>> entrySet()
750      {
751        return Collections.unmodifiableSet(hintMap.entrySet());
752      }
753    
754      /**
755       * Checks this collection for equality with an arbitrary object.
756       *
757       * @param o  the object (<code>null</code> permitted)
758       *
759       * @return A boolean.
760       */
761      public boolean equals(Object o)
762      {
763        return hintMap.equals(o);
764      }
765    
766      /**
767       * Returns a hash code for the collection of hints.
768       *
769       * @return A hash code.
770       */
771      public int hashCode()
772      {
773        return hintMap.hashCode();
774      }
775    
776      /**
777       * Creates a clone of this instance.
778       *
779       * @return A clone.
780       */
781      public Object clone()
782      {
783        try
784          {
785            RenderingHints copy = (RenderingHints) super.clone();
786            copy.hintMap = new HashMap<Object,Object>(hintMap);
787            return copy;
788          }
789        catch (CloneNotSupportedException e)
790          {
791            throw (Error) new InternalError().initCause(e); // Impossible
792          }
793      }
794    
795      /**
796       * Returns a string representation of this instance.
797       *
798       * @return A string.
799       */
800      public String toString()
801      {
802        return hintMap.toString();
803      }
804    } // class RenderingHints