1 /*
2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /**
25  * Copyright (C) 2013-2014 IBM Corporation and Others. All Rights Reserved.
26  */
27 
28 import java.awt.Color;
29 import java.awt.Composite;
30 import java.awt.Font;
31 import java.awt.FontFormatException;
32 import java.awt.FontMetrics;
33 import java.awt.Graphics;
34 import java.awt.Graphics2D;
35 import java.awt.GraphicsConfiguration;
36 import java.awt.Image;
37 import java.awt.Paint;
38 import java.awt.Rectangle;
39 import java.awt.RenderingHints;
40 import java.awt.RenderingHints.Key;
41 import java.awt.Shape;
42 import java.awt.Stroke;
43 import java.awt.font.FontRenderContext;
44 import java.awt.font.GlyphVector;
45 import java.awt.font.TextLayout;
46 import java.awt.geom.AffineTransform;
47 import java.awt.image.BufferedImage;
48 import java.awt.image.BufferedImageOp;
49 import java.awt.image.ImageObserver;
50 import java.awt.image.RenderedImage;
51 import java.awt.image.renderable.RenderableImage;
52 import java.io.BufferedInputStream;
53 import java.io.File;
54 import java.io.FileInputStream;
55 import java.io.FileNotFoundException;
56 import java.io.IOException;
57 import java.io.InputStream;
58 import java.text.AttributedCharacterIterator;
59 import java.util.ArrayList;
60 import java.util.List;
61 import java.util.Map;
62 import java.util.MissingResourceException;
63 import java.util.TreeMap;
64 
65 import javax.xml.parsers.DocumentBuilder;
66 import javax.xml.parsers.DocumentBuilderFactory;
67 import javax.xml.parsers.ParserConfigurationException;
68 
69 import org.w3c.dom.Document;
70 import org.w3c.dom.Element;
71 import org.w3c.dom.NamedNodeMap;
72 import org.w3c.dom.Node;
73 import org.w3c.dom.NodeList;
74 import org.xml.sax.SAXException;
75 
76 /**
77  * This test runs against a test XML file. It opens the fonts and attempts
78  * to shape and layout glyphs.
79  * Note that the test is highly environment dependent- you must have
80  * the same versions of the same fonts available or the test will fail.
81  *
82  * It is similar to letest which is part of ICU.
83  * For reference, here are some reference items:
84  * ICU's test file:
85  *  http://source.icu-project.org/repos/icu/icu/trunk/source/test/testdata/letest.xml
86  * ICU's readme for the similar test:
87  *  http://source.icu-project.org/repos/icu/icu/trunk/source/test/letest/readme.html
88  *
89  * @bug 8054203
90  * @test
91  * @summary manual test of layout engine behavior. Takes an XML control file.
92  * @compile TestLayoutVsICU.java
93  * @author srl
94  * @run main/manual
95  */
96 public class TestLayoutVsICU {
97 
98     public static boolean OPT_DRAW = false;
99     public static boolean OPT_VERBOSE = false;
100     public static boolean OPT_FAILMISSING = false;
101     public static boolean OPT_NOTHROW= false; // if true - don't stop on failure
102 
103     public static int docs = 0; // # docs processed
104     public static int skipped = 0; // cases skipped due to bad font
105     public static int total = 0; // cases processed
106     public static int bad = 0; // cases with errs
107 
108     public static final String XML_LAYOUT_TESTS = "layout-tests"; // top level
109     public static final String XML_TEST_CASE = "test-case";
110     public static final String XML_TEST_FONT = "test-font";
111     public static final String XML_TEST_TEXT = "test-text";
112     public static final String XML_RESULT_GLYPHS = "result-glyphs";
113     public static final String XML_ID = "id";
114     public static final String XML_SCRIPT = "script";
115     public static final String XML_NAME = "name";
116     public static final String XML_VERSION = "version";
117     public static final String XML_CHECKSUM = "checksum";
118     public static final String XML_RESULT_INDICES = "result-indices";
119     public static final String XML_RESULT_POSITIONS = "result-positions";
120 
121     /**
122      * @param args
123      * @throws IOException
124      * @throws SAXException
125      * @throws ParserConfigurationException
126      */
main(String[] args)127     public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
128         System.out.println("Java " + System.getProperty("java.version") + " from " + System.getProperty("java.vendor"));
129         TestLayoutVsICU tlvi = null;
130         for(String arg : args) {
131             if(arg.equals("-d")) {
132                 OPT_DRAW = true;
133             } else if(arg.equals("-n")) {
134                 OPT_NOTHROW = true;
135             } else if(arg.equals("-v")) {
136                 OPT_VERBOSE = true;
137             } else if(arg.equals("-f")) {
138                 OPT_FAILMISSING = true;
139             } else {
140                 if(tlvi == null) {
141                     tlvi = new TestLayoutVsICU();
142                 }
143                 try {
144                     tlvi.show(arg);
145                 } finally {
146                     if(OPT_VERBOSE) {
147                         System.out.println("# done with " + arg);
148                     }
149                 }
150             }
151         }
152 
153         if(tlvi == null) {
154             throw new IllegalArgumentException("No XML input. Usage: " + TestLayoutVsICU.class.getSimpleName() + " [-d][-v][-f] letest.xml ...");
155         } else {
156             System.out.println("\n\nRESULTS:\n");
157             System.out.println(skipped+"\tskipped due to missing font");
158             System.out.println(total+"\ttested of which:");
159             System.out.println(bad+"\twere bad");
160 
161             if(bad>0) {
162                 throw new InternalError("One or more failure(s)");
163             }
164         }
165     }
166 
167     String id;
168 
show(String arg)169     private void show(String arg) throws ParserConfigurationException, SAXException, IOException {
170         id = "<none>";
171         File xmlFile = new File(arg);
172         if(!xmlFile.exists()) {
173             throw new FileNotFoundException("Can't open input XML file " + arg);
174         }
175         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
176         DocumentBuilder db = dbf.newDocumentBuilder();
177         if(OPT_VERBOSE) {
178             System.out.println("# Parsing " + xmlFile.getAbsolutePath());
179         }
180         Document doc = db.parse(xmlFile);
181         Element e = doc.getDocumentElement();
182         if(!XML_LAYOUT_TESTS.equals(e.getNodeName())) {
183             throw new IllegalArgumentException("Document " + xmlFile.getAbsolutePath() + " does not have <layout-tests> as its base");
184         }
185 
186         NodeList testCases = e.getElementsByTagName(XML_TEST_CASE);
187         for(int caseNo=0;caseNo<testCases.getLength();caseNo++) {
188             final Node testCase = testCases.item(caseNo);
189             final Map<String,String> testCaseAttrs = attrs(testCase);
190             id = testCaseAttrs.get(XML_ID);
191             final String script = testCaseAttrs.get(XML_SCRIPT);
192             String testText = null;
193             Integer[] expectGlyphs = null;
194             Integer[] expectIndices = null;
195             Map<String,String> fontAttrs = null;
196             if(OPT_VERBOSE) {
197                 System.out.println("#"+caseNo+" id="+id + ", script="+script);
198             }
199             NodeList children = testCase.getChildNodes();
200             for(int sub=0;sub<children.getLength();sub++) {
201                 Node n = children.item(sub);
202                 if(n.getNodeType()!=Node.ELEMENT_NODE) continue;
203                 String nn = n.getNodeName();
204                 if(nn.equals(XML_TEST_FONT)) {
205                     fontAttrs = attrs(n);
206                 } else if(nn.equals(XML_TEST_TEXT)) {
207                     testText = n.getTextContent();
208                 } else if(nn.equals(XML_RESULT_GLYPHS)) {
209                     String hex = n.getTextContent();
210                     expectGlyphs = parseHexArray(hex);
211                 } else if(nn.equals(XML_RESULT_INDICES)) {
212                     String hex = n.getTextContent();
213                     expectIndices = parseHexArray(hex);
214                 } else if(OPT_VERBOSE) {
215                     System.out.println("Ignoring node " + nn);
216                 }
217             }
218             if(fontAttrs == null) {
219                 throw new IllegalArgumentException(id + " Missing node " + XML_TEST_FONT);
220             }
221             if(testText == null) {
222                 throw new IllegalArgumentException(id + " Missing node " + XML_TEST_TEXT);
223             }
224 
225             String fontName = fontAttrs.get(XML_NAME);
226             Font f = getFont(fontName, fontAttrs);
227             if(f==null) {
228                 if(OPT_FAILMISSING) {
229                     throw new MissingResourceException("Missing font,  abort test", Font.class.getName(), fontName);
230                 }
231                 System.out.println("Skipping " + id + " because font is missing: " + fontName);
232                 skipped++;
233                 continue;
234             }
235             FontRenderContext frc = new FontRenderContext(null, true, true);
236             TextLayout tl = new TextLayout(testText,f,frc);
237             final List<GlyphVector> glyphs = new ArrayList<GlyphVector>();
238             Graphics2D myg2 = new Graphics2D(){
239 
240                     @Override
241                     public void draw(Shape s) {
242                         // TODO Auto-generated method stub
243 
244                     }
245 
246                     @Override
247                     public boolean drawImage(Image img, AffineTransform xform,
248                                              ImageObserver obs) {
249                         // TODO Auto-generated method stub
250                         return false;
251                     }
252 
253                     @Override
254                     public void drawImage(BufferedImage img,
255                                           BufferedImageOp op, int x, int y) {
256                         // TODO Auto-generated method stub
257 
258                     }
259 
260                     @Override
261                     public void drawRenderedImage(RenderedImage img,
262                                                   AffineTransform xform) {
263                         // TODO Auto-generated method stub
264 
265                     }
266 
267                     @Override
268                     public void drawRenderableImage(RenderableImage img,
269                                                     AffineTransform xform) {
270                         // TODO Auto-generated method stub
271 
272                     }
273 
274                     @Override
275                     public void drawString(String str, int x, int y) {
276                         // TODO Auto-generated method stub
277 
278                     }
279 
280                     @Override
281                     public void drawString(String str, float x, float y) {
282                         // TODO Auto-generated method stub
283 
284                     }
285 
286                     @Override
287                     public void drawString(
288                                            AttributedCharacterIterator iterator, int x, int y) {
289                         // TODO Auto-generated method stub
290 
291                     }
292 
293                     @Override
294                     public void drawString(
295                                            AttributedCharacterIterator iterator, float x,
296                                            float y) {
297                         // TODO Auto-generated method stub
298 
299                     }
300 
301                     @Override
302                     public void drawGlyphVector(GlyphVector g, float x, float y) {
303                         if(x!=0.0 || y!=0.0) {
304                             throw new InternalError("x,y should be 0 but got " + x+","+y);
305                         }
306                         //System.err.println("dGV : " + g.toString() + " @ "+x+","+y);
307                         glyphs.add(g);
308                     }
309 
310                     @Override
311                     public void fill(Shape s) {
312                         // TODO Auto-generated method stub
313 
314                     }
315 
316                     @Override
317                     public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
318                         // TODO Auto-generated method stub
319                         return false;
320                     }
321 
322                     @Override
323                     public GraphicsConfiguration getDeviceConfiguration() {
324                         // TODO Auto-generated method stub
325                         return null;
326                     }
327 
328                     @Override
329                     public void setComposite(Composite comp) {
330                         // TODO Auto-generated method stub
331 
332                     }
333 
334                     @Override
335                     public void setPaint(Paint paint) {
336                         // TODO Auto-generated method stub
337 
338                     }
339 
340                     @Override
341                     public void setStroke(Stroke s) {
342                         // TODO Auto-generated method stub
343 
344                     }
345 
346                     @Override
347                     public void setRenderingHint(Key hintKey, Object hintValue) {
348                         // TODO Auto-generated method stub
349 
350                     }
351 
352                     @Override
353                     public Object getRenderingHint(Key hintKey) {
354                         // TODO Auto-generated method stub
355                         return null;
356                     }
357 
358                     @Override
359                     public void setRenderingHints(Map<?, ?> hints) {
360                         // TODO Auto-generated method stub
361 
362                     }
363 
364                     @Override
365                     public void addRenderingHints(Map<?, ?> hints) {
366                         // TODO Auto-generated method stub
367 
368                     }
369 
370                     @Override
371                     public RenderingHints getRenderingHints() {
372                         // TODO Auto-generated method stub
373                         return null;
374                     }
375 
376                     @Override
377                     public void translate(int x, int y) {
378                         // TODO Auto-generated method stub
379 
380                     }
381 
382                     @Override
383                     public void translate(double tx, double ty) {
384                         // TODO Auto-generated method stub
385 
386                     }
387 
388                     @Override
389                     public void rotate(double theta) {
390                         // TODO Auto-generated method stub
391 
392                     }
393 
394                     @Override
395                     public void rotate(double theta, double x, double y) {
396                         // TODO Auto-generated method stub
397 
398                     }
399 
400                     @Override
401                     public void scale(double sx, double sy) {
402                         // TODO Auto-generated method stub
403 
404                     }
405 
406                     @Override
407                     public void shear(double shx, double shy) {
408                         // TODO Auto-generated method stub
409 
410                     }
411 
412                     @Override
413                     public void transform(AffineTransform Tx) {
414                         // TODO Auto-generated method stub
415 
416                     }
417 
418                     @Override
419                     public void setTransform(AffineTransform Tx) {
420                         // TODO Auto-generated method stub
421 
422                     }
423 
424                     @Override
425                     public AffineTransform getTransform() {
426                         // TODO Auto-generated method stub
427                         return null;
428                     }
429 
430                     @Override
431                     public Paint getPaint() {
432                         // TODO Auto-generated method stub
433                         return null;
434                     }
435 
436                     @Override
437                     public Composite getComposite() {
438                         // TODO Auto-generated method stub
439                         return null;
440                     }
441 
442                     @Override
443                     public void setBackground(Color color) {
444                         // TODO Auto-generated method stub
445 
446                     }
447 
448                     @Override
449                     public Color getBackground() {
450                         // TODO Auto-generated method stub
451                         return null;
452                     }
453 
454                     @Override
455                     public Stroke getStroke() {
456                         // TODO Auto-generated method stub
457                         return null;
458                     }
459 
460                     @Override
461                     public void clip(Shape s) {
462                         // TODO Auto-generated method stub
463 
464                     }
465 
466                     @Override
467                     public FontRenderContext getFontRenderContext() {
468                         // TODO Auto-generated method stub
469                         return null;
470                     }
471 
472                     @Override
473                     public Graphics create() {
474                         // TODO Auto-generated method stub
475                         return null;
476                     }
477 
478                     @Override
479                     public Color getColor() {
480                         // TODO Auto-generated method stub
481                         return null;
482                     }
483 
484                     @Override
485                     public void setColor(Color c) {
486                         // TODO Auto-generated method stub
487 
488                     }
489 
490                     @Override
491                     public void setPaintMode() {
492                         // TODO Auto-generated method stub
493 
494                     }
495 
496                     @Override
497                     public void setXORMode(Color c1) {
498                         // TODO Auto-generated method stub
499 
500                     }
501 
502                     @Override
503                     public Font getFont() {
504                         // TODO Auto-generated method stub
505                         return null;
506                     }
507 
508                     @Override
509                     public void setFont(Font font) {
510                         // TODO Auto-generated method stub
511 
512                     }
513 
514                     @Override
515                     public FontMetrics getFontMetrics(Font f) {
516                         // TODO Auto-generated method stub
517                         return null;
518                     }
519 
520                     @Override
521                     public Rectangle getClipBounds() {
522                         // TODO Auto-generated method stub
523                         return null;
524                     }
525 
526                     @Override
527                     public void clipRect(int x, int y, int width, int height) {
528                         // TODO Auto-generated method stub
529 
530                     }
531 
532                     @Override
533                     public void setClip(int x, int y, int width, int height) {
534                         // TODO Auto-generated method stub
535 
536                     }
537 
538                     @Override
539                     public Shape getClip() {
540                         // TODO Auto-generated method stub
541                         return null;
542                     }
543 
544                     @Override
545                     public void setClip(Shape clip) {
546                         // TODO Auto-generated method stub
547 
548                     }
549 
550                     @Override
551                     public void copyArea(int x, int y, int width, int height,
552                                          int dx, int dy) {
553                         // TODO Auto-generated method stub
554 
555                     }
556 
557                     @Override
558                     public void drawLine(int x1, int y1, int x2, int y2) {
559                         // TODO Auto-generated method stub
560 
561                     }
562 
563                     @Override
564                     public void fillRect(int x, int y, int width, int height) {
565                         // TODO Auto-generated method stub
566 
567                     }
568 
569                     @Override
570                     public void clearRect(int x, int y, int width, int height) {
571                         // TODO Auto-generated method stub
572 
573                     }
574 
575                     @Override
576                     public void drawRoundRect(int x, int y, int width,
577                                               int height, int arcWidth, int arcHeight) {
578                         // TODO Auto-generated method stub
579 
580                     }
581 
582                     @Override
583                     public void fillRoundRect(int x, int y, int width,
584                                               int height, int arcWidth, int arcHeight) {
585                         // TODO Auto-generated method stub
586 
587                     }
588 
589                     @Override
590                     public void drawOval(int x, int y, int width, int height) {
591                         // TODO Auto-generated method stub
592 
593                     }
594 
595                     @Override
596                     public void fillOval(int x, int y, int width, int height) {
597                         // TODO Auto-generated method stub
598 
599                     }
600 
601                     @Override
602                     public void drawArc(int x, int y, int width, int height,
603                                         int startAngle, int arcAngle) {
604                         // TODO Auto-generated method stub
605 
606                     }
607 
608                     @Override
609                     public void fillArc(int x, int y, int width, int height,
610                                         int startAngle, int arcAngle) {
611                         // TODO Auto-generated method stub
612 
613                     }
614 
615                     @Override
616                     public void drawPolyline(int[] xPoints, int[] yPoints,
617                                              int nPoints) {
618                         // TODO Auto-generated method stub
619 
620                     }
621 
622                     @Override
623                     public void drawPolygon(int[] xPoints, int[] yPoints,
624                                             int nPoints) {
625                         // TODO Auto-generated method stub
626 
627                     }
628 
629                     @Override
630                     public void fillPolygon(int[] xPoints, int[] yPoints,
631                                             int nPoints) {
632                         // TODO Auto-generated method stub
633 
634                     }
635 
636                     @Override
637                     public boolean drawImage(Image img, int x, int y,
638                                              ImageObserver observer) {
639                         // TODO Auto-generated method stub
640                         return false;
641                     }
642 
643                     @Override
644                     public boolean drawImage(Image img, int x, int y,
645                                              int width, int height, ImageObserver observer) {
646                         // TODO Auto-generated method stub
647                         return false;
648                     }
649 
650                     @Override
651                     public boolean drawImage(Image img, int x, int y,
652                                              Color bgcolor, ImageObserver observer) {
653                         // TODO Auto-generated method stub
654                         return false;
655                     }
656 
657                     @Override
658                     public boolean drawImage(Image img, int x, int y,
659                                              int width, int height, Color bgcolor,
660                                              ImageObserver observer) {
661                         // TODO Auto-generated method stub
662                         return false;
663                     }
664 
665                     @Override
666                     public boolean drawImage(Image img, int dx1, int dy1,
667                                              int dx2, int dy2, int sx1, int sy1, int sx2,
668                                              int sy2, ImageObserver observer) {
669                         // TODO Auto-generated method stub
670                         return false;
671                     }
672 
673                     @Override
674                     public boolean drawImage(Image img, int dx1, int dy1,
675                                              int dx2, int dy2, int sx1, int sy1, int sx2,
676                                              int sy2, Color bgcolor, ImageObserver observer) {
677                         // TODO Auto-generated method stub
678                         return false;
679                     }
680 
681                     @Override
682                     public void dispose() {
683                         // TODO Auto-generated method stub
684 
685                     }
686 
687                 };
688             tl.draw(myg2, 0, 0);
689             if(glyphs.size() != 1) {
690                 err("drew " + glyphs.size() + " times - expected 1");
691                 total++;
692                 bad++;
693                 continue;
694             }
695             boolean isBad = false;
696             GlyphVector gv = glyphs.get(0);
697 
698             // GLYPHS
699             int gotGlyphs[] = gv.getGlyphCodes(0, gv.getNumGlyphs(), new int[gv.getNumGlyphs()]);
700 
701             int count = Math.min(gotGlyphs.length, expectGlyphs.length); // go up to this count
702 
703             for(int i=0;i<count;i++) {
704                 if(gotGlyphs[i]!=expectGlyphs[i]) {
705                     err("@"+i+" - got \tglyph 0x" + Integer.toHexString(gotGlyphs[i]) + " wanted 0x" + Integer.toHexString(expectGlyphs[i]));
706                     isBad=true;
707                     break;
708                 }
709             }
710 
711             // INDICES
712             int gotIndices[] = gv.getGlyphCharIndices(0, gv.getNumGlyphs(), new int[gv.getNumGlyphs()]);
713             for(int i=0;i<count;i++) {
714                 if(gotIndices[i]!=expectIndices[i]) {
715                     err("@"+i+" - got \tindex 0x" + Integer.toHexString(gotGlyphs[i]) + " wanted 0x" + Integer.toHexString(expectGlyphs[i]));
716                     isBad=true;
717                     break;
718                 }
719             }
720 
721 
722             // COUNT
723             if(gotGlyphs.length != expectGlyphs.length) {
724                 System.out.println("Got " + gotGlyphs.length + " wanted " + expectGlyphs.length + " glyphs");
725                 isBad=true;
726             } else {
727                 if(OPT_VERBOSE) {
728                     System.out.println(">> OK: " + gotGlyphs.length + " glyphs");
729                 }
730             }
731 
732 
733             if(isBad) {
734                 bad++;
735                 System.out.println("* FAIL: " + id + "  /\t" + fontName);
736             } else {
737                 System.out.println("* OK  : " + id + "  /\t" + fontName);
738             }
739             total++;
740         }
741     }
742 
743 
verifyFont(File f, Map<String, String> fontAttrs)744     private boolean verifyFont(File f, Map<String, String> fontAttrs) {
745         InputStream fis = null;
746         String fontName = fontAttrs.get(XML_NAME);
747         int count=0;
748         try {
749             fis = new BufferedInputStream(new FileInputStream(f));
750 
751             int i = 0;
752             int r;
753             try {
754                 while((r=fis.read())!=-1) {
755                     i+=(int)r;
756                     count++;
757                 }
758             } catch (IOException e) {
759                 // TODO Auto-generated catch block
760                 e.printStackTrace();
761                 return false;
762             }
763             if(OPT_VERBOSE) {
764                 System.out.println("for " + f.getAbsolutePath() + " chks = 0x" + Integer.toHexString(i) + " size=" + count);
765             }
766             String theirStr = fontAttrs.get("rchecksum");
767 
768             String ourStr = Integer.toHexString(i).toLowerCase();
769 
770             if(theirStr!=null) {
771                 if(theirStr.startsWith("0x")) {
772                     theirStr = theirStr.substring(2).toLowerCase();
773                 } else {
774                     theirStr = theirStr.toLowerCase();
775                 }
776                 long theirs = Integer.parseInt(theirStr, 16);
777                 if(theirs != i) {
778                     err("WARNING: rchecksum for " + fontName + " was " + i  + " (0x"+ourStr+") "+ " but file said " + theirs +" (0x"+theirStr+")  - perhaps a different font?");
779                     return false;
780                 } else {
781                     if(OPT_VERBOSE) {
782                         System.out.println(" rchecksum for " + fontName + " OK");
783                     }
784                     return true;
785                 }
786             } else {
787                 //if(OPT_VERBOSE) {
788                 System.err.println("WARNING: rchecksum for " + fontName + " was " + i  + " (0x"+ourStr+") "+ " but rchecksum was MISSING. Old ICU data?");
789                 //}
790             }
791         } catch (FileNotFoundException e) {
792             // TODO Auto-generated catch block
793             e.printStackTrace();
794             return false;
795         } finally {
796             try {
797                 fis.close();
798             } catch (IOException e) {
799                 // TODO Auto-generated catch block
800                 e.printStackTrace();
801             }
802         }
803         return true;
804     }
805 
806 
parseHexArray(String hex)807     private Integer[] parseHexArray(String hex) {
808         List<Integer> ret = new ArrayList<Integer>();
809         String items[] = hex.split("[\\s,]");
810         for(String i : items) {
811             if(i.isEmpty()) continue;
812             if(i.startsWith("0x")) {
813                 i = i.substring(2);
814             }
815             ret.add(Integer.parseInt(i, 16));
816         }
817         return ret.toArray(new Integer[0]);
818     }
819 
820 
err(String string)821     private void err(String string) {
822         if(OPT_NOTHROW) {
823             System.out.println(id+" ERROR: " + string +" (continuing due to -n)");
824         } else {
825             throw new InternalError(id+ ": " + string);
826         }
827     }
828 
829 
getFont(String fontName, Map<String, String> fontAttrs)830     private Font getFont(String fontName, Map<String, String> fontAttrs) {
831         Font f;
832         if(false)
833             try {
834                 f = Font.getFont(fontName);
835                 if(f!=null)  {
836                     if(OPT_VERBOSE) {
837                         System.out.println("Loaded default path to " + fontName);
838                     }
839                     return f;
840                 }
841             } catch(Throwable t) {
842                 if(OPT_VERBOSE) {
843                     t.printStackTrace();
844                     System.out.println("problem loading font " + fontName + " - " + t.toString());
845                 }
846             }
847 
848         File homeDir = new File(System.getProperty("user.home"));
849         File fontDir = new File(homeDir, "fonts");
850         File fontFile = new File(fontDir, fontName);
851         //System.out.println("## trying " + fontFile.getAbsolutePath());
852         if(fontFile.canRead()) {
853             try {
854                 if(!verifyFont(fontFile,fontAttrs)) {
855                     System.out.println("Warning: failed to verify " + fontName);
856                 }
857                 f = Font.createFont(Font.TRUETYPE_FONT, fontFile);
858                 if(f!=null & OPT_VERBOSE) {
859                     System.out.println("> loaded from " + fontFile.getAbsolutePath() + " - " + f.toString());
860                 }
861                 return f;
862             } catch (FontFormatException e) {
863                 if(OPT_VERBOSE) {
864                     e.printStackTrace();
865                     System.out.println("problem loading font " + fontName + " - " + e.toString());
866                 }
867             } catch (IOException e) {
868                 if(OPT_VERBOSE) {
869                     e.printStackTrace();
870                     System.out.println("problem loading font " + fontName + " - " + e.toString());
871                 }
872             }
873         }
874         return null;
875     }
876 
877 
attrs(Node testCase)878     private static Map<String, String> attrs(Node testCase) {
879         Map<String,String> rv = new TreeMap<String,String>();
880         NamedNodeMap nnm = testCase.getAttributes();
881         for(int i=0;i<nnm.getLength();i++) {
882             Node n = nnm.item(i);
883             String k = n.getNodeName();
884             String v = n.getNodeValue();
885             rv.put(k, v);
886         }
887         return rv;
888     }
889 }
890