+++ /dev/null
-/*
- **********************************************************************
- * Copyright (c) 2009-2012, Google, International Business Machines
- * Corporation and others. All Rights Reserved.
- **********************************************************************
- * Author: Mark Davis
- **********************************************************************
- */
-package com.ibm.icu.dev.tool.cldr;
-import java.awt.Font;
-import java.awt.GraphicsEnvironment;
-import java.awt.Shape;
-import java.awt.font.FontRenderContext;
-import java.awt.font.GlyphVector;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Rectangle2D;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import com.ibm.icu.dev.util.BagFormatter;
-import com.ibm.icu.dev.util.Tabber.HTMLTabber;
-import com.ibm.icu.dev.util.TransliteratorUtilities;
-import com.ibm.icu.dev.util.UnicodeMap;
-import com.ibm.icu.dev.util.UnicodeMap.Composer;
-import com.ibm.icu.dev.util.UnicodeMapIterator;
-import com.ibm.icu.dev.util.XEquivalenceClass.SetMaker;
-import com.ibm.icu.impl.Row;
-import com.ibm.icu.impl.Row.R2;
-import com.ibm.icu.impl.Utility;
-import com.ibm.icu.lang.UCharacter;
-import com.ibm.icu.lang.UScript;
-import com.ibm.icu.text.Collator;
-import com.ibm.icu.text.Normalizer;
-import com.ibm.icu.text.UTF16;
-import com.ibm.icu.text.UnicodeSet;
-import com.ibm.icu.text.UnicodeSetIterator;
-
-
-public class CheckSystemFonts {
-
- static String outputDirectoryName;
- static Set<String> SKIP_SHAPES = new HashSet<String>();
-
- public static void main(String[] args) throws IOException {
- System.out.println("Arguments:\t" + Arrays.asList(args));
- if (args.length < 2) {
- throw new IllegalArgumentException("Need command-line args:" +
- "\n\t\tfont-name-regex" +
- "\n\t\toutput-directory"
- );
- }
- Matcher nameMatcher = Pattern.compile(args[0], Pattern.CASE_INSENSITIVE).matcher("");
- outputDirectoryName = args[1].trim();
- File outputDirectory = new File(outputDirectoryName);
- if (!outputDirectory.isDirectory()) {
- throw new IllegalArgumentException("2nd arg must be valid directory");
- }
- loadSkipShapes();
-
- Map<UnicodeSet,Set<String>> data = new TreeMap<UnicodeSet, Set<String>>();
- Map<String, Font> fontMap = new TreeMap<String, Font>();
- getFontData(nameMatcher, data, fontMap);
-
- showInvisibles();
- showSameGlyphs();
-
- UnicodeMap<Set<String>> map = showEquivalentCoverage(data);
-
- showRawCoverage(data);
-
- Map<Set<String>, String> toShortName = showRawCoverage(map);
-
- showFullCoverage(map, toShortName);
- }
-
- private static void loadSkipShapes() {
- try {
- BufferedReader in = BagFormatter.openUTF8Reader(outputDirectoryName, "skip_fonts.txt");
- while (true) {
- String line = in.readLine();
- if (line == null) break;
- String[] fonts = line.trim().split("\\s+");
- for (String font : fonts) {
- SKIP_SHAPES.add(font);
- }
- }
- in.close();
- } catch (IOException e) {
- System.err.println("Couldn't open:\t" + outputDirectoryName + "/" + "skip_fonts.txt");
- }
- }
-
-
- private static final Collator English = Collator.getInstance();
-
- static {
- English.setStrength(Collator.SECONDARY);
- }
-
- public static final UnicodeSet DONT_CARE = new UnicodeSet("[[:cn:][:co:][:cs:]]").freeze();
- public static final UnicodeSet COVERAGE = new UnicodeSet(DONT_CARE).complement().freeze();
-
- private static final Comparator<String> SHORTER_FIRST = new Comparator<String>() {
- public int compare(String n1, String n2) {
- int result = n1.length() - n2.length();
- if (result != 0) return result;
- return n1.compareTo(n2);
- }
- };
-
- private static final Comparator<UnicodeSet> LONGER_SET_FIRST = new Comparator<UnicodeSet>() {
- public int compare(UnicodeSet n1, UnicodeSet n2) {
- int result = n1.size() - n2.size();
- if (result != 0) return -result;
- return n1.compareTo(n2);
- }
- };
-
- private static final Comparator<Collection> SHORTER_COLLECTION_FIRST = new Comparator<Collection>() {
- public int compare(Collection n1, Collection n2) {
- int result = n1.size() - n2.size();
- if (result != 0) return result;
- return UnicodeSet.compare(n1, n2);
- }
- };
-
- private static final HashSet SKIP_TERMS = new HashSet(Arrays.asList("black", "blackitalic", "bold", "boldit", "bolditalic", "bolditalicmt", "boldmt",
- "boldob", "boldoblique", "boldslanted", "book", "bookitalic", "condensed", "condensedblack", "condensedbold", "condensedextrabold",
- "condensedlight", "condensedmedium", "extracondensed", "extralight", "heavy", "italic", "italicmt", "light", "lightit", "lightitalic", "medium",
- "mediumitalic", "oblique", "regular", "roman", "semibold", "semibolditalic", "shadow", "slanted", "ultrabold", "ultralight", "ultralightitalic"
- ));
-
- private static Composer<Set<String>> composer = new Composer<Set<String>>() {
- Map<R2<Set<String>, Set<String>>,Set<String>> cache = new HashMap<R2<Set<String>, Set<String>>,Set<String>>();
- public Set<String> compose(int codePoint, String string, Set<String> a, Set<String> b) {
- return a == null ? b
- : b == null ? null
- : intern(a,b);
- }
- private Set<String> intern(Set<String> a, Set<String> b) {
- R2<Set<String>, Set<String>> row = Row.of(a, b);
- Set<String> result = cache.get(row);
- if (result == null) {
- result = new TreeSet<String>(English);
- result.addAll(a);
- result.addAll(b);
- cache.put(row, result);
- }
- return result;
- }
- };
-
-
- private static void showFullCoverage(UnicodeMap<Set<String>> map, Map<Set<String>, String> toShortName) throws IOException {
- System.out.println("\n***COVERAGE:\t" + map.keySet().size() + "\n");
- PrintWriter out = BagFormatter.openUTF8Writer(outputDirectoryName, "coverage.txt");
-
- for (UnicodeMapIterator<String> it = new UnicodeMapIterator<String>(map); it.nextRange();) {
- String codes = "U+" + Utility.hex(it.codepoint);
- String names = UCharacter.getExtendedName(it.codepoint);
- if (it.codepointEnd != it.codepoint) {
- codes += "..U+" + Utility.hex(it.codepointEnd);
- names += ".." + UCharacter.getExtendedName(it.codepointEnd);
- }
- out.println(codes + "\t" + toShortName.get(map.get(it.codepoint)) + "\t" + names);
- }
-
- UnicodeSet missing = new UnicodeSet(COVERAGE).removeAll(map.keySet());
- out.println("\nMISSING:\t" + missing.size() + "\n");
-
- UnicodeMap<String> missingMap = new UnicodeMap<String>();
- for (UnicodeSetIterator it = new UnicodeSetIterator(missing); it.next();) {
- missingMap.put(it.codepoint, UScript.getName(UScript.getScript(it.codepoint)) + "-" + getShortAge(it.codepoint));
- }
-
- Set<String> sorted = new TreeSet<String>(English);
- sorted.addAll(missingMap.values());
- for (String value : sorted) {
- UnicodeSet items = missingMap.getSet(value);
- for (UnicodeSetIterator it = new UnicodeSetIterator(items); it.nextRange();) {
- String codes = "U+" + Utility.hex(it.codepoint);
- String names = UCharacter.getExtendedName(it.codepoint);
- if (it.codepointEnd != it.codepoint) {
- codes += "..U+" + Utility.hex(it.codepointEnd);
- names += ".." + UCharacter.getExtendedName(it.codepointEnd);
- }
- out.println(codes + "\t" + value + "\t" + names);
- }
- out.println();
- }
- out.close();
- }
-
- private static Map<Set<String>, String> showRawCoverage(UnicodeMap<Set<String>> map) throws IOException {
- System.out.println("\n***COMBO NAMES\n");
- PrintWriter out = BagFormatter.openUTF8Writer(outputDirectoryName, "combo_names.txt");
-
- int count = 0;
- Map<Set<String>, String> toShortName = new HashMap<Set<String>, String>();
- TreeSet<Set<String>> sortedValues = new TreeSet<Set<String>>(SHORTER_COLLECTION_FIRST);
- sortedValues.addAll(map.values());
- for (Set<String> value : sortedValues) {
- String shortName = "combo" + count++;
- Set<String> contained = getLargestContained(value, toShortName.keySet());
- String valueName;
- if (contained != null) {
- Set<String> remainder = new TreeSet<String>();
- remainder.addAll(value);
- remainder.removeAll(contained);
- valueName = toShortName.get(contained) + " + " + remainder;
- } else {
- valueName = value.toString();
- }
- toShortName.put(value, shortName);
- out.println(shortName + "\t" + valueName);
- }
- out.close();
- return toShortName;
- }
-
- private static void showRawCoverage(Map<UnicodeSet, Set<String>> data) throws IOException {
- System.out.println("\n***RAW COVERAGE (bridging unassigned)\n");
- PrintWriter out = BagFormatter.openUTF8Writer(outputDirectoryName, "raw_coverage.txt");
-
- for (Entry<UnicodeSet, Set<String>> entry : data.entrySet()) {
- UnicodeSet s = entry.getKey();
- Set<String> nameSet = entry.getValue();
- String name = nameSet.iterator().next();
- UnicodeSet bridged = new UnicodeSet(s).addBridges(DONT_CARE);
- out.println(name + "\t" + s.size() + "\t" + bridged);
- }
- out.close();
- }
-
- private static UnicodeMap<Set<String>> showEquivalentCoverage(Map<UnicodeSet, Set<String>> data) throws IOException {
- System.out.println("\n***EQUIVALENT COVERAGE\n");
- PrintWriter out = BagFormatter.openUTF8Writer(outputDirectoryName, "equiv_coverage.txt");
-
- UnicodeMap<Set<String>> map = new UnicodeMap<Set<String>>();
-
- Map<String,Set<String>> nameToSingleton = new HashMap<String,Set<String>>();
-
- for (Entry<UnicodeSet, Set<String>> entry : data.entrySet()) {
- UnicodeSet s = entry.getKey();
- Set<String> nameSet = entry.getValue();
- String name = nameSet.iterator().next();
- //System.out.println(s);
- Set<String> temp2 = nameToSingleton.get(name);
- if (temp2 == null) {
- temp2 = new TreeSet<String>(English);
- temp2.add(name);
- }
- map.composeWith(s, temp2, composer);
- if (nameSet.size() > 1) {
- TreeSet<String> temp = new TreeSet<String>(English);
- temp.addAll(nameSet);
- temp.remove(name);
- out.println(name + "\t" + temp);
- }
- }
- out.close();
- return map;
- }
-
- private static void showSameGlyphs() throws IOException {
- System.out.println("\n***Visual Equivalences");
- PrintWriter out = BagFormatter.openUTF8Writer(outputDirectoryName, "same_glyphs.txt");
- PrintWriter out2 = BagFormatter.openUTF8Writer(outputDirectoryName, "same_glyphs.html");
- out2.println("<html><head>");
- out2.println("<meta content=\"text/html; charset=utf-8\" http-equiv=Content-Type></HEAD>");
- out2.println("<link rel='stylesheet' href='index.css' type='text/css'>");
- out2.println("</head><body><table>");
- HTMLTabber tabber = new HTMLTabber();
-
- out2.println(tabber.process("Code1\tCode2\tNFC1\tNFC1\tCh1\tCh1\tCh1/F\tCh2/F\tName1\tName2\tFonts"));
- tabber.setParameters(0, "class='c'");
- tabber.setParameters(1, "class='c'");
- tabber.setParameters(2, "class='nf'");
- tabber.setParameters(3, "class='nf'");
- tabber.setParameters(4, "class='p'");
- tabber.setParameters(5, "class='p'");
- //tabber.setParameters(6, "class='q'");
- //tabber.setParameters(7, "class='q'");
- tabber.setParameters(8, "class='n'");
- tabber.setParameters(9, "class='n'");
- tabber.setParameters(10, "class='f'");
-
- for (R2<Integer,Integer> sample : equivalences.keySet()) {
- final Set<String> reasonSet = equivalences.get(sample);
- String reasons = reasonSet.toString();
- if (reasons.length() > 100) reasons = reasons.substring(0,100) + "...";
- final Integer codepoint1 = sample.get0();
- final Integer codepoint2 = sample.get1();
-
- out.println("U+" + Utility.hex(codepoint1) + "\t" + "U+" + Utility.hex(codepoint2)
- + "\t" + showNfc(codepoint1) + "\t" + showNfc(codepoint2)
- + "\t" + showChar(codepoint1, false) + "\t" + showChar(codepoint2, false)
- + "\t" + UCharacter.getExtendedName(codepoint1) + "\t" + UCharacter.getExtendedName(codepoint2)
- + "\t" + reasons);
- String line = "U+" + Utility.hex(codepoint1) + "\t" + "U+" + Utility.hex(codepoint2)
- + "\t" + showNfc(codepoint1) + "\t" + showNfc(codepoint2)
- + "\t" + showChar(codepoint1, false) + "\t" + showChar(codepoint2, true)
- + "\t" + showChar(codepoint1, false) + "\t" + showChar(codepoint2, true)
- + "\t" + UCharacter.getExtendedName(codepoint1) + "\t" + UCharacter.getExtendedName(codepoint2)
- + "\t" + reasons;
-
- String fonts = "class='q' style='font-family:";
- int maxCount = 5;
- for (String font : reasonSet) {
- if (maxCount != 5) {
- fonts += ",";
- }
- fonts += font;
- --maxCount;
- if (maxCount <= 0) break;
- }
- fonts += "'";
- tabber.setParameters(6, fonts);
- tabber.setParameters(7, fonts);
- out2.println(tabber.process(line));
- }
- out2.println("</table></body>");
- out2.close();
- out.close();
- }
-
- private static void showInvisibles() throws IOException {
- System.out.println("\n***Invisibles Equivalences");
- PrintWriter out = BagFormatter.openUTF8Writer(outputDirectoryName, "invisibles.txt");
- for (String sample : invisibles) {
- String reasons = invisibles.get(sample).toString();
- if (reasons.length() > 100) reasons = reasons.substring(0,100) + "...";
- int codepoint = sample.codePointAt(0);
- out.println("U+" + Utility.hex(sample)
- + "\t" + showChar(codepoint, false)
- + "\t" + showNfc(codepoint)
- + "\t" + UCharacter.getExtendedName(codepoint)
- + "\t" + reasons);
-
- }
- out.close();
- }
-
- private static void getFontData(Matcher nameMatcher, Map<UnicodeSet, Set<String>> data, Map<String, Font> fontMap) {
- GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
- Font[] fonts = env.getAllFonts();
- for (Font font : fonts) {
- if (!font.isPlain()) {
- continue;
- }
- String name = font.getName();
- int lastDash = name.lastIndexOf('-');
- String term = lastDash < 0 ? "" : name.substring(lastDash+1).toLowerCase();
- if (SKIP_TERMS.contains(term)) {
- continue;
- }
- if (nameMatcher != null && !nameMatcher.reset(name).find()) {
- continue;
- }
- fontMap.put(name,font);
- }
- for (Entry<String, Font> entry : fontMap.entrySet()) {
- String name = entry.getKey();
- Font font = entry.getValue();
- System.out.println(name);
- UnicodeSet coverage = getCoverage(font);
- Set<String> sameFonts = data.get(coverage);
- if (sameFonts == null) {
- data.put(coverage, sameFonts = new TreeSet<String>(SHORTER_FIRST));
- } else {
- System.out.println("\tNote: same coverage as " + sameFonts.iterator().next());
- }
- sameFonts.add(name);
- }
- }
-
- static Comparator<Integer> NFCLower = new Comparator<Integer>() {
- public int compare(Integer o1, Integer o2) {
- boolean n1 = Normalizer.isNormalized(o1, Normalizer.NFC, 0);
- boolean n2 = Normalizer.isNormalized(o2, Normalizer.NFC, 0);
- if (n1 != n2) return n1 ? -1 : 1;
- n1 = Normalizer.isNormalized(o1, Normalizer.NFKC, 0);
- n2 = Normalizer.isNormalized(o2, Normalizer.NFKC, 0);
- if (n1 != n2) return n1 ? -1 : 1;
- return o1.compareTo(o2);
- }
- };
-
- static Comparator<R2<Integer,Integer>> NFCLowerR2 = new Comparator<R2<Integer,Integer>>() {
- public int compare(R2<Integer, Integer> o1, R2<Integer, Integer> o2) {
- int diff = NFCLower.compare(o1.get0(), o2.get0());
- if (diff != 0) return diff;
- return NFCLower.compare(o1.get1(), o2.get1());
- }
- };
-
- private static String showNfc(int codepoint) {
- return Normalizer.isNormalized(codepoint, Normalizer.NFC, 0) ? ""
- : Normalizer.isNormalized(codepoint, Normalizer.NFKC, 0) ? "!C" : "!K";
- }
-
- private static String showChar(Integer item, boolean html) {
- return rtlProtect(UTF16.valueOf(item), html);
- }
- static UnicodeSet RTL = new UnicodeSet("[[:bc=R:][:bc=AL:][:bc=AN:]]").freeze();
- static UnicodeSet CONTROLS = new UnicodeSet("[[:cc:][:Zl:][:Zp:]]").freeze();
- static UnicodeSet INVISIBLES = new UnicodeSet("[:di:]").freeze();
- static final char LRM = '\u200E';
-
- private static String rtlProtect(String source, boolean html) {
- if (CONTROLS.containsSome(source)) {
- source = "";
- } else if (INVISIBLES.containsSome(source)) {
- source = "";
- } else if (RTL.containsSome(source) || source.startsWith("\"")) {
- source = LRM + source + LRM;
- }
- return html ? TransliteratorUtilities.toHTML.transform(source) : source;
- }
-
-
- private static Set<String> getLargestContained(Set<String> value, Collection<Set<String>> collection) {
- Set<String> best = null;
- for (Set<String> set : collection) {
- if (best != null && best.size() > set.size()) {
- continue;
- }
- if (value.containsAll(set)) {
- best = set;
- }
- }
- return best;
- }
-
- private static String getShortAge(int i) {
- String age = UCharacter.getAge(i).toString();
- return age.substring(0,age.indexOf('.',age.indexOf('.') + 1));
- }
-
- static SetMaker setMaker = new SetMaker() {
- public Set make() {
- return new TreeSet();
- }
- };
-
- static UnicodeMap<Set<String>> invisibles = new UnicodeMap();
- static Map<R2<Integer,Integer>, Set<String>> equivalences = new TreeMap<R2<Integer,Integer>, Set<String>>(NFCLowerR2);
-// static Set<String> SKIP_SHAPES = new HashSet<String>(Arrays.asList(
-// "MT-Extra",
-// "JCsmPC",
-// "DFKaiShu-SB-Estd-BF",
-// "LiGothicMed",
-// "LiHeiPro",
-// "LiSongPro",
-// "LiSungLight",
-// "PMingLiU",
-// "SIL-Hei-Med-Jian",
-// "SIL-Kai-Reg-Jian",
-// "CharcoalCY",
-// "GenevaCY",
-// "HelveticaCYBoldOblique",
-// "HelveticaCYOblique",
-// "HelveticaCYPlain",
-// "HoeflerText-Ornaments",
-// "Apple-Chancery",
-// "MSReferenceSpecialty",
-// "Stencil",
-// "Hooge0555",
-// "Hooge0556",
-// "Desdemona",
-// "EccentricStd",
-// "EngraversMT",
-// "MesquiteStd",
-// "RosewoodStd-Fill",
-// "Stencil",
-// "StencilStd",
-// "Osaka",
-// "Osaka-Mono",
-// "Kroeger0455",
-// "Kroeger0456",
-// "Uni0563",
-// "Uni0564",
-// "Code2001",
-// "AppleSymbols",
-// "AppleGothic",
-// "AppleMyungjo",
-// "JCkg",
-// "MalithiWeb",
-// "JCfg"
-// ));
-
- // bug on Mac: http://forums.sun.com/thread.jspa?threadID=5209611
- private static UnicodeSet getCoverage(Font font) {
- String name = font.getFontName();
- boolean skipShapes = SKIP_SHAPES.contains(name);
- UnicodeSet result = new UnicodeSet();
- final FontRenderContext fontRenderContext = new FontRenderContext(null, false, false);
- char[] array = new char[1];
- char[] array2 = new char[2];
- Map<Rectangle2D,Map<Shape,UnicodeSet>> boundsToData = new TreeMap<Rectangle2D,Map<Shape,UnicodeSet>>(ShapeComparator);
- for (UnicodeSetIterator it = new UnicodeSetIterator(COVERAGE); it.next();) {
- if (font.canDisplay(it.codepoint)) {
- char[] temp;
- if (it.codepoint <= 0xFFFF) {
- array[0] = (char) it.codepoint;
- temp = array;
- } else {
- Character.toChars(it.codepoint, array2, 0);
- temp = array2;
- }
-
- GlyphVector glyphVector = font.createGlyphVector(fontRenderContext, temp);
- int glyphCode = glyphVector.getGlyphCode(0);
- boolean validchar = (glyphCode > 0);
- if (!validchar) continue;
-
- result.add(it.codepoint);
-
- if (skipShapes) continue;
- Shape shape = glyphVector.getOutline();
- if (isInvisible(shape)) {
- Set<String> set = invisibles.get(it.codepoint);
- if (set == null) {
- invisibles.put(it.codepoint, set = new TreeSet<String>());
- }
- set.add(name);
- } else {
- Rectangle2D bounds = glyphVector.getVisualBounds();
- Map<Shape, UnicodeSet> map = boundsToData.get(bounds);
- if (map == null) {
- boundsToData.put(bounds, map = new TreeMap<Shape,UnicodeSet>(ShapeComparator));
- }
- UnicodeSet set = map.get(shape);
- if (set == null) {
- map.put(shape, set = new UnicodeSet());
- }
- if (false && set.size() != 0) {
- System.out.println("Adding " + Utility.hex(it.codepoint) + "\t" + UTF16.valueOf(it.codepoint) + "\tto " + set.toPattern(false));
- }
- set.add(it.codepoint);
- }
- }
- }
- //System.out.println(result.size() + "\t" + result);
- for (Rectangle2D bounds : boundsToData.keySet()) {
- Map<Shape, UnicodeSet> map = boundsToData.get(bounds);
- for (UnicodeSet set : map.values()) {
- set.removeAll(CONTROLS);
- if (set.size() != 1) {
- //System.out.println(set.toPattern(false));
- for (UnicodeSetIterator it = new UnicodeSetIterator(set); it.next();) {
- for (UnicodeSetIterator it2 = new UnicodeSetIterator(set); it2.next();) {
- int cp = it.codepoint;
- int cp2 = it2.codepoint;
- if (cp >= cp2) continue;
- R2<Integer, Integer> r = Row.of(cp, cp2);
- Set<String> reasons = equivalences.get(r);
- if (reasons == null) {
- equivalences.put(r, reasons = new TreeSet());
- }
- reasons.add(name);
- }
- }
- }
- }
- }
- return result.freeze();
- }
-
- static Comparator<Rectangle2D> RectComparator = new Comparator<Rectangle2D>() {
-
- public int compare(Rectangle2D r1, Rectangle2D r2) {
- int diff;
- if (0 != (diff = compareDiff(r1.getX(),r2.getX()))) return diff;
- if (0 != (diff = compareDiff(r1.getY(),r2.getY()))) return diff;
- if (0 != (diff = compareDiff(r1.getWidth(),r2.getWidth()))) return diff;
- if (0 != (diff = compareDiff(r1.getHeight(),r2.getHeight()))) return diff;
- return 0;
- }
-
- };
-
- static final AffineTransform IDENTITY = new AffineTransform();
-
- static boolean isInvisible(Shape shape) {
- return shape.getPathIterator(IDENTITY).isDone();
- }
-
- static Comparator<Shape> ShapeComparator = new Comparator<Shape>() {
- float[] coords1 = new float[6];
- float[] coords2 = new float[6];
-
- public int compare(Shape s1, Shape s2) {
- int diff;
- PathIterator p1 = s1.getPathIterator(IDENTITY);
- PathIterator p2 = s2.getPathIterator(IDENTITY);
- while (true) {
- if (p1.isDone()) {
- return p2.isDone() ? 0 : -1;
- } else if (p2.isDone()) {
- return 1;
- }
- int t1 = p1.currentSegment(coords1);
- int t2 = p2.currentSegment(coords2);
- diff = t1 - t2;
- if (diff != 0) return diff;
- /*
- * SEG_MOVETO and SEG_LINETO types returns one point,
- * SEG_QUADTO returns two points,
- * SEG_CUBICTO returns 3 points
- * and SEG_CLOSE does not return any points.
- */
- switch (t1) {
- case PathIterator.SEG_CUBICTO:
- if (0 != (diff = compareDiff(coords1[5],coords2[5]))) return diff;
- if (0 != (diff = compareDiff(coords1[4],coords2[4]))) return diff;
- case PathIterator.SEG_QUADTO:
- if (0 != (diff = compareDiff(coords1[3],coords2[3]))) return diff;
- if (0 != (diff = compareDiff(coords1[2],coords2[2]))) return diff;
- case PathIterator.SEG_MOVETO:
- case PathIterator.SEG_LINETO:
- if (0 != (diff = compareDiff(coords1[1],coords2[1]))) return diff;
- if (0 != (diff = compareDiff(coords1[0],coords2[0]))) return diff;
- case PathIterator.SEG_CLOSE: break;
- default: throw new IllegalArgumentException();
- }
- p1.next();
- p2.next();
- }
- }
- };
-
- private static int compareDiff(float f, float g) {
- return f < g ? -1 : f > g ? 1 : 0;
- }
- private static int compareDiff(double f, double g) {
- return f < g ? -1 : f > g ? 1 : 0;
- }
-}