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
47package j2dbench.tests.text;
48
49import java.awt.Font;
50import java.awt.FontMetrics;
51import java.awt.Rectangle;
52import java.awt.Shape;
53import java.awt.font.GlyphMetrics;
54import java.awt.font.GlyphVector;
55import java.awt.font.TextHitInfo;
56import java.awt.font.TextLayout;
57import java.awt.geom.AffineTransform;
58import java.awt.geom.Rectangle2D;
59import java.text.Bidi;
60import java.util.ArrayList;
61
62import j2dbench.Group;
63import j2dbench.Result;
64import j2dbench.TestEnvironment;
65
66public 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 abstract static 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 abstract static 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 abstract static 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}
656