1 /* 2 * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.javafx.css.converters; 27 28 import com.sun.javafx.css.Size; 29 import com.sun.javafx.css.SizeUnits; 30 import com.sun.javafx.css.StyleConverterImpl; 31 import com.sun.javafx.css.StyleManager; 32 import javafx.css.ParsedValue; 33 import javafx.css.StyleConverter; 34 import javafx.scene.image.Image; 35 import javafx.scene.paint.CycleMethod; 36 import javafx.scene.paint.ImagePattern; 37 import javafx.scene.paint.LinearGradient; 38 import javafx.scene.paint.Paint; 39 import javafx.scene.paint.RadialGradient; 40 import javafx.scene.paint.Stop; 41 import javafx.scene.text.Font; 42 43 44 public final class PaintConverter extends StyleConverterImpl<ParsedValue<?, Paint>, Paint> { 45 46 // lazy, thread-safe instantiation 47 private static class Holder { 48 static final PaintConverter INSTANCE = new PaintConverter(); 49 static final SequenceConverter SEQUENCE_INSTANCE = new SequenceConverter(); 50 static final LinearGradientConverter LINEAR_GRADIENT_INSTANCE = new LinearGradientConverter(); 51 static final ImagePatternConverter IMAGE_PATTERN_INSTANCE = new ImagePatternConverter(); 52 static final RepeatingImagePatternConverter REPEATING_IMAGE_PATTERN_INSTANCE = new RepeatingImagePatternConverter(); 53 static final RadialGradientConverter RADIAL_GRADIENT_INSTANCE = new RadialGradientConverter(); 54 } 55 56 public static StyleConverter<ParsedValue<?, Paint>, Paint> getInstance() { 57 return Holder.INSTANCE; 58 } 59 60 private PaintConverter() { 61 super(); 62 } 63 64 @Override 65 public Paint convert(ParsedValue<ParsedValue<?, Paint>, Paint> value, Font font) { 66 Object obj = value.getValue(); 67 if (obj instanceof Paint) { 68 return (Paint) obj; 69 } 70 return value.getValue().convert(font); 71 } 72 73 @Override 74 public String toString() { 75 return "PaintConverter"; 76 } 77 78 /** 79 * Convert [<paint]+ to Paint[] 80 */ 81 public static final class SequenceConverter extends StyleConverterImpl<ParsedValue<?, Paint>[], Paint[]> { 82 83 public static SequenceConverter getInstance() { 84 return Holder.SEQUENCE_INSTANCE; 85 } 86 87 private SequenceConverter() { 88 super(); 89 } 90 91 @Override 92 public Paint[] convert(ParsedValue<ParsedValue<?, Paint>[], Paint[]> value, Font font) { 93 ParsedValue<?, Paint>[] values = value.getValue(); 94 Paint[] paints = new Paint[values.length]; 95 for (int p = 0; p < values.length; p++) { 96 paints[p] = values[p].convert(font); 97 } 98 return paints; 99 } 100 101 @Override 102 public String toString() { 103 return "Paint.SequenceConverter"; 104 } 105 } 106 107 public static final class LinearGradientConverter extends StyleConverterImpl<ParsedValue[], Paint> { 108 109 public static LinearGradientConverter getInstance() { 110 return Holder.LINEAR_GRADIENT_INSTANCE; 111 } 112 113 private LinearGradientConverter() { 114 super(); 115 } 116 117 @Override 118 public Paint convert(ParsedValue<ParsedValue[], Paint> value, Font font) { 119 120 Paint paint = super.getCachedValue(value); 121 if (paint != null) return paint; 122 123 ParsedValue[] values = value.getValue(); 124 int v = 0; 125 final Size startX = (Size) values[v++].convert(font); 126 final Size startY = (Size) values[v++].convert(font); 127 final Size endX = (Size) values[v++].convert(font); 128 final Size endY = (Size) values[v++].convert(font); 129 boolean proportional = startX.getUnits() == SizeUnits.PERCENT && startX.getUnits() == startY.getUnits() && startX.getUnits() == endX.getUnits() && startX.getUnits() == endY.getUnits(); 130 final CycleMethod cycleMethod = (CycleMethod) values[v++].convert(font); 131 final Stop[] stops = new Stop[values.length - v]; 132 for (int s = v; s < values.length; s++) { 133 stops[s - v] = (Stop) values[s].convert(font); 134 } 135 paint = new LinearGradient(startX.pixels(font), startY.pixels(font), endX.pixels(font), endY.pixels(font), proportional, cycleMethod, stops); 136 137 super.cacheValue(value, paint); 138 return paint; 139 } 140 141 @Override 142 public String toString() { 143 return "LinearGradientConverter"; 144 } 145 } 146 147 public static final class ImagePatternConverter extends StyleConverterImpl<ParsedValue[], Paint> { 148 149 public static ImagePatternConverter getInstance() { 150 return Holder.IMAGE_PATTERN_INSTANCE; 151 } 152 153 private ImagePatternConverter() { 154 super(); 155 } 156 157 @Override 158 public Paint convert(ParsedValue<ParsedValue[], Paint> value, Font font) { 159 160 Paint paint = super.getCachedValue(value); 161 if (paint != null) return paint; 162 163 ParsedValue[] values = value.getValue(); 164 ParsedValue<?,?> urlParsedValue = values[0]; 165 String url = (String) urlParsedValue.convert(font); 166 if (values.length == 1) { 167 return new ImagePattern(StyleManager.getInstance().getCachedImage(url)); 168 } 169 170 Size x = (Size) values[1].convert(font); 171 Size y = (Size) values[2].convert(font); 172 Size w = (Size) values[3].convert(font); 173 Size h = (Size) values[4].convert(font); 174 boolean p = values.length < 6 ? true : (Boolean) values[5].getValue(); 175 176 paint = new ImagePattern( 177 new Image(url), 178 x.getValue(), 179 y.getValue(), 180 w.getValue(), 181 h.getValue(), p); 182 183 super.cacheValue(value, paint); 184 return paint; 185 } 186 187 @Override 188 public String toString() { 189 return "ImagePatternConverter"; 190 } 191 } 192 193 public static final class RepeatingImagePatternConverter extends StyleConverterImpl<ParsedValue[], Paint> { 194 195 public static RepeatingImagePatternConverter getInstance() { 196 return Holder.REPEATING_IMAGE_PATTERN_INSTANCE; 197 } 198 199 private RepeatingImagePatternConverter() { 200 super(); 201 } 202 203 @Override 204 public Paint convert(ParsedValue<ParsedValue[], Paint> value, Font font) { 205 206 Paint paint = super.getCachedValue(value); 207 if (paint != null) return paint; 208 209 ParsedValue[] values = value.getValue(); 210 ParsedValue<?, ?> url = values[0]; 211 String u = (String) url.convert(font); 212 // If u is null, then we failed to locate the image associated with the url specified in the CSS file. 213 if (u == null) return null; 214 final Image image = new Image(u); 215 paint = new ImagePattern(image, 0, 0, image.getWidth(), image.getHeight(), false); 216 217 super.cacheValue(value, paint); 218 return paint; 219 } 220 221 @Override 222 public String toString() { 223 return "RepeatingImagePatternConverter"; 224 } 225 } 226 227 public static final class RadialGradientConverter extends StyleConverterImpl<ParsedValue[], Paint> { 228 229 public static RadialGradientConverter getInstance() { 230 return Holder.RADIAL_GRADIENT_INSTANCE; 231 } 232 233 private RadialGradientConverter() { 234 super(); 235 } 236 237 @Override 238 public Paint convert(ParsedValue<ParsedValue[], Paint> value, Font font) { 239 240 Paint paint = super.getCachedValue(value); 241 if (paint != null) return paint; 242 243 final ParsedValue[] values = value.getValue(); 244 int v = 0; 245 // First four values are for startX, startY, endX, endY 246 // and are type ParsedValue<Value<?,Size>,Double>. To figure out 247 // proportional, we need to get to the Size. getValue() will 248 // return ParsedValue<?,Size>, so getValue().convert(font) will 249 // give us the size. 250 final Size focusAngle = values[v++] != null ? (Size) values[v-1].convert(font) : null; 251 final Size focusDistance = values[v++] != null ? (Size) values[v-1].convert(font) : null; 252 final Size centerX = values[v++] != null ? (Size) values[v-1].convert(font) : null; 253 final Size centerY = values[v++] != null ? (Size) values[v-1].convert(font) : null; 254 final Size radius = (Size) values[v++].convert(font); 255 boolean proportional = radius.getUnits().equals(SizeUnits.PERCENT); 256 boolean unitsAgree = centerX != null ? proportional == centerX.getUnits().equals(SizeUnits.PERCENT) : true; 257 unitsAgree = unitsAgree && centerY != null ? proportional == centerY.getUnits().equals(SizeUnits.PERCENT) : true; 258 if (!unitsAgree) { 259 throw new IllegalArgumentException("units do not agree"); 260 } 261 final CycleMethod cycleMethod = (CycleMethod) values[v++].convert(font); 262 final Stop[] stops = new Stop[values.length - v]; 263 for (int s = v; s < values.length; s++) { 264 stops[s - v] = (Stop) values[s].convert(font); 265 } 266 //If the focus-angle is a percentage, the value is mutiplied 267 // by 360, modulo 360. 268 double fa = 0; 269 if (focusAngle != null) { 270 fa = focusAngle.pixels(font); 271 if (focusAngle.getUnits().equals(SizeUnits.PERCENT)) { 272 fa = (fa * 360) % 360; 273 } 274 } 275 paint = new RadialGradient(fa, focusDistance != null ? focusDistance.pixels() : 0, centerX != null ? centerX.pixels() : 0, centerY != null ? centerY.pixels() : 0, radius != null ? radius.pixels() : 1, proportional, cycleMethod, stops); 276 277 super.cacheValue(value, paint); 278 return paint; 279 } 280 281 @Override 282 public String toString() { 283 return "RadialGradientConverter"; 284 } 285 } 286 }