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