modules/graphics/src/main/java/javafx/css/StyleConverter.java

Print this page
rev 9240 : 8076423: JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization

@@ -23,34 +23,61 @@
  * questions.
  */
 
 package javafx.css;
 
-import com.sun.javafx.css.converters.BooleanConverter;
-import com.sun.javafx.css.converters.ColorConverter;
-import com.sun.javafx.css.converters.DurationConverter;
-import com.sun.javafx.css.converters.EffectConverter;
-import com.sun.javafx.css.converters.EnumConverter;
-import com.sun.javafx.css.converters.FontConverter;
-import com.sun.javafx.css.converters.InsetsConverter;
-import com.sun.javafx.css.converters.PaintConverter;
-import com.sun.javafx.css.converters.SizeConverter;
-import com.sun.javafx.css.converters.StringConverter;
-import com.sun.javafx.css.converters.URLConverter;
+import javafx.css.converter.BooleanConverter;
+import javafx.css.converter.ColorConverter;
+import javafx.css.converter.DeriveColorConverter;
+import javafx.css.converter.DeriveSizeConverter;
+import javafx.css.converter.DurationConverter;
+import javafx.css.converter.EffectConverter;
+import javafx.css.converter.EnumConverter;
+import javafx.css.converter.FontConverter;
+import javafx.css.converter.InsetsConverter;
+import javafx.css.converter.LadderConverter;
+import javafx.css.converter.PaintConverter;
+import javafx.css.converter.SizeConverter;
+import javafx.css.converter.StopConverter;
+import javafx.css.converter.StringConverter;
+import javafx.css.converter.URLConverter;
 import javafx.geometry.Insets;
 import javafx.scene.effect.Effect;
 import javafx.scene.paint.Color;
 import javafx.scene.paint.Paint;
 import javafx.scene.text.Font;
 import javafx.util.Duration;
 
+import com.sun.javafx.scene.layout.region.CornerRadiiConverter;
+import com.sun.javafx.util.Logging;
+import sun.util.logging.PlatformLogger;
+import sun.util.logging.PlatformLogger.Level;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+
 /**
- * Converter converts {@code ParsedValue&tl;F,T>} from type F to type T. the
+ * StyleConverter converts {@code ParsedValue&tl;F,T>} from type F to type T. The
  * {@link CssMetaData} API requires a {@code StyleConverter} which is used
  * when computing a value for the {@see StyleableProperty}. There are
  * a number of predefined converters which are accessible by the static 
  * methods of this class.
+ *
+ * F is the type of the parsed value, T is the converted type of
+ * the ParsedValueImpl. For example, a converter from String to Color would
+ * be declared
+ * <p>&nbsp;&nbsp;&nbsp;&nbsp;
+ * <code>public Color convert(ParsedValueImpl&lt;String,Color&gt; value, Font font)</code>
+ * </p>
+ *
  * @see ParsedValue
  * @see StyleableProperty
  * @since JavaFX 8.0
  */
 public class StyleConverter<F, T> {

@@ -183,6 +210,330 @@
     public static StyleConverter<ParsedValue[], String> getUrlConverter() {
         return URLConverter.getInstance();
     }
     
 
+
+
+    /**
+     * Convert from the constituent values to the target property type.
+     * Implemented by Types that have Keys with subKeys.
+     *
+     * @since 9
+     */
+    public T convert(Map<CssMetaData<? extends Styleable, ?>,Object> convertedValues) {
+        return null;
+    }
+
+    /**
+     *
+     * @since 9
+     */
+    public void writeBinary(DataOutputStream os, StringStore sstore)
+            throws IOException {
+
+        String cname = getClass().getName();
+        int index = sstore.addString(cname);
+        os.writeShort(index);
+    }
+
+    private static Map<ParsedValue, Object> cache;
+
+    /**
+     *
+     * @since 9
+     */
+    public static void clearCache() { 
+        if (cache != null) {
+            cache.clear(); 
+        }
+    }
+
+    /**
+     *
+     * @since 9
+     */
+    protected T getCachedValue(ParsedValue key) {
+        if (cache != null) {
+            return (T)cache.get(key);
+        }
+        return null;
+    }
+
+    /**
+     *
+     * @since 9
+     */
+    protected void cacheValue(ParsedValue key, Object value) {
+        if (cache == null) cache = new WeakHashMap<>();
+        cache.put(key, value);
+    }
+
+    // map of StyleConverter class name to StyleConverter
+    private static Map<String,StyleConverter<?, ?>> tmap;
+
+    /**
+     *
+     * @since 9
+     */
+    @SuppressWarnings("rawtypes")
+    public static StyleConverter<?,?> readBinary(DataInputStream is, String[] strings)
+            throws IOException {
+
+        int index = is.readShort();
+        String cname = strings[index];
+
+        if (cname == null || cname.isEmpty()) return null;
+
+        if (cname.startsWith("com.sun.javafx.css.converters.")) {
+            // JavaFX 9: converter classes were moved from
+            // com.sun.javafx.css.converters.* to javafx.css.converter.*
+            // Note: the word 'converters' has become 'converter'.
+            cname = "javafx.css.converter." + cname.substring("com.sun.javafx.css.converters.".length());
+        }
+        if (cname.startsWith("javafx.css.converter.EnumConverter")) {
+            return (StyleConverter)javafx.css.converter.EnumConverter.readBinary(is, strings);
+        }
+
+        // Make a new entry in tmap, if necessary
+        if (tmap == null || !tmap.containsKey(cname)) {
+            StyleConverter<?,?> converter = getInstance(cname);
+            if (converter == null) {
+                final PlatformLogger logger = Logging.getCSSLogger();
+                if (logger.isLoggable(Level.SEVERE)) {
+                    logger.severe("could not deserialize " + cname);
+                }
+            }
+            if (converter == null) {
+                System.err.println("could not deserialize " + cname);
+            }
+            if (tmap == null) tmap = new HashMap<String,StyleConverter<?,?>>();
+            tmap.put(cname, converter);
+            return converter;
+        }
+        return tmap.get(cname);
+    }
+
+    // package for unit test purposes
+    static StyleConverter<?,?> getInstance(final String converterClass) {
+
+        StyleConverter<?,?> styleConverter = null;
+
+        switch(converterClass) {
+        case "javafx.css.converter.BooleanConverter" :
+            styleConverter = javafx.css.converter.BooleanConverter.getInstance();
+            break;
+        case "javafx.css.converter.ColorConverter" :
+            styleConverter = javafx.css.converter.ColorConverter.getInstance();
+            break;
+        case "javafx.css.converter.CursorConverter" :
+            styleConverter = javafx.css.converter.CursorConverter.getInstance();
+            break;
+        case "javafx.css.converter.EffectConverter" :
+            styleConverter = javafx.css.converter.EffectConverter.getInstance();
+            break;
+        case "javafx.css.converter.EffectConverter$DropShadowConverter" :
+            styleConverter = javafx.css.converter.EffectConverter.DropShadowConverter.getInstance();
+            break;
+        case "javafx.css.converter.EffectConverter$InnerShadowConverter" :
+            styleConverter = javafx.css.converter.EffectConverter.InnerShadowConverter.getInstance();
+            break;
+        case "javafx.css.converter.FontConverter" :
+            styleConverter = javafx.css.converter.FontConverter.getInstance();
+            break;
+        case "javafx.css.converter.FontConverter$FontStyleConverter" :
+        case "javafx.css.converter.FontConverter$StyleConverter" :
+            styleConverter = javafx.css.converter.FontConverter.FontStyleConverter.getInstance();
+            break;
+        case "javafx.css.converter.FontConverter$FontWeightConverter" :
+        case "javafx.css.converter.FontConverter$WeightConverter" :
+            styleConverter = javafx.css.converter.FontConverter.FontWeightConverter.getInstance();
+            break;
+        case "javafx.css.converter.FontConverter$FontSizeConverter" :
+        case "javafx.css.converter.FontConverter$SizeConverter" :
+            styleConverter = javafx.css.converter.FontConverter.FontSizeConverter.getInstance();
+            break;
+
+        case "javafx.css.converter.InsetsConverter" :
+            styleConverter = javafx.css.converter.InsetsConverter.getInstance();
+            break;
+        case "javafx.css.converter.InsetsConverter$SequenceConverter" :
+            styleConverter = javafx.css.converter.InsetsConverter.SequenceConverter.getInstance();
+            break;
+
+        case "javafx.css.converter.PaintConverter" :
+            styleConverter = javafx.css.converter.PaintConverter.getInstance();
+            break;
+        case "javafx.css.converter.PaintConverter$SequenceConverter" :
+            styleConverter = javafx.css.converter.PaintConverter.SequenceConverter.getInstance();
+            break;
+        case "javafx.css.converter.PaintConverter$LinearGradientConverter" :
+            styleConverter = javafx.css.converter.PaintConverter.LinearGradientConverter.getInstance();
+            break;
+        case "javafx.css.converter.PaintConverter$RadialGradientConverter" :
+            styleConverter = javafx.css.converter.PaintConverter.RadialGradientConverter.getInstance();
+            break;
+
+        case "javafx.css.converter.SizeConverter" :
+            styleConverter = javafx.css.converter.SizeConverter.getInstance();
+            break;
+        case "javafx.css.converter.SizeConverter$SequenceConverter" :
+            styleConverter = javafx.css.converter.SizeConverter.SequenceConverter.getInstance();
+            break;
+
+        case "javafx.css.converter.StringConverter" :
+            styleConverter = javafx.css.converter.StringConverter.getInstance();
+            break;
+        case "javafx.css.converter.StringConverter$SequenceConverter" :
+            styleConverter = javafx.css.converter.StringConverter.SequenceConverter.getInstance();
+            break;
+        case "javafx.css.converter.URLConverter" :
+            styleConverter = javafx.css.converter.URLConverter.getInstance();
+            break;
+        case "javafx.css.converter.URLConverter$SequenceConverter" :
+            styleConverter = javafx.css.converter.URLConverter.SequenceConverter.getInstance();
+            break;
+
+        // Region stuff  - including 2.x class names
+        case "com.sun.javafx.scene.layout.region.BackgroundPositionConverter" :
+        case "com.sun.javafx.scene.layout.region.BackgroundImage$BackgroundPositionConverter" :
+            styleConverter = com.sun.javafx.scene.layout.region.BackgroundPositionConverter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.BackgroundSizeConverter" :
+        case "com.sun.javafx.scene.layout.region.BackgroundImage$BackgroundSizeConverter" :
+            styleConverter = com.sun.javafx.scene.layout.region.BackgroundSizeConverter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.BorderImageSliceConverter" :
+        case "com.sun.javafx.scene.layout.region.BorderImage$SliceConverter" :
+            styleConverter = com.sun.javafx.scene.layout.region.BorderImageSliceConverter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.BorderImageWidthConverter" :
+            styleConverter = com.sun.javafx.scene.layout.region.BorderImageWidthConverter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.BorderImageWidthsSequenceConverter" :
+            styleConverter = com.sun.javafx.scene.layout.region.BorderImageWidthsSequenceConverter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.BorderStrokeStyleSequenceConverter" :
+        case "com.sun.javafx.scene.layout.region.StrokeBorder$BorderStyleSequenceConverter" :
+            styleConverter = com.sun.javafx.scene.layout.region.BorderStrokeStyleSequenceConverter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.BorderStyleConverter" :
+        case "com.sun.javafx.scene.layout.region.StrokeBorder$BorderStyleConverter" :
+            styleConverter = com.sun.javafx.scene.layout.region.BorderStyleConverter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.LayeredBackgroundPositionConverter" :
+        case "com.sun.javafx.scene.layout.region.BackgroundImage$LayeredBackgroundPositionConverter" :
+            styleConverter = com.sun.javafx.scene.layout.region.LayeredBackgroundPositionConverter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.LayeredBackgroundSizeConverter" :
+        case "com.sun.javafx.scene.layout.region.BackgroundImage$LayeredBackgroundSizeConverter" :
+            styleConverter = com.sun.javafx.scene.layout.region.LayeredBackgroundSizeConverter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.LayeredBorderPaintConverter" :
+        case "com.sun.javafx.scene.layout.region.StrokeBorder$LayeredBorderPaintConverter" :
+           styleConverter = com.sun.javafx.scene.layout.region.LayeredBorderPaintConverter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.LayeredBorderStyleConverter" :
+        case "com.sun.javafx.scene.layout.region.StrokeBorder$LayeredBorderStyleConverter" :
+            styleConverter = com.sun.javafx.scene.layout.region.LayeredBorderStyleConverter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.RepeatStructConverter" :
+        case "com.sun.javafx.scene.layout.region.BackgroundImage$BackgroundRepeatConverter" :
+        case "com.sun.javafx.scene.layout.region.BorderImage$RepeatConverter" :
+            styleConverter = com.sun.javafx.scene.layout.region.RepeatStructConverter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.SliceSequenceConverter" :
+        case "com.sun.javafx.scene.layout.region.BorderImage$SliceSequenceConverter" :
+            styleConverter = com.sun.javafx.scene.layout.region.SliceSequenceConverter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.StrokeBorderPaintConverter" :
+        case "com.sun.javafx.scene.layout.region.StrokeBorder$BorderPaintConverter" :
+            styleConverter = com.sun.javafx.scene.layout.region.StrokeBorderPaintConverter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.Margins$Converter" :
+            styleConverter = com.sun.javafx.scene.layout.region.Margins.Converter.getInstance();
+            break;
+        case "com.sun.javafx.scene.layout.region.Margins$SequenceConverter" :
+            styleConverter = com.sun.javafx.scene.layout.region.Margins.SequenceConverter.getInstance();
+            break;
+        case "javafx.scene.layout.CornerRadiiConverter" :  // Fix for RT-39665
+        case "com.sun.javafx.scene.layout.region.CornerRadiiConverter" :
+            styleConverter = CornerRadiiConverter.getInstance();
+            break;
+
+        // parser stuff
+        case "javafx.css.converter.DeriveColorConverter":
+        case "com.sun.javafx.css.parser.DeriveColorConverter" :
+            styleConverter = DeriveColorConverter.getInstance();
+            break;
+        case "javafx.css.converter.DeriveSizeConverter":
+        case "com.sun.javafx.css.parser.DeriveSizeConverter" :
+            styleConverter = DeriveSizeConverter.getInstance();
+            break;
+        case "javafx.css.converter.LadderConverter":
+        case "com.sun.javafx.css.parser.LadderConverter" :
+            styleConverter = LadderConverter.getInstance();
+            break;
+        case "javafx.css.converter.StopConverter":
+        case "com.sun.javafx.css.parser.StopConverter" :
+            styleConverter = StopConverter.getInstance();
+            break;
+
+            default :
+            final PlatformLogger logger = Logging.getCSSLogger();
+            if (logger.isLoggable(Level.SEVERE)) {
+                logger.severe("StyleConverter : converter Class is null for : "+converterClass);
+            }
+            break;
+        }
+
+        return styleConverter;
+    }
+
+
+    /**
+     *
+     * @since 9
+     */
+    public static class StringStore {
+        private final Map<String,Integer> stringMap = new HashMap<String,Integer>();
+        public final List<String> strings = new ArrayList<String>();
+
+        public int addString(String s) {
+            Integer index = stringMap.get(s);
+            if (index == null) {
+                index = strings.size();
+                strings.add(s);
+                stringMap.put(s,index);
+            }
+            return index;
+        }
+
+        public void writeBinary(DataOutputStream os) throws IOException {
+            os.writeShort(strings.size());
+            if (stringMap.containsKey(null)) {
+                Integer index = stringMap.get(null);
+                os.writeShort(index);
+            } else {
+                os.writeShort(-1);
+            }
+            for (int n=0; n<strings.size(); n++) {
+                String s = strings.get(n);
+                if (s == null) continue;
+                os.writeUTF(s);
+            }
+        }
+
+        // TODO: this isn't parallel with writeBinary
+        public static String[] readBinary(DataInputStream is) throws IOException {
+            int nStrings = is.readShort();
+            int nullIndex = is.readShort();
+            String[] strings = new String[nStrings];
+            java.util.Arrays.fill(strings, null);
+            for (int n=0; n<nStrings; n++) {
+                if (n == nullIndex) continue;
+                strings[n] = is.readUTF();
+            }
+            return strings;
+        }
+    }
 }