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.Font;
  50 import java.awt.FontMetrics;
  51 import java.awt.Rectangle;
  52 import java.awt.Shape;
  53 import java.awt.font.GlyphMetrics;
  54 import java.awt.font.GlyphVector;
  55 import java.awt.font.TextHitInfo;
  56 import java.awt.font.TextLayout;
  57 import java.awt.geom.AffineTransform;
  58 import java.awt.geom.Rectangle2D;
  59 import java.text.Bidi;
  60 import java.util.ArrayList;
  61 
  62 import j2dbench.Group;
  63 import j2dbench.Result;
  64 import j2dbench.TestEnvironment;
  65 
  66 public abstract class TextMeasureTests extends TextTests {
  67     static Group measureroot;
  68     static Group measuretestroot;
  69 
  70     public static void init() {
  71         measureroot = new Group(textroot, "Measuring", "Measuring Benchmarks");
  72         measuretestroot = new Group(measureroot, "tests", "Measuring Tests");
  73 
  74         new StringWidth();
  75         new StringBounds();
  76         new CharsWidth();
  77         new CharsBounds();
  78         new FontCanDisplay();
  79 
  80         if (hasGraphics2D) {
  81             new GVWidth();
  82             new GVLogicalBounds();
  83             new GVVisualBounds();
  84             new GVPixelBounds();
  85             new GVOutline();
  86             new GVGlyphLogicalBounds();
  87             new GVGlyphVisualBounds();
  88             new GVGlyphPixelBounds();
  89             new GVGlyphOutline();
  90             new GVGlyphTransform();
  91             new GVGlyphMetrics();
  92 
  93             new TLAdvance();
  94             new TLAscent();
  95             new TLBounds();
  96             new TLGetCaretInfo();
  97             new TLGetNextHit();
  98             new TLGetCaretShape();
  99             new TLGetLogicalHighlightShape();
 100             new TLHitTest();
 101             new TLOutline();
 102 
 103         /*
 104             new FontLineMetrics();
 105             new FontStringBounds();
 106         */
 107         }
 108     }
 109 
 110     public TextMeasureTests(Group parent, String nodeName, String description) {
 111         super(parent, nodeName, description);
 112     }
 113 
 114     static class SWContext extends TextContext {
 115         FontMetrics fm;
 116 
 117         public void init(TestEnvironment env, Result results) {
 118             super.init(env, results);
 119             fm = graphics.getFontMetrics(font);
 120         }
 121     }
 122 
 123     public Context createContext() {
 124         return new SWContext();
 125     }
 126 
 127     public static class StringWidth extends TextMeasureTests {
 128         public StringWidth() {
 129             super(measuretestroot, "stringWidth", "Measuring String Width");
 130         }
 131 
 132         public void runTest(Object ctx, int numReps) {
 133             SWContext swctx = (SWContext)ctx;
 134             String text = swctx.text;
 135             FontMetrics fm = swctx.fm;
 136             int wid = 0;
 137             do {
 138                 wid += fm.stringWidth(text);
 139             } while (--numReps >= 0);
 140         }
 141     }
 142 
 143     public static class StringBounds extends TextMeasureTests {
 144         public StringBounds() {
 145             super(measuretestroot, "stringBounds", "Measuring String Bounds");
 146         }
 147 
 148         public void runTest(Object ctx, int numReps) {
 149             SWContext swctx = (SWContext)ctx;
 150             String text = swctx.text;
 151             FontMetrics fm = swctx.fm;
 152             int wid = 0;
 153             Rectangle r = null;
 154             do {
 155                 r = null;
 156                 int dx = fm.stringWidth(text);
 157                 int dy = fm.getAscent() + fm.getDescent() + fm.getLeading();
 158                 int x = 0;
 159                 int y = -fm.getAscent();
 160                 r = new Rectangle(x, y, dx, dy);
 161             } while (--numReps >= 0);
 162         }
 163     }
 164 
 165     public static class CharsWidth extends TextMeasureTests {
 166         public CharsWidth() {
 167             super(measuretestroot, "charsWidth", "Measuring Chars Width");
 168         }
 169 
 170         public void runTest(Object ctx, int numReps) {
 171             SWContext swctx = (SWContext)ctx;
 172             FontMetrics fm = swctx.fm;
 173             char[] chars = swctx.chars;
 174             int wid = 0;
 175             do {
 176                 wid += fm.charsWidth(chars, 0, chars.length);
 177             } while (--numReps >= 0);
 178         }
 179     }
 180 
 181     public static class CharsBounds extends TextMeasureTests {
 182         public CharsBounds() {
 183             super(measuretestroot, "charsBounds", "Measuring Chars Bounds");
 184         }
 185 
 186         public void runTest(Object ctx, int numReps) {
 187             SWContext swctx = (SWContext)ctx;
 188             FontMetrics fm = swctx.fm;
 189             char[] chars = swctx.chars;
 190             int wid = 0;
 191             Rectangle r = null;
 192             do {
 193                 r = null;
 194                 int dx = fm.charsWidth(chars, 0, chars.length);
 195                 int dy = fm.getAscent() + fm.getDescent() + fm.getLeading();
 196                 int x = 0;
 197                 int y = -fm.getAscent();
 198                 r = new Rectangle(x, y, dx, dy);
 199             } while (--numReps >= 0);
 200         }
 201     }
 202 
 203     public static class FontCanDisplay extends TextMeasureTests {
 204         public FontCanDisplay() {
 205             super(measuretestroot, "fontcandisplay", "Font canDisplay(char)");
 206         }
 207 
 208         public void runTest(Object ctx, int numReps) {
 209             Font font = ((TextContext)ctx).font;
 210             boolean b = false;
 211             do {
 212                 for (int i = 0; i < 0x10000; i += 0x64) {
 213                     b ^= font.canDisplay((char)i);
 214                 }
 215             } while (--numReps >= 0);
 216         }
 217     }
 218 
 219     public static class GVContext extends G2DContext {
 220         GlyphVector gv;
 221 
 222         public void init(TestEnvironment env, Result results) {
 223             super.init(env, results);
 224 
 225             int flags = Font.LAYOUT_LEFT_TO_RIGHT;
 226             if (Bidi.requiresBidi(chars, 0, chars.length)) { // assume rtl
 227                 flags = Font.LAYOUT_RIGHT_TO_LEFT;
 228             }
 229             gv = font.layoutGlyphVector(frc, chars, 0, chars.length, flags);
 230 
 231             // gv options
 232         }
 233     }
 234 
 235     public static abstract class GVMeasureTest extends TextMeasureTests {
 236         protected GVMeasureTest(Group parent, String nodeName, String description) {
 237             super(parent, nodeName, description);
 238         }
 239 
 240         public Context createContext() {
 241             return new GVContext();
 242         }
 243     }
 244 
 245     public static class GVWidth extends GVMeasureTest {
 246         public GVWidth() {
 247             super(measuretestroot, "gvWidth", "Measuring GV Width");
 248         }
 249 
 250         public void runTest(Object ctx, int numReps) {
 251             GVContext gvctx = (GVContext)ctx;
 252             GlyphVector gv = gvctx.gv;
 253             double wid = 0;
 254             do {
 255                 wid += gv.getGlyphPosition(gv.getNumGlyphs()).getX();
 256             } while (--numReps >= 0);
 257         }
 258     }
 259 
 260     public static class GVLogicalBounds extends GVMeasureTest {
 261         public GVLogicalBounds() {
 262             super(measuretestroot, "gvLogicalBounds", "Measuring GV Logical Bounds");
 263         }
 264 
 265         public void runTest(Object ctx, int numReps) {
 266             GVContext gvctx = (GVContext)ctx;
 267             GlyphVector gv = gvctx.gv;
 268             Rectangle2D r;
 269             do {
 270                 r = gv.getLogicalBounds();
 271             } while (--numReps >= 0);
 272         }
 273     }
 274 
 275     public static class GVVisualBounds extends GVMeasureTest {
 276         public GVVisualBounds() {
 277             super(measuretestroot, "gvVisualBounds", "Measuring GV Visual Bounds");
 278         }
 279 
 280         public void runTest(Object ctx, int numReps) {
 281             GVContext gvctx = (GVContext)ctx;
 282             GlyphVector gv = gvctx.gv;
 283             Rectangle2D r;
 284             do {
 285                 r = gv.getVisualBounds();
 286             } while (--numReps >= 0);
 287         }
 288     }
 289 
 290     public static class GVPixelBounds extends GVMeasureTest {
 291         public GVPixelBounds() {
 292             super(measuretestroot, "gvPixelBounds", "Measuring GV Pixel Bounds");
 293         }
 294 
 295         public void runTest(Object ctx, int numReps) {
 296             GVContext gvctx = (GVContext)ctx;
 297             GlyphVector gv = gvctx.gv;
 298             Rectangle2D r;
 299             do {
 300                 r = gv.getPixelBounds(null, 0, 0); // !!! add opt to provide different frc?
 301             } while (--numReps >= 0);
 302         }
 303     }
 304 
 305     public static class GVOutline extends GVMeasureTest {
 306         public GVOutline() {
 307             super(measuretestroot, "gvOutline", "Getting GV Outline");
 308         }
 309 
 310         public void runTest(Object ctx, int numReps) {
 311             GVContext gvctx = (GVContext)ctx;
 312             GlyphVector gv = gvctx.gv;
 313             Shape s;
 314             do {
 315                 s = gv.getOutline();
 316             } while (--numReps >= 0);
 317         }
 318     }
 319 
 320     public static class GVGlyphLogicalBounds extends GVMeasureTest {
 321         public GVGlyphLogicalBounds() {
 322             super(measuretestroot, "gvGlyphLogicalBounds", "Measuring GV Glyph Logical Bounds");
 323         }
 324 
 325         public void runTest(Object ctx, int numReps) {
 326             GVContext gvctx = (GVContext)ctx;
 327             GlyphVector gv = gvctx.gv;
 328             Shape s;
 329             do {
 330                 for (int i = 0, e = gv.getNumGlyphs(); i < e; ++i) {
 331                     s = gv.getGlyphLogicalBounds(i);
 332                 }
 333             } while (--numReps >= 0);
 334         }
 335     }
 336 
 337     public static class GVGlyphVisualBounds extends GVMeasureTest {
 338         public GVGlyphVisualBounds() {
 339             super(measuretestroot, "gvGlyphVisualBounds", "Measuring GV Glyph Visual Bounds");
 340         }
 341 
 342         public void runTest(Object ctx, int numReps) {
 343             GVContext gvctx = (GVContext)ctx;
 344             GlyphVector gv = gvctx.gv;
 345             Shape s;
 346             do {
 347                 for (int i = 0, e = gv.getNumGlyphs(); i < e; ++i) {
 348                     s = gv.getGlyphVisualBounds(i);
 349                 }
 350             } while (--numReps >= 0);
 351         }
 352     }
 353 
 354 
 355     public static class GVGlyphPixelBounds extends GVMeasureTest {
 356         public GVGlyphPixelBounds() {
 357             super(measuretestroot, "gvGlyphPixelBounds", "Measuring GV Glyph Pixel Bounds");
 358         }
 359 
 360         public void runTest(Object ctx, int numReps) {
 361             GVContext gvctx = (GVContext)ctx;
 362             GlyphVector gv = gvctx.gv;
 363             Rectangle2D r;
 364             do {
 365                 for (int i = 0, e = gv.getNumGlyphs(); i < e; ++i) {
 366                     r = gv.getGlyphPixelBounds(i, null, 0, 0); // !!! add opt to provide different frc?
 367                 }
 368             } while (--numReps >= 0);
 369         }
 370     }
 371 
 372     public static class GVGlyphOutline extends GVMeasureTest {
 373         public GVGlyphOutline() {
 374             super(measuretestroot, "gvGlyphOutline", "Getting GV Glyph Outline");
 375         }
 376 
 377         public void runTest(Object ctx, int numReps) {
 378             GVContext gvctx = (GVContext)ctx;
 379             GlyphVector gv = gvctx.gv;
 380             Shape s;
 381             do {
 382                 for (int i = 0, e = gv.getNumGlyphs(); i < e; ++i) {
 383                     s = gv.getGlyphOutline(i);
 384                 }
 385             } while (--numReps >= 0);
 386         }
 387     }
 388 
 389     public static class GVGlyphTransform extends GVMeasureTest {
 390         public GVGlyphTransform() {
 391             super(measuretestroot, "gvGlyphTransform", "Getting GV Glyph Transform");
 392         }
 393 
 394         public void runTest(Object ctx, int numReps) {
 395             GVContext gvctx = (GVContext)ctx;
 396             GlyphVector gv = gvctx.gv;
 397             AffineTransform tx;
 398             do {
 399                 for (int i = 0, e = gv.getNumGlyphs(); i < e; ++i) {
 400                     tx = gv.getGlyphTransform(i);
 401                 }
 402             } while (--numReps >= 0);
 403         }
 404     }
 405 
 406     public static class GVGlyphMetrics extends GVMeasureTest {
 407         public GVGlyphMetrics() {
 408             super(measuretestroot, "gvGlyphMetrics", "Getting GV Glyph Metrics");
 409         }
 410 
 411         public void runTest(Object ctx, int numReps) {
 412             GVContext gvctx = (GVContext)ctx;
 413             GlyphVector gv = gvctx.gv;
 414             GlyphMetrics gm;
 415             do {
 416                 for (int i = 0, e = gv.getNumGlyphs(); i < e; ++i) {
 417                     gm = gv.getGlyphMetrics(i);
 418                 }
 419             } while (--numReps >= 0);
 420         }
 421     }
 422 
 423     public static class TLContext extends G2DContext {
 424         TextLayout tl;
 425 
 426         public void init(TestEnvironment env, Result results) {
 427             super.init(env, results);
 428 
 429             // need more tl options here
 430             tl = new TextLayout(text, font, frc);
 431         }
 432     }
 433 
 434     public static abstract class TLMeasureTest extends TextMeasureTests {
 435         protected TLMeasureTest(Group parent, String nodeName, String description) {
 436             super(parent, nodeName, description);
 437         }
 438 
 439         public Context createContext() {
 440             return new TLContext();
 441         }
 442     }
 443 
 444     public static class TLAdvance extends TLMeasureTest {
 445         public TLAdvance() {
 446             super(measuretestroot, "tlAdvance", "Measuring TL advance");
 447         }
 448 
 449         public void runTest(Object ctx, int numReps) {
 450             TLContext tlctx = (TLContext)ctx;
 451             TextLayout tl = tlctx.tl;
 452             double wid = 0;
 453             do {
 454                 wid += tl.getAdvance();
 455             } while (--numReps >= 0);
 456         }
 457     }
 458 
 459     public static class TLAscent extends TLMeasureTest {
 460         public TLAscent() {
 461             super(measuretestroot, "tlAscent", "Measuring TL ascent");
 462         }
 463 
 464         public void runTest(Object ctx, int numReps) {
 465             TLContext tlctx = (TLContext)ctx;
 466             TextLayout tl = tlctx.tl;
 467             float ht = 0;
 468             do {
 469                 ht += tl.getAscent();
 470             } while (--numReps >= 0);
 471         }
 472     }
 473 
 474     public static class TLBounds extends TLMeasureTest {
 475         public TLBounds() {
 476             super(measuretestroot, "tlBounds", "Measuring TL advance");
 477         }
 478 
 479         public void runTest(Object ctx, int numReps) {
 480             TLContext tlctx = (TLContext)ctx;
 481             TextLayout tl = tlctx.tl;
 482             Rectangle2D r;
 483             do {
 484                 r = tl.getBounds();
 485             } while (--numReps >= 0);
 486         }
 487     }
 488 
 489     static class TLExContext extends TLContext {
 490         TextHitInfo[] hits;
 491         Rectangle2D lb;
 492 
 493         public void init(TestEnvironment env, Result results) {
 494             super.init(env, results);
 495 
 496             ArrayList list = new ArrayList(text.length() * 2 + 2);
 497             TextHitInfo hit = TextHitInfo.trailing(-1);
 498             do {
 499                 list.add(hit);
 500                 hit = tl.getNextRightHit(hit);
 501             } while (hit != null);
 502             hits = (TextHitInfo[])list.toArray(new TextHitInfo[list.size()]);
 503 
 504             lb = tl.getBounds();
 505             lb.setRect(lb.getMinX() - 10, lb.getMinY(), lb.getWidth() + 20, lb.getHeight());
 506         }
 507     }
 508 
 509     public static abstract class TLExtendedMeasureTest extends TLMeasureTest {
 510         protected TLExtendedMeasureTest(Group parent, String nodeName, String description) {
 511             super(parent, nodeName, description);
 512         }
 513 
 514         public Context createContext() {
 515             return new TLExContext();
 516         }
 517     }
 518 
 519     public static class TLGetCaretInfo extends TLExtendedMeasureTest {
 520         public TLGetCaretInfo() {
 521             super(measuretestroot, "tlGetCaretInfo", "Measuring TL caret info");
 522         }
 523 
 524         public void runTest(Object ctx, int numReps) {
 525             TLExContext tlctx = (TLExContext)ctx;
 526             TextLayout tl = tlctx.tl;
 527             TextHitInfo[] hits = tlctx.hits;
 528             do {
 529                 for (int i = 0; i < hits.length; ++i) {
 530                     tl.getCaretInfo(hits[i]);
 531                 }
 532             } while (--numReps >= 0);
 533         }
 534     }
 535 
 536     public static class TLGetNextHit extends TLExtendedMeasureTest {
 537         public TLGetNextHit() {
 538             super(measuretestroot, "tlGetNextHit", "Measuring TL getNextRight/LeftHit");
 539         }
 540 
 541         public void runTest(Object ctx, int numReps) {
 542             TLExContext tlctx = (TLExContext)ctx;
 543             TextLayout tl = tlctx.tl;
 544             TextHitInfo[] hits = tlctx.hits;
 545             TextHitInfo hit;
 546             do {
 547                 for (int i = 0; i < hits.length; ++i) {
 548                     hit = tl.getNextLeftHit(hits[i]);
 549                 }
 550             } while (--numReps >= 0);
 551         }
 552     }
 553 
 554     public static class TLGetCaretShape extends TLExtendedMeasureTest {
 555         public TLGetCaretShape() {
 556             super(measuretestroot, "tlGetCaretShape", "Measuring TL getCaretShape");
 557         }
 558 
 559         public void runTest(Object ctx, int numReps) {
 560             TLExContext tlctx = (TLExContext)ctx;
 561             TextLayout tl = tlctx.tl;
 562             TextHitInfo[] hits = tlctx.hits;
 563             Shape s;
 564             do {
 565                 for (int i = 0; i < hits.length; ++i) {
 566                     s = tl.getCaretShape(hits[i]);
 567                 }
 568             } while (--numReps >= 0);
 569         }
 570     }
 571 
 572     public static class TLGetLogicalHighlightShape extends TLExtendedMeasureTest {
 573         public TLGetLogicalHighlightShape() {
 574             super(measuretestroot, "tlGetLogicalHighlightShape", "Measuring TL getLogicalHighlightShape");
 575         }
 576 
 577         public void runTest(Object ctx, int numReps) {
 578             TLExContext tlctx = (TLExContext)ctx;
 579             TextLayout tl = tlctx.tl;
 580             int len = tlctx.text.length();
 581             Rectangle2D lb = tlctx.lb;
 582             Shape s;
 583             if (len < 3) {
 584                 do {
 585                     s = tl.getLogicalHighlightShape(0, len, lb);
 586                 } while (--numReps >= 0);
 587             } else {
 588                 do {
 589                     for (int i = 3; i < len; ++i) {
 590                         s = tl.getLogicalHighlightShape(i-3, i, lb);
 591                     }
 592                 } while (--numReps >= 0);
 593             }
 594         }
 595     }
 596 
 597     public static class TLGetVisualHighlightShape extends TLExtendedMeasureTest {
 598         public TLGetVisualHighlightShape() {
 599             super(measuretestroot, "tlGetVisualHighlightShape", "Measuring TL getVisualHighlightShape");
 600         }
 601 
 602         public void runTest(Object ctx, int numReps) {
 603             TLExContext tlctx = (TLExContext)ctx;
 604             TextLayout tl = tlctx.tl;
 605             TextHitInfo[] hits = tlctx.hits;
 606             Rectangle2D lb = tlctx.lb;
 607             Shape s;
 608             if (hits.length < 3) {
 609                 do {
 610                     s = tl.getVisualHighlightShape(hits[0], hits[hits.length - 1], lb);
 611                 } while (--numReps >= 0);
 612             } else {
 613                 do {
 614                     for (int i = 3; i < hits.length; ++i) {
 615                         s = tl.getVisualHighlightShape(hits[i-3], hits[i], lb);
 616                     }
 617                 } while (--numReps >= 0);
 618             }
 619         }
 620     }
 621 
 622     public static class TLHitTest extends TLExtendedMeasureTest {
 623         public TLHitTest() {
 624             super(measuretestroot, "tlHitTest", "Measuring TL hitTest");
 625         }
 626 
 627         public void runTest(Object ctx, int numReps) {
 628             TLExContext tlctx = (TLExContext)ctx;
 629             TextLayout tl = tlctx.tl;
 630             int numhits = tlctx.hits.length;
 631             Rectangle2D lb = tlctx.lb;
 632             TextHitInfo hit;
 633             for (int i = 0; i <= numhits; ++i) {
 634                 float x = (float)(lb.getMinX() + lb.getWidth() * i / numhits);
 635                 float y = (float)(lb.getMinY() + lb.getHeight() * i / numhits);
 636                 hit = tl.hitTestChar(x, y, lb);
 637             }
 638         }
 639     }
 640 
 641     public static class TLOutline extends TLMeasureTest {
 642         public TLOutline() {
 643             super(measuretestroot, "tlOutline", "Measuring TL outline");
 644         }
 645 
 646         public void runTest(Object ctx, int numReps) {
 647             TLContext tlctx = (TLContext)ctx;
 648             TextLayout tl = tlctx.tl;
 649             Shape s;
 650             do {
 651                 s = tl.getOutline(null);
 652             } while (--numReps >= 0);
 653         }
 654     }
 655 }