Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/CSSColor.java
URL: 
http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/CSSColor.java?rev=1913470&r1=1913469&r2=1913470&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/CSSColor.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/CSSColor.java Tue Oct 31 19:15:47 
2023
@@ -1,376 +1,376 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License,
- * Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.pivot.wtk;
-
-import java.awt.Color;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.pivot.wtk.util.ColorUtilities;
-
-/**
- * The complete enumeration of the CSS3/X11 color names and values,
- * taken from here:
- * <a 
href="http://www.w3.org/TR/css3-color/";>http://www.w3.org/TR/css3-color/</a>,
- * and including the Java {@link Color} names (with all British/American
- * spelling variants).
- * <p> Ugly note: Several of these colors including (but not limited to), 
"pink",
- * "green", the "grays", etc. are different between the Java colors and these 
CSS
- * definitions. So, to support everything, the following conventions have been
- * established:
- * <ol><li>The color names are (more-or-less) case-sensitive.</li>
- * <li>Where there are CSS colors and Java colors with similar names (except 
for
- * case differences), the Java colors are found using all lower case (e.g., 
"green")
- * or all UPPER case (e.g., "GREEN") and the CSS value with a mixed-case name
- * (e.g., "Green").</li>
- * <li>If there is no duplicate (e.g., "AliceBlue") then the value can be found
- * using any of these variants.</li>
- * <li>NOTE: this means that other combinations (e.g., "gReEn") which might 
have
- * worked in the past will now fail and throw an exception.
- * </ol>
- * <p> This list also contains the Java versions of the names (complete with 
spelling
- * variations) for complete compatibility, and we put the Java variants in 
first
- * for the sake of the lookup maps.
- * <p> Note: these are available through the
- * {@link GraphicsUtilities#decodeColor GraphicsUtilities.decodeColor()}
- * and {@link org.apache.pivot.wtk.content.ColorItem#allCSSColors} methods.
- */
-public enum CSSColor {
-               AliceBlue(240, 248, 255),
-            AntiqueWhite(250, 235, 215),
-                    Aqua(  0, 255, 255),
-              Aquamarine(127, 255, 212),
-                   Azure(240, 255, 255),
-                   Beige(245, 245, 220),
-                  Bisque(255, 228, 196),
-                   black(Color.black),
-                   BLACK(Color.BLACK),
-                   Black(  0,   0,   0),
-          BlanchedAlmond(255, 235, 205),
-                    blue(Color.blue),
-                    BLUE(Color.BLUE),
-                    Blue(  0,   0, 255),
-              BlueViolet(138,  43, 226),
-                   Brown(165,  42,  42),
-               Burlywood(222, 184, 135),
-               CadetBlue( 95, 158, 160),
-              Chartreuse(127, 255,   0),
-               Chocolate(210, 105,  30),
-                   Coral(255, 127,  80),
-          CornflowerBlue(100, 149, 237),
-                Cornsilk(255, 248, 220),
-                 Crimson(220,  20,  60),
-                    cyan(Color.cyan),
-                    CYAN(Color.CYAN),
-                    Cyan(  0, 255, 255),
-                DarkBlue(  0,   0, 139),
-                DarkCyan(  0, 139, 139),
-           DarkGoldenrod(184, 134,  11),
-                darkGray(Color.darkGray),
-               DARK_GRAY(Color.DARK_GRAY),
-                DarkGray(169, 169, 169),
-               DarkGreen(  0, 100,   0),
-                DarkGrey(169, 169, 169),
-               DarkKhaki(189, 183, 107),
-             DarkMagenta(139,   0, 139),
-          DarkOliveGreen( 85, 107,  47),
-              DarkOrange(255, 140,   0),
-              DarkOrchid(153,  50, 204),
-                 DarkRed(139,   0,   0),
-              DarkSalmon(233, 150, 122),
-            DarkSeaGreen(143, 188, 143),
-           DarkSlateBlue( 72,  61, 139),
-           DarkSlateGray( 47,  79,  79),
-           DarkSlateGrey( 47,  79,  79),
-           DarkTurquoise(  0, 206, 209),
-              DarkViolet(148,   0, 211),
-                DeepPink(255,  20, 147),
-             DeepSkyBlue(  0, 191, 255),
-                 DimGray(105, 105, 105),
-                 DimGrey(105, 105, 105),
-              DodgerBlue( 30, 144, 255),
-               FireBrick(178,  34,  34),
-             FloralWhite(255, 250, 240),
-             ForestGreen( 34, 139,  34),
-                 Fuchsia(255,   0, 255),
-               Gainsboro(220, 220, 220),
-              GhostWhite(248, 248, 255),
-                    Gold(255, 215,   0),
-               Goldenrod(218, 165,  32),
-                    gray(Color.gray),
-                    GRAY(Color.GRAY),
-                    Gray(128, 128, 128),
-                   green(Color.green),
-                   GREEN(Color.GREEN),
-                   Green(  0, 128,   0),
-             GreenYellow(173, 255,  47),
-                    Grey(128, 128, 128),
-                Honeydew(240, 255, 240),
-                 HotPink(255, 105, 180),
-               IndianRed(205,  92,  92),
-                  Indigo( 75,   0, 130),
-                   Ivory(255, 255, 240),
-                   Khaki(240, 230, 140),
-                Lavender(230, 230, 250),
-           LavenderBlush(255, 240, 245),
-               LawnGreen(124, 252,   0),
-            LemonChiffon(255, 250, 205),
-               LightBlue(173, 216, 230),
-              LightCoral(240, 128, 128),
-               LightCyan(224, 255, 255),
-    LightGoldenrodYellow(250, 250, 210),
-               lightGray(Color.lightGray),
-              LIGHT_GRAY(Color.LIGHT_GRAY),
-               LightGray(211, 211, 211),
-              LightGreen(144, 238, 144),
-               LightGrey(211, 211, 211),
-               LightPink(255, 182, 193),
-             LightSalmon(255, 160, 122),
-           LightSeaGreen( 32, 178, 170),
-            LightSkyBlue(135, 206, 250),
-          LightSlateGray(119, 136, 153),
-          LightSlateGrey(119, 136, 153),
-          LightSteelBlue(176, 196, 222),
-             LightYellow(255, 255, 224),
-                    Lime(  0, 255,   0),
-               LimeGreen( 50, 205,  50),
-                   Linen(250, 240, 230),
-                 magenta(Color.magenta),
-                 MAGENTA(Color.MAGENTA),
-                 Magenta(255,   0, 255),
-                  Maroon(128,   0,   0),
-        MediumAquamarine(102, 205, 170),
-              MediumBlue(  0,   0, 205),
-            MediumOrchid(186,  85, 211),
-            MediumPurple(147, 112, 219),
-          MediumSeaGreen( 60, 179, 113),
-         MediumSlateBlue(123, 104, 238),
-       MediumSpringGreen(  0, 250, 154),
-         MediumTurquoise( 72, 209, 204),
-         MediumVioletRed(199,  21, 133),
-            MidnightBlue( 25,  25, 112),
-               MintCream(245, 255, 250),
-               MistyRose(255, 228, 225),
-                Moccasin(255, 228, 181),
-             NavajoWhite(255, 222, 173),
-                    Navy(  0,   0, 128),
-                 OldLace(253, 245, 230),
-                   Olive(128, 128,   0),
-               OliveDrab(107, 142,  35),
-                  orange(Color.orange),
-                  ORANGE(Color.ORANGE),
-                  Orange(255, 165,   0),
-               OrangeRed(255,  69,   0),
-                  Orchid(218, 112, 214),
-           PaleGoldenrod(238, 232, 170),
-               PaleGreen(152, 251, 152),
-           PaleTurquoise(175, 238, 238),
-           PaleVioletRed(219, 112, 147),
-              PapayaWhip(255, 239, 213),
-               PeachPuff(255, 218, 185),
-                    Peru(205, 133,  63),
-                    pink(Color.pink),
-                    PINK(Color.PINK),
-                    Pink(255, 192, 203),
-                    Plum(221, 160, 221),
-              PowderBlue(176, 224, 230),
-                  Purple(128,   0, 128),
-                     red(Color.red),
-                     RED(Color.RED),
-                     Red(255,   0,   0),
-               RosyBrown(188, 143, 143),
-               RoyalBlue( 65, 105, 225),
-             SaddleBrown(139,  69,  19),
-                  Salmon(250, 128, 114),
-              SandyBrown(244, 164,  96),
-                SeaGreen( 46, 139,  87),
-                Seashell(255, 245, 238),
-                  Sienna(160,  82,  45),
-                  Silver(192, 192, 192),
-                 SkyBlue(135, 206, 235),
-               SlateBlue(106,  90, 205),
-               SlateGray(112, 128, 144),
-               SlateGrey(112, 128, 144),
-                    Snow(255, 250, 250),
-             SpringGreen(  0, 255, 127),
-               SteelBlue( 70, 130, 180),
-                     Tan(210, 180, 140),
-                    Teal(  0, 128, 128),
-                 Thistle(216, 191, 216),
-                  Tomato(255,  99,  71),
-               Turquoise( 64, 224, 208),
-                  Violet(238, 130, 238),
-                   Wheat(245, 222, 179),
-                   white(Color.white),
-                   WHITE(Color.WHITE),
-                   White(255, 255, 255),
-              WhiteSmoke(245, 245, 245),
-                  yellow(Color.yellow),
-                  YELLOW(Color.YELLOW),
-                  Yellow(255, 255,   0),
-             YellowGreen(154, 205,  50);
-
-    /** The color value associated with this CSS color name. */
-    private Color color;
-    /** The enum name for this color for matching (note: this value, plus the 
upper- or lower-case
-     * equivalent can be used). */
-    private String colorName;
-
-    /**
-     * Private class that allows us to initialize lookup maps at constructor 
time,
-     * instead of in a static initializer block later.
-     */
-    private static class Lookup {
-        /** A map to translate from a color name to the enum value. */
-        private static Map<String, CSSColor> colorNameMap = new HashMap<>();
-        /** A map to translate from a color value to the enum value. */
-        private static Map<Color, CSSColor> colorValueMap = new HashMap<>();
-    }
-
-    /**
-     * Construct from integer R,G,B values.
-     * @param r The red component of the color.
-     * @param g The green component.
-     * @param b And finally the blue value.
-     */
-    CSSColor(final int r, final int g, final int b) {
-        this(new Color(r, g, b));
-    }
-
-    /**
-     * Construct from one of the {@link Color} equivalents.
-     * @param awtColor The Java AWT color value this corresponds to.
-     */
-    CSSColor(final Color awtColor) {
-        this.color = awtColor;
-        // Okay, this is ugly, BUT Color.GREEN isn't the same color as our 
"Green"
-        // (0,255,0) vs. (0,128,0), so make an ugly hack involving case, such 
that
-        // "Green" is our color, but "green" or "GREEN" is the Java version.
-        String cssName = super.toString();
-        this.colorName = cssName;
-        String lowerName = cssName.toLowerCase(Locale.ENGLISH);
-        String upperName = cssName.toUpperCase(Locale.ENGLISH);
-        // Put the value in as both the native version and the lower- and
-        // upper-case variants, if they differ.
-        // Note: this generally means the Java equivalents (in lower- and
-        // upper-case) must come before the CSS version in mixed-case in
-        // the enum list.
-        Lookup.colorNameMap.put(cssName, this);
-        Lookup.colorNameMap.putIfAbsent(lowerName, this);
-        Lookup.colorNameMap.putIfAbsent(upperName, this);
-        // Note: this reverse map WILL have values replaced by later enums
-        // since many of these colors have the same RGB values.
-        Lookup.colorValueMap.put(this.color, this);
-    }
-
-    /**
-     * @return The standard color value (RGB) for this color according
-     * to the W3C CSS color spec.
-     */
-    public Color getColor() {
-        return this.color;
-    }
-
-    /**
-     * @return The name of this color (as defined in the
-     * W3C CSS color spec), or the Java {@link Color} name.
-     */
-    public String getColorName() {
-        return this.colorName;
-    }
-
-    /**
-     * @return The enum value of the given color name (which can be upper-, 
lower-,
-     * or mixed-case) if it can be found.
-     * @param colorName The name of a color to match with one of our values.
-     * @throws IllegalArgumentException if the color name cannot be found.
-     */
-    public static CSSColor fromString(final String colorName) {
-        // Note: we entered names as lower-, upper-, or mixed-case values
-        // (for the "green" confusion), so one of the variants should match.
-        CSSColor color = Lookup.colorNameMap.get(colorName);
-        if (color == null) {
-            throw new IllegalArgumentException("Incorrect Color format.  "
-                + "Color name \"" + colorName + "\" is not valid.");
-        }
-        return color;
-    }
-
-    /**
-     * @return The enum value of the given color value (solid color)
-     * if it can be found.  Any transparency in the given color is stripped out
-     * before a match is attempted.
-     * @param color The solid color to match with one of our values.
-     * @throws IllegalArgumentException if the color value cannot be found.
-     */
-    public static CSSColor fromColor(final Color color) {
-        Color solidColor = ColorUtilities.toSolidColor(color);
-        CSSColor cssColor = Lookup.colorValueMap.get(solidColor);
-        if (cssColor == null) {
-            throw new IllegalArgumentException("Incorrect Color value.  "
-                + color.toString() + " does not match any CSS color.");
-        }
-        return cssColor;
-    }
-
-    /**
-     * Return the set of all these colors with the same RGB value as the given 
color.
-     * <p> This could be a bit time-consuming because we have to search all 
the values.
-     * @param color An RGB (solid) color to match with these values.
-     * @return The complete set (could be empty) of these colors with the same 
RGB values.
-     */
-    public static Set<CSSColor> getMatchingColors(final Color color) {
-        Set<CSSColor> matches = EnumSet.noneOf(CSSColor.class);
-        Color solidColor = ColorUtilities.toSolidColor(color);
-        for (CSSColor cssColor : values()) {
-            if (cssColor.color.equals(solidColor)) {
-                matches.add(cssColor);
-            }
-        }
-        return matches;
-    }
-
-    /**
-     * Return the set of all these colors with the same RGB value as the given 
{@code CSSColor},
-     * in other words, the synonyms for this color.
-     * <p> This could be a bit time-consuming because we have to search all 
the values.
-     * @param color One of these colors to find the matching enum values.
-     * @return The complete set (could be empty) of these colors with the same 
RGB value (not
-     * including the given color).
-     */
-    public static Set<CSSColor> getMatchingColors(final CSSColor color) {
-        Set<CSSColor> matches = EnumSet.noneOf(CSSColor.class);
-        Color solidColor = color.color;
-        for (CSSColor cssColor : values()) {
-            if (cssColor.color.equals(solidColor) && cssColor != color) {
-                matches.add(cssColor);
-            }
-        }
-        return matches;
-    }
-
-    /**
-     * @return The number of colors in this list.
-     */
-    public static int numberOfColors() {
-        return values().length;
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pivot.wtk;
+
+import java.awt.Color;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.pivot.wtk.util.ColorUtilities;
+
+/**
+ * The complete enumeration of the CSS3/X11 color names and values,
+ * taken from here:
+ * <a 
href="http://www.w3.org/TR/css3-color/";>http://www.w3.org/TR/css3-color/</a>,
+ * and including the Java {@link Color} names (with all British/American
+ * spelling variants).
+ * <p> Ugly note: Several of these colors including (but not limited to), 
"pink",
+ * "green", the "grays", etc. are different between the Java colors and these 
CSS
+ * definitions. So, to support everything, the following conventions have been
+ * established:
+ * <ol><li>The color names are (more-or-less) case-sensitive.</li>
+ * <li>Where there are CSS colors and Java colors with similar names (except 
for
+ * case differences), the Java colors are found using all lower case (e.g., 
"green")
+ * or all UPPER case (e.g., "GREEN") and the CSS value with a mixed-case name
+ * (e.g., "Green").</li>
+ * <li>If there is no duplicate (e.g., "AliceBlue") then the value can be found
+ * using any of these variants.</li>
+ * <li>NOTE: this means that other combinations (e.g., "gReEn") which might 
have
+ * worked in the past will now fail and throw an exception.
+ * </ol>
+ * <p> This list also contains the Java versions of the names (complete with 
spelling
+ * variations) for complete compatibility, and we put the Java variants in 
first
+ * for the sake of the lookup maps.
+ * <p> Note: these are available through the
+ * {@link GraphicsUtilities#decodeColor GraphicsUtilities.decodeColor()}
+ * and {@link org.apache.pivot.wtk.content.ColorItem#allCSSColors} methods.
+ */
+public enum CSSColor {
+               AliceBlue(240, 248, 255),
+            AntiqueWhite(250, 235, 215),
+                    Aqua(  0, 255, 255),
+              Aquamarine(127, 255, 212),
+                   Azure(240, 255, 255),
+                   Beige(245, 245, 220),
+                  Bisque(255, 228, 196),
+                   black(Color.black),
+                   BLACK(Color.BLACK),
+                   Black(  0,   0,   0),
+          BlanchedAlmond(255, 235, 205),
+                    blue(Color.blue),
+                    BLUE(Color.BLUE),
+                    Blue(  0,   0, 255),
+              BlueViolet(138,  43, 226),
+                   Brown(165,  42,  42),
+               Burlywood(222, 184, 135),
+               CadetBlue( 95, 158, 160),
+              Chartreuse(127, 255,   0),
+               Chocolate(210, 105,  30),
+                   Coral(255, 127,  80),
+          CornflowerBlue(100, 149, 237),
+                Cornsilk(255, 248, 220),
+                 Crimson(220,  20,  60),
+                    cyan(Color.cyan),
+                    CYAN(Color.CYAN),
+                    Cyan(  0, 255, 255),
+                DarkBlue(  0,   0, 139),
+                DarkCyan(  0, 139, 139),
+           DarkGoldenrod(184, 134,  11),
+                darkGray(Color.darkGray),
+               DARK_GRAY(Color.DARK_GRAY),
+                DarkGray(169, 169, 169),
+               DarkGreen(  0, 100,   0),
+                DarkGrey(169, 169, 169),
+               DarkKhaki(189, 183, 107),
+             DarkMagenta(139,   0, 139),
+          DarkOliveGreen( 85, 107,  47),
+              DarkOrange(255, 140,   0),
+              DarkOrchid(153,  50, 204),
+                 DarkRed(139,   0,   0),
+              DarkSalmon(233, 150, 122),
+            DarkSeaGreen(143, 188, 143),
+           DarkSlateBlue( 72,  61, 139),
+           DarkSlateGray( 47,  79,  79),
+           DarkSlateGrey( 47,  79,  79),
+           DarkTurquoise(  0, 206, 209),
+              DarkViolet(148,   0, 211),
+                DeepPink(255,  20, 147),
+             DeepSkyBlue(  0, 191, 255),
+                 DimGray(105, 105, 105),
+                 DimGrey(105, 105, 105),
+              DodgerBlue( 30, 144, 255),
+               FireBrick(178,  34,  34),
+             FloralWhite(255, 250, 240),
+             ForestGreen( 34, 139,  34),
+                 Fuchsia(255,   0, 255),
+               Gainsboro(220, 220, 220),
+              GhostWhite(248, 248, 255),
+                    Gold(255, 215,   0),
+               Goldenrod(218, 165,  32),
+                    gray(Color.gray),
+                    GRAY(Color.GRAY),
+                    Gray(128, 128, 128),
+                   green(Color.green),
+                   GREEN(Color.GREEN),
+                   Green(  0, 128,   0),
+             GreenYellow(173, 255,  47),
+                    Grey(128, 128, 128),
+                Honeydew(240, 255, 240),
+                 HotPink(255, 105, 180),
+               IndianRed(205,  92,  92),
+                  Indigo( 75,   0, 130),
+                   Ivory(255, 255, 240),
+                   Khaki(240, 230, 140),
+                Lavender(230, 230, 250),
+           LavenderBlush(255, 240, 245),
+               LawnGreen(124, 252,   0),
+            LemonChiffon(255, 250, 205),
+               LightBlue(173, 216, 230),
+              LightCoral(240, 128, 128),
+               LightCyan(224, 255, 255),
+    LightGoldenrodYellow(250, 250, 210),
+               lightGray(Color.lightGray),
+              LIGHT_GRAY(Color.LIGHT_GRAY),
+               LightGray(211, 211, 211),
+              LightGreen(144, 238, 144),
+               LightGrey(211, 211, 211),
+               LightPink(255, 182, 193),
+             LightSalmon(255, 160, 122),
+           LightSeaGreen( 32, 178, 170),
+            LightSkyBlue(135, 206, 250),
+          LightSlateGray(119, 136, 153),
+          LightSlateGrey(119, 136, 153),
+          LightSteelBlue(176, 196, 222),
+             LightYellow(255, 255, 224),
+                    Lime(  0, 255,   0),
+               LimeGreen( 50, 205,  50),
+                   Linen(250, 240, 230),
+                 magenta(Color.magenta),
+                 MAGENTA(Color.MAGENTA),
+                 Magenta(255,   0, 255),
+                  Maroon(128,   0,   0),
+        MediumAquamarine(102, 205, 170),
+              MediumBlue(  0,   0, 205),
+            MediumOrchid(186,  85, 211),
+            MediumPurple(147, 112, 219),
+          MediumSeaGreen( 60, 179, 113),
+         MediumSlateBlue(123, 104, 238),
+       MediumSpringGreen(  0, 250, 154),
+         MediumTurquoise( 72, 209, 204),
+         MediumVioletRed(199,  21, 133),
+            MidnightBlue( 25,  25, 112),
+               MintCream(245, 255, 250),
+               MistyRose(255, 228, 225),
+                Moccasin(255, 228, 181),
+             NavajoWhite(255, 222, 173),
+                    Navy(  0,   0, 128),
+                 OldLace(253, 245, 230),
+                   Olive(128, 128,   0),
+               OliveDrab(107, 142,  35),
+                  orange(Color.orange),
+                  ORANGE(Color.ORANGE),
+                  Orange(255, 165,   0),
+               OrangeRed(255,  69,   0),
+                  Orchid(218, 112, 214),
+           PaleGoldenrod(238, 232, 170),
+               PaleGreen(152, 251, 152),
+           PaleTurquoise(175, 238, 238),
+           PaleVioletRed(219, 112, 147),
+              PapayaWhip(255, 239, 213),
+               PeachPuff(255, 218, 185),
+                    Peru(205, 133,  63),
+                    pink(Color.pink),
+                    PINK(Color.PINK),
+                    Pink(255, 192, 203),
+                    Plum(221, 160, 221),
+              PowderBlue(176, 224, 230),
+                  Purple(128,   0, 128),
+                     red(Color.red),
+                     RED(Color.RED),
+                     Red(255,   0,   0),
+               RosyBrown(188, 143, 143),
+               RoyalBlue( 65, 105, 225),
+             SaddleBrown(139,  69,  19),
+                  Salmon(250, 128, 114),
+              SandyBrown(244, 164,  96),
+                SeaGreen( 46, 139,  87),
+                Seashell(255, 245, 238),
+                  Sienna(160,  82,  45),
+                  Silver(192, 192, 192),
+                 SkyBlue(135, 206, 235),
+               SlateBlue(106,  90, 205),
+               SlateGray(112, 128, 144),
+               SlateGrey(112, 128, 144),
+                    Snow(255, 250, 250),
+             SpringGreen(  0, 255, 127),
+               SteelBlue( 70, 130, 180),
+                     Tan(210, 180, 140),
+                    Teal(  0, 128, 128),
+                 Thistle(216, 191, 216),
+                  Tomato(255,  99,  71),
+               Turquoise( 64, 224, 208),
+                  Violet(238, 130, 238),
+                   Wheat(245, 222, 179),
+                   white(Color.white),
+                   WHITE(Color.WHITE),
+                   White(255, 255, 255),
+              WhiteSmoke(245, 245, 245),
+                  yellow(Color.yellow),
+                  YELLOW(Color.YELLOW),
+                  Yellow(255, 255,   0),
+             YellowGreen(154, 205,  50);
+
+    /** The color value associated with this CSS color name. */
+    private Color color;
+    /** The enum name for this color for matching (note: this value, plus the 
upper- or lower-case
+     * equivalent can be used). */
+    private String colorName;
+
+    /**
+     * Private class that allows us to initialize lookup maps at constructor 
time,
+     * instead of in a static initializer block later.
+     */
+    private static class Lookup {
+        /** A map to translate from a color name to the enum value. */
+        private static Map<String, CSSColor> colorNameMap = new HashMap<>();
+        /** A map to translate from a color value to the enum value. */
+        private static Map<Color, CSSColor> colorValueMap = new HashMap<>();
+    }
+
+    /**
+     * Construct from integer R,G,B values.
+     * @param r The red component of the color.
+     * @param g The green component.
+     * @param b And finally the blue value.
+     */
+    CSSColor(final int r, final int g, final int b) {
+        this(new Color(r, g, b));
+    }
+
+    /**
+     * Construct from one of the {@link Color} equivalents.
+     * @param awtColor The Java AWT color value this corresponds to.
+     */
+    CSSColor(final Color awtColor) {
+        this.color = awtColor;
+        // Okay, this is ugly, BUT Color.GREEN isn't the same color as our 
"Green"
+        // (0,255,0) vs. (0,128,0), so make an ugly hack involving case, such 
that
+        // "Green" is our color, but "green" or "GREEN" is the Java version.
+        String cssName = super.toString();
+        this.colorName = cssName;
+        String lowerName = cssName.toLowerCase(Locale.ENGLISH);
+        String upperName = cssName.toUpperCase(Locale.ENGLISH);
+        // Put the value in as both the native version and the lower- and
+        // upper-case variants, if they differ.
+        // Note: this generally means the Java equivalents (in lower- and
+        // upper-case) must come before the CSS version in mixed-case in
+        // the enum list.
+        Lookup.colorNameMap.put(cssName, this);
+        Lookup.colorNameMap.putIfAbsent(lowerName, this);
+        Lookup.colorNameMap.putIfAbsent(upperName, this);
+        // Note: this reverse map WILL have values replaced by later enums
+        // since many of these colors have the same RGB values.
+        Lookup.colorValueMap.put(this.color, this);
+    }
+
+    /**
+     * @return The standard color value (RGB) for this color according
+     * to the W3C CSS color spec.
+     */
+    public Color getColor() {
+        return this.color;
+    }
+
+    /**
+     * @return The name of this color (as defined in the
+     * W3C CSS color spec), or the Java {@link Color} name.
+     */
+    public String getColorName() {
+        return this.colorName;
+    }
+
+    /**
+     * @return The enum value of the given color name (which can be upper-, 
lower-,
+     * or mixed-case) if it can be found.
+     * @param colorName The name of a color to match with one of our values.
+     * @throws IllegalArgumentException if the color name cannot be found.
+     */
+    public static CSSColor fromString(final String colorName) {
+        // Note: we entered names as lower-, upper-, or mixed-case values
+        // (for the "green" confusion), so one of the variants should match.
+        CSSColor color = Lookup.colorNameMap.get(colorName);
+        if (color == null) {
+            throw new IllegalArgumentException("Incorrect Color format.  "
+                + "Color name \"" + colorName + "\" is not valid.");
+        }
+        return color;
+    }
+
+    /**
+     * @return The enum value of the given color value (solid color)
+     * if it can be found.  Any transparency in the given color is stripped out
+     * before a match is attempted.
+     * @param color The solid color to match with one of our values.
+     * @throws IllegalArgumentException if the color value cannot be found.
+     */
+    public static CSSColor fromColor(final Color color) {
+        Color solidColor = ColorUtilities.toSolidColor(color);
+        CSSColor cssColor = Lookup.colorValueMap.get(solidColor);
+        if (cssColor == null) {
+            throw new IllegalArgumentException("Incorrect Color value.  "
+                + color.toString() + " does not match any CSS color.");
+        }
+        return cssColor;
+    }
+
+    /**
+     * Return the set of all these colors with the same RGB value as the given 
color.
+     * <p> This could be a bit time-consuming because we have to search all 
the values.
+     * @param color An RGB (solid) color to match with these values.
+     * @return The complete set (could be empty) of these colors with the same 
RGB values.
+     */
+    public static Set<CSSColor> getMatchingColors(final Color color) {
+        Set<CSSColor> matches = EnumSet.noneOf(CSSColor.class);
+        Color solidColor = ColorUtilities.toSolidColor(color);
+        for (CSSColor cssColor : values()) {
+            if (cssColor.color.equals(solidColor)) {
+                matches.add(cssColor);
+            }
+        }
+        return matches;
+    }
+
+    /**
+     * Return the set of all these colors with the same RGB value as the given 
{@code CSSColor},
+     * in other words, the synonyms for this color.
+     * <p> This could be a bit time-consuming because we have to search all 
the values.
+     * @param color One of these colors to find the matching enum values.
+     * @return The complete set (could be empty) of these colors with the same 
RGB value (not
+     * including the given color).
+     */
+    public static Set<CSSColor> getMatchingColors(final CSSColor color) {
+        Set<CSSColor> matches = EnumSet.noneOf(CSSColor.class);
+        Color solidColor = color.color;
+        for (CSSColor cssColor : values()) {
+            if (cssColor.color.equals(solidColor) && cssColor != color) {
+                matches.add(cssColor);
+            }
+        }
+        return matches;
+    }
+
+    /**
+     * @return The number of colors in this list.
+     */
+    public static int numberOfColors() {
+        return values().length;
+    }
+
+}

Propchange: pivot/trunk/wtk/src/org/apache/pivot/wtk/CSSColor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
pivot/trunk/wtk/src/org/apache/pivot/wtk/ComponentTextInputMethodListener.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: pivot/trunk/wtk/src/org/apache/pivot/wtk/FontUtilities.java
URL: 
http://svn.apache.org/viewvc/pivot/trunk/wtk/src/org/apache/pivot/wtk/FontUtilities.java?rev=1913470&r1=1913469&r2=1913470&view=diff
==============================================================================
--- pivot/trunk/wtk/src/org/apache/pivot/wtk/FontUtilities.java (original)
+++ pivot/trunk/wtk/src/org/apache/pivot/wtk/FontUtilities.java Tue Oct 31 
19:15:47 2023
@@ -1,407 +1,407 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to you under the Apache License,
- * Version 2.0 (the "License"); you may not use this file except in
- * compliance with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.pivot.wtk;
-
-import java.awt.Font;
-import java.awt.FontFormatException;
-import java.awt.GraphicsEnvironment;
-import java.io.File;
-import java.io.InputStream;
-import java.io.IOException;
-import java.util.Locale;
-
-import org.apache.pivot.collections.Dictionary;
-import org.apache.pivot.json.JSONSerializer;
-import org.apache.pivot.serialization.SerializationException;
-import org.apache.pivot.util.Utils;
-
-/**
- * Utility class for dealing with fonts.
- */
-public final class FontUtilities {
-
-    /** The standard name for the {@code Arial} font. */
-    public static final String ARIAL = "Arial";
-
-    /**
-     * A list of "standard" sans-serif fonts, useful when cross-platform
-     * support is necessary.
-     */
-    public static final String SANS_SERIF_FONTS =
-        "Verdana, Helvetica, Arial, SansSerif";
-
-    /**
-     * A list of monospaced fonts, useful for text editing areas for code, 
where
-     * column position must be consistent.
-     * <p> Note: this list is adapted from the list at
-     * <a href="https://en.wikipedia.org/wiki/List_of_monospaced_typefaces";>
-     * https://en.wikipedia.org/wiki/List_of_monospaced_typefaces</a> with the 
most-popular or
-     * readily available ones listed here.
-     */
-    public static final String MONOSPACED_FONTS =
-        "Courier New, Andale Mono, Cascadia Code, Consolas, Courier, DejaVu 
Sans Mono, "
-      + "Droid Sans Mono, FreeMono, Inconsolata, Letter Gothic, Liberation 
Mono, "
-      + "Lucida Console, Menlo, Monaco, Noto Mono, Overpass Mono, Monospaced";
-
-
-    /** The obvious factor needed to convert a number to a percentage value. */
-    private static final float PERCENT_SCALE = 100.0f;
-
-    /**
-     * Private constructor for utility class.
-     */
-    private FontUtilities() {
-    }
-
-    /**
-     * Parse out just the "name" part of a font specification.
-     * <p> Note: this logic follows the logic in {@link Font#decode(String)}.
-     *
-     * @param str The font specification to parse.
-     * @return    Just the font name part (which could be a list).
-     */
-    private static String getFontName(final String str) {
-        String fontName = str;
-        int lastHyphen  = str.lastIndexOf('-');
-        int lastSpace   = str.lastIndexOf(' ');
-        char sepChar    = (lastHyphen > lastSpace) ? '-' : ' ';
-        int sizeIndex   = str.lastIndexOf(sepChar);
-        int styleIndex  = str.lastIndexOf(sepChar, sizeIndex - 1);
-        int length      = str.length();
-
-        if (sizeIndex > 0 && sizeIndex + 1 < length) {
-            try {
-                Integer.valueOf(str.substring(sizeIndex + 1));
-            } catch (NumberFormatException nfe) {
-                /* Invalid size, maybe this is the style */
-                styleIndex = sizeIndex;
-                sizeIndex  = length;
-                while (sizeIndex > 0 && str.charAt(sizeIndex - 1) == sepChar) {
-                    sizeIndex--;
-                }
-            }
-        }
-
-        if (styleIndex >= 0 && styleIndex + 1 < length) {
-            String styleName = str.substring(styleIndex + 1, sizeIndex);
-            styleName = styleName.toLowerCase(Locale.ENGLISH);
-            switch (styleName) {
-                case "bolditalic":
-                case "italic":
-                case "bold":
-                case "plain":
-                    break;
-                default:
-                    /* Not a recognized style, must be part of the name */
-                    styleIndex = sizeIndex;
-                    while (styleIndex > 0 && str.charAt(styleIndex - 1) == 
sepChar) {
-                        styleIndex--;
-                    }
-                    break;
-            }
-            fontName = str.substring(0, styleIndex);
-        } else {
-            int fontEnd = length;
-            if (styleIndex > 0) {
-                fontEnd = styleIndex;
-            } else if (sizeIndex > 0) {
-                fontEnd = sizeIndex;
-            }
-            while (fontEnd > 0 && str.charAt(fontEnd - 1) == sepChar) {
-                fontEnd--;
-            }
-            fontName = str.substring(0, fontEnd);
-        }
-
-        return fontName;
-    }
-
-    /**
-     * Interpret a string as a font specification.
-     *
-     * @param value Either a JSON dictionary {@link Theme#deriveFont describing
-     * a font relative to the current theme}, or one of the
-     * {@link Font#decode(String) standard Java font specifications}.
-     * @return The font corresponding to the specification.
-     * @throws IllegalArgumentException if the given string is {@code null}
-     * or empty or the font specification cannot be decoded.
-     */
-    public static Font decodeFont(final String value) {
-        Utils.checkNullOrEmpty(value, "font");
-
-        Font font;
-        if (value.startsWith("{")) {
-            try {
-                font = Theme.deriveFont(JSONSerializer.parseMap(value));
-            } catch (SerializationException exception) {
-                throw new IllegalArgumentException(exception);
-            }
-        } else {
-            font = decode(value);
-        }
-
-        return font;
-    }
-
-    /**
-     * Decode a font specification.
-     * <p> This is the same as {@link Font#decode(String)} except that we will 
allow multiple
-     * font/family names separated by commas as the 
<code><i>fontname</i></code> part of the
-     * spec (much the same as CSS allows).
-     * <p>The list of allowed formats is:
-     * <ul><li><i>fontname-style-pointsize</i></li>
-     * <li><i>fontname-pointsize</i></li>
-     * <li><i>fontname-style</i></li>
-     * <li><i>fontname</i></li>
-     * <li><i>fontname style pointsize</i></li>
-     * <li><i>fontname pointsize</i></li>
-     * <li><i>fontname style</i></li>
-     * <li><i>fontname</i></li>
-     * </ul>
-     * where <i>fontname</i> can be <i>fontname</i>[,<i>fontname</i>]*.
-     *
-     * @param str The font specification as above.
-     * @return    The font according to the desired specification as much as 
possible.
-     * @see       Font#decode(String)
-     */
-    public static Font decode(final String str) {
-        if (Utils.isNullOrEmpty(str)) {
-            return Font.decode(str);
-        }
-
-        if (str.indexOf(',') > 0) {
-            String name = getFontName(str);
-            int pos     = name.length();
-            String spec = pos < str.length() ? str.substring(pos) : "";
-
-            String[] names = name.split("\\s*,\\s*");
-            for (String nm : names) {
-                Font f = Font.decode(nm + spec);
-                if (f.getName().equalsIgnoreCase(nm) || 
f.getFamily().equalsIgnoreCase(nm)) {
-                    return f;
-                }
-            }
-
-            // No names matched in the list, so use the default name
-            return Font.decode(Font.DIALOG + spec);
-        }
-
-        return Font.decode(str);
-    }
-
-    /**
-     * Decode a font specification, choosing the first font in the list 
capable of displaying
-     * the given characters. If only one font name is given, that font will be 
selected
-     * regardless of its ability to display the test string of characters. If 
no fonts in the
-     * list are capable of displaying the characters then the default system 
font (<code>DIALOG</code>)
-     * will be returned.
-     * <p> This is the same as {@link Font#decode(String)} except that we will 
allow multiple
-     * font/family names separated by commas as the 
<code><i>fontname</i></code> part of the
-     * spec (much the same as CSS allows), with the proviso that any font 
chosen from the list must be
-     * capable of displaying all the given characters.
-     * <p>The list of allowed formats is:
-     * <ul><li><i>fontname-style-pointsize</i></li>
-     * <li><i>fontname-pointsize</i></li>
-     * <li><i>fontname-style</i></li>
-     * <li><i>fontname</i></li>
-     * <li><i>fontname style pointsize</i></li>
-     * <li><i>fontname pointsize</i></li>
-     * <li><i>fontname style</i></li>
-     * <li><i>fontname</i></li>
-     * </ul>
-     * where <i>fontname</i> can be <i>fontname</i>[,<i>fontname</i>]*.
-     *
-     * @param str        The font specification as above.
-     * @param testString The characters that must have glyphs available to 
display (can be <code>null</code>
-     *                   to skip the "capable" test) (only applicable if 
multiple font names are given to
-     *                   choose from).
-     * @return           The font according to the desired specification as 
much as possible.
-     * @see              Font#decode(String)
-     */
-    public static Font decodeCapable(final String str, final String 
testString) {
-        if (Utils.isNullOrEmpty(str)) {
-            return Font.decode(str);
-        }
-
-        if (str.indexOf(',') > 0) {
-            String name = getFontName(str);
-            int pos     = name.length();
-            String spec = pos < str.length() ? str.substring(pos) : "";
-
-            String[] names = name.split("\\s*,\\s*");
-            for (String nm : names) {
-                Font f = Font.decode(nm + spec);
-                if (f.getName().equalsIgnoreCase(nm) || 
f.getFamily().equalsIgnoreCase(nm)) {
-                    if (testString == null || testString.isEmpty() || 
f.canDisplayUpTo(testString) < 0) {
-                        return f;
-                    }
-                }
-            }
-
-            // No names matched in the list, so use the default name (either 
monospaced or not)
-            if (str.indexOf("Mono") >= 0) {
-                return Font.decode(Font.MONOSPACED + spec);
-            } else {
-                return Font.decode(Font.DIALOG + spec);
-            }
-        }
-
-        return Font.decode(str);
-    }
-    /**
-     * Get a new font with the given name, style, and size.
-     * <p> The {@code name} can be a comma-separated list of names, and the 
first one matched will be used.
-     *
-     * @param name  The font name, which can be a list (such as 
<code>Arial,Verdana,SansSerif</code> with
-     *              no spaces).
-     * @param style The integer font style (as in {@link Font#PLAIN} or {@link 
Font#ITALIC}).
-     * @param size  The integer font size (in points).
-     * @return      The newly created font with these attributes.
-     */
-    public static Font getFont(final String name, final int style, final int 
size) {
-        if (Utils.isNullOrEmpty(name)) {
-            return new Font(name, style, size);
-        }
-
-        if (name.indexOf(',') > 0) {
-            String[] names = name.split("\\s*,\\s*");
-            for (String nm : names) {
-                Font f = new Font(nm, style, size);
-                if (f.getName().equalsIgnoreCase(nm) || 
f.getFamily().equalsIgnoreCase(nm)) {
-                    return f;
-                }
-            }
-
-            // No names matched in the list, so use the default name
-            return new Font(Font.DIALOG, style, size);
-        }
-
-        return new Font(name, style, size);
-    }
-
-    /**
-     * Decode a font size specification, taking into account "nnn%" form, and 
the existing size.
-     *
-     * @param sizeValue The input size value, could be a number or a numeric 
string, or a number
-     * followed by "%".
-     * @param existingSize The existing font size, which will be adjusted by 
the percentage.
-     * Can be null, in which case the original size is returned. Otherwise it 
is unused.
-     * @return The new font size value.
-     * @throws IllegalArgumentException if the sizeValue cannot be decoded.
-     */
-    public static int decodeFontSize(final Object sizeValue, final int 
existingSize) {
-        int adjustedSize = existingSize;
-
-        if (sizeValue != null) {
-            if (sizeValue instanceof String) {
-                String string = (String) sizeValue;
-
-                try {
-                    if (string.endsWith("%")) {
-                        float percentage = 
Float.parseFloat(string.substring(0, string.length() - 1)) / PERCENT_SCALE;
-                        adjustedSize = Math.round(existingSize * percentage);
-                    } else {
-                        adjustedSize = Float.valueOf(string).intValue();
-                    }
-                } catch (NumberFormatException nfe) {
-                    throw new IllegalArgumentException("\"" + sizeValue + "\" 
is not a valid font size!");
-                }
-            } else if (sizeValue instanceof Number) {
-                adjustedSize = ((Number) sizeValue).intValue();
-            } else {
-                throw new IllegalArgumentException("\"" + sizeValue + "\" is 
not a valid font size!");
-            }
-        }
-
-        return adjustedSize;
-    }
-
-    /**
-     * Convert any object we support into its corresponding font.
-     * <p> Uses {@link #decodeFont} or {@link Theme#deriveFont}
-     * to do the work.
-     *
-     * @param fontValue The object to be converted to a font.
-     * @return The converted font.
-     * @throws IllegalArgumentException if the value is {@code null} or
-     * cannot be converted.
-     */
-    public static Font fromObject(final Object fontValue) {
-        Utils.checkNull(fontValue, "font");
-
-        if (fontValue instanceof Font) {
-            return (Font) fontValue;
-        } else if (fontValue instanceof String) {
-            return decodeFont((String) fontValue);
-        } else if (fontValue instanceof Dictionary) {
-            @SuppressWarnings("unchecked")
-            Dictionary<String, ?> fontDictionary = (Dictionary<String, ?>) 
fontValue;
-            return Theme.deriveFont(fontDictionary);
-        } else {
-            throw new IllegalArgumentException("Unable to convert "
-                + fontValue.getClass().getSimpleName() + " to Font!");
-        }
-    }
-
-    /**
-     * Install a new font for use by this program (only).
-     *
-     * @param fullFontFilePath The complete path (on disk) to the local font 
file
-     *                         (must be a TrueType font in this case).
-     * @return The newly created / registered font if successful, 
<code>null</code> otherwise.
-     * @throws IOException if there was a problem reading the font from the 
file.
-     * @throws FontFormatException if the font file itself was malformed.
-     */
-    public static Font registerFont(final File fullFontFilePath)
-        throws IOException, FontFormatException {
-        try {
-            GraphicsEnvironment ge = 
GraphicsEnvironment.getLocalGraphicsEnvironment();
-            Font f = Font.createFont(Font.TRUETYPE_FONT, fullFontFilePath);
-            if (ge.registerFont(f)) {
-                return f;
-            }
-            return null;
-        } catch (IOException | FontFormatException ex) {
-            throw ex;
-        }
-    }
-
-    /**
-     * Install a new font for use by this program (only).
-     *
-     * @param fontInputStream The stream of bytes describing this font
-     *                        (must be a TrueType font in this case). Also 
note that the
-     *                        caller is responsible for closing this input 
stream.
-     * @return The newly created / registered font if successful, 
<code>null</code> otherwise.
-     * @throws IOException if there was a problem reading the font from the 
file.
-     * @throws FontFormatException if the font file itself was malformed.
-     */
-    public static Font registerFont(final InputStream fontInputStream)
-        throws IOException, FontFormatException {
-        try {
-            GraphicsEnvironment ge = 
GraphicsEnvironment.getLocalGraphicsEnvironment();
-            Font f = Font.createFont(Font.TRUETYPE_FONT, fontInputStream);
-            if (ge.registerFont(f)) {
-                return f;
-            }
-            return null;
-        } catch (IOException | FontFormatException ex) {
-            throw ex;
-        }
-    }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pivot.wtk;
+
+import java.awt.Font;
+import java.awt.FontFormatException;
+import java.awt.GraphicsEnvironment;
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Locale;
+
+import org.apache.pivot.collections.Dictionary;
+import org.apache.pivot.json.JSONSerializer;
+import org.apache.pivot.serialization.SerializationException;
+import org.apache.pivot.util.Utils;
+
+/**
+ * Utility class for dealing with fonts.
+ */
+public final class FontUtilities {
+
+    /** The standard name for the {@code Arial} font. */
+    public static final String ARIAL = "Arial";
+
+    /**
+     * A list of "standard" sans-serif fonts, useful when cross-platform
+     * support is necessary.
+     */
+    public static final String SANS_SERIF_FONTS =
+        "Verdana, Helvetica, Arial, SansSerif";
+
+    /**
+     * A list of monospaced fonts, useful for text editing areas for code, 
where
+     * column position must be consistent.
+     * <p> Note: this list is adapted from the list at
+     * <a href="https://en.wikipedia.org/wiki/List_of_monospaced_typefaces";>
+     * https://en.wikipedia.org/wiki/List_of_monospaced_typefaces</a> with the 
most-popular or
+     * readily available ones listed here.
+     */
+    public static final String MONOSPACED_FONTS =
+        "Courier New, Andale Mono, Cascadia Code, Consolas, Courier, DejaVu 
Sans Mono, "
+      + "Droid Sans Mono, FreeMono, Inconsolata, Letter Gothic, Liberation 
Mono, "
+      + "Lucida Console, Menlo, Monaco, Noto Mono, Overpass Mono, Monospaced";
+
+
+    /** The obvious factor needed to convert a number to a percentage value. */
+    private static final float PERCENT_SCALE = 100.0f;
+
+    /**
+     * Private constructor for utility class.
+     */
+    private FontUtilities() {
+    }
+
+    /**
+     * Parse out just the "name" part of a font specification.
+     * <p> Note: this logic follows the logic in {@link Font#decode(String)}.
+     *
+     * @param str The font specification to parse.
+     * @return    Just the font name part (which could be a list).
+     */
+    private static String getFontName(final String str) {
+        String fontName = str;
+        int lastHyphen  = str.lastIndexOf('-');
+        int lastSpace   = str.lastIndexOf(' ');
+        char sepChar    = (lastHyphen > lastSpace) ? '-' : ' ';
+        int sizeIndex   = str.lastIndexOf(sepChar);
+        int styleIndex  = str.lastIndexOf(sepChar, sizeIndex - 1);
+        int length      = str.length();
+
+        if (sizeIndex > 0 && sizeIndex + 1 < length) {
+            try {
+                Integer.valueOf(str.substring(sizeIndex + 1));
+            } catch (NumberFormatException nfe) {
+                /* Invalid size, maybe this is the style */
+                styleIndex = sizeIndex;
+                sizeIndex  = length;
+                while (sizeIndex > 0 && str.charAt(sizeIndex - 1) == sepChar) {
+                    sizeIndex--;
+                }
+            }
+        }
+
+        if (styleIndex >= 0 && styleIndex + 1 < length) {
+            String styleName = str.substring(styleIndex + 1, sizeIndex);
+            styleName = styleName.toLowerCase(Locale.ENGLISH);
+            switch (styleName) {
+                case "bolditalic":
+                case "italic":
+                case "bold":
+                case "plain":
+                    break;
+                default:
+                    /* Not a recognized style, must be part of the name */
+                    styleIndex = sizeIndex;
+                    while (styleIndex > 0 && str.charAt(styleIndex - 1) == 
sepChar) {
+                        styleIndex--;
+                    }
+                    break;
+            }
+            fontName = str.substring(0, styleIndex);
+        } else {
+            int fontEnd = length;
+            if (styleIndex > 0) {
+                fontEnd = styleIndex;
+            } else if (sizeIndex > 0) {
+                fontEnd = sizeIndex;
+            }
+            while (fontEnd > 0 && str.charAt(fontEnd - 1) == sepChar) {
+                fontEnd--;
+            }
+            fontName = str.substring(0, fontEnd);
+        }
+
+        return fontName;
+    }
+
+    /**
+     * Interpret a string as a font specification.
+     *
+     * @param value Either a JSON dictionary {@link Theme#deriveFont describing
+     * a font relative to the current theme}, or one of the
+     * {@link Font#decode(String) standard Java font specifications}.
+     * @return The font corresponding to the specification.
+     * @throws IllegalArgumentException if the given string is {@code null}
+     * or empty or the font specification cannot be decoded.
+     */
+    public static Font decodeFont(final String value) {
+        Utils.checkNullOrEmpty(value, "font");
+
+        Font font;
+        if (value.startsWith("{")) {
+            try {
+                font = Theme.deriveFont(JSONSerializer.parseMap(value));
+            } catch (SerializationException exception) {
+                throw new IllegalArgumentException(exception);
+            }
+        } else {
+            font = decode(value);
+        }
+
+        return font;
+    }
+
+    /**
+     * Decode a font specification.
+     * <p> This is the same as {@link Font#decode(String)} except that we will 
allow multiple
+     * font/family names separated by commas as the 
<code><i>fontname</i></code> part of the
+     * spec (much the same as CSS allows).
+     * <p>The list of allowed formats is:
+     * <ul><li><i>fontname-style-pointsize</i></li>
+     * <li><i>fontname-pointsize</i></li>
+     * <li><i>fontname-style</i></li>
+     * <li><i>fontname</i></li>
+     * <li><i>fontname style pointsize</i></li>
+     * <li><i>fontname pointsize</i></li>
+     * <li><i>fontname style</i></li>
+     * <li><i>fontname</i></li>
+     * </ul>
+     * where <i>fontname</i> can be <i>fontname</i>[,<i>fontname</i>]*.
+     *
+     * @param str The font specification as above.
+     * @return    The font according to the desired specification as much as 
possible.
+     * @see       Font#decode(String)
+     */
+    public static Font decode(final String str) {
+        if (Utils.isNullOrEmpty(str)) {
+            return Font.decode(str);
+        }
+
+        if (str.indexOf(',') > 0) {
+            String name = getFontName(str);
+            int pos     = name.length();
+            String spec = pos < str.length() ? str.substring(pos) : "";
+
+            String[] names = name.split("\\s*,\\s*");
+            for (String nm : names) {
+                Font f = Font.decode(nm + spec);
+                if (f.getName().equalsIgnoreCase(nm) || 
f.getFamily().equalsIgnoreCase(nm)) {
+                    return f;
+                }
+            }
+
+            // No names matched in the list, so use the default name
+            return Font.decode(Font.DIALOG + spec);
+        }
+
+        return Font.decode(str);
+    }
+
+    /**
+     * Decode a font specification, choosing the first font in the list 
capable of displaying
+     * the given characters. If only one font name is given, that font will be 
selected
+     * regardless of its ability to display the test string of characters. If 
no fonts in the
+     * list are capable of displaying the characters then the default system 
font (<code>DIALOG</code>)
+     * will be returned.
+     * <p> This is the same as {@link Font#decode(String)} except that we will 
allow multiple
+     * font/family names separated by commas as the 
<code><i>fontname</i></code> part of the
+     * spec (much the same as CSS allows), with the proviso that any font 
chosen from the list must be
+     * capable of displaying all the given characters.
+     * <p>The list of allowed formats is:
+     * <ul><li><i>fontname-style-pointsize</i></li>
+     * <li><i>fontname-pointsize</i></li>
+     * <li><i>fontname-style</i></li>
+     * <li><i>fontname</i></li>
+     * <li><i>fontname style pointsize</i></li>
+     * <li><i>fontname pointsize</i></li>
+     * <li><i>fontname style</i></li>
+     * <li><i>fontname</i></li>
+     * </ul>
+     * where <i>fontname</i> can be <i>fontname</i>[,<i>fontname</i>]*.
+     *
+     * @param str        The font specification as above.
+     * @param testString The characters that must have glyphs available to 
display (can be <code>null</code>
+     *                   to skip the "capable" test) (only applicable if 
multiple font names are given to
+     *                   choose from).
+     * @return           The font according to the desired specification as 
much as possible.
+     * @see              Font#decode(String)
+     */
+    public static Font decodeCapable(final String str, final String 
testString) {
+        if (Utils.isNullOrEmpty(str)) {
+            return Font.decode(str);
+        }
+
+        if (str.indexOf(',') > 0) {
+            String name = getFontName(str);
+            int pos     = name.length();
+            String spec = pos < str.length() ? str.substring(pos) : "";
+
+            String[] names = name.split("\\s*,\\s*");
+            for (String nm : names) {
+                Font f = Font.decode(nm + spec);
+                if (f.getName().equalsIgnoreCase(nm) || 
f.getFamily().equalsIgnoreCase(nm)) {
+                    if (testString == null || testString.isEmpty() || 
f.canDisplayUpTo(testString) < 0) {
+                        return f;
+                    }
+                }
+            }
+
+            // No names matched in the list, so use the default name (either 
monospaced or not)
+            if (str.indexOf("Mono") >= 0) {
+                return Font.decode(Font.MONOSPACED + spec);
+            } else {
+                return Font.decode(Font.DIALOG + spec);
+            }
+        }
+
+        return Font.decode(str);
+    }
+    /**
+     * Get a new font with the given name, style, and size.
+     * <p> The {@code name} can be a comma-separated list of names, and the 
first one matched will be used.
+     *
+     * @param name  The font name, which can be a list (such as 
<code>Arial,Verdana,SansSerif</code> with
+     *              no spaces).
+     * @param style The integer font style (as in {@link Font#PLAIN} or {@link 
Font#ITALIC}).
+     * @param size  The integer font size (in points).
+     * @return      The newly created font with these attributes.
+     */
+    public static Font getFont(final String name, final int style, final int 
size) {
+        if (Utils.isNullOrEmpty(name)) {
+            return new Font(name, style, size);
+        }
+
+        if (name.indexOf(',') > 0) {
+            String[] names = name.split("\\s*,\\s*");
+            for (String nm : names) {
+                Font f = new Font(nm, style, size);
+                if (f.getName().equalsIgnoreCase(nm) || 
f.getFamily().equalsIgnoreCase(nm)) {
+                    return f;
+                }
+            }
+
+            // No names matched in the list, so use the default name
+            return new Font(Font.DIALOG, style, size);
+        }
+
+        return new Font(name, style, size);
+    }
+
+    /**
+     * Decode a font size specification, taking into account "nnn%" form, and 
the existing size.
+     *
+     * @param sizeValue The input size value, could be a number or a numeric 
string, or a number
+     * followed by "%".
+     * @param existingSize The existing font size, which will be adjusted by 
the percentage.
+     * Can be null, in which case the original size is returned. Otherwise it 
is unused.
+     * @return The new font size value.
+     * @throws IllegalArgumentException if the sizeValue cannot be decoded.
+     */
+    public static int decodeFontSize(final Object sizeValue, final int 
existingSize) {
+        int adjustedSize = existingSize;
+
+        if (sizeValue != null) {
+            if (sizeValue instanceof String) {
+                String string = (String) sizeValue;
+
+                try {
+                    if (string.endsWith("%")) {
+                        float percentage = 
Float.parseFloat(string.substring(0, string.length() - 1)) / PERCENT_SCALE;
+                        adjustedSize = Math.round(existingSize * percentage);
+                    } else {
+                        adjustedSize = Float.valueOf(string).intValue();
+                    }
+                } catch (NumberFormatException nfe) {
+                    throw new IllegalArgumentException("\"" + sizeValue + "\" 
is not a valid font size!");
+                }
+            } else if (sizeValue instanceof Number) {
+                adjustedSize = ((Number) sizeValue).intValue();
+            } else {
+                throw new IllegalArgumentException("\"" + sizeValue + "\" is 
not a valid font size!");
+            }
+        }
+
+        return adjustedSize;
+    }
+
+    /**
+     * Convert any object we support into its corresponding font.
+     * <p> Uses {@link #decodeFont} or {@link Theme#deriveFont}
+     * to do the work.
+     *
+     * @param fontValue The object to be converted to a font.
+     * @return The converted font.
+     * @throws IllegalArgumentException if the value is {@code null} or
+     * cannot be converted.
+     */
+    public static Font fromObject(final Object fontValue) {
+        Utils.checkNull(fontValue, "font");
+
+        if (fontValue instanceof Font) {
+            return (Font) fontValue;
+        } else if (fontValue instanceof String) {
+            return decodeFont((String) fontValue);
+        } else if (fontValue instanceof Dictionary) {
+            @SuppressWarnings("unchecked")
+            Dictionary<String, ?> fontDictionary = (Dictionary<String, ?>) 
fontValue;
+            return Theme.deriveFont(fontDictionary);
+        } else {
+            throw new IllegalArgumentException("Unable to convert "
+                + fontValue.getClass().getSimpleName() + " to Font!");
+        }
+    }
+
+    /**
+     * Install a new font for use by this program (only).
+     *
+     * @param fullFontFilePath The complete path (on disk) to the local font 
file
+     *                         (must be a TrueType font in this case).
+     * @return The newly created / registered font if successful, 
<code>null</code> otherwise.
+     * @throws IOException if there was a problem reading the font from the 
file.
+     * @throws FontFormatException if the font file itself was malformed.
+     */
+    public static Font registerFont(final File fullFontFilePath)
+        throws IOException, FontFormatException {
+        try {
+            GraphicsEnvironment ge = 
GraphicsEnvironment.getLocalGraphicsEnvironment();
+            Font f = Font.createFont(Font.TRUETYPE_FONT, fullFontFilePath);
+            if (ge.registerFont(f)) {
+                return f;
+            }
+            return null;
+        } catch (IOException | FontFormatException ex) {
+            throw ex;
+        }
+    }
+
+    /**
+     * Install a new font for use by this program (only).
+     *
+     * @param fontInputStream The stream of bytes describing this font
+     *                        (must be a TrueType font in this case). Also 
note that the
+     *                        caller is responsible for closing this input 
stream.
+     * @return The newly created / registered font if successful, 
<code>null</code> otherwise.
+     * @throws IOException if there was a problem reading the font from the 
file.
+     * @throws FontFormatException if the font file itself was malformed.
+     */
+    public static Font registerFont(final InputStream fontInputStream)
+        throws IOException, FontFormatException {
+        try {
+            GraphicsEnvironment ge = 
GraphicsEnvironment.getLocalGraphicsEnvironment();
+            Font f = Font.createFont(Font.TRUETYPE_FONT, fontInputStream);
+            if (ge.registerFont(f)) {
+                return f;
+            }
+            return null;
+        } catch (IOException | FontFormatException ex) {
+            throw ex;
+        }
+    }
+
+}

Propchange: pivot/trunk/wtk/src/org/apache/pivot/wtk/FontUtilities.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to