1 /*
2  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   - Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  *
11  *   - Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  *
15  *   - Neither the name of Oracle nor the names of its
16  *     contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * This source code is provided to illustrate the usage of a given feature
34  * or technique and has been deliberately simplified. Additional steps
35  * required for a production-quality application, such as security checks,
36  * input validation and proper error handling, might not be present in
37  * this sample code.
38  */
39 
40 
41 /*
42  * (C) Copyright IBM Corp. 2003, All Rights Reserved.
43  * This technology is protected by multiple US and International
44  * patents. This notice and attribution to IBM may not be removed.
45  */
46 
47 package j2dbench.tests.text;
48 
49 import java.awt.Color;
50 import java.awt.Font;
51 import java.awt.Graphics;
52 import java.awt.Graphics2D;
53 import java.awt.GraphicsEnvironment;
54 import java.awt.RenderingHints;
55 import java.awt.font.NumericShaper;
56 import java.awt.font.TextAttribute;
57 import java.awt.font.FontRenderContext;
58 import java.awt.geom.AffineTransform;
59 import java.io.InputStream;
60 import java.io.BufferedReader;
61 import java.io.InputStreamReader;
62 import java.io.IOException;
63 import java.io.PrintWriter;
64 import java.util.HashMap;
65 import java.util.HashSet;
66 import java.util.Map;
67 import java.util.Set;
68 import javax.swing.JComponent;
69 
70 import j2dbench.Destinations;
71 import j2dbench.Group;
72 import j2dbench.Node;
73 import j2dbench.Option;
74 import j2dbench.Option.ObjectList;
75 import j2dbench.Result;
76 import j2dbench.Test;
77 import j2dbench.TestEnvironment;
78 
79 public abstract class TextTests extends Test {
80     public static boolean hasGraphics2D;
81 
82     static {
83         try {
84             hasGraphics2D = (Graphics2D.class != null);
85         } catch (NoClassDefFoundError e) {
86         }
87     }
88 
89     // core data
90     static final int[] tlengths = {
91         1, 2, 4, 8, 16, 32, 64, 128, 256, 512
92     };
93 
94     static final String[] tscripts = {
95         // german, vietnamese, surrogate, dingbats
96         "english", "arabic", "greek", "hebrew", "hindi", "japanese", "korean", "thai",
97         "english-arabic", "english-greek", "english-hindi", "english-arabic-hindi"
98     };
99 
100     static final float[] fsizes = {
101         1f, 6f, 8f, 10f, 12f, 12.5f, 13f, 13.5f, 16f, 20f, 36f, 72f, 128f
102     };
103 
104     static final float[] fintsizes = {
105         1f, 6f, 8f, 10f, 12f, 13f, 16f, 20f, 36f, 72f, 128f
106     };
107 
108     // utilties
floatObjectList(float[] input)109     static Float[] floatObjectList(float[] input) {
110         Float[] result = new Float[input.length];
111         for (int i = 0; i < result.length; ++i) {
112             result[i] = new Float(input[i]);
113         }
114         return result;
115     }
116 
floatStringList(float[] input)117     static String[] floatStringList(float[] input) {
118         return floatStringList("", input, "");
119     }
120 
floatStringList(float[] input, String sfx)121     static String[] floatStringList(float[] input, String sfx) {
122         return floatStringList("", input, sfx);
123     }
124 
floatStringList(String pfx, float[] input, String sfx)125     static String[] floatStringList(String pfx, float[] input, String sfx) {
126         String[] result = new String[input.length];
127         for (int i = 0; i < result.length; ++i) {
128             result[i] = pfx + input[i] + sfx;
129         }
130         return result;
131     }
132 
intStringList(int[] input)133     static String[] intStringList(int[] input) {
134         return intStringList("", input, "");
135     }
136 
intStringList(int[] input, String sfx)137     static String[] intStringList(int[] input, String sfx) {
138         return intStringList("", input, sfx);
139     }
140 
intStringList(String pfx, int[] input, String sfx)141     static String[] intStringList(String pfx, int[] input, String sfx) {
142         String[] result = new String[input.length];
143         for (int i = 0; i < result.length; ++i) {
144             result[i] = pfx + input[i] + sfx;
145         }
146         return result;
147     }
148 
149     static final String[] txNames;
150     static final String[] txDescNames;
151     static final AffineTransform[] txList;
152     static final Map[] maps;
153     static {
154         AffineTransform identity = new AffineTransform();
155         AffineTransform sm_scale = AffineTransform.getScaleInstance(.5, .5);
156         AffineTransform lg_scale = AffineTransform.getScaleInstance(2, 2);
157         AffineTransform wide = AffineTransform.getScaleInstance(2, .8);
158         AffineTransform tall = AffineTransform.getScaleInstance(.8, 2);
159         AffineTransform x_trans = AffineTransform.getTranslateInstance(50, 0);
160         AffineTransform y_trans = AffineTransform.getTranslateInstance(0, -30);
161         AffineTransform xy_trans = AffineTransform.getTranslateInstance(50, -30);
162         AffineTransform sm_rot = AffineTransform.getRotateInstance(Math.PI / 3);
163         AffineTransform lg_rot = AffineTransform.getRotateInstance(Math.PI * 4 / 3);
164         AffineTransform pi2_rot = AffineTransform.getRotateInstance(Math.PI / 2);
165         AffineTransform x_shear = AffineTransform.getShearInstance(.4, 0);
166         AffineTransform y_shear = AffineTransform.getShearInstance(0, -.4);
167         AffineTransform xy_shear = AffineTransform.getShearInstance(.3, .3);
168         AffineTransform x_flip = AffineTransform.getScaleInstance(-1, 1);
169         AffineTransform y_flip = AffineTransform.getScaleInstance(1, -1);
170         AffineTransform xy_flip = AffineTransform.getScaleInstance(-1, -1);
171         AffineTransform w_rot = AffineTransform.getRotateInstance(Math.PI / 3);
172         w_rot.scale(2, .8);
173         AffineTransform w_y_shear = AffineTransform.getShearInstance(0, -.4);
174         w_y_shear.scale(2, .8);
175         AffineTransform w_r_trans = AffineTransform.getTranslateInstance(3, -7);
176         w_r_trans.rotate(Math.PI / 3);
177         w_r_trans.scale(2, .8);
178         AffineTransform w_t_rot = AffineTransform.getRotateInstance(Math.PI / 3);
179         w_t_rot.translate(3, -7);
180         w_t_rot.scale(2, .8);
181         AffineTransform w_y_s_r_trans = AffineTransform.getTranslateInstance(3, -7);
182         w_y_s_r_trans.rotate(Math.PI / 3);
183         w_y_s_r_trans.shear(0, -.4);
184         w_y_s_r_trans.scale(2, .8);
185 
186         txNames = new String[] {
187             "ident",
188             "smsc", "lgsc", "wide", "tall",
189             "xtrn", "ytrn", "xytrn",
190             "srot", "lrot", "hrot",
191             "xshr", "yshr", "xyshr",
192             "flx", "fly", "flxy",
193             "wr", "wys", "wrt",
194             "wtr", "wysrt"
195         };
196 
197         txDescNames = new String[] {
198             "Identity",
199             "Sm Scale", "Lg Scale", "Wide", "Tall",
200             "X Trans", "Y Trans", "XY Trans",
201             "Sm Rot", "Lg Rot", "PI/2 Rot",
202             "X Shear", "Y Shear", "XY Shear",
203             "FlipX", "FlipY", "FlipXY",
204             "WRot", "WYShear", "WRTrans",
205             "WTRot", "WYSRTrans"
206         };
207 
208         txList = new AffineTransform[] {
209             identity,
210             sm_scale, lg_scale, wide, tall,
211             x_trans, y_trans, xy_trans,
212             sm_rot, lg_rot, pi2_rot,
213             x_shear, y_shear, xy_shear,
214             x_flip, y_flip, xy_flip,
215             w_rot, w_y_shear, w_r_trans,
216             w_t_rot, w_y_s_r_trans,
217         };
218 
219         // maps
220         HashMap fontMap = new HashMap();
fontMap.put(TextAttribute.FONT, new Font(R, Font.ITALIC, 18))221         fontMap.put(TextAttribute.FONT, new Font("Dialog", Font.ITALIC, 18));
222 
223         HashMap emptyMap = new HashMap();
224 
225         HashMap simpleMap = new HashMap();
simpleMap.put(TextAttribute.FAMILY, R)226         simpleMap.put(TextAttribute.FAMILY, "Lucida Sans");
simpleMap.put(TextAttribute.SIZE, new Float(14))227         simpleMap.put(TextAttribute.SIZE, new Float(14));
simpleMap.put(TextAttribute.FOREGROUND, Color.blue)228         simpleMap.put(TextAttribute.FOREGROUND, Color.blue);
229 
230         HashMap complexMap = new HashMap();
complexMap.put(TextAttribute.FAMILY, R)231         complexMap.put(TextAttribute.FAMILY, "Serif");
complexMap.put(TextAttribute.TRANSFORM, tall)232         complexMap.put(TextAttribute.TRANSFORM, tall);
complexMap.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON)233         complexMap.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
complexMap.put(TextAttribute.RUN_DIRECTION, TextAttribute.RUN_DIRECTION_RTL)234         complexMap.put(TextAttribute.RUN_DIRECTION,
235                        TextAttribute.RUN_DIRECTION_RTL);
236         try {
complexMap.put(TextAttribute.NUMERIC_SHAPING, NumericShaper.getContextualShaper(NumericShaper.ALL_RANGES))237             complexMap.put(TextAttribute.NUMERIC_SHAPING,
238                            NumericShaper.getContextualShaper(NumericShaper.ALL_RANGES));
239         } catch (NoSuchFieldError e) {
240         }
241 
242         maps = new Map[] {
243             fontMap,
244             emptyMap,
245             simpleMap,
246             complexMap,
247         };
248     }
249 
getString(Object key, int len)250     static String getString(Object key, int len) {
251         String keyString = key.toString();
252         String[] strings = new String[4]; // leave room for index == 3 to return null
253         int span = Math.min(32, len);
254         int n = keyString.indexOf('-');
255         if (n == -1) {
256             strings[0] = getSimpleString(keyString);
257         } else {
258             strings[0] = getSimpleString(keyString.substring(0, n));
259             int m = keyString.indexOf('-', n+1);
260             if (m == -1) {
261                 strings[1] = getSimpleString(keyString.substring(n+1));
262                 // 2 to 1 ratio, short spans between 1 and 16 chars long
263                 span = Math.max(1, Math.min(16, len / 3));
264             } else {
265                 strings[1] = getSimpleString(keyString.substring(n+1, m));
266                 strings[2] = getSimpleString(keyString.substring(m+1));
267                 span = Math.max(1, Math.min(16, len / 4));
268             }
269         }
270         String s = "";
271         int pos = 0;
272         int strx = 0;
273         while (s.length() < len) {
274             String src;
275             if (strings[strx] == null) {
276                 src = strings[0]; // use strings[0] twice for each other string
277                 strx = 0;
278             } else {
279                 src = strings[strx++];
280             }
281             if (pos + span > src.length()) {
282                 pos = 0; // we know all strings are longer than span
283             }
284             s += src.substring(pos, pos+span);
285             pos += span;
286         }
287         return s.substring(0, len);
288     }
289 
290 
291     static HashMap strcache = new HashMap(tscripts.length);
getSimpleString(Object key)292     private static String getSimpleString(Object key) {
293         String s = (String)strcache.get(key);
294         if (s == null) {
295             String fname = "textdata/" + key + ".ut8.txt";
296             try {
297                 InputStream is = TextTests.class.getResourceAsStream(fname);
298                 if (is == null) {
299                     throw new IOException("Can't load resource " + fname);
300                 }
301                 BufferedReader r =
302                     new BufferedReader(new InputStreamReader(is, "utf8"));
303                 StringBuffer buf = new StringBuffer(r.readLine());
304                 while (null != (s = r.readLine())) {
305                     buf.append("  ");
306                     buf.append(s);
307                 }
308                 s = buf.toString();
309                 if (s.charAt(0) == '\ufeff') {
310                     s = s.substring(1);
311                 }
312             }
313             catch (IOException e) {
314                 s = "This is a dummy ascii string because " +
315                     fname + " was not found.";
316             }
317             strcache.put(key, s);
318         }
319         return s;
320     }
321 
322     static Group textroot;
323     static Group txoptroot;
324     static Group txoptdataroot;
325     static Group txoptfontroot;
326     static Group txoptgraphicsroot;
327     static Group advoptsroot;
328 
329     static Option tlengthList;
330     static Option tscriptList;
331     static Option fnameList;
332     static Option fstyleList;
333     static Option fsizeList;
334     static Option ftxList;
335     static Option taaList;
336     static Option tfmTog;
337     static Option gaaTog;
338     static Option gtxList;
339     static Option gvstyList;
340     static Option tlrunList;
341     static Option tlmapList;
342 
343     // core is textlength, text script, font name/style/size/tx, frc
344 
345     // drawing
346     //   drawString, drawChars, drawBytes, drawGlyphVector, TextLayout.draw, drawAttributedString
347     // length of text
348     //   1, 2, 4, 8, 16, 32, 64, 128, 256 chars
349     // script of text
350     //   simple: latin-1, japanese, arabic, hebrew, indic, thai, surrogate, dingbats
351     //   mixed:  latin-1 + x  (1, 2, 3, 4 pairs)
352     // font of text
353     //   name (composite, not), style, size (6, 12, 18, 24, 30, 36, 42, 48, 54, 60), transform (full set)
354     // text rendering hints
355     //   aa, fm, gaa
356     // graphics transform (full set)
357     // (gv) gtx, gpos
358     // (tl, as) num style runs
359     //
360     // querying/measuring
361     //   ascent/descent/leading
362     //   advance
363     //   (gv) lb, vb, pb, glb, gvb, glb, gp, gjust, gmet, gtx
364     //   (tl) bounds, charpos, cursor
365     //
366     // construction/layout
367     //   (bidi) no controls, controls, styles
368     //   (gv) createGV, layoutGV
369     //   (tl) TL constructors
370     //   (tm) line break
371 
init()372     public static void init() {
373         textroot = new Group("text", "Text Benchmarks");
374         textroot.setTabbed();
375 
376         txoptroot = new Group(textroot, "opts", "Text Options");
377         txoptroot.setTabbed();
378 
379         txoptdataroot = new Group(txoptroot, "data", "Text Data");
380 
381         tlengthList = new Option.IntList(txoptdataroot, "tlength",
382                                         "Text Length",
383                                         tlengths,
384                                         intStringList(tlengths),
385                                         intStringList(tlengths, " chars"),
386                                         0x10);
387         ((Option.ObjectList) tlengthList).setNumRows(5);
388 
389         tscriptList = new Option.ObjectList(txoptdataroot, "tscript",
390                                             "Text Script",
391                                             tscripts,
392                                             tscripts,
393                                             tscripts,
394                                             tscripts,
395                                             0x1);
396         ((Option.ObjectList) tscriptList).setNumRows(4);
397 
398         txoptfontroot = new Group(txoptroot, "font", "Font");
399 
400         fnameList = new FontOption(txoptfontroot, "fname", "Family Name");
401 
402         fstyleList = new Option.IntList(txoptfontroot, "fstyle",
403                                         "Style",
404                                         new int[] {
405                                             Font.PLAIN, Font.BOLD, Font.ITALIC, Font.BOLD + Font.ITALIC,
406                                         },
407                                         new String[] {
408                                             "plain", "bold", "italic", "bolditalic",
409                                         },
410                                         new String[] {
411                                             "Plain", "Bold", "Italic", "Bold Italic",
412                                         },
413                                         0x1);
414 
415         float[] fsl = hasGraphics2D ? fsizes : fintsizes;
416         fsizeList = new Option.ObjectList(txoptfontroot, "fsize",
417                                           "Size",
418                                           floatStringList(fsl),
419                                           floatObjectList(fsl),
420                                           floatStringList(fsl),
421                                           floatStringList(fsl, "pt"),
422                                           0x40);
423         ((Option.ObjectList) fsizeList).setNumRows(5);
424 
425         if (hasGraphics2D) {
426             ftxList = new Option.ObjectList(txoptfontroot, "ftx",
427                                             "Transform",
428                                             txDescNames,
429                                             txList,
430                                             txNames,
431                                             txDescNames,
432                                             0x1);
433             ((Option.ObjectList) ftxList).setNumRows(6);
434 
435             txoptgraphicsroot = new Group(txoptroot, "graphics", "Graphics");
436 
437             String[] taaNames;
438             Object[] taaHints;
439             try {
440                 taaNames = new String[] {
441                     "Off", "On",
442                     "LCD_HRGB", "LCD_HBGR", "LCD_VRGB", "LCD_VBGR"
443                 };
444                 taaHints = new Object[] {
445                     RenderingHints.VALUE_TEXT_ANTIALIAS_OFF,
446                     RenderingHints.VALUE_TEXT_ANTIALIAS_ON,
447                     RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB,
448                     RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR,
449                     RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB,
450                     RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR,
451                 };
452             } catch (NoSuchFieldError e) {
453                 taaNames = new String[] {
454                     "Off", "On"
455                 };
456                 taaHints = new Object[] {
457                     RenderingHints.VALUE_TEXT_ANTIALIAS_OFF,
458                     RenderingHints.VALUE_TEXT_ANTIALIAS_ON,
459                 };
460             }
461             taaList = new Option.ObjectList(txoptgraphicsroot, "textaa",
462                                             "Text AntiAlias",
463                                             taaNames, taaHints,
464                                             taaNames, taaNames,
465                                             0x1);
466             ((Option.ObjectList) taaList).setNumRows(6);
467             // add special TextAAOpt for backwards compatibility with
468             // older options files
469             new TextAAOpt();
470 
471             tfmTog = new Option.Toggle(txoptgraphicsroot, "tfm",
472                                        "Fractional Metrics", Option.Toggle.Off);
473             gaaTog = new Option.Toggle(txoptgraphicsroot, "gaa",
474                                        "Graphics AntiAlias", Option.Toggle.Off);
475 
476             gtxList = new Option.ObjectList(txoptgraphicsroot, "gtx",
477                                             "Transform",
478                                             txDescNames,
479                                             txList,
480                                             txNames,
481                                             txDescNames,
482                                             0x1);
483             ((Option.ObjectList) gtxList).setNumRows(6);
484 
485             advoptsroot = new Group(txoptroot, "advopts", "Advanced Options");
486             gvstyList = new Option.IntList(advoptsroot, "gvstyle", "Style",
487                                            new int[] { 0, 1, 2, 3 },
488                                            new String[] { "std", "wave", "twist", "circle" },
489                                            new String[] { "Standard",
490                                                           "Positions adjusted",
491                                                           "Glyph angles adjusted",
492                                                           "Layout to circle"
493                                            },
494                                            0x1);
495 
496             int[] runs = { 1, 2, 4, 8 };
497             tlrunList = new Option.IntList(advoptsroot, "tlruns", "Attribute Runs",
498                                            runs,
499                                            intStringList(runs),
500                                            intStringList(runs, " runs"),
501                                            0x1);
502 
503             String[] tlmapnames = new String[] { "FONT", "Empty", "Simple", "Complex" };
504             tlmapList = new Option.ObjectList(advoptsroot, "maptype", "Map",
505                                               tlmapnames,
506                                               maps,
507                                               new String[] { "font", "empty", "simple", "complex" },
508                                               tlmapnames,
509                                               0x1);
510         }
511     }
512 
513     /**
514      * This "virtual Node" implementation is here to maintain backward
515      * compatibility with older J2DBench releases, specifically those
516      * options files that were created before we added LCD-optimized text
517      * hints in JDK 6.  This class will translate the text antialias settings
518      * from the old "taa" On/Off/Both choice into the new expanded version.
519      */
520     private static class TextAAOpt extends Node {
TextAAOpt()521         public TextAAOpt() {
522             super(txoptgraphicsroot, "taa", "Text AntiAlias");
523         }
524 
getJComponent()525         public JComponent getJComponent() {
526             return null;
527         }
528 
restoreDefault()529         public void restoreDefault() {
530             // no-op
531         }
532 
write(PrintWriter pw)533         public void write(PrintWriter pw) {
534             // no-op (the old "taa" choice will be saved as part of the
535             // new "textaa" option)
536         }
537 
setOption(String key, String value)538         public String setOption(String key, String value) {
539             String opts;
540             if (value.equals("On")) {
541                 opts = "On";
542             } else if (value.equals("Off")) {
543                 opts = "Off";
544             } else if (value.equals("Both")) {
545                 opts = "On,Off";
546             } else {
547                 return "Bad value";
548             }
549             return ((Option.ObjectList)taaList).setValueFromString(opts);
550         }
551     }
552 
553     public static class Context {
init(TestEnvironment env, Result result)554         void init(TestEnvironment env, Result result) {}
cleanup(TestEnvironment env)555         void cleanup(TestEnvironment env) {}
556     }
557 
558     public static class TextContext extends Context {
559         Graphics graphics;
560         String text;
561         char[] chars;
562         Font font;
563 
init(TestEnvironment env, Result result)564         public void init(TestEnvironment env, Result result) {
565             // graphics
566             graphics = env.getGraphics();
567 
568             // text
569             String sname = (String)env.getModifier(tscriptList);
570             int slen = env.getIntValue(tlengthList);
571             text = getString(sname, slen);
572 
573             // chars
574             chars = text.toCharArray();
575 
576             // font
577             String fname = (String)env.getModifier(fnameList);
578             if ("Physical".equals(fname)) {
579                 fname = physicalFontNameFor(sname, slen, text);
580             }
581             int fstyle = env.getIntValue(fstyleList);
582             float fsize = ((Float)env.getModifier(fsizeList)).floatValue();
583             AffineTransform ftx = (AffineTransform)env.getModifier(ftxList);
584             font = new Font(fname, fstyle, (int)fsize);
585             if (hasGraphics2D) {
586                 if (fsize != Math.floor(fsize)) {
587                     font = font.deriveFont(fsize);
588                 }
589                 if (!ftx.isIdentity()) {
590                     font = font.deriveFont(ftx);
591                 }
592             }
593 
594             // graphics
595             if (hasGraphics2D) {
596                 Graphics2D g2d = (Graphics2D)graphics;
597                 g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
598                                      env.getModifier(taaList));
599                 g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
600                                      env.isEnabled(tfmTog)
601                                      ? RenderingHints.VALUE_FRACTIONALMETRICS_ON
602                                      : RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
603                 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
604                                      env.isEnabled(gaaTog)
605                                      ? RenderingHints.VALUE_ANTIALIAS_ON
606                                      : RenderingHints.VALUE_ANTIALIAS_OFF);
607                 g2d.transform((AffineTransform)env.getModifier(gtxList));
608             }
609 
610             // set result
611             result.setUnits(text.length());
612             result.setUnitName("char");
613         }
614 
cleanup(TestEnvironment env)615         public void cleanup(TestEnvironment env) {
616             graphics.dispose();
617             graphics = null;
618         }
619     }
620 
621     public static class G2DContext extends TextContext {
622         Graphics2D g2d;
623         FontRenderContext frc;
624 
init(TestEnvironment env, Result results)625         public void init(TestEnvironment env, Result results){
626             super.init(env, results);
627             g2d = (Graphics2D)graphics;
628             frc = g2d.getFontRenderContext();
629         }
630     }
631 
TextTests(Group parent, String nodeName, String description)632     public TextTests(Group parent, String nodeName, String description) {
633         super(parent, nodeName, description);
634         addDependency(Destinations.destroot);
635         addDependencies(txoptroot, true);
636     }
637 
createContext()638     public Context createContext() {
639         return new TextContext();
640     }
641 
initTest(TestEnvironment env, Result result)642     public Object initTest(TestEnvironment env, Result result) {
643         Context ctx = createContext();
644         ctx.init(env, result);
645         return ctx;
646     }
647 
cleanupTest(TestEnvironment env, Object ctx)648     public void cleanupTest(TestEnvironment env, Object ctx) {
649         ((Context)ctx).cleanup(env);
650     }
651 
652     static Map physicalMap = new HashMap();
physicalFontNameFor(String textname, int textlen, String text)653     public static String physicalFontNameFor(String textname, int textlen, String text) {
654         Map lenMap = (Map)physicalMap.get(textname);
655         if (lenMap == null) {
656             lenMap = new HashMap();
657             physicalMap.put(textname, lenMap);
658         }
659         Integer key = new Integer(textlen);
660         Font textfont = (Font)lenMap.get(key);
661         if (textfont == null) {
662             Font[] fontsToTry = null;
663             if (lenMap.isEmpty()) {
664                 fontsToTry = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
665             } else {
666                 Set fontset = new HashSet();
667                 java.util.Iterator iter = lenMap.entrySet().iterator();
668                 while (iter.hasNext()) {
669                     Map.Entry e = (Map.Entry)iter.next();
670                     fontset.add(e.getValue());
671                 }
672                 fontsToTry = (Font[])fontset.toArray(new Font[fontset.size()]);
673             }
674 
675             Font bestFont = null;
676             int bestCount = 0;
677             for (int i = 0; i < fontsToTry.length; ++i) {
678                 Font font = fontsToTry[i];
679                 int count = 0;
680                 for (int j = 0, limit = text.length(); j < limit; ++j) {
681                     if (font.canDisplay(text.charAt(j))) {
682                         ++count;
683                     }
684                 }
685                 if (count > bestCount) {
686                     bestFont = font;
687                     bestCount = count;
688                 }
689             }
690 
691             textfont = bestFont;
692             lenMap.put(key, textfont);
693         }
694         return textfont.getName();
695     }
696 
697     static class FontOption extends ObjectList {
698         static String[] optionnames = {
699             "default", "serif", "lucida", "physical"
700         };
701         static String[] descnames = {
702             "Default", "Serif", "Lucida Sans", "Physical"
703         };
704 
FontOption(Group parent, String nodeName, String description)705         public FontOption(Group parent, String nodeName, String description) {
706             super(parent, nodeName, description,
707                   optionnames, descnames, optionnames, descnames, 0xa);
708         }
709 
getValString(Object value)710         public String getValString(Object value) {
711             return value.toString();
712         }
713 
getAbbreviatedModifierDescription(Object value)714         public String getAbbreviatedModifierDescription(Object value) {
715             return value.toString();
716         }
717     }
718 }
719 
720