• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2013, Mike Samuel
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions
6 // are met:
7 //
8 // Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // Neither the name of the OWASP nor the names of its contributors may
14 // be used to endorse or promote products derived from this software
15 // without specific prior written permission.
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20 // COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
28 
29 package org.owasp.html;
30 
31 import java.util.Map;
32 import java.util.Set;
33 import java.util.SortedSet;
34 
35 import javax.annotation.Nullable;
36 
37 import com.google.common.collect.ImmutableMap;
38 import com.google.common.collect.ImmutableSet;
39 import com.google.common.collect.Maps;
40 import com.google.common.collect.Sets;
41 
42 /** Describes the kinds of tokens a CSS property's value can safely contain. */
43 @TCB
44 public final class CssSchema {
45 
46   static final class Property {
47     /** A bitfield of BIT_* constants describing groups of allowed tokens. */
48     final int bits;
49     /** Specific allowed values. */
50     final ImmutableSet<String> literals;
51     /**
52      * Maps lower-case function tokens to the schema key for their parameters.
53      */
54     final ImmutableMap<String, String> fnKeys;
55 
Property( int bits, ImmutableSet<String> literals, ImmutableMap<String, String> fnKeys)56     private Property(
57         int bits, ImmutableSet<String> literals,
58         ImmutableMap<String, String> fnKeys) {
59       this.bits = bits;
60       this.literals = literals;
61       this.fnKeys = fnKeys;
62     }
63   }
64 
65   static final int BIT_QUANTITY = 1;
66   static final int BIT_HASH_VALUE = 2;
67   static final int BIT_NEGATIVE = 4;
68   static final int BIT_STRING = 8;
69   static final int BIT_URL = 16;
70   static final int BIT_UNRESERVED_WORD = 64;
71   static final int BIT_UNICODE_RANGE = 128;
72 
73   static final Property DISALLOWED = new Property(
74       0, ImmutableSet.<String>of(), ImmutableMap.<String, String>of());
75 
76   private final ImmutableMap<String, Property> properties;
77 
CssSchema(ImmutableMap<String, Property> properties)78   private CssSchema(ImmutableMap<String, Property> properties) {
79     if (properties == null) { throw new NullPointerException(); }
80     this.properties = properties;
81   }
82 
83   /**
84    * A schema that includes all and only the named properties.
85    *
86    * @param propertyNames a series of lower-case CSS property names that appear
87    *    in the built-in CSS definitions.  It is an error to mention an unknown
88    *    property name.  This class's {@code main} method will dump a list of
89    *    known property names when run with zero arguments.
90    */
withProperties( Iterable<? extends String> propertyNames)91   public static CssSchema withProperties(
92       Iterable<? extends String> propertyNames) {
93     ImmutableMap.Builder<String, Property> propertiesBuilder =
94         ImmutableMap.builder();
95     for (String propertyName : propertyNames) {
96       Property prop = DEFINITIONS.get(propertyName);
97       if (prop == null) { throw new IllegalArgumentException(propertyName); }
98       propertiesBuilder.put(propertyName, prop);
99     }
100     return new CssSchema(propertiesBuilder.build());
101   }
102 
103   /**
104    * A schema that represents the union of the input schemas.
105    *
106    * @return A schema that allows all and only CSS properties that are allowed
107    *    by at least one of the inputs.
108    */
union(CssSchema... cssSchemas)109   public static CssSchema union(CssSchema... cssSchemas) {
110     if (cssSchemas.length == 1) { return cssSchemas[0]; }
111     Map<String, Property> properties = Maps.newLinkedHashMap();
112     for (CssSchema cssSchema : cssSchemas) {
113       properties.putAll(cssSchema.properties);
114     }
115     return new CssSchema(ImmutableMap.copyOf(properties));
116   }
117 
118   /**
119    * The set of CSS properties allowed by this schema.
120    *
121    * @return an immutable set.
122    */
allowedProperties()123   public Set<String> allowedProperties() {
124     return properties.keySet();
125   }
126 
127   /** The schema for the named property or function key. */
forKey(String propertyName)128   Property forKey(String propertyName) {
129     propertyName = Strings.toLowerCase(propertyName);
130     Property property = properties.get(propertyName);
131     if (property != null) { return property; }
132     int n = propertyName.length();
133     if (n != 0 && propertyName.charAt(0) == '-') {
134       String barePropertyName = stripVendorPrefix(propertyName);
135       property = properties.get(barePropertyName);
136       if (property != null) { return property; }
137     }
138     return DISALLOWED;
139   }
140 
141   /** {@code "-moz-foo"} &rarr; {@code "foo"}. */
stripVendorPrefix(String cssKeyword)142   private static @Nullable String stripVendorPrefix(String cssKeyword) {
143     int prefixLen = 0;
144     switch (cssKeyword.charAt(1)) {
145       case 'm':
146         if (cssKeyword.startsWith("-ms-")) {
147           prefixLen = 4;
148         } else if (cssKeyword.startsWith("-moz-")) {
149           prefixLen = 5;
150         }
151         break;
152       case 'o':
153         if (cssKeyword.startsWith("-o-")) { prefixLen = 3; }
154         break;
155       case 'w':
156         if (cssKeyword.startsWith("-webkit-")) { prefixLen = 8; }
157         break;
158       default: break;
159     }
160     return prefixLen == 0 ? null : cssKeyword.substring(prefixLen);
161   }
162 
163   /** Maps lower-cased CSS property names to information about them. */
164   static final ImmutableMap<String, Property> DEFINITIONS;
165   static {
166     ImmutableMap<String, String> zeroFns = ImmutableMap.of();
167     ImmutableMap.Builder<String, Property> builder
168         = ImmutableMap.builder();
169     ImmutableSet<String> mozBorderRadiusLiterals0 = ImmutableSet.of("/");
170     ImmutableSet<String> mozOpacityLiterals0 = ImmutableSet.of("inherit");
171     ImmutableSet<String> mozOutlineLiterals0 = ImmutableSet.of(
172         "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
173         "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
174         "burlywood", "cadetblue", "chartreuse", "chocolate", "coral",
175         "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan",
176         "darkgoldenrod", "darkgray", "darkgreen", "darkkhaki", "darkmagenta",
177         "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon",
178         "darkseagreen", "darkslateblue", "darkslategray", "darkturquoise",
179         "darkviolet", "deeppink", "deepskyblue", "dimgray", "dodgerblue",
180         "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro",
181         "ghostwhite", "gold", "goldenrod", "gray", "green", "greenyellow",
182         "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki",
183         "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue",
184         "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgreen",
185         "lightgrey", "lightpink", "lightsalmon", "lightseagreen",
186         "lightskyblue", "lightslategray", "lightsteelblue", "lightyellow",
187         "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine",
188         "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen",
189         "mediumslateblue", "mediumspringgreen", "mediumturquoise",
190         "mediumvioletred", "midnightblue", "mintcream", "mistyrose",
191         "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab",
192         "orange", "orangered", "orchid", "palegoldenrod", "palegreen",
193         "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru",
194         "pink", "plum", "powderblue", "purple", "red", "rosybrown", "royalblue",
195         "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna",
196         "silver", "skyblue", "slateblue", "slategray", "snow", "springgreen",
197         "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet",
198         "wheat", "white", "whitesmoke", "yellow", "yellowgreen");
199     ImmutableSet<String> mozOutlineLiterals1 = ImmutableSet.of(
200         "dashed", "dotted", "double", "groove", "outset", "ridge", "solid");
201     ImmutableSet<String> mozOutlineLiterals2 = ImmutableSet.of("thick", "thin");
202     ImmutableSet<String> mozOutlineLiterals3 = ImmutableSet.of(
203         "hidden", "inherit", "inset", "invert", "medium", "none");
204     ImmutableMap<String, String> mozOutlineFunctions =
205       ImmutableMap.<String, String>of("rgb(", "rgb()", "rgba(", "rgba()");
206     ImmutableSet<String> mozOutlineColorLiterals0 =
207       ImmutableSet.of("inherit", "invert");
208     ImmutableSet<String> mozOutlineStyleLiterals0 =
209       ImmutableSet.of("hidden", "inherit", "inset", "none");
210     ImmutableSet<String> mozOutlineWidthLiterals0 =
211       ImmutableSet.of("inherit", "medium");
212     ImmutableSet<String> oTextOverflowLiterals0 =
213       ImmutableSet.of("clip", "ellipsis");
214     ImmutableSet<String> azimuthLiterals0 = ImmutableSet.of(
215         "behind", "center-left", "center-right", "far-left", "far-right",
216         "left-side", "leftwards", "right-side", "rightwards");
217     ImmutableSet<String> azimuthLiterals1 = ImmutableSet.of("left", "right");
218     ImmutableSet<String> azimuthLiterals2 =
219       ImmutableSet.of("center", "inherit");
220     ImmutableSet<String> backgroundLiterals0 = ImmutableSet.of(
221         "border-box", "contain", "content-box", "cover", "padding-box");
222     ImmutableSet<String> backgroundLiterals1 =
223       ImmutableSet.of("no-repeat", "repeat-x", "repeat-y", "round", "space");
224     ImmutableSet<String> backgroundLiterals2 = ImmutableSet.of("bottom", "top");
225     ImmutableSet<String> backgroundLiterals3 = ImmutableSet.of(
226         ",", "/", "auto", "center", "fixed", "inherit", "local", "none",
227         "repeat", "scroll", "transparent");
228     ImmutableMap<String, String> backgroundFunctions =
229       ImmutableMap.<String, String>builder()
230       .put("image(", "image()")
231       .put("linear-gradient(", "linear-gradient()")
232       .put("radial-gradient(", "radial-gradient()")
233       .put("repeating-linear-gradient(", "repeating-linear-gradient()")
234       .put("repeating-radial-gradient(", "repeating-radial-gradient()")
235       .put("rgb(", "rgb()").put("rgba(", "rgba()")
236       .build();
237     ImmutableSet<String> backgroundAttachmentLiterals0 =
238       ImmutableSet.of(",", "fixed", "local", "scroll");
239     ImmutableSet<String> backgroundColorLiterals0 =
240       ImmutableSet.of("inherit", "transparent");
241     ImmutableSet<String> backgroundImageLiterals0 =
242       ImmutableSet.of(",", "none");
243     ImmutableMap<String, String> backgroundImageFunctions =
244       ImmutableMap.<String, String>of(
245           "image(", "image()",
246           "linear-gradient(", "linear-gradient()",
247           "radial-gradient(", "radial-gradient()",
248           "repeating-linear-gradient(", "repeating-linear-gradient()",
249           "repeating-radial-gradient(", "repeating-radial-gradient()");
250     ImmutableSet<String> backgroundPositionLiterals0 = ImmutableSet.of(
251         ",", "center");
252     ImmutableSet<String> backgroundRepeatLiterals0 = ImmutableSet.of(
253         ",", "repeat");
254     ImmutableSet<String> borderLiterals0 = ImmutableSet.of(
255         "hidden", "inherit", "inset", "medium", "none", "transparent");
256     ImmutableSet<String> borderCollapseLiterals0 = ImmutableSet.of(
257         "collapse", "inherit", "separate");
258     ImmutableSet<String> bottomLiterals0 = ImmutableSet.of("auto", "inherit");
259     ImmutableSet<String> boxShadowLiterals0 = ImmutableSet.of(
260         ",", "inset", "none");
261     ImmutableSet<String> clearLiterals0 = ImmutableSet.of(
262         "both", "inherit", "none");
263     ImmutableMap<String, String> clipFunctions =
264         ImmutableMap.<String, String>of("rect(", "rect()");
265     ImmutableSet<String> contentLiterals0 = ImmutableSet.of("none", "normal");
266     ImmutableSet<String> cueLiterals0 = ImmutableSet.of("inherit", "none");
267     ImmutableSet<String> cursorLiterals0 = ImmutableSet.of(
268         "all-scroll", "col-resize", "crosshair", "default", "e-resize",
269         "hand", "help", "move", "n-resize", "ne-resize", "no-drop",
270         "not-allowed", "nw-resize", "pointer", "progress", "row-resize",
271         "s-resize", "se-resize", "sw-resize", "text", "vertical-text",
272         "w-resize", "wait");
273     ImmutableSet<String> cursorLiterals1 = ImmutableSet.of(
274         ",", "auto", "inherit");
275     ImmutableSet<String> directionLiterals0 = ImmutableSet.of("ltr", "rtl");
276     ImmutableSet<String> displayLiterals0 = ImmutableSet.of(
277         "-moz-inline-box", "-moz-inline-stack", "block", "inline",
278         "inline-block", "inline-table", "list-item", "run-in", "table",
279         "table-caption", "table-cell", "table-column", "table-column-group",
280         "table-footer-group", "table-header-group", "table-row",
281         "table-row-group");
282     ImmutableSet<String> elevationLiterals0 = ImmutableSet.of(
283         "above", "below", "higher", "level", "lower");
284     ImmutableSet<String> emptyCellsLiterals0 = ImmutableSet.of("hide", "show");
285     //ImmutableMap<String, String> filterFunctions =
286     //  ImmutableMap.<String, String>of("alpha(", "alpha()");
287     ImmutableSet<String> fontLiterals0 = ImmutableSet.of(
288         "100", "200", "300", "400", "500", "600", "700", "800", "900", "bold",
289         "bolder", "lighter");
290     ImmutableSet<String> fontLiterals1 = ImmutableSet.of(
291         "large", "larger", "small", "smaller", "x-large", "x-small",
292         "xx-large", "xx-small");
293     ImmutableSet<String> fontLiterals2 = ImmutableSet.of(
294         "caption", "icon", "menu", "message-box", "small-caption",
295         "status-bar");
296     ImmutableSet<String> fontLiterals3 = ImmutableSet.of(
297         "cursive", "fantasy", "monospace", "sans-serif", "serif");
298     ImmutableSet<String> fontLiterals4 = ImmutableSet.of("italic", "oblique");
299     ImmutableSet<String> fontLiterals5 = ImmutableSet.of(
300         ",", "/", "inherit", "medium", "normal", "small-caps");
301     ImmutableSet<String> fontFamilyLiterals0 = ImmutableSet.of(",", "inherit");
302     ImmutableSet<String> fontStretchLiterals0 = ImmutableSet.of(
303         "condensed", "expanded", "extra-condensed", "extra-expanded",
304         "narrower", "semi-condensed", "semi-expanded", "ultra-condensed",
305         "ultra-expanded", "wider");
306     ImmutableSet<String> fontStretchLiterals1 = ImmutableSet.of("normal");
307     ImmutableSet<String> fontStyleLiterals0 = ImmutableSet.of(
308         "inherit", "normal");
309     ImmutableSet<String> fontVariantLiterals0 = ImmutableSet.of(
310         "inherit", "normal", "small-caps");
311     ImmutableSet<String> listStyleLiterals0 = ImmutableSet.of(
312         "armenian", "cjk-decimal", "decimal", "decimal-leading-zero", "disc",
313         "disclosure-closed", "disclosure-open", "ethiopic-numeric", "georgian",
314         "hebrew", "hiragana", "hiragana-iroha", "japanese-formal",
315         "japanese-informal", "katakana", "katakana-iroha",
316         "korean-hangul-formal", "korean-hanja-formal",
317         "korean-hanja-informal", "lower-alpha", "lower-greek", "lower-latin",
318         "lower-roman", "simp-chinese-formal", "simp-chinese-informal",
319         "square", "trad-chinese-formal", "trad-chinese-informal",
320         "upper-alpha", "upper-latin", "upper-roman");
321     ImmutableSet<String> listStyleLiterals1 = ImmutableSet.of(
322         "inside", "outside");
323     ImmutableSet<String> listStyleLiterals2 = ImmutableSet.of(
324         "circle", "inherit", "none");
325     ImmutableSet<String> maxHeightLiterals0 = ImmutableSet.of(
326         "auto", "inherit", "none");
327     ImmutableSet<String> overflowLiterals0 = ImmutableSet.of(
328         "auto", "hidden", "inherit", "scroll", "visible");
329     ImmutableSet<String> overflowXLiterals0 = ImmutableSet.of(
330         "no-content", "no-display");
331     ImmutableSet<String> overflowXLiterals1 = ImmutableSet.of(
332         "auto", "hidden", "scroll", "visible");
333     ImmutableSet<String> pageBreakAfterLiterals0 = ImmutableSet.of(
334         "always", "auto", "avoid", "inherit");
335     ImmutableSet<String> pageBreakInsideLiterals0 = ImmutableSet.of(
336         "auto", "avoid", "inherit");
337     ImmutableSet<String> pitchLiterals0 = ImmutableSet.of(
338         "high", "low", "x-high", "x-low");
339     ImmutableSet<String> playDuringLiterals0 = ImmutableSet.of(
340         "auto", "inherit", "mix", "none", "repeat");
341     ImmutableSet<String> positionLiterals0 = ImmutableSet.of(
342         "absolute", "relative", "static");
343     ImmutableSet<String> speakLiterals0 = ImmutableSet.of(
344         "inherit", "none", "normal", "spell-out");
345     ImmutableSet<String> speakHeaderLiterals0 = ImmutableSet.of(
346         "always", "inherit", "once");
347     ImmutableSet<String> speakNumeralLiterals0 = ImmutableSet.of(
348         "continuous", "digits");
349     ImmutableSet<String> speakPunctuationLiterals0 = ImmutableSet.of(
350         "code", "inherit", "none");
351     ImmutableSet<String> speechRateLiterals0 = ImmutableSet.of(
352         "fast", "faster", "slow", "slower", "x-fast", "x-slow");
353     ImmutableSet<String> tableLayoutLiterals0 = ImmutableSet.of(
354         "auto", "fixed", "inherit");
355     ImmutableSet<String> textAlignLiterals0 = ImmutableSet.of(
356         "center", "inherit", "justify");
357     ImmutableSet<String> textDecorationLiterals0 = ImmutableSet.of(
358         "blink", "line-through", "overline", "underline");
359     ImmutableSet<String> textTransformLiterals0 = ImmutableSet.of(
360         "capitalize", "lowercase", "uppercase");
361     ImmutableSet<String> textWrapLiterals0 = ImmutableSet.of(
362         "suppress", "unrestricted");
363     ImmutableSet<String> unicodeBidiLiterals0 = ImmutableSet.of(
364         "bidi-override", "embed");
365     ImmutableSet<String> verticalAlignLiterals0 = ImmutableSet.of(
366         "baseline", "middle", "sub", "super", "text-bottom", "text-top");
367     ImmutableSet<String> visibilityLiterals0 = ImmutableSet.of(
368         "collapse", "hidden", "inherit", "visible");
369     ImmutableSet<String> voiceFamilyLiterals0 = ImmutableSet.of(
370         "child", "female", "male");
371     ImmutableSet<String> volumeLiterals0 = ImmutableSet.of(
372         "loud", "silent", "soft", "x-loud", "x-soft");
373     ImmutableSet<String> whiteSpaceLiterals0 = ImmutableSet.of(
374         "-moz-pre-wrap", "-o-pre-wrap", "-pre-wrap", "nowrap", "pre",
375         "pre-line", "pre-wrap");
376     ImmutableSet<String> wordWrapLiterals0 = ImmutableSet.of(
377         "break-word", "normal");
378     ImmutableSet<String> rgb$FunLiterals0 = ImmutableSet.of(",");
379     ImmutableSet<String> linearGradient$FunLiterals0 = ImmutableSet.of(
380         ",", "to");
381     ImmutableSet<String> radialGradient$FunLiterals0 = ImmutableSet.of(
382         "at", "closest-corner", "closest-side", "ellipse", "farthest-corner",
383         "farthest-side");
384     ImmutableSet<String> radialGradient$FunLiterals1 = ImmutableSet.of(
385         ",", "center", "circle");
386     ImmutableSet<String> rect$FunLiterals0 = ImmutableSet.of(",", "auto");
387     //ImmutableSet<String> alpha$FunLiterals0 = ImmutableSet.of("=", "opacity");
388     Property mozBorderRadius =
389        new Property(5, mozBorderRadiusLiterals0, zeroFns);
390     builder.put("-moz-border-radius", mozBorderRadius);
391     Property mozBorderRadiusBottomleft =
392        new Property(5, ImmutableSet.<String>of(), zeroFns);
393     builder.put("-moz-border-radius-bottomleft", mozBorderRadiusBottomleft);
394     Property mozOpacity = new Property(1, mozOpacityLiterals0, zeroFns);
395     builder.put("-moz-opacity", mozOpacity);
396     @SuppressWarnings("unchecked")
397     Property mozOutline = new Property(
398         7,
399         union(mozOutlineLiterals0, mozOutlineLiterals1, mozOutlineLiterals2,
400               mozOutlineLiterals3),
401         mozOutlineFunctions);
402     builder.put("-moz-outline", mozOutline);
403     @SuppressWarnings("unchecked")
404     Property mozOutlineColor = new Property(
405         2, union(mozOutlineColorLiterals0, mozOutlineLiterals0),
406         mozOutlineFunctions);
407     builder.put("-moz-outline-color", mozOutlineColor);
408     @SuppressWarnings("unchecked")
409     Property mozOutlineStyle = new Property(
410         0, union(mozOutlineLiterals1, mozOutlineStyleLiterals0), zeroFns);
411     builder.put("-moz-outline-style", mozOutlineStyle);
412     @SuppressWarnings("unchecked")
413     Property mozOutlineWidth = new Property(
414         5, union(mozOutlineLiterals2, mozOutlineWidthLiterals0), zeroFns);
415     builder.put("-moz-outline-width", mozOutlineWidth);
416     Property oTextOverflow = new Property(0, oTextOverflowLiterals0, zeroFns);
417     builder.put("-o-text-overflow", oTextOverflow);
418     @SuppressWarnings("unchecked")
419     Property azimuth = new Property(
420         5, union(azimuthLiterals0, azimuthLiterals1, azimuthLiterals2),
421         zeroFns);
422     builder.put("azimuth", azimuth);
423     @SuppressWarnings("unchecked")
424     Property background = new Property(
425         23,
426         union(azimuthLiterals1, backgroundLiterals0, backgroundLiterals1,
427               backgroundLiterals2, backgroundLiterals3, mozOutlineLiterals0),
428         backgroundFunctions);
429     builder.put("background", background);
430     builder.put("background-attachment",
431                 new Property(0, backgroundAttachmentLiterals0, zeroFns));
432     @SuppressWarnings("unchecked")
433     Property backgroundColor = new Property(
434         258, union(backgroundColorLiterals0, mozOutlineLiterals0),
435         mozOutlineFunctions);
436     builder.put("background-color", backgroundColor);
437     builder.put("background-image",
438                 new Property(16, backgroundImageLiterals0,
439                              backgroundImageFunctions));
440     @SuppressWarnings("unchecked")
441     Property backgroundPosition = new Property(
442         5,
443         union(azimuthLiterals1, backgroundLiterals2,
444               backgroundPositionLiterals0),
445         zeroFns);
446     builder.put("background-position", backgroundPosition);
447     @SuppressWarnings("unchecked")
448     Property backgroundRepeat = new Property(
449         0, union(backgroundLiterals1, backgroundRepeatLiterals0), zeroFns);
450     builder.put("background-repeat", backgroundRepeat);
451     @SuppressWarnings("unchecked")
452     Property border = new Property(
453         7,
454         union(borderLiterals0, mozOutlineLiterals0, mozOutlineLiterals1,
455               mozOutlineLiterals2),
456         mozOutlineFunctions);
457     builder.put("border", border);
458     @SuppressWarnings("unchecked")
459     Property borderBottomColor = new Property(
460         2, union(backgroundColorLiterals0, mozOutlineLiterals0),
461         mozOutlineFunctions);
462     builder.put("border-bottom-color", borderBottomColor);
463     builder.put("border-collapse",
464                 new Property(0, borderCollapseLiterals0, zeroFns));
465     Property borderSpacing = new Property(5, mozOpacityLiterals0, zeroFns);
466     builder.put("border-spacing", borderSpacing);
467     Property bottom = new Property(5, bottomLiterals0, zeroFns);
468     builder.put("bottom", bottom);
469     @SuppressWarnings("unchecked")
470     Property boxShadow = new Property(
471         7, union(boxShadowLiterals0, mozOutlineLiterals0), mozOutlineFunctions);
472     builder.put("box-shadow", boxShadow);
473     @SuppressWarnings("unchecked")
474     Property captionSide = new Property(
475         0, union(backgroundLiterals2, mozOpacityLiterals0), zeroFns);
476     builder.put("caption-side", captionSide);
477     @SuppressWarnings("unchecked")
478     Property clear = new Property(
479         0, union(azimuthLiterals1, clearLiterals0), zeroFns);
480     builder.put("clear", clear);
481     builder.put("clip", new Property(0, bottomLiterals0, clipFunctions));
482     @SuppressWarnings("unchecked")
483     Property color = new Property(
484         258, union(mozOpacityLiterals0, mozOutlineLiterals0),
485         mozOutlineFunctions);
486     builder.put("color", color);
487     builder.put("content", new Property(8, contentLiterals0, zeroFns));
488     Property cue = new Property(16, cueLiterals0, zeroFns);
489     builder.put("cue", cue);
490     @SuppressWarnings("unchecked")
491     Property cursor = new Property(
492         272, union(cursorLiterals0, cursorLiterals1), zeroFns);
493     builder.put("cursor", cursor);
494     @SuppressWarnings("unchecked")
495     Property direction = new Property(
496         0, union(directionLiterals0, mozOpacityLiterals0), zeroFns);
497     builder.put("direction", direction);
498     @SuppressWarnings("unchecked")
499     Property display = new Property(
500         0, union(cueLiterals0, displayLiterals0), zeroFns);
501     builder.put("display", display);
502     @SuppressWarnings("unchecked")
503     Property elevation = new Property(
504         5, union(elevationLiterals0, mozOpacityLiterals0), zeroFns);
505     builder.put("elevation", elevation);
506     @SuppressWarnings("unchecked")
507     Property emptyCells = new Property(
508         0, union(emptyCellsLiterals0, mozOpacityLiterals0), zeroFns);
509     builder.put("empty-cells", emptyCells);
510     //builder.put("filter",
511     //            new Property(0, ImmutableSet.<String>of(), filterFunctions));
512     @SuppressWarnings("unchecked")
513     Property cssFloat = new Property(
514         0, union(azimuthLiterals1, cueLiterals0), zeroFns);
515     builder.put("float", cssFloat);
516     @SuppressWarnings("unchecked")
517     Property font = new Property(
518         73,
519         union(fontLiterals0, fontLiterals1, fontLiterals2, fontLiterals3,
520               fontLiterals4, fontLiterals5),
521         zeroFns);
522     builder.put("font", font);
523     @SuppressWarnings("unchecked")
524     Property fontFamily = new Property(
525         72, union(fontFamilyLiterals0, fontLiterals3), zeroFns);
526     builder.put("font-family", fontFamily);
527     @SuppressWarnings("unchecked")
528     Property fontSize = new Property(
529         1, union(fontLiterals1, mozOutlineWidthLiterals0), zeroFns);
530     builder.put("font-size", fontSize);
531     @SuppressWarnings("unchecked")
532     Property fontStretch = new Property(
533         0, union(fontStretchLiterals0, fontStretchLiterals1), zeroFns);
534     builder.put("font-stretch", fontStretch);
535     @SuppressWarnings("unchecked")
536     Property fontStyle = new Property(
537         0, union(fontLiterals4, fontStyleLiterals0), zeroFns);
538     builder.put("font-style", fontStyle);
539     builder.put("font-variant", new Property(
540         0, fontVariantLiterals0, zeroFns));
541     @SuppressWarnings("unchecked")
542     Property fontWeight = new Property(
543         0, union(fontLiterals0, fontStyleLiterals0), zeroFns);
544     builder.put("font-weight", fontWeight);
545     Property height = new Property(5, bottomLiterals0, zeroFns);
546     builder.put("height", height);
547     Property letterSpacing = new Property(5, fontStyleLiterals0, zeroFns);
548     builder.put("letter-spacing", letterSpacing);
549     builder.put("line-height", new Property(1, fontStyleLiterals0, zeroFns));
550     @SuppressWarnings("unchecked")
551     Property listStyle = new Property(
552         16,
553         union(listStyleLiterals0, listStyleLiterals1, listStyleLiterals2),
554         backgroundImageFunctions);
555     builder.put("list-style", listStyle);
556     builder.put("list-style-image", new Property(
557         16, cueLiterals0, backgroundImageFunctions));
558     @SuppressWarnings("unchecked")
559     Property listStylePosition = new Property(
560         0, union(listStyleLiterals1, mozOpacityLiterals0), zeroFns);
561     builder.put("list-style-position", listStylePosition);
562     @SuppressWarnings("unchecked")
563     Property listStyleType = new Property(
564         0, union(listStyleLiterals0, listStyleLiterals2), zeroFns);
565     builder.put("list-style-type", listStyleType);
566     Property margin = new Property(1, bottomLiterals0, zeroFns);
567     builder.put("margin", margin);
568     Property maxHeight = new Property(1, maxHeightLiterals0, zeroFns);
569     builder.put("max-height", maxHeight);
570     Property opacity = new Property(1, mozOpacityLiterals0, zeroFns);
571     builder.put("opacity", opacity);
572     builder.put("overflow", new Property(0, overflowLiterals0, zeroFns));
573     @SuppressWarnings("unchecked")
574     Property overflowX = new Property(
575         0, union(overflowXLiterals0, overflowXLiterals1), zeroFns);
576     builder.put("overflow-x", overflowX);
577     Property padding = new Property(1, mozOpacityLiterals0, zeroFns);
578     builder.put("padding", padding);
579     @SuppressWarnings("unchecked")
580     Property pageBreakAfter = new Property(
581         0, union(azimuthLiterals1, pageBreakAfterLiterals0), zeroFns);
582     builder.put("page-break-after", pageBreakAfter);
583     builder.put("page-break-inside", new Property(
584         0, pageBreakInsideLiterals0, zeroFns));
585     @SuppressWarnings("unchecked")
586     Property pitch = new Property(
587         5, union(mozOutlineWidthLiterals0, pitchLiterals0), zeroFns);
588     builder.put("pitch", pitch);
589     builder.put("play-during", new Property(
590         16, playDuringLiterals0, zeroFns));
591     @SuppressWarnings("unchecked")
592     Property position = new Property(
593         0, union(mozOpacityLiterals0, positionLiterals0), zeroFns);
594     builder.put("position", position);
595     builder.put("quotes", new Property(8, cueLiterals0, zeroFns));
596     builder.put("speak", new Property(0, speakLiterals0, zeroFns));
597     builder.put("speak-header", new Property(
598         0, speakHeaderLiterals0, zeroFns));
599     @SuppressWarnings("unchecked")
600     Property speakNumeral = new Property(
601         0, union(mozOpacityLiterals0, speakNumeralLiterals0), zeroFns);
602     builder.put("speak-numeral", speakNumeral);
603     builder.put("speak-punctuation", new Property(
604         0, speakPunctuationLiterals0, zeroFns));
605     @SuppressWarnings("unchecked")
606     Property speechRate = new Property(
607         5, union(mozOutlineWidthLiterals0, speechRateLiterals0), zeroFns);
608     builder.put("speech-rate", speechRate);
609     builder.put("table-layout", new Property(
610         0, tableLayoutLiterals0, zeroFns));
611     @SuppressWarnings("unchecked")
612     Property textAlign = new Property(
613         0, union(azimuthLiterals1, textAlignLiterals0), zeroFns);
614     builder.put("text-align", textAlign);
615     @SuppressWarnings("unchecked")
616     Property textDecoration = new Property(
617         0, union(cueLiterals0, textDecorationLiterals0), zeroFns);
618     builder.put("text-decoration", textDecoration);
619     @SuppressWarnings("unchecked")
620     Property textTransform = new Property(
621         0, union(cueLiterals0, textTransformLiterals0), zeroFns);
622     builder.put("text-transform", textTransform);
623     @SuppressWarnings("unchecked")
624     Property textWrap = new Property(
625         0, union(contentLiterals0, textWrapLiterals0), zeroFns);
626     builder.put("text-wrap", textWrap);
627     @SuppressWarnings("unchecked")
628     Property unicodeBidi = new Property(
629         0, union(fontStyleLiterals0, unicodeBidiLiterals0), zeroFns);
630     builder.put("unicode-bidi", unicodeBidi);
631     @SuppressWarnings("unchecked")
632     Property verticalAlign = new Property(
633         5,
634         union(backgroundLiterals2, mozOpacityLiterals0, verticalAlignLiterals0),
635         zeroFns);
636     builder.put("vertical-align", verticalAlign);
637     builder.put("visibility", new Property(0, visibilityLiterals0, zeroFns));
638     @SuppressWarnings("unchecked")
639     Property voiceFamily = new Property(
640         8, union(fontFamilyLiterals0, voiceFamilyLiterals0), zeroFns);
641     builder.put("voice-family", voiceFamily);
642     @SuppressWarnings("unchecked")
643     Property volume = new Property(
644         1, union(mozOutlineWidthLiterals0, volumeLiterals0), zeroFns);
645     builder.put("volume", volume);
646     @SuppressWarnings("unchecked")
647     Property whiteSpace = new Property(
648         0, union(fontStyleLiterals0, whiteSpaceLiterals0), zeroFns);
649     builder.put("white-space", whiteSpace);
650     builder.put("word-wrap", new Property(0, wordWrapLiterals0, zeroFns));
651     builder.put("zoom", new Property(1, fontStretchLiterals1, zeroFns));
652     Property rgb$Fun = new Property(1, rgb$FunLiterals0, zeroFns);
653     builder.put("rgb()", rgb$Fun);
654     @SuppressWarnings("unchecked")
655     Property image$Fun = new Property(
656         18, union(mozOutlineLiterals0, rgb$FunLiterals0), mozOutlineFunctions);
657     builder.put("image()", image$Fun);
658     @SuppressWarnings("unchecked")
659     Property linearGradient$Fun = new Property(
660         7,
661         union(azimuthLiterals1, backgroundLiterals2,
662               linearGradient$FunLiterals0, mozOutlineLiterals0),
663         mozOutlineFunctions);
664     builder.put("linear-gradient()", linearGradient$Fun);
665     @SuppressWarnings("unchecked")
666     Property radialGradient$Fun = new Property(
667         7,
668         union(azimuthLiterals1, backgroundLiterals2, mozOutlineLiterals0,
669               radialGradient$FunLiterals0, radialGradient$FunLiterals1),
670         mozOutlineFunctions);
671     builder.put("radial-gradient()", radialGradient$Fun);
672     builder.put("rect()", new Property(5, rect$FunLiterals0, zeroFns));
673     //builder.put("alpha()", new Property(1, alpha$FunLiterals0, zeroFns));
674     builder.put("-moz-border-radius-bottomright", mozBorderRadiusBottomleft);
675     builder.put("-moz-border-radius-topleft", mozBorderRadiusBottomleft);
676     builder.put("-moz-border-radius-topright", mozBorderRadiusBottomleft);
677     builder.put("-moz-box-shadow", boxShadow);
678     builder.put("-webkit-border-bottom-left-radius", mozBorderRadiusBottomleft);
679     builder.put("-webkit-border-bottom-right-radius",
680                 mozBorderRadiusBottomleft);
681     builder.put("-webkit-border-radius", mozBorderRadius);
682     builder.put("-webkit-border-radius-bottom-left", mozBorderRadiusBottomleft);
683     builder.put("-webkit-border-radius-bottom-right",
684                 mozBorderRadiusBottomleft);
685     builder.put("-webkit-border-radius-top-left", mozBorderRadiusBottomleft);
686     builder.put("-webkit-border-radius-top-right", mozBorderRadiusBottomleft);
687     builder.put("-webkit-border-top-left-radius", mozBorderRadiusBottomleft);
688     builder.put("-webkit-border-top-right-radius", mozBorderRadiusBottomleft);
689     builder.put("-webkit-box-shadow", boxShadow);
690     builder.put("border-bottom", border);
691     builder.put("border-bottom-left-radius", mozBorderRadiusBottomleft);
692     builder.put("border-bottom-right-radius", mozBorderRadiusBottomleft);
693     builder.put("border-bottom-style", mozOutlineStyle);
694     builder.put("border-bottom-width", mozOutlineWidth);
695     builder.put("border-color", borderBottomColor);
696     builder.put("border-left", border);
697     builder.put("border-left-color", borderBottomColor);
698     builder.put("border-left-style", mozOutlineStyle);
699     builder.put("border-left-width", mozOutlineWidth);
700     builder.put("border-radius", mozBorderRadius);
701     builder.put("border-right", border);
702     builder.put("border-right-color", borderBottomColor);
703     builder.put("border-right-style", mozOutlineStyle);
704     builder.put("border-right-width", mozOutlineWidth);
705     builder.put("border-style", mozOutlineStyle);
706     builder.put("border-top", border);
707     builder.put("border-top-color", borderBottomColor);
708     builder.put("border-top-left-radius", mozBorderRadiusBottomleft);
709     builder.put("border-top-right-radius", mozBorderRadiusBottomleft);
710     builder.put("border-top-style", mozOutlineStyle);
711     builder.put("border-top-width", mozOutlineWidth);
712     builder.put("border-width", mozOutlineWidth);
713     builder.put("cue-after", cue);
714     builder.put("cue-before", cue);
715     builder.put("left", height);
716     builder.put("margin-bottom", margin);
717     builder.put("margin-left", margin);
718     builder.put("margin-right", margin);
719     builder.put("margin-top", margin);
720     builder.put("max-width", maxHeight);
721     builder.put("min-height", margin);
722     builder.put("min-width", margin);
723     builder.put("outline", mozOutline);
724     builder.put("outline-color", mozOutlineColor);
725     builder.put("outline-style", mozOutlineStyle);
726     builder.put("outline-width", mozOutlineWidth);
727     builder.put("overflow-y", overflowX);
728     builder.put("padding-bottom", padding);
729     builder.put("padding-left", padding);
730     builder.put("padding-right", padding);
731     builder.put("padding-top", padding);
732     builder.put("page-break-before", pageBreakAfter);
733     builder.put("pause", borderSpacing);
734     builder.put("pause-after", borderSpacing);
735     builder.put("pause-before", borderSpacing);
736     builder.put("pitch-range", borderSpacing);
737     builder.put("richness", borderSpacing);
738     builder.put("right", height);
739     builder.put("stress", borderSpacing);
740     builder.put("text-indent", borderSpacing);
741     builder.put("text-overflow", oTextOverflow);
742     builder.put("text-shadow", boxShadow);
743     builder.put("top", height);
744     builder.put("width", margin);
745     builder.put("word-spacing", letterSpacing);
746     builder.put("z-index", bottom);
747     builder.put("rgba()", rgb$Fun);
748     builder.put("repeating-linear-gradient()", linearGradient$Fun);
749     builder.put("repeating-radial-gradient()", radialGradient$Fun);
750     DEFINITIONS = builder.build();
751   }
752 
union(ImmutableSet<T>.... subsets)753   private static <T> ImmutableSet<T> union(ImmutableSet<T>... subsets) {
754     ImmutableSet.Builder<T> all = ImmutableSet.builder();
755     for (ImmutableSet<T> subset : subsets) {
756       all.addAll(subset);
757     }
758     return all.build();
759   }
760 
761   static final ImmutableSet<String> DEFAULT_WHITELIST = ImmutableSet.of(
762       "-moz-border-radius",
763       "-moz-border-radius-bottomleft",
764       "-moz-border-radius-bottomright",
765       "-moz-border-radius-topleft",
766       "-moz-border-radius-topright",
767       "-moz-box-shadow",
768       "-moz-outline",
769       "-moz-outline-color",
770       "-moz-outline-style",
771       "-moz-outline-width",
772       "-o-text-overflow",
773       "-webkit-border-bottom-left-radius",
774       "-webkit-border-bottom-right-radius",
775       "-webkit-border-radius",
776       "-webkit-border-radius-bottom-left",
777       "-webkit-border-radius-bottom-right",
778       "-webkit-border-radius-top-left",
779       "-webkit-border-radius-top-right",
780       "-webkit-border-top-left-radius",
781       "-webkit-border-top-right-radius",
782       "-webkit-box-shadow",
783       "azimuth",
784       "background",
785       "background-attachment",
786       "background-color",
787       "background-image",
788       "background-position",
789       "background-repeat",
790       "border",
791       "border-bottom",
792       "border-bottom-color",
793       "border-bottom-left-radius",
794       "border-bottom-right-radius",
795       "border-bottom-style",
796       "border-bottom-width",
797       "border-collapse",
798       "border-color",
799       "border-left",
800       "border-left-color",
801       "border-left-style",
802       "border-left-width",
803       "border-radius",
804       "border-right",
805       "border-right-color",
806       "border-right-style",
807       "border-right-width",
808       "border-spacing",
809       "border-style",
810       "border-top",
811       "border-top-color",
812       "border-top-left-radius",
813       "border-top-right-radius",
814       "border-top-style",
815       "border-top-width",
816       "border-width",
817       "box-shadow",
818       "caption-side",
819       "color",
820       "cue",
821       "cue-after",
822       "cue-before",
823       "direction",
824       "elevation",
825       "empty-cells",
826       "font",
827       "font-family",
828       "font-size",
829       "font-stretch",
830       "font-style",
831       "font-variant",
832       "font-weight",
833       "height",
834       "image()",
835       "letter-spacing",
836       "line-height",
837       "linear-gradient()",
838       "list-style",
839       "list-style-image",
840       "list-style-position",
841       "list-style-type",
842       "margin",
843       "margin-bottom",
844       "margin-left",
845       "margin-right",
846       "margin-top",
847       "max-height",
848       "max-width",
849       "min-height",
850       "min-width",
851       "outline",
852       "outline-color",
853       "outline-style",
854       "outline-width",
855       "padding",
856       "padding-bottom",
857       "padding-left",
858       "padding-right",
859       "padding-top",
860       "pause",
861       "pause-after",
862       "pause-before",
863       "pitch",
864       "pitch-range",
865       "quotes",
866       "radial-gradient()",
867       "rect()",
868       "repeating-linear-gradient()",
869       "repeating-radial-gradient()",
870       "rgb()",
871       "rgba()",
872       "richness",
873       "speak",
874       "speak-header",
875       "speak-numeral",
876       "speak-punctuation",
877       "speech-rate",
878       "stress",
879       "table-layout",
880       "text-align",
881       "text-decoration",
882       "text-indent",
883       "text-overflow",
884       "text-shadow",
885       "text-transform",
886       "text-wrap",
887       "unicode-bidi",
888       "vertical-align",
889       "voice-family",
890       "volume",
891       "white-space",
892       "width",
893       "word-spacing",
894       "word-wrap"
895   );
896 
897   /**
898    * A schema that includes only those properties on the default schema
899    * white-list.
900    */
901   public static final CssSchema DEFAULT =
902       CssSchema.withProperties(DEFAULT_WHITELIST);
903 
904   /** Dumps key and literal list to stdout for easy examination. */
main(String... argv)905   public static void main(String... argv) {
906     SortedSet<String> keys = Sets.newTreeSet();
907     SortedSet<String> literals = Sets.newTreeSet();
908 
909     for (ImmutableMap.Entry<String, Property> e : DEFINITIONS.entrySet()) {
910       keys.add(e.getKey());
911       literals.addAll(e.getValue().literals);
912     }
913 
914     System.out.println(
915         "# Below two blocks of tokens.\n"
916             + "#\n"
917         + "# First are all property names.\n"
918         + "# Those followed by an asterisk (*) are in the default white-list.\n"
919         + "#\n"
920         + "# Second are the literal tokens recognized in any defined property\n"
921         + "# value.\n"
922         );
923     for (String key : keys) {
924       System.out.print(key);
925       if (DEFAULT_WHITELIST.contains(key)) { System.out.print("*"); }
926       System.out.println();
927     }
928     System.out.println();
929     for (String literal : literals) {
930       System.out.println(literal);
931     }
932   }
933 }
934