1 /*
   2  * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  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 test.javafx.css;
  27 
  28 import com.sun.javafx.css.*;
  29 
  30 import java.io.ByteArrayInputStream;
  31 import java.io.ByteArrayOutputStream;
  32 import java.io.DataInputStream;
  33 import java.io.DataOutputStream;
  34 import java.io.IOException;
  35 import java.util.Arrays;
  36 import java.util.List;
  37 import java.util.Map;
  38 import javafx.css.CssParser;
  39 import javafx.css.CssParserShim;
  40 import javafx.css.Declaration;
  41 import javafx.css.FontFace;
  42 
  43 import javafx.css.ParsedValue;
  44 import javafx.css.ParsedValue;
  45 import javafx.css.Rule;
  46 import javafx.css.RuleShim;
  47 import javafx.css.Stylesheet;
  48 import javafx.scene.paint.Color;
  49 import javafx.scene.paint.LinearGradient;
  50 import javafx.scene.paint.Paint;
  51 import javafx.scene.paint.Stop;
  52 import javafx.scene.text.Font;
  53 import javafx.util.Duration;
  54 import org.junit.Test;
  55 import static org.junit.Assert.*;
  56 
  57 
  58 public class CssParserTest {
  59 
  60     @Test
  61     public void testRT_16959() {
  62 
  63         CssParser instance = new CssParser();
  64 
  65         // RT-16959 is an infinite loop on incomplete linear gradient
  66         ParsedValue result = new CssParserShim(instance)
  67                 .parseExpr("-fx-background-color", "linear-gradient(from 0% 0% to 0% 100%, )");
  68         assertNull("parseExpr", result);
  69 
  70         // The bad syntax should be skipped. The stylesheet should have one
  71         // linear gradient with colors red, white, blue.
  72         Stylesheet ss = instance.parse(
  73             "* { "
  74             +   "-fx-background-color: linear-gradient(from 0% 0% to 0% 100%, ); "
  75             +   "-fx-background-color: linear-gradient(from 0% 0% to 0% 100%, red, white, blue); "
  76             + "}"
  77         );
  78 
  79         assertNotNull(ss);
  80         List<Rule> rules = ss.getRules();
  81         assertEquals(1,rules.size(),0);
  82         List<Declaration> decls = RuleShim.getUnobservedDeclarationList(ss.getRules().get(0));
  83         assertTrue(decls.size()==1);
  84         Declaration decl = decls.get(0);
  85         ParsedValue value = decl.getParsedValue();
  86         assertTrue(value != null);
  87 
  88         Paint[] layers = (Paint[])value.convert(null);
  89         assertTrue(layers.length == 1);
  90 
  91         LinearGradient lg = (LinearGradient)layers[0];
  92         List<Stop> stops = lg.getStops();
  93         assertTrue(stops.size()==3);
  94         assertEquals(Color.RED, stops.get(0).getColor());
  95         assertEquals(Color.WHITE, stops.get(1).getColor());
  96         assertEquals(Color.BLUE, stops.get(2).getColor());
  97 
  98     }
  99 
 100 
 101     @Test
 102     public void testRT_17770() {
 103 
 104         // RT-17770 is an infinite loop on a dangling comma.
 105         // Missing term should be ignored
 106         String stylesheetText =
 107             "* {"
 108             +   "-fx-background-color: linear-gradient( "
 109             +   "to right, "
 110             +   "rgba(141, 138, 125, 0.0), "
 111             +   "rgba(248, 248, 246, 0.3) 45%, "
 112             +   "rgba(248, 248, 246, 0.8) 50%, "
 113             +   "rgba(248, 248, 246, 0.3) 55%, "
 114             +   "rgba(141, 138, 125, 0.0), "
 115             +   "); "
 116             + "}";
 117 
 118         CssParser instance = new CssParser();
 119 
 120         Stylesheet ss = instance.parse(stylesheetText);
 121 
 122         assertNotNull(ss);
 123         List<Rule> rules = ss.getRules();
 124         assertEquals(1,rules.size(),0);
 125         List<Declaration> decls = RuleShim.getUnobservedDeclarationList(ss.getRules().get(0));
 126         assertTrue(decls.size()==1);
 127         Declaration decl = decls.get(0);
 128         ParsedValue value = decl.getParsedValue();
 129         assertTrue(value != null);
 130 
 131         Paint[] layers = (Paint[])value.convert(null);
 132         assertTrue(layers.length == 1);
 133 
 134         LinearGradient lg = (LinearGradient)layers[0];
 135         List<Stop> stops = lg.getStops();
 136         assertTrue(stops.size()==5);
 137         assertEquals(Color.rgb(141, 138, 125, 0.0), stops.get(0).getColor());
 138         assertEquals(Color.rgb(248, 248, 246, 0.3), stops.get(1).getColor());
 139         assertEquals(Color.rgb(248, 248, 246, 0.8), stops.get(2).getColor());
 140         assertEquals(Color.rgb(248, 248, 246, 0.3), stops.get(3).getColor());
 141         assertEquals(Color.rgb(141, 138, 125, 0.0), stops.get(4).getColor());
 142 
 143     }
 144 
 145     @Test
 146     public void testParseSizeWithInvalidDigits() {
 147 
 148         CssParser instance = new CssParser();
 149 
 150         // RT-16959 is an infinite loop on incomplete linear gradient
 151         ParsedValue result = new CssParserShim(instance).parseExpr("-fx-font-size", "10ptx");
 152         assertNull("parseExpr", result);
 153 
 154         // The bad syntax should be skipped.
 155         Stylesheet ss = instance.parse(
 156             "* {"
 157             +  "-fx-font-size: 10ptx; "
 158             +  "-fx-font-size: 12px; "
 159             + "}"
 160         );
 161 
 162         assertNotNull(ss);
 163         List<Rule> rules = ss.getRules();
 164         assertEquals(1,rules.size(),0);
 165         List<Declaration> decls = RuleShim.getUnobservedDeclarationList(ss.getRules().get(0));
 166         assertTrue(decls.size()==1);
 167         Declaration decl = decls.get(0);
 168         ParsedValue value = decl.getParsedValue();
 169         assertTrue(value != null);
 170 
 171         Double size = (Double)value.convert(Font.font("Amble", 12));
 172         assertTrue(Double.compare(size, 12) == 0);
 173     }
 174 
 175 
 176     @Test
 177     public void testRT_17830() {
 178 
 179         CssParser instance = new CssParser();
 180 
 181         // The empty declaration should be skipped. The stylesheet should have
 182         // two declarations.
 183         Stylesheet ss = instance.parse(".rt17830 {-fx-fill: red;; -fx-stroke: yellow; }");
 184 
 185         assertNotNull(ss);
 186         List<Rule> rules = ss.getRules();
 187         assertEquals(1,rules.size(),0);
 188         List<Declaration> decls = RuleShim.getUnobservedDeclarationList(ss.getRules().get(0));
 189         assertEquals(2,decls.size(),0);
 190 
 191         Declaration decl = decls.get(0);
 192         ParsedValue value = decl.getParsedValue();
 193         assertTrue(value != null);
 194         Paint paint = (Paint)value.convert(null);
 195         assertEquals(Color.RED, paint);
 196 
 197         decl = decls.get(1);
 198         value = decl.getParsedValue();
 199         assertTrue(value != null);
 200         paint = (Paint)value.convert(null);
 201         assertEquals(Color.YELLOW, paint);
 202     }
 203 
 204     @Test
 205     public void testRT_20311() {
 206 
 207         CssParser instance = new CssParser();
 208 
 209         try {
 210             instance.parse(".rt-20311 {  -fx-background-color:red\n-fx-border-color:black; }");
 211         } catch (Exception e) {
 212             fail(e.toString());
 213         }
 214 
 215     }
 216 
 217     @Test public void testFontFace() {
 218 
 219         // http://fonts.googleapis.com/css?family=Bree+Serif
 220         String css = "@font-face {\n" +
 221             "font-family: 'Bree Serif';\n" +
 222             "font-style: normal;\n" +
 223             "font-weight: 400;\n" +
 224             "src: local('Bree Serif'), local('BreeSerif-Regular'), url(http://themes.googleusercontent.com/static/fonts/breeserif/v2/LQ7WLTaITDg4OSRuOZCps73hpw3pgy2gAi-Ip7WPMi0.woff) format('woff');\n"+
 225         "}";
 226 
 227         Stylesheet stylesheet = new CssParser().parse(css);
 228 
 229         int nFontFaceSrcs = checkFontFace(stylesheet);
 230 
 231         assertEquals(3, nFontFaceSrcs);
 232     }
 233 
 234     @Test public void testFontFaceMoreThanOneSrc() {
 235 
 236         // http://fonts.googleapis.com/css?family=Bree+Serif
 237         String css = "@font-face {\n" +
 238                 "font-family: 'Bree Serif';\n" +
 239                 "font-style: normal;\n" +
 240                 "font-weight: 400;\n" +
 241                 "src: local('Bree Serif'), local('BreeSerif-Regular'), url(http://themes.googleusercontent.com/static/fonts/breeserif/v2/LQ7WLTaITDg4OSRuOZCps73hpw3pgy2gAi-Ip7WPMi0.woff) format('woff'),\n"+
 242                 "     local('Bree Serif'), local('BreeSerif-Regular'), url(http://themes.googleusercontent.com/static/fonts/breeserif/v2/LQ7WLTaITDg4OSRuOZCps73hpw3pgy2gAi-Ip7WPMi0.woff) format('woff');\n"+
 243                 "}";
 244 
 245         Stylesheet stylesheet = new CssParser().parse(css);
 246 
 247         int nFontFaceSrcs = checkFontFace(stylesheet);
 248         assertEquals(6, nFontFaceSrcs);
 249     }
 250 
 251     public static int checkFontFace(Stylesheet stylesheet) {
 252 
 253         List<FontFace> fontFaces = stylesheet.getFontFaces();
 254         assertNotNull(fontFaces);
 255         assertEquals(1, fontFaces.size());
 256 
 257         FontFaceImpl fontFace = (FontFaceImpl)fontFaces.get(0);
 258 
 259         Map<String,String> descriptors = fontFace.getDescriptors();
 260         assertEquals("'Bree Serif'", descriptors.get("font-family"));
 261         assertEquals("normal", descriptors.get("font-style"));
 262         assertEquals("400", descriptors.get("font-weight"));
 263 
 264         List<FontFaceImpl.FontFaceSrc> fontFaceSrcs = fontFace.getSources();
 265 
 266         int nFontFaceSrcs = fontFaceSrcs != null ? fontFaceSrcs.size() : 0;
 267 
 268         for(int n=0; n<nFontFaceSrcs; n++) {
 269             FontFaceImpl.FontFaceSrc fontFaceSrc = fontFaceSrcs.get(n);
 270             FontFaceImpl.FontFaceSrcType type = fontFaceSrc.getType();
 271             switch(type) {
 272                 case LOCAL: {
 273                     String src = fontFaceSrc.getSrc();
 274                     assertTrue("Bree Serif".equals(src) || "BreeSerif-Regular".equals(src));
 275                     assertNull(fontFaceSrc.getFormat());
 276                     break;
 277                 }
 278                 case URL: {
 279                     String src = fontFaceSrc.getSrc();
 280                     assertEquals(src, "http://themes.googleusercontent.com/static/fonts/breeserif/v2/LQ7WLTaITDg4OSRuOZCps73hpw3pgy2gAi-Ip7WPMi0.woff");
 281                     assertEquals(fontFaceSrc.getFormat(), "woff");
 282                     break;
 283                 }
 284                 case REFERENCE:
 285                 default:
 286                         fail();
 287             }
 288         }
 289 
 290         return nFontFaceSrcs;
 291     }
 292 
 293     @Test public void testRT_32522() {
 294 
 295         ParsedValue value = new CssParserShim().parseExpr("foo", "1 2em 3 4;");
 296         Object obj = value.convert(Font.font(13));
 297         assert obj instanceof Number[];
 298         assertArrayEquals(new Number[] {1d, 26d, 3d, 4d}, (Number[])obj);
 299 
 300         value = new CssParserShim().parseExpr("foo", "1;");
 301         obj = value.convert(null);
 302         assert obj instanceof Number;
 303         assertEquals(1d, (Number)obj);
 304 
 305     }
 306 
 307     @Test public void testRT_38483() {
 308 
 309         Duration expected = Duration.millis(42);
 310         ParsedValue value = new CssParserShim().parseExpr("foo", "42ms;");
 311         Object observed = value.convert(null);
 312         assertEquals(expected, observed);
 313 
 314         value = new CssParserShim().parseExpr("foo", "indefinite;");
 315         observed = value.convert(null);
 316         assertEquals(Duration.INDEFINITE, observed);
 317     }
 318 }