2 |
3 | Permission is hereby granted,
4 | free of charge, to any person obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without restriction, including without
6 | limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7 | and/or sell copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice
11 | and this permission notice shall be included in all copies or substantial portions
12 | of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
17 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
19 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | CSS Color Palette Extractor
2 | ---------------------------
3 |
4 | Demo: [http://svay.com/experiences/css-color-palette-extractor/](http://svay.com/experiences/css-color-palette-extractor/)
5 |
6 | Paste your CSS. Click the button. Get the color palette.
7 | The larger the color bar, the more occurences in your CSS.
8 |
9 | Includes code from [glazman.org/JSCSSP](http://glazman.org/JSCSSP/) & [github.com/brehaut/color-js](https://github.com/brehaut/color-js)
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | CSS Color Palette Extractor
7 |
58 |
59 |
60 | CSS Color Palette extractor
61 |
62 | Extract colors
63 | Greyscale
64 | -
65 | Colors
66 | -
67 |
68 |
72 |
73 |
74 |
75 |
76 |
97 |
98 |
--------------------------------------------------------------------------------
/js/color.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2008, Andrew Brehaut, Tim Baumann
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 are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright notice,
8 | // this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright notice,
10 | // this list of conditions and the following disclaimer in the documentation
11 | // and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
17 | // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 | // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 | // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 | // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 | // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
23 | // POSSIBILITY OF SUCH DAMAGE.
24 |
25 | // color.js - version 0.4
26 | //
27 | // HSV <-> RGB code based on code from http://www.cs.rit.edu/~ncs/color/t_convert.html
28 | // object function created by Douglas Crockford.
29 | // Color scheme degrees taken from the colorjack.com colorpicker
30 | //
31 | // HSL support kindly provided by Tim Baumann - http://github.com/timjb
32 |
33 | // create namespaces
34 | /*global net */
35 | if ("undefined" == typeof net) { var net = {}; }
36 | if (!net.brehaut) { net.brehaut = {}; }
37 |
38 | // this module function is called with net.brehaut as 'this'
39 | (function ( ) {
40 | // Constants
41 |
42 | // css_colors maps color names onto their hex values
43 | // these names are defined by W3C
44 | var css_colors = {aliceblue:'#F0F8FF',antiquewhite:'#FAEBD7',aqua:'#00FFFF',aquamarine:'#7FFFD4',azure:'#F0FFFF',beige:'#F5F5DC',bisque:'#FFE4C4',black:'#000000',blanchedalmond:'#FFEBCD',blue:'#0000FF',blueviolet:'#8A2BE2',brown:'#A52A2A',burlywood:'#DEB887',cadetblue:'#5F9EA0',chartreuse:'#7FFF00',chocolate:'#D2691E',coral:'#FF7F50',cornflowerblue:'#6495ED',cornsilk:'#FFF8DC',crimson:'#DC143C',cyan:'#00FFFF',darkblue:'#00008B',darkcyan:'#008B8B',darkgoldenrod:'#B8860B',darkgray:'#A9A9A9',darkgrey:'#A9A9A9',darkgreen:'#006400',darkkhaki:'#BDB76B',darkmagenta:'#8B008B',darkolivegreen:'#556B2F',darkorange:'#FF8C00',darkorchid:'#9932CC',darkred:'#8B0000',darksalmon:'#E9967A',darkseagreen:'#8FBC8F',darkslateblue:'#483D8B',darkslategray:'#2F4F4F',darkslategrey:'#2F4F4F',darkturquoise:'#00CED1',darkviolet:'#9400D3',deeppink:'#FF1493',deepskyblue:'#00BFFF',dimgray:'#696969',dimgrey:'#696969',dodgerblue:'#1E90FF',firebrick:'#B22222',floralwhite:'#FFFAF0',forestgreen:'#228B22',fuchsia:'#FF00FF',gainsboro:'#DCDCDC',ghostwhite:'#F8F8FF',gold:'#FFD700',goldenrod:'#DAA520',gray:'#808080',grey:'#808080',green:'#008000',greenyellow:'#ADFF2F',honeydew:'#F0FFF0',hotpink:'#FF69B4',indianred:'#CD5C5C',indigo:'#4B0082',ivory:'#FFFFF0',khaki:'#F0E68C',lavender:'#E6E6FA',lavenderblush:'#FFF0F5',lawngreen:'#7CFC00',lemonchiffon:'#FFFACD',lightblue:'#ADD8E6',lightcoral:'#F08080',lightcyan:'#E0FFFF',lightgoldenrodyellow:'#FAFAD2',lightgray:'#D3D3D3',lightgrey:'#D3D3D3',lightgreen:'#90EE90',lightpink:'#FFB6C1',lightsalmon:'#FFA07A',lightseagreen:'#20B2AA',lightskyblue:'#87CEFA',lightslategray:'#778899',lightslategrey:'#778899',lightsteelblue:'#B0C4DE',lightyellow:'#FFFFE0',lime:'#00FF00',limegreen:'#32CD32',linen:'#FAF0E6',magenta:'#FF00FF',maroon:'#800000',mediumaquamarine:'#66CDAA',mediumblue:'#0000CD',mediumorchid:'#BA55D3',mediumpurple:'#9370D8',mediumseagreen:'#3CB371',mediumslateblue:'#7B68EE',mediumspringgreen:'#00FA9A',mediumturquoise:'#48D1CC',mediumvioletred:'#C71585',midnightblue:'#191970',mintcream:'#F5FFFA',mistyrose:'#FFE4E1',moccasin:'#FFE4B5',navajowhite:'#FFDEAD',navy:'#000080',oldlace:'#FDF5E6',olive:'#808000',olivedrab:'#6B8E23',orange:'#FFA500',orangered:'#FF4500',orchid:'#DA70D6',palegoldenrod:'#EEE8AA',palegreen:'#98FB98',paleturquoise:'#AFEEEE',palevioletred:'#D87093',papayawhip:'#FFEFD5',peachpuff:'#FFDAB9',peru:'#CD853F',pink:'#FFC0CB',plum:'#DDA0DD',powderblue:'#B0E0E6',purple:'#800080',red:'#FF0000',rosybrown:'#BC8F8F',royalblue:'#4169E1',saddlebrown:'#8B4513',salmon:'#FA8072',sandybrown:'#F4A460',seagreen:'#2E8B57',seashell:'#FFF5EE',sienna:'#A0522D',silver:'#C0C0C0',skyblue:'#87CEEB',slateblue:'#6A5ACD',slategray:'#708090',slategrey:'#708090',snow:'#FFFAFA',springgreen:'#00FF7F',transparent:'#000',steelblue:'#4682B4',tan:'#D2B48C',teal:'#008080',thistle:'#D8BFD8',tomato:'#FF6347',turquoise:'#40E0D0',violet:'#EE82EE',wheat:'#F5DEB3',white:'#FFFFFF',whitesmoke:'#F5F5F5',yellow:'#FFFF00',yellowgreen:'#9ACD32"'};
45 |
46 | // CSS value regexes, according to http://www.w3.org/TR/css3-values/
47 | var css_integer = '(?:\\+|-)?\\d+';
48 | var css_float = '(?:\\+|-)?\\d*\\.\\d+';
49 | var css_number = '(?:' + css_integer + ')|(?:' + css_float + ')';
50 | css_integer = '(' + css_integer + ')';
51 | css_float = '(' + css_float + ')';
52 | css_number = '(' + css_number + ')';
53 | var css_percentage = css_number + '%';
54 | var css_whitespace = '\\s*?';
55 |
56 | // http://www.w3.org/TR/2003/CR-css3-color-20030514/
57 | var hsl_hsla_regex = new RegExp([
58 | '^hsl(a?)\\(', css_number, ',', css_percentage, ',', css_percentage, '(,', css_number, ')?\\)$'
59 | ].join(css_whitespace) );
60 | var rgb_rgba_integer_regex = new RegExp([
61 | '^rgb(a?)\\(', css_integer, ',', css_integer, ',', css_integer, '(,', css_number, ')?\\)$'
62 | ].join(css_whitespace) );
63 | var rgb_rgba_percentage_regex = new RegExp([
64 | '^rgb(a?)\\(', css_percentage, ',', css_percentage, ',', css_percentage, '(,', css_number, ')?\\)$'
65 | ].join(css_whitespace) );
66 |
67 | // Package wide variables
68 |
69 | // becomes the top level prototype object
70 | var color;
71 |
72 | /* registered_models contains the template objects for all the
73 | * models that have been registered for the color class.
74 | */
75 | var registered_models = [];
76 |
77 |
78 | /* factories contains methods to create new instance of
79 | * different color models that have been registered.
80 | */
81 | var factories = {};
82 |
83 | // Utility functions
84 |
85 | /* object is Douglas Crockfords object function for prototypal
86 | * inheritance.
87 | */
88 | if (!this.object) {
89 | this.object = function (o) {
90 | function F () { }
91 | F.prototype = o;
92 | return new F();
93 | };
94 | }
95 | var object = this.object;
96 |
97 | /* takes a value, converts to string if need be, then pads it
98 | * to a minimum length.
99 | */
100 | function pad ( val, len ) {
101 | val = val.toString();
102 | var padded = [];
103 |
104 | for (var i = 0, j = Math.max( len - val.length, 0); i < j; i++) {
105 | padded.push('0');
106 | }
107 |
108 | padded.push(val);
109 | return padded.join('');
110 | }
111 |
112 |
113 | /* takes a string and returns a new string with the first letter
114 | * capitalised
115 | */
116 | function capitalise ( s ) {
117 | return s.slice(0,1).toUpperCase() + s.slice(1);
118 | }
119 |
120 | /* removes leading and trailing whitespace
121 | */
122 | function trim ( str ) {
123 | return str.replace(/^\s+|\s+$/g, '');
124 | }
125 |
126 | /* used to apply a method to object non-destructively by
127 | * cloning the object and then apply the method to that
128 | * new object
129 | */
130 | function cloneOnApply( meth ) {
131 | return function ( ) {
132 | var cloned = this.clone();
133 | meth.apply(cloned, arguments);
134 | return cloned;
135 | };
136 | }
137 |
138 |
139 | /* registerModel is used to add additional representations
140 | * to the color code, and extend the color API with the new
141 | * operatiosn that model provides. see before for examples
142 | */
143 | function registerModel( name, model ) {
144 | var proto = object(color);
145 | var fields = []; // used for cloning and generating accessors
146 |
147 | var to_meth = 'to'+ capitalise(name);
148 |
149 | function convertAndApply( meth ) {
150 | return function ( ) {
151 | return meth.apply(this[to_meth](), arguments);
152 | };
153 | }
154 |
155 | for (var key in model) if (model.hasOwnProperty(key)) {
156 | proto[key] = model[key];
157 | var prop = proto[key];
158 |
159 | if (key.slice(0,1) == '_') { continue; }
160 | if (!(key in color) && "function" == typeof prop) {
161 | // the method found on this object is a) public and b) not
162 | // currently supported by the color object. Create an impl that
163 | // calls the toModel function and passes that new object
164 | // onto the correct method with the args.
165 | color[key] = convertAndApply(prop);
166 | }
167 | else if ("function" != typeof prop) {
168 | // we have found a public property. create accessor methods
169 | // and bind them up correctly
170 | fields.push(key);
171 | var getter = 'get'+capitalise(key);
172 | var setter = 'set'+capitalise(key);
173 |
174 | color[getter] = convertAndApply(
175 | proto[getter] = (function ( key ) {
176 | return function ( ) {
177 | return this[key];
178 | };
179 | })( key )
180 | );
181 |
182 | color[setter] = convertAndApply(
183 | proto[setter] = (function ( key ) {
184 | return function ( val ) {
185 | var cloned = this.clone();
186 | cloned[key] = val;
187 | return cloned;
188 | };
189 | })( key )
190 | );
191 | }
192 | } // end of for over model
193 |
194 | // a method to create a new object - largely so prototype chains dont
195 | // get insane. This uses an unrolled 'object' so that F is cached
196 | // for later use. this is approx a 25% speed improvement
197 | function F () { }
198 | F.prototype = proto;
199 | function factory ( ) {
200 | return new F();
201 | }
202 | factories[name] = factory;
203 |
204 | proto.clone = function () {
205 | var cloned = factory();
206 | for (var i = 0, j = fields.length; i < j; i++) {
207 | var key = fields[i];
208 | cloned[key] = this[key];
209 | }
210 | return cloned;
211 | };
212 |
213 | color[to_meth] = function ( ) {
214 | return factory();
215 | };
216 |
217 | registered_models.push(proto);
218 |
219 | return proto;
220 | }// end of registerModel
221 |
222 | // Template Objects
223 |
224 | /* color is the root object in the color hierarchy. It starts
225 | * life as a very simple object, but as color models are
226 | * registered it has methods programmatically added to manage
227 | * conversions as needed.
228 | */
229 | color = {
230 | /* fromObject takes an argument and delegates to the internal
231 | * color models to try to create a new instance.
232 | */
233 | fromObject: function ( o ) {
234 | if (!o) {
235 | return object(color);
236 | }
237 |
238 | for (var i = 0, j = registered_models.length; i < j; i++) {
239 | var nu = registered_models[i].fromObject(o);
240 | if (nu) {
241 | return nu;
242 | }
243 | }
244 |
245 | return object(color);
246 | },
247 |
248 | toString: function ( ) {
249 | return this.toCSS();
250 | }
251 | };
252 |
253 |
254 | /* RGB is the red green blue model. This definition is converted
255 | * to a template object by registerModel.
256 | */
257 | registerModel('RGB', {
258 | red: 0,
259 | green: 0,
260 | blue: 0,
261 |
262 | /* getLuminance returns a value between 0 and 1, this is the
263 | * luminance calcuated according to
264 | * http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC9
265 | */
266 | getLuminance: function ( ) {
267 | return (this.red * 0.2126) + (this.green * 0.7152) + (this.blue * 0.0722);
268 | },
269 |
270 | /* does an alpha based blend of color onto this. alpha is the
271 | * amount of 'color' to use. (0 to 1)
272 | */
273 | blend: function ( color , alpha ) {
274 | color = color.toRGB();
275 | alpha = Math.min(Math.max(alpha, 0), 1);
276 | var rgb = this.clone();
277 |
278 | rgb.red = (rgb.red * (1 - alpha)) + (color.red * alpha);
279 | rgb.green = (rgb.green * (1 - alpha)) + (color.green * alpha);
280 | rgb.blue = (rgb.blue * (1 - alpha)) + (color.blue * alpha);
281 |
282 | return rgb;
283 | },
284 |
285 | /* fromObject attempts to convert an object o to and RGB
286 | * instance. This accepts an object with red, green and blue
287 | * members or a string. If the string is a known CSS color name
288 | * or a hexdecimal string it will accept it.
289 | */
290 | fromObject: function ( o ) {
291 | if ("string" == typeof o) {
292 | return this._fromCSS( trim( o ) );
293 | }
294 | if (o.hasOwnProperty('red') &&
295 | o.hasOwnProperty('green') &&
296 | o.hasOwnProperty('blue')) {
297 | return this._fromRGB ( o );
298 | }
299 | // nothing matchs, not an RGB object
300 | },
301 |
302 | _stringParsers: [
303 | // CSS RGB(A) literal:
304 | function ( css ) {
305 | css = trim(css);
306 |
307 | var withInteger = match(rgb_rgba_integer_regex, 255);
308 | if(withInteger) {
309 | return withInteger;
310 | }
311 | return match(rgb_rgba_percentage_regex, 100);
312 |
313 | function match(regex, max_value) {
314 | var colorGroups = css.match( regex );
315 |
316 | // If there is an "a" after "rgb", there must be a fourth parameter and the other way round
317 | if (!colorGroups || (!!colorGroups[1] + !!colorGroups[5] === 1)) {
318 | return null;
319 | }
320 |
321 | var rgb = factories.RGB();
322 | rgb.red = Math.min(1, Math.max(0, colorGroups[2] / max_value));
323 | rgb.green = Math.min(1, Math.max(0, colorGroups[3] / max_value));
324 | rgb.blue = Math.min(1, Math.max(0, colorGroups[4] / max_value));
325 |
326 | return rgb;
327 | }
328 | },
329 |
330 | function ( css ) {
331 | var lower = css.toLowerCase();
332 | if (lower in css_colors) {
333 | css = css_colors[lower];
334 | }
335 |
336 | if (!css.match(/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/)) {
337 | return;
338 | }
339 |
340 | css = css.replace(/^#/,'');
341 |
342 | var bytes = css.length / 3;
343 |
344 | var max = Math.pow(16, bytes) - 1;
345 |
346 | var rgb = factories.RGB();
347 | rgb.red = parseInt(css.slice(0, bytes), 16) / max;
348 | rgb.green = parseInt(css.slice(bytes * 1,bytes * 2), 16) / max;
349 | rgb.blue = parseInt(css.slice(bytes * 2), 16) / max;
350 | return rgb;
351 | }
352 | ],
353 |
354 | _fromCSS: function ( css ) {
355 | var color = null;
356 | for (var i = 0, j = this._stringParsers.length; i < j; i++) {
357 | color = this._stringParsers[i](css);
358 | if (color) return color;
359 | }
360 | },
361 |
362 | _fromRGB: function ( RGB ) {
363 | var newRGB = factories.RGB();
364 |
365 | newRGB.red = RGB.red;
366 | newRGB.green = RGB.green;
367 | newRGB.blue = RGB.blue;
368 |
369 | return newRGB;
370 | },
371 |
372 | // convert to a CSS string. defaults to two bytes a value
373 | toCSS: function ( bytes ) {
374 | bytes = bytes || 2;
375 | var max = Math.pow(16, bytes) - 1;
376 | var css = [
377 | "#",
378 | pad ( Math.round(this.red * max).toString( 16 ).toUpperCase(), bytes ),
379 | pad ( Math.round(this.green * max).toString( 16 ).toUpperCase(), bytes ),
380 | pad ( Math.round(this.blue * max).toString( 16 ).toUpperCase(), bytes )
381 | ];
382 |
383 | return css.join('');
384 | },
385 |
386 | toHSV: function ( ) {
387 | var hsv = factories.HSV();
388 | var min, max, delta;
389 |
390 | min = Math.min(this.red, this.green, this.blue);
391 | max = Math.max(this.red, this.green, this.blue);
392 | hsv.value = max; // v
393 |
394 | delta = max - min;
395 |
396 | if( delta == 0 ) { // white, grey, black
397 | hsv.hue = hsv.saturation = 0;
398 | }
399 | else { // chroma
400 | hsv.saturation = delta / max;
401 |
402 | if( this.red == max ) {
403 | hsv.hue = ( this.green - this.blue ) / delta; // between yellow & magenta
404 | }
405 | else if( this.green == max ) {
406 | hsv.hue = 2 + ( this.blue - this.red ) / delta; // between cyan & yellow
407 | }
408 | else {
409 | hsv.hue = 4 + ( this.red - this.green ) / delta; // between magenta & cyan
410 | }
411 |
412 | hsv.hue = ((hsv.hue * 60) + 360) % 360; // degrees
413 | }
414 |
415 | return hsv;
416 | },
417 | toHSL: function ( ) {
418 | return this.toHSV().toHSL();
419 | },
420 |
421 | toRGB: function ( ) {
422 | return this.clone();
423 | }
424 | });
425 |
426 |
427 | /* Like RGB above, this object describes what will become the HSV
428 | * template object. This model handles hue, saturation and value.
429 | * hue is the number of degrees around the color wheel, saturation
430 | * describes how much color their is and value is the brightness.
431 | */
432 | registerModel('HSV', {
433 | hue: 0,
434 | saturation: 0,
435 | value: 1,
436 |
437 | shiftHue: cloneOnApply(function ( degrees ) {
438 | var hue = (this.hue + degrees) % 360;
439 | if (hue < 0) {
440 | hue = (360 + hue) % 360;
441 | }
442 |
443 | this.hue = hue;
444 | }),
445 |
446 | darkenByAmount: cloneOnApply(function ( val ) {
447 | this.value = Math.min(1, Math.max(this.value - val, 0));
448 | }),
449 |
450 | darkenByRatio: cloneOnApply(function ( val ) {
451 | this.value = Math.min(1, Math.max(this.value * (1 - val), 0));
452 | }),
453 |
454 | lightenByAmount: cloneOnApply(function ( val ) {
455 | this.value = Math.min(1, Math.max(this.value + val, 0));
456 | }),
457 |
458 | lightenByRatio: cloneOnApply(function ( val ) {
459 | this.value = Math.min(1, Math.max(this.value * (1 + val), 0));
460 | }),
461 |
462 | desaturateByAmount: cloneOnApply(function ( val ) {
463 | this.saturation = Math.min(1, Math.max(this.saturation - val, 0));
464 | }),
465 |
466 | desaturateByRatio: cloneOnApply(function ( val ) {
467 | this.saturation = Math.min(1, Math.max(this.saturation * (1 - val), 0));
468 | }),
469 |
470 | saturateByAmount: cloneOnApply(function ( val ) {
471 | this.saturation = Math.min(1, Math.max(this.saturation + val, 0));
472 | }),
473 |
474 | saturateByRatio: cloneOnApply(function ( val ) {
475 | this.saturation = Math.min(1, Math.max(this.saturation * (1 + val), 0));
476 | }),
477 |
478 | schemeFromDegrees: function ( degrees ) {
479 | var newColors = [];
480 | for (var i = 0, j = degrees.length; i < j; i++) {
481 | var col = this.clone();
482 | col.hue = (this.hue + degrees[i]) % 360;
483 | newColors.push(col);
484 | }
485 | return newColors;
486 | },
487 |
488 | complementaryScheme: function ( ) {
489 | return this.schemeFromDegrees([0,180]);
490 | },
491 |
492 | splitComplementaryScheme: function ( ) {
493 | return this.schemeFromDegrees([0,150,320]);
494 | },
495 |
496 | splitComplementaryCWScheme: function ( ) {
497 | return this.schemeFromDegrees([0,150,300]);
498 | },
499 |
500 | splitComplementaryCCWScheme: function ( ) {
501 | return this.schemeFromDegrees([0,60,210]);
502 | },
503 |
504 | triadicScheme: function ( ) {
505 | return this.schemeFromDegrees([0,120,240]);
506 | },
507 |
508 | clashScheme: function ( ) {
509 | return this.schemeFromDegrees([0,90,270]);
510 | },
511 |
512 | tetradicScheme: function ( ) {
513 | return this.schemeFromDegrees([0,90,180,270]);
514 | },
515 |
516 | fourToneCWScheme: function ( ) {
517 | return this.schemeFromDegrees([0,60,180,240]);
518 | },
519 |
520 | fourToneCCWScheme: function ( ) {
521 | return this.schemeFromDegrees([0,120,180,300]);
522 | },
523 |
524 | fiveToneAScheme: function ( ) {
525 | return this.schemeFromDegrees([0,115,155,205,245]);
526 | },
527 |
528 | fiveToneBScheme: function ( ) {
529 | return this.schemeFromDegrees([0,40,90,130,245]);
530 | },
531 |
532 | fiveToneCScheme: function ( ) {
533 | return this.schemeFromDegrees([0,50,90,205,320]);
534 | },
535 |
536 | fiveToneDScheme: function ( ) {
537 | return this.schemeFromDegrees([0,40,155,270,310]);
538 | },
539 |
540 | fiveToneEScheme: function ( ) {
541 | return this.schemeFromDegrees([0,115,230,270,320]);
542 | },
543 |
544 | sixToneCWScheme: function ( ) {
545 | return this.schemeFromDegrees([0,30,120,150,240,270]);
546 | },
547 |
548 | sixToneCCWScheme: function ( ) {
549 | return this.schemeFromDegrees([0,90,120,210,240,330]);
550 | },
551 |
552 | neutralScheme: function ( ) {
553 | return this.schemeFromDegrees([0,15,30,45,60,75]);
554 | },
555 |
556 | analogousScheme: function ( ) {
557 | return this.schemeFromDegrees([0,30,60,90,120,150]);
558 | },
559 |
560 | fromObject: function ( o ) {
561 | if (o.hasOwnProperty('hue') &&
562 | o.hasOwnProperty('saturation') &&
563 | o.hasOwnProperty('value')) {
564 | var hsv = factories.HSV();
565 |
566 | hsv.hue = o.hue;
567 | hsv.saturation = o.saturation;
568 | hsv.value = o.value;
569 |
570 | return hsv;
571 | }
572 | // nothing matchs, not an HSV object
573 | return null;
574 | },
575 |
576 | _normalise: function ( ) {
577 | this.hue %= 360;
578 | this.saturation = Math.min(Math.max(0, this.saturation), 1);
579 | this.value = Math.min(Math.max(0, this.value));
580 | },
581 |
582 | toRGB: function ( ) {
583 | this._normalise();
584 |
585 | var rgb = factories.RGB();
586 | var i;
587 | var f, p, q, t;
588 |
589 | if( this.saturation === 0 ) {
590 | // achromatic (grey)
591 | rgb.red = this.value;
592 | rgb.green = this.value;
593 | rgb.blue = this.value;
594 | return rgb;
595 | }
596 |
597 | var h = this.hue / 60; // sector 0 to 5
598 | i = Math.floor( h );
599 | f = h - i; // factorial part of h
600 | p = this.value * ( 1 - this.saturation );
601 | q = this.value * ( 1 - this.saturation * f );
602 | t = this.value * ( 1 - this.saturation * ( 1 - f ) );
603 |
604 | switch( i ) {
605 | case 0:
606 | rgb.red = this.value;
607 | rgb.green = t;
608 | rgb.blue = p;
609 | break;
610 | case 1:
611 | rgb.red = q;
612 | rgb.green = this.value;
613 | rgb.blue = p;
614 | break;
615 | case 2:
616 | rgb.red = p;
617 | rgb.green = this.value;
618 | rgb.blue = t;
619 | break;
620 | case 3:
621 | rgb.red = p;
622 | rgb.green = q;
623 | rgb.blue = this.value;
624 | break;
625 | case 4:
626 | rgb.red = t;
627 | rgb.green = p;
628 | rgb.blue = this.value;
629 | break;
630 | default: // case 5:
631 | rgb.red = this.value;
632 | rgb.green = p;
633 | rgb.blue = q;
634 | break;
635 | }
636 |
637 | return rgb;
638 | },
639 | toHSL: function() {
640 | this._normalise();
641 |
642 | var hsl = factories.HSL();
643 |
644 | hsl.hue = this.hue;
645 | var l = (2 - this.saturation) * this.value,
646 | s = this.saturation * this.value;
647 | if(l && 2 - l) {
648 | s /= (l <= 1) ? l : 2 - l;
649 | }
650 | l /= 2;
651 | hsl.saturation = s;
652 | hsl.lightness = l;
653 |
654 | return hsl;
655 | },
656 |
657 | toHSV: function ( ) {
658 | return this.clone();
659 | }
660 | });
661 |
662 | registerModel('HSL', {
663 | hue: 0,
664 | saturation: 0,
665 | lightness: 0,
666 |
667 | fromObject: function ( o ) {
668 | if ("string" == typeof o) {
669 | return this._fromCSS( o );
670 | }
671 | if (o.hasOwnProperty('hue') &&
672 | o.hasOwnProperty('saturation') &&
673 | o.hasOwnProperty('lightness')) {
674 | return this._fromHSL ( o );
675 | }
676 | // nothing matchs, not an RGB object
677 | },
678 |
679 | _fromCSS: function ( css ) {
680 | var colorGroups = trim( css ).match( hsl_hsla_regex );
681 |
682 | // if there is an "a" after "hsl", there must be a fourth parameter and the other way round
683 | if (!colorGroups || (!!colorGroups[1] + !!colorGroups[5] === 1)) {
684 | return null;
685 | }
686 |
687 | var hsl = factories.HSL();
688 | hsl.hue = (colorGroups[2] % 360 + 360) % 360;
689 | hsl.saturation = Math.max(0, Math.min(parseInt(colorGroups[3], 10) / 100, 1));
690 | hsl.lightness = Math.max(0, Math.min(parseInt(colorGroups[4], 10) / 100, 1));
691 |
692 | return hsl;
693 | },
694 |
695 | _fromHSL: function ( HSL ) {
696 | var newHSL = factories.HSL();
697 |
698 | newHSL.hue = HSL.hue;
699 | newHSL.saturation = HSL.saturation;
700 | newHSL.lightness = HSL.lightness;
701 |
702 | return newHSL;
703 | },
704 |
705 | _normalise: function ( ) {
706 | this.hue = (this.hue % 360 + 360) % 360;
707 | this.saturation = Math.min(Math.max(0, this.saturation), 1);
708 | this.lightness = Math.min(Math.max(0, this.lightness));
709 | },
710 |
711 | toHSL: function() {
712 | return this.clone();
713 | },
714 | toHSV: function() {
715 | this._normalise();
716 |
717 | var hsv = factories.HSV();
718 |
719 | // http://ariya.blogspot.com/2008/07/converting-between-hsl-and-hsv.html
720 | hsv.hue = this.hue; // H
721 | var l = 2 * this.lightness,
722 | s = this.saturation * ((l <= 1) ? l : 2 - l);
723 | hsv.value = (l + s) / 2; // V
724 | hsv.saturation = ((2 * s) / (l + s)) || 0; // S
725 |
726 | return hsv;
727 | },
728 | toRGB: function() {
729 | return this.toHSV().toRGB();
730 | }
731 | });
732 |
733 | // Package specific exports
734 |
735 | /* the Color function is a factory for new color objects.
736 | */
737 | function Color( o ) {
738 | return color.fromObject( o );
739 | }
740 | Color.isValid = function( str ) {
741 | var c = Color( str );
742 |
743 | var length = 0;
744 | for(key in c) {
745 | if(c.hasOwnProperty(key)) {
746 | length++;
747 | }
748 | }
749 |
750 | return length > 0;
751 | };
752 | net.brehaut.Color = Color;
753 | }).call(net.brehaut);
754 |
755 | /* Export to CommonJS
756 | */
757 | var module;
758 | if(module) {
759 | module.exports.Color = net.brehaut.Color;
760 | }
761 |
--------------------------------------------------------------------------------
/js/cssParser.js:
--------------------------------------------------------------------------------
1 | /* ***** BEGIN LICENSE BLOCK *****
2 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 | *
4 | * The contents of this file are subject to the Mozilla Public License Version
5 | * 1.1 (the "License"); you may not use this file except in compliance with
6 | * the License. You may obtain a copy of the License at
7 | * http://www.mozilla.org/MPL/
8 | *
9 | * Software distributed under the License is distributed on an "AS IS" basis,
10 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 | * for the specific language governing rights and limitations under the
12 | * License.
13 | *
14 | * The Original Code is mozilla.org code.
15 | *
16 | * The Initial Developer of the Original Code is
17 | * Netscape Communications Corporation.
18 | * Portions created by the Initial Developer are Copyright (C) 1998
19 | * the Initial Developer. All Rights Reserved.
20 | *
21 | * Contributor(s):
22 | * emk
23 | * Daniel Glazman
24 | * L. David Baron
25 | * Boris Zbarsky
26 | * Mats Palmgren
27 | * Christian Biesinger
28 | * Jeff Walden
29 | * Jonathon Jongsma , Collabora Ltd.
30 | * Siraj Razick , Collabora Ltd.
31 | * Daniel Glazman
32 | *
33 | * Alternatively, the contents of this file may be used under the terms of
34 | * either of the GNU General Public License Version 2 or later (the "GPL"),
35 | * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
36 | * in which case the provisions of the GPL or the LGPL are applicable instead
37 | * of those above. If you wish to allow use of your version of this file only
38 | * under the terms of either the GPL or the LGPL, and not to allow others to
39 | * use your version of this file under the terms of the MPL, indicate your
40 | * decision by deleting the provisions above and replace them with the notice
41 | * and other provisions required by the GPL or the LGPL. If you do not delete
42 | * the provisions above, a recipient may use your version of this file under
43 | * the terms of any one of the MPL, the GPL or the LGPL.
44 | *
45 | * ***** END LICENSE BLOCK ***** */
46 |
47 | const kCHARSET_RULE_MISSING_SEMICOLON = "Missing semicolon at the end of @charset rule";
48 | const kCHARSET_RULE_CHARSET_IS_STRING = "The charset in the @charset rule should be a string";
49 | const kCHARSET_RULE_MISSING_WS = "Missing mandatory whitespace after @charset";
50 | const kIMPORT_RULE_MISSING_URL = "Missing URL in @import rule";
51 | const kURL_EOF = "Unexpected end of stylesheet";
52 | const kURL_WS_INSIDE = "Multiple tokens inside a url() notation";
53 | const kVARIABLES_RULE_POSITION = "@variables rule invalid at this position in the stylesheet";
54 | const kIMPORT_RULE_POSITION = "@import rule invalid at this position in the stylesheet";
55 | const kNAMESPACE_RULE_POSITION = "@namespace rule invalid at this position in the stylesheet";
56 | const kCHARSET_RULE_CHARSET_SOF = "@charset rule invalid at this position in the stylesheet";
57 | const kUNKNOWN_AT_RULE = "Unknow @-rule";
58 |
59 | /* FROM http://peter.sh/data/vendor-prefixed-css.php?js=1 */
60 |
61 | const kENGINES = [
62 | "webkit",
63 | "presto",
64 | "trident",
65 | "generic"
66 | ];
67 |
68 | const kCSS_VENDOR_VALUES = {
69 | "-moz-box": {"webkit": "-webkit-box", "presto": "", "trident": "", "generic": "box" },
70 | "-moz-inline-box": {"webkit": "-webkit-inline-box", "presto": "", "trident": "", "generic": "inline-box" },
71 | "-moz-initial": {"webkit": "", "presto": "", "trident": "", "generic": "initial" },
72 | "-moz-linear-gradient": {"webkit20110101": FilterLinearGradientForOutput,
73 | "webkit": FilterLinearGradientForOutput,
74 | "presto": "",
75 | "trident": "",
76 | "generic": FilterLinearGradientForOutput },
77 | "-moz-radial-gradient": {"webkit20110101": FilterRadialGradientForOutput,
78 | "webkit": FilterRadialGradientForOutput,
79 | "presto": "",
80 | "trident": "",
81 | "generic": FilterRadialGradientForOutput },
82 | "-moz-repeating-linear-gradient": {"webkit20110101": "",
83 | "webkit": FilterRepeatingGradientForOutput,
84 | "presto": "",
85 | "trident": "",
86 | "generic": FilterRepeatingGradientForOutput },
87 | "-moz-repeating-radial-gradient": {"webkit20110101": "",
88 | "webkit": FilterRepeatingGradientForOutput,
89 | "presto": "",
90 | "trident": "",
91 | "generic": FilterRepeatingGradientForOutput }
92 | };
93 |
94 | const kCSS_VENDOR_PREFIXES = {"lastUpdate":1304175007,"properties":[{"gecko":"","webkit":"","presto":"","trident":"-ms-accelerator","status":"P"},
95 | {"gecko":"","webkit":"","presto":"-wap-accesskey","trident":"","status":""},
96 | {"gecko":"-moz-animation","webkit":"-webkit-animation","presto":"","trident":"","status":"WD"},
97 | {"gecko":"-moz-animation-delay","webkit":"-webkit-animation-delay","presto":"","trident":"","status":"WD"},
98 | {"gecko":"-moz-animation-direction","webkit":"-webkit-animation-direction","presto":"","trident":"","status":"WD"},
99 | {"gecko":"-moz-animation-duration","webkit":"-webkit-animation-duration","presto":"","trident":"","status":"WD"},
100 | {"gecko":"-moz-animation-fill-mode","webkit":"-webkit-animation-fill-mode","presto":"","trident":"","status":"ED"},
101 | {"gecko":"-moz-animation-iteration-count","webkit":"-webkit-animation-iteration-count","presto":"","trident":"","status":"WD"},
102 | {"gecko":"-moz-animation-name","webkit":"-webkit-animation-name","presto":"","trident":"","status":"WD"},
103 | {"gecko":"-moz-animation-play-state","webkit":"-webkit-animation-play-state","presto":"","trident":"","status":"WD"},
104 | {"gecko":"-moz-animation-timing-function","webkit":"-webkit-animation-timing-function","presto":"","trident":"","status":"WD"},
105 | {"gecko":"-moz-appearance","webkit":"-webkit-appearance","presto":"","trident":"","status":"CR"},
106 | {"gecko":"","webkit":"-webkit-backface-visibility","presto":"","trident":"","status":"WD"},
107 | {"gecko":"background-clip","webkit":"-webkit-background-clip","presto":"background-clip","trident":"background-clip","status":"WD"},
108 | {"gecko":"","webkit":"-webkit-background-composite","presto":"","trident":"","status":""},
109 | {"gecko":"-moz-background-inline-policy","webkit":"","presto":"","trident":"","status":"P"},
110 | {"gecko":"background-origin","webkit":"-webkit-background-origin","presto":"background-origin","trident":"background-origin","status":"WD"},
111 | {"gecko":"","webkit":"background-position-x","presto":"","trident":"-ms-background-position-x","status":""},
112 | {"gecko":"","webkit":"background-position-y","presto":"","trident":"-ms-background-position-y","status":""},
113 | {"gecko":"background-size","webkit":"-webkit-background-size","presto":"background-size","trident":"background-size","status":"WD"},
114 | {"gecko":"","webkit":"","presto":"","trident":"-ms-behavior","status":""},
115 | {"gecko":"-moz-binding","webkit":"","presto":"","trident":"","status":"P"},
116 | {"gecko":"","webkit":"","presto":"","trident":"-ms-block-progression","status":""},
117 | {"gecko":"","webkit":"-webkit-border-after","presto":"","trident":"","status":"ED"},
118 | {"gecko":"","webkit":"-webkit-border-after-color","presto":"","trident":"","status":"ED"},
119 | {"gecko":"","webkit":"-webkit-border-after-style","presto":"","trident":"","status":"ED"},
120 | {"gecko":"","webkit":"-webkit-border-after-width","presto":"","trident":"","status":"ED"},
121 | {"gecko":"","webkit":"-webkit-border-before","presto":"","trident":"","status":"ED"},
122 | {"gecko":"","webkit":"-webkit-border-before-color","presto":"","trident":"","status":"ED"},
123 | {"gecko":"","webkit":"-webkit-border-before-style","presto":"","trident":"","status":"ED"},
124 | {"gecko":"","webkit":"-webkit-border-before-width","presto":"","trident":"","status":"ED"},
125 | {"gecko":"-moz-border-bottom-colors","webkit":"","presto":"","trident":"","status":"P"},
126 | {"gecko":"border-bottom-left-radius","webkit":"-webkit-border-bottom-left-radius","presto":"border-bottom-left-radius","trident":"border-bottom-left-radius","status":"WD"},
127 | {"gecko":"","webkit":"-webkit-border-bottom-left-radius = border-bottom-left-radius","presto":"","trident":"","status":""},
128 | {"gecko":"border-bottom-right-radius","webkit":"-webkit-border-bottom-right-radius","presto":"border-bottom-right-radius","trident":"border-bottom-right-radius","status":"WD"},
129 | {"gecko":"","webkit":"-webkit-border-bottom-right-radius = border-bottom-right-radius","presto":"","trident":"","status":""},
130 | {"gecko":"-moz-border-end","webkit":"-webkit-border-end","presto":"","trident":"","status":"ED"},
131 | {"gecko":"-moz-border-end-color","webkit":"-webkit-border-end-color","presto":"","trident":"","status":"ED"},
132 | {"gecko":"-moz-border-end-style","webkit":"-webkit-border-end-style","presto":"","trident":"","status":"ED"},
133 | {"gecko":"-moz-border-end-width","webkit":"-webkit-border-end-width","presto":"","trident":"","status":"ED"},
134 | {"gecko":"","webkit":"-webkit-border-fit","presto":"","trident":"","status":""},
135 | {"gecko":"","webkit":"-webkit-border-horizontal-spacing","presto":"","trident":"","status":""},
136 | {"gecko":"-moz-border-image","webkit":"-webkit-border-image","presto":"-o-border-image","trident":"","status":"WD"},
137 | {"gecko":"-moz-border-left-colors","webkit":"","presto":"","trident":"","status":"P"},
138 | {"gecko":"border-radius","webkit":"-webkit-border-radius","presto":"border-radius","trident":"border-radius","status":"WD"},
139 | {"gecko":"-moz-border-right-colors","webkit":"","presto":"","trident":"","status":"P"},
140 | {"gecko":"-moz-border-start","webkit":"-webkit-border-start","presto":"","trident":"","status":"ED"},
141 | {"gecko":"-moz-border-start-color","webkit":"-webkit-border-start-color","presto":"","trident":"","status":"ED"},
142 | {"gecko":"-moz-border-start-style","webkit":"-webkit-border-start-style","presto":"","trident":"","status":"ED"},
143 | {"gecko":"-moz-border-start-width","webkit":"-webkit-border-start-width","presto":"","trident":"","status":"ED"},
144 | {"gecko":"-moz-border-top-colors","webkit":"","presto":"","trident":"","status":"P"},
145 | {"gecko":"border-top-left-radius","webkit":"-webkit-border-top-left-radius","presto":"border-top-left-radius","trident":"border-top-left-radius","status":"WD"},
146 | {"gecko":"","webkit":"-webkit-border-top-left-radius = border-top-left-radius","presto":"","trident":"","status":""},
147 | {"gecko":"border-top-right-radius","webkit":"-webkit-border-top-right-radius","presto":"border-top-right-radius","trident":"border-top-right-radius","status":"WD"},
148 | {"gecko":"","webkit":"-webkit-border-top-right-radius = border-top-right-radius","presto":"","trident":"","status":""},
149 | {"gecko":"","webkit":"-webkit-border-vertical-spacing","presto":"","trident":"","status":""},
150 | {"gecko":"-moz-box-align","webkit":"-webkit-box-align","presto":"","trident":"-ms-box-align","status":"WD"},
151 | {"gecko":"-moz-box-direction","webkit":"-webkit-box-direction","presto":"","trident":"-ms-box-direction","status":"WD"},
152 | {"gecko":"-moz-box-flex","webkit":"-webkit-box-flex","presto":"","trident":"-ms-box-flex","status":"WD"},
153 | {"gecko":"","webkit":"-webkit-box-flex-group","presto":"","trident":"","status":"WD"},
154 | {"gecko":"","webkit":"","presto":"","trident":"-ms-box-line-progression","status":""},
155 | {"gecko":"","webkit":"-webkit-box-lines","presto":"","trident":"-ms-box-lines","status":"WD"},
156 | {"gecko":"-moz-box-ordinal-group","webkit":"-webkit-box-ordinal-group","presto":"","trident":"-ms-box-ordinal-group","status":"WD"},
157 | {"gecko":"-moz-box-orient","webkit":"-webkit-box-orient","presto":"","trident":"-ms-box-orient","status":"WD"},
158 | {"gecko":"-moz-box-pack","webkit":"-webkit-box-pack","presto":"","trident":"-ms-box-pack","status":"WD"},
159 | {"gecko":"","webkit":"-webkit-box-reflect","presto":"","trident":"","status":""},
160 | {"gecko":"box-shadow","webkit":"-webkit-box-shadow","presto":"box-shadow","trident":"box-shadow","status":"WD"},
161 | {"gecko":"-moz-box-sizing","webkit":"box-sizing","presto":"box-sizing","trident":"","status":"CR"},
162 | {"gecko":"","webkit":"-webkit-box-sizing = box-sizing","presto":"","trident":"","status":""},
163 | {"gecko":"","webkit":"-epub-caption-side = caption-side","presto":"","trident":"","status":""},
164 | {"gecko":"","webkit":"-webkit-color-correction","presto":"","trident":"","status":""},
165 | {"gecko":"","webkit":"-webkit-column-break-after","presto":"","trident":"","status":""},
166 | {"gecko":"","webkit":"-webkit-column-break-before","presto":"","trident":"","status":""},
167 | {"gecko":"","webkit":"-webkit-column-break-inside","presto":"","trident":"","status":""},
168 | {"gecko":"-moz-column-count","webkit":"-webkit-column-count","presto":"column-count","trident":"column-count","status":"CR"},
169 | {"gecko":"-moz-column-gap","webkit":"-webkit-column-gap","presto":"column-gap","trident":"column-gap","status":"CR"},
170 | {"gecko":"-moz-column-rule","webkit":"-webkit-column-rule","presto":"column-rule","trident":"column-rule","status":"CR"},
171 | {"gecko":"-moz-column-rule-color","webkit":"-webkit-column-rule-color","presto":"column-rule-color","trident":"column-rule-color","status":"CR"},
172 | {"gecko":"-moz-column-rule-style","webkit":"-webkit-column-rule-style","presto":"column-rule-style","trident":"column-rule-style","status":"CR"},
173 | {"gecko":"-moz-column-rule-width","webkit":"-webkit-column-rule-width","presto":"column-rule-width","trident":"column-rule-width","status":"CR"},
174 | {"gecko":"","webkit":"-webkit-column-span","presto":"column-span","trident":"column-span","status":"CR"},
175 | {"gecko":"-moz-column-width","webkit":"-webkit-column-width","presto":"column-width","trident":"column-width","status":"CR"},
176 | {"gecko":"","webkit":"-webkit-columns","presto":"columns","trident":"columns","status":"CR"},
177 | {"gecko":"","webkit":"-webkit-dashboard-region","presto":"-apple-dashboard-region","trident":"","status":""},
178 | {"gecko":"filter","webkit":"","presto":"filter","trident":"-ms-filter","status":""},
179 | {"gecko":"-moz-float-edge","webkit":"","presto":"","trident":"","status":"P"},
180 | {"gecko":"","webkit":"","presto":"-o-focus-opacity","trident":"","status":""},
181 | {"gecko":"-moz-font-feature-settings","webkit":"","presto":"","trident":"","status":""},
182 | {"gecko":"-moz-font-language-override","webkit":"","presto":"","trident":"","status":""},
183 | {"gecko":"","webkit":"-webkit-font-size-delta","presto":"","trident":"","status":""},
184 | {"gecko":"","webkit":"-webkit-font-smoothing","presto":"","trident":"","status":""},
185 | {"gecko":"-moz-force-broken-image-icon","webkit":"","presto":"","trident":"","status":""},
186 | {"gecko":"","webkit":"","presto":"","trident":"-ms-grid-column","status":"WD"},
187 | {"gecko":"","webkit":"","presto":"","trident":"-ms-grid-column-align","status":"WD"},
188 | {"gecko":"","webkit":"","presto":"","trident":"-ms-grid-column-span","status":"WD"},
189 | {"gecko":"","webkit":"","presto":"","trident":"-ms-grid-columns","status":"WD"},
190 | {"gecko":"","webkit":"","presto":"","trident":"-ms-grid-layer","status":"WD"},
191 | {"gecko":"","webkit":"","presto":"","trident":"-ms-grid-row","status":"WD"},
192 | {"gecko":"","webkit":"","presto":"","trident":"-ms-grid-row-align","status":"WD"},
193 | {"gecko":"","webkit":"","presto":"","trident":"-ms-grid-row-span","status":"WD"},
194 | {"gecko":"","webkit":"","presto":"","trident":"-ms-grid-rows","status":"WD"},
195 | {"gecko":"","webkit":"-webkit-highlight","presto":"","trident":"","status":""},
196 | {"gecko":"","webkit":"-webkit-hyphenate-character","presto":"","trident":"","status":"WD"},
197 | {"gecko":"","webkit":"-webkit-hyphenate-limit-after","presto":"","trident":"","status":""},
198 | {"gecko":"","webkit":"-webkit-hyphenate-limit-before","presto":"","trident":"","status":""},
199 | {"gecko":"","webkit":"-webkit-hyphens","presto":"","trident":"","status":"WD"},
200 | {"gecko":"","webkit":"-epub-hyphens = -webkit-hyphens","presto":"","trident":"","status":""},
201 | {"gecko":"-moz-image-region","webkit":"","presto":"","trident":"","status":"P"},
202 | {"gecko":"ime-mode","webkit":"","presto":"","trident":"-ms-ime-mode","status":""},
203 | {"gecko":"","webkit":"","presto":"-wap-input-format","trident":"","status":""},
204 | {"gecko":"","webkit":"","presto":"-wap-input-required","trident":"","status":""},
205 | {"gecko":"","webkit":"","presto":"","trident":"-ms-interpolation-mode","status":""},
206 | {"gecko":"","webkit":"","presto":"-xv-interpret-as","trident":"","status":""},
207 | {"gecko":"","webkit":"","presto":"","trident":"-ms-layout-flow","status":""},
208 | {"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid","status":""},
209 | {"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid-char","status":""},
210 | {"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid-line","status":""},
211 | {"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid-mode","status":""},
212 | {"gecko":"","webkit":"","presto":"","trident":"-ms-layout-grid-type","status":""},
213 | {"gecko":"","webkit":"-webkit-line-box-contain","presto":"","trident":"","status":""},
214 | {"gecko":"","webkit":"-webkit-line-break","presto":"","trident":"-ms-line-break","status":""},
215 | {"gecko":"","webkit":"-webkit-line-clamp","presto":"","trident":"","status":""},
216 | {"gecko":"","webkit":"","presto":"","trident":"-ms-line-grid-mode","status":""},
217 | {"gecko":"","webkit":"","presto":"-o-link","trident":"","status":""},
218 | {"gecko":"","webkit":"","presto":"-o-link-source","trident":"","status":""},
219 | {"gecko":"","webkit":"-webkit-locale","presto":"","trident":"","status":""},
220 | {"gecko":"","webkit":"-webkit-logical-height","presto":"","trident":"","status":"ED"},
221 | {"gecko":"","webkit":"-webkit-logical-width","presto":"","trident":"","status":"ED"},
222 | {"gecko":"","webkit":"-webkit-margin-after","presto":"","trident":"","status":"ED"},
223 | {"gecko":"","webkit":"-webkit-margin-after-collapse","presto":"","trident":"","status":""},
224 | {"gecko":"","webkit":"-webkit-margin-before","presto":"","trident":"","status":"ED"},
225 | {"gecko":"","webkit":"-webkit-margin-before-collapse","presto":"","trident":"","status":""},
226 | {"gecko":"","webkit":"-webkit-margin-bottom-collapse","presto":"","trident":"","status":""},
227 | {"gecko":"","webkit":"-webkit-margin-collapse","presto":"","trident":"","status":""},
228 | {"gecko":"-moz-margin-end","webkit":"-webkit-margin-end","presto":"","trident":"","status":"ED"},
229 | {"gecko":"-moz-margin-start","webkit":"-webkit-margin-start","presto":"","trident":"","status":"ED"},
230 | {"gecko":"","webkit":"-webkit-margin-top-collapse","presto":"","trident":"","status":""},
231 | {"gecko":"","webkit":"-webkit-marquee","presto":"","trident":"","status":""},
232 | {"gecko":"","webkit":"","presto":"-wap-marquee-dir","trident":"","status":""},
233 | {"gecko":"","webkit":"-webkit-marquee-direction","presto":"","trident":"","status":"WD"},
234 | {"gecko":"","webkit":"-webkit-marquee-increment","presto":"","trident":"","status":""},
235 | {"gecko":"","webkit":"","presto":"-wap-marquee-loop","trident":"","status":"WD"},
236 | {"gecko":"","webkit":"-webkit-marquee-repetition","presto":"","trident":"","status":""},
237 | {"gecko":"","webkit":"-webkit-marquee-speed","presto":"-wap-marquee-speed","trident":"","status":"WD"},
238 | {"gecko":"","webkit":"-webkit-marquee-style","presto":"-wap-marquee-style","trident":"","status":"WD"},
239 | {"gecko":"mask","webkit":"-webkit-mask","presto":"mask","trident":"","status":""},
240 | {"gecko":"","webkit":"-webkit-mask-attachment","presto":"","trident":"","status":""},
241 | {"gecko":"","webkit":"-webkit-mask-box-image","presto":"","trident":"","status":""},
242 | {"gecko":"","webkit":"-webkit-mask-clip","presto":"","trident":"","status":""},
243 | {"gecko":"","webkit":"-webkit-mask-composite","presto":"","trident":"","status":""},
244 | {"gecko":"","webkit":"-webkit-mask-image","presto":"","trident":"","status":""},
245 | {"gecko":"","webkit":"-webkit-mask-origin","presto":"","trident":"","status":""},
246 | {"gecko":"","webkit":"-webkit-mask-position","presto":"","trident":"","status":""},
247 | {"gecko":"","webkit":"-webkit-mask-position-x","presto":"","trident":"","status":""},
248 | {"gecko":"","webkit":"-webkit-mask-position-y","presto":"","trident":"","status":""},
249 | {"gecko":"","webkit":"-webkit-mask-repeat","presto":"","trident":"","status":""},
250 | {"gecko":"","webkit":"-webkit-mask-repeat-x","presto":"","trident":"","status":""},
251 | {"gecko":"","webkit":"-webkit-mask-repeat-y","presto":"","trident":"","status":""},
252 | {"gecko":"","webkit":"-webkit-mask-size","presto":"","trident":"","status":""},
253 | {"gecko":"","webkit":"-webkit-match-nearest-mail-blockquote-color","presto":"","trident":"","status":""},
254 | {"gecko":"","webkit":"-webkit-max-logical-height","presto":"","trident":"","status":""},
255 | {"gecko":"","webkit":"-webkit-max-logical-width","presto":"","trident":"","status":"ED"},
256 | {"gecko":"","webkit":"-webkit-min-logical-height","presto":"","trident":"","status":"ED"},
257 | {"gecko":"","webkit":"-webkit-min-logical-width","presto":"","trident":"","status":"ED"},
258 | {"gecko":"","webkit":"","presto":"-o-mini-fold","trident":"","status":""},
259 | {"gecko":"","webkit":"-webkit-nbsp-mode","presto":"","trident":"","status":"P"},
260 | {"gecko":"","webkit":"","presto":"-o-object-fit","trident":"","status":"ED"},
261 | {"gecko":"","webkit":"","presto":"-o-object-position","trident":"","status":"ED"},
262 | {"gecko":"opacity","webkit":"-webkit-opacity","presto":"opacity","trident":"opacity","status":"WD"},
263 | {"gecko":"","webkit":"-webkit-opacity = opacity","presto":"","trident":"","status":""},
264 | {"gecko":"-moz-outline-radius","webkit":"","presto":"","trident":"","status":"P"},
265 | {"gecko":"-moz-outline-radius-bottomleft","webkit":"","presto":"","trident":"","status":"P"},
266 | {"gecko":"-moz-outline-radius-bottomright","webkit":"","presto":"","trident":"","status":"P"},
267 | {"gecko":"-moz-outline-radius-topleft","webkit":"","presto":"","trident":"","status":"P"},
268 | {"gecko":"-moz-outline-radius-topright","webkit":"","presto":"","trident":"","status":"P"},
269 | {"gecko":"overflow-x","webkit":"overflow-x","presto":"overflow-x","trident":"-ms-overflow-x","status":"WD"},
270 | {"gecko":"overflow-y","webkit":"overflow-y","presto":"overflow-y","trident":"-ms-overflow-y","status":"WD"},
271 | {"gecko":"","webkit":"-webkit-padding-after","presto":"","trident":"","status":"ED"},
272 | {"gecko":"","webkit":"-webkit-padding-before","presto":"","trident":"","status":"ED"},
273 | {"gecko":"-moz-padding-end","webkit":"-webkit-padding-end","presto":"","trident":"","status":"ED"},
274 | {"gecko":"-moz-padding-start","webkit":"-webkit-padding-start","presto":"","trident":"","status":"ED"},
275 | {"gecko":"","webkit":"-webkit-perspective","presto":"","trident":"","status":"WD"},
276 | {"gecko":"","webkit":"-webkit-perspective-origin","presto":"","trident":"","status":"WD"},
277 | {"gecko":"","webkit":"-webkit-perspective-origin-x","presto":"","trident":"","status":""},
278 | {"gecko":"","webkit":"-webkit-perspective-origin-y","presto":"","trident":"","status":""},
279 | {"gecko":"","webkit":"","presto":"-xv-phonemes","trident":"","status":""},
280 | {"gecko":"","webkit":"-webkit-rtl-ordering","presto":"","trident":"","status":"P"},
281 | {"gecko":"-moz-script-level","webkit":"","presto":"","trident":"","status":""},
282 | {"gecko":"-moz-script-min-size","webkit":"","presto":"","trident":"","status":""},
283 | {"gecko":"-moz-script-size-multiplier","webkit":"","presto":"","trident":"","status":""},
284 | {"gecko":"","webkit":"","presto":"scrollbar-3dlight-color","trident":"-ms-scrollbar-3dlight-color","status":"P"},
285 | {"gecko":"","webkit":"","presto":"scrollbar-arrow-color","trident":"-ms-scrollbar-arrow-color","status":"P"},
286 | {"gecko":"","webkit":"","presto":"scrollbar-base-color","trident":"-ms-scrollbar-base-color","status":"P"},
287 | {"gecko":"","webkit":"","presto":"scrollbar-darkshadow-color","trident":"-ms-scrollbar-darkshadow-color","status":"P"},
288 | {"gecko":"","webkit":"","presto":"scrollbar-face-color","trident":"-ms-scrollbar-face-color","status":"P"},
289 | {"gecko":"","webkit":"","presto":"scrollbar-highlight-color","trident":"-ms-scrollbar-highlight-color","status":"P"},
290 | {"gecko":"","webkit":"","presto":"scrollbar-shadow-color","trident":"-ms-scrollbar-shadow-color","status":"P"},
291 | {"gecko":"","webkit":"","presto":"scrollbar-track-color","trident":"-ms-scrollbar-track-color","status":"P"},
292 | {"gecko":"-moz-stack-sizing","webkit":"","presto":"","trident":"","status":"P"},
293 | {"gecko":"","webkit":"-webkit-svg-shadow","presto":"","trident":"","status":""},
294 | {"gecko":"-moz-tab-size","webkit":"","presto":"-o-tab-size","trident":"","status":""},
295 | {"gecko":"","webkit":"","presto":"-o-table-baseline","trident":"","status":""},
296 | {"gecko":"","webkit":"-webkit-tap-highlight-color","presto":"","trident":"","status":"P"},
297 | {"gecko":"","webkit":"","presto":"","trident":"-ms-text-align-last","status":"WD"},
298 | {"gecko":"","webkit":"","presto":"","trident":"-ms-text-autospace","status":"WD"},
299 | {"gecko":"-moz-text-blink","webkit":"","presto":"","trident":"","status":""},
300 | {"gecko":"","webkit":"-webkit-text-combine","presto":"","trident":"","status":""},
301 | {"gecko":"","webkit":"-epub-text-combine = -webkit-text-combine","presto":"","trident":"","status":""},
302 | {"gecko":"-moz-text-decoration-color","webkit":"","presto":"","trident":"","status":""},
303 | {"gecko":"-moz-text-decoration-line","webkit":"","presto":"","trident":"","status":""},
304 | {"gecko":"-moz-text-decoration-style","webkit":"","presto":"","trident":"","status":""},
305 | {"gecko":"","webkit":"-webkit-text-decorations-in-effect","presto":"","trident":"","status":""},
306 | {"gecko":"","webkit":"-webkit-text-emphasis","presto":"","trident":"","status":""},
307 | {"gecko":"","webkit":"-epub-text-emphasis = -webkit-text-emphasis","presto":"","trident":"","status":""},
308 | {"gecko":"","webkit":"-webkit-text-emphasis-color","presto":"","trident":"","status":""},
309 | {"gecko":"","webkit":"-epub-text-emphasis-color = -webkit-text-emphasis-color","presto":"","trident":"","status":""},
310 | {"gecko":"","webkit":"-webkit-text-emphasis-position","presto":"","trident":"","status":""},
311 | {"gecko":"","webkit":"-webkit-text-emphasis-style","presto":"","trident":"","status":""},
312 | {"gecko":"","webkit":"-epub-text-emphasis-style = -webkit-text-emphasis-style","presto":"","trident":"","status":""},
313 | {"gecko":"","webkit":"-webkit-text-fill-color","presto":"","trident":"","status":"P"},
314 | {"gecko":"","webkit":"","presto":"","trident":"-ms-text-justify","status":"WD"},
315 | {"gecko":"","webkit":"","presto":"","trident":"-ms-text-kashida-space","status":"P"},
316 | {"gecko":"","webkit":"-webkit-text-orientation","presto":"","trident":"","status":""},
317 | {"gecko":"","webkit":"-epub-text-orientation = -webkit-text-orientation","presto":"","trident":"","status":""},
318 | {"gecko":"","webkit":"text-overflow","presto":"text-overflow","trident":"-ms-text-overflow","status":"WD"},
319 | {"gecko":"","webkit":"-webkit-text-security","presto":"","trident":"","status":"P"},
320 | {"gecko":"","webkit":"-webkit-text-size-adjust","presto":"","trident":"-ms-text-size-adjust","status":""},
321 | {"gecko":"","webkit":"-webkit-text-stroke","presto":"","trident":"","status":"P"},
322 | {"gecko":"","webkit":"-webkit-text-stroke-color","presto":"","trident":"","status":"P"},
323 | {"gecko":"","webkit":"-webkit-text-stroke-width","presto":"","trident":"","status":"P"},
324 | {"gecko":"","webkit":"-epub-text-transform = text-transform","presto":"","trident":"","status":""},
325 | {"gecko":"","webkit":"","presto":"","trident":"-ms-text-underline-position","status":"P"},
326 | {"gecko":"","webkit":"-webkit-touch-callout","presto":"","trident":"","status":"P"},
327 | {"gecko":"-moz-transform","webkit":"-webkit-transform","presto":"-o-transform","trident":"-ms-transform","status":"WD"},
328 | {"gecko":"-moz-transform-origin","webkit":"-webkit-transform-origin","presto":"-o-transform-origin","trident":"-ms-transform-origin","status":"WD"},
329 | {"gecko":"","webkit":"-webkit-transform-origin-x","presto":"","trident":"","status":"P"},
330 | {"gecko":"","webkit":"-webkit-transform-origin-y","presto":"","trident":"","status":"P"},
331 | {"gecko":"","webkit":"-webkit-transform-origin-z","presto":"","trident":"","status":"P"},
332 | {"gecko":"","webkit":"-webkit-transform-style","presto":"","trident":"","status":"WD"},
333 | {"gecko":"-moz-transition","webkit":"-webkit-transition","presto":"-o-transition","trident":"","status":"WD"},
334 | {"gecko":"-moz-transition-delay","webkit":"-webkit-transition-delay","presto":"-o-transition-delay","trident":"","status":"WD"},
335 | {"gecko":"-moz-transition-duration","webkit":"-webkit-transition-duration","presto":"-o-transition-duration","trident":"","status":"WD"},
336 | {"gecko":"-moz-transition-property","webkit":"-webkit-transition-property","presto":"-o-transition-property","trident":"","status":"WD"},
337 | {"gecko":"-moz-transition-timing-function","webkit":"-webkit-transition-timing-function","presto":"-o-transition-timing-function","trident":"","status":"WD"},
338 | {"gecko":"","webkit":"-webkit-user-drag","presto":"","trident":"","status":"P"},
339 | {"gecko":"-moz-user-focus","webkit":"","presto":"","trident":"","status":"P"},
340 | {"gecko":"-moz-user-input","webkit":"","presto":"","trident":"","status":"P"},
341 | {"gecko":"-moz-user-modify","webkit":"-webkit-user-modify","presto":"","trident":"","status":"P"},
342 | {"gecko":"-moz-user-select","webkit":"-webkit-user-select","presto":"","trident":"","status":"P"},
343 | {"gecko":"","webkit":"","presto":"-xv-voice-balance","trident":"","status":""},
344 | {"gecko":"","webkit":"","presto":"-xv-voice-duration","trident":"","status":""},
345 | {"gecko":"","webkit":"","presto":"-xv-voice-pitch","trident":"","status":""},
346 | {"gecko":"","webkit":"","presto":"-xv-voice-pitch-range","trident":"","status":""},
347 | {"gecko":"","webkit":"","presto":"-xv-voice-rate","trident":"","status":""},
348 | {"gecko":"","webkit":"","presto":"-xv-voice-stress","trident":"","status":""},
349 | {"gecko":"","webkit":"","presto":"-xv-voice-volume","trident":"","status":""},
350 | {"gecko":"-moz-window-shadow","webkit":"","presto":"","trident":"","status":"P"},
351 | {"gecko":"","webkit":"word-break","presto":"","trident":"-ms-word-break","status":"WD"},
352 | {"gecko":"","webkit":"-epub-word-break = word-break","presto":"","trident":"","status":""},
353 | {"gecko":"word-wrap","webkit":"word-wrap","presto":"word-wrap","trident":"-ms-word-wrap","status":"WD"},
354 | {"gecko":"","webkit":"-webkit-writing-mode","presto":"writing-mode","trident":"-ms-writing-mode","status":"ED"},
355 | {"gecko":"","webkit":"-epub-writing-mode = -webkit-writing-mode","presto":"","trident":"","status":""},
356 | {"gecko":"","webkit":"zoom","presto":"","trident":"-ms-zoom","status":""}]};
357 |
358 | const kCSS_PREFIXED_VALUE = [
359 | {"gecko": "-moz-box", "webkit": "-moz-box", "presto": "", "trident": "", "generic": "box"}
360 | ];
361 |
362 | var CssInspector = {
363 |
364 | mVENDOR_PREFIXES: null,
365 |
366 | kEXPORTS_FOR_GECKO: true,
367 | kEXPORTS_FOR_WEBKIT: true,
368 | kEXPORTS_FOR_PRESTO: true,
369 | kEXPORTS_FOR_TRIDENT: true,
370 |
371 | cleanPrefixes: function()
372 | {
373 | this.mVENDOR_PREFIXES = null;
374 | },
375 |
376 | prefixesForProperty: function(aProperty)
377 | {
378 | if (!this.mVENDOR_PREFIXES) {
379 |
380 | this.mVENDOR_PREFIXES = {};
381 | for (var i = 0; i < kCSS_VENDOR_PREFIXES.properties.length; i++) {
382 | var p = kCSS_VENDOR_PREFIXES.properties[i];
383 | if (p.gecko && (p.webkit || p.presto || p.trident)) {
384 | var o = {};
385 | if (this.kEXPORTS_FOR_GECKO) o[p.gecko] = true;
386 | if (this.kEXPORTS_FOR_WEBKIT && p.webkit) o[p.webkit] = true;
387 | if (this.kEXPORTS_FOR_PRESTO && p.presto) o[p.presto] = true;
388 | if (this.kEXPORTS_FOR_TRIDENT && p.trident) o[p.trident] = true;
389 | this.mVENDOR_PREFIXES[p.gecko] = [];
390 | for (var j in o)
391 | this.mVENDOR_PREFIXES[p.gecko].push(j)
392 | }
393 | }
394 | }
395 | if (aProperty in this.mVENDOR_PREFIXES)
396 | return this.mVENDOR_PREFIXES[aProperty].sort();
397 | return null;
398 | },
399 |
400 | parseColorStop: function(parser, token)
401 | {
402 | var color = parser.parseColor(token);
403 | var position = "";
404 | if (!color)
405 | return null;
406 | token = parser.getToken(true, true);
407 | if (token.isPercentage() ||
408 | token.isDimensionOfUnit("cm") ||
409 | token.isDimensionOfUnit("mm") ||
410 | token.isDimensionOfUnit("in") ||
411 | token.isDimensionOfUnit("pc") ||
412 | token.isDimensionOfUnit("px") ||
413 | token.isDimensionOfUnit("em") ||
414 | token.isDimensionOfUnit("ex") ||
415 | token.isDimensionOfUnit("pt")) {
416 | position = token.value;
417 | token = parser.getToken(true, true);
418 | }
419 | return { color: color, position: position }
420 | },
421 |
422 | parseGradient: function (parser, token)
423 | {
424 | var isRadial = false;
425 | var gradient = { isRepeating: false };
426 | if (token.isNotNull()) {
427 | if (token.isFunction("-moz-linear-gradient(") ||
428 | token.isFunction("-moz-radial-gradient(") ||
429 | token.isFunction("-moz-repeating-linear-gradient(") ||
430 | token.isFunction("-moz-repeating-radial-gradient(")) {
431 | if (token.isFunction("-moz-radial-gradient(") ||
432 | token.isFunction("-moz-repeating-radial-gradient(")) {
433 | gradient.isRadial = true;
434 | }
435 | if (token.isFunction("-moz-repeating-linear-gradient(") ||
436 | token.isFunction("-moz-repeating-radial-gradient(")) {
437 | gradient.isRepeating = true;
438 | }
439 |
440 |
441 | token = parser.getToken(true, true);
442 | var haveGradientLine = false;
443 | var foundHorizPosition = false;
444 | var haveAngle = false;
445 |
446 | if (token.isAngle()) {
447 | gradient.angle = token.value;
448 | haveGradientLine = true;
449 | haveAngle = true;
450 | token = parser.getToken(true, true);
451 | }
452 |
453 | if (token.isLength()
454 | || token.isIdent("top")
455 | || token.isIdent("center")
456 | || token.isIdent("bottom")
457 | || token.isIdent("left")
458 | || token.isIdent("right")) {
459 | haveGradientLine = true;
460 | if (token.isLength()
461 | || token.isIdent("left")
462 | || token.isIdent("right")) {
463 | foundHorizPosition = true;
464 | }
465 | gradient.position = token.value;
466 | token = parser.getToken(true, true);
467 | }
468 |
469 | if (haveGradientLine) {
470 | if (!haveAngle && token.isAngle()) { // we have an angle here
471 | gradient.angle = token.value;
472 | haveAngle = true;
473 | token = parser.getToken(true, true);
474 | }
475 |
476 | else if (token.isLength()
477 | || (foundHorizPosition && (token.isIdent("top")
478 | || token.isIdent("center")
479 | || token.isIdent("bottom")))
480 | || (!foundHorizPosition && (token.isLength()
481 | || token.isIdent("top")
482 | || token.isIdent("center")
483 | || token.isIdent("bottom")
484 | || token.isIdent("left")
485 | || token.isIdent("right")))) {
486 | gradient.position = ("position" in gradient) ? gradient.position + " ": "";
487 | gradient.position += token.value;
488 | token = parser.getToken(true, true);
489 | }
490 |
491 | if (!haveAngle && token.isAngle()) { // we have an angle here
492 | gradient.angle = token.value;
493 | haveAngle = true;
494 | token = parser.getToken(true, true);
495 | }
496 |
497 | // we must find a comma here
498 | if (!token.isSymbol(","))
499 | return null;
500 | token = parser.getToken(true, true);
501 | }
502 |
503 | // ok... Let's deal with the rest now
504 | if (gradient.isRadial) {
505 | if (token.isIdent("circle") ||
506 | token.isIdent("ellipse")) {
507 | gradient.shape = token.value;
508 | token = parser.getToken(true, true);
509 | }
510 | if (token.isIdent("closest-side") ||
511 | token.isIdent("closest-corner") ||
512 | token.isIdent("farthest-side") ||
513 | token.isIdent("farthest-corner") ||
514 | token.isIdent("contain") ||
515 | token.isIdent("cover")) {
516 | gradient.size = token.value;
517 | token = parser.getToken(true, true);
518 | }
519 | if (!("shape" in gradient) &&
520 | (token.isIdent("circle") ||
521 | token.isIdent("ellipse"))) {
522 | // we can still have the second value...
523 | gradient.shape = token.value;
524 | token = parser.getToken(true, true);
525 | }
526 | if ((("shape" in gradient) || ("size" in gradient)) && !token.isSymbol(","))
527 | return null;
528 | else if (("shape" in gradient) || ("size" in gradient))
529 | token = parser.getToken(true, true);
530 | }
531 |
532 | // now color stops...
533 | var stop1 = this.parseColorStop(parser, token);
534 | if (!stop1)
535 | return null;
536 | token = parser.currentToken();
537 | if (!token.isSymbol(","))
538 | return null;
539 | token = parser.getToken(true, true);
540 | var stop2 = this.parseColorStop(parser, token);
541 | if (!stop2)
542 | return null;
543 | token = parser.currentToken();
544 | if (token.isSymbol(",")) {
545 | token = parser.getToken(true, true);
546 | }
547 | // ok we have at least two color stops
548 | gradient.stops = [stop1, stop2];
549 | while (!token.isSymbol(")")) {
550 | var colorstop = this.parseColorStop(parser, token);
551 | if (!colorstop)
552 | return null;
553 | token = parser.currentToken();
554 | if (!token.isSymbol(")") && !token.isSymbol(","))
555 | return null;
556 | if (token.isSymbol(","))
557 | token = parser.getToken(true, true);
558 | gradient.stops.push(colorstop);
559 | }
560 | return gradient;
561 | }
562 | }
563 | return null;
564 | },
565 |
566 | parseBoxShadows: function(aString)
567 | {
568 | var parser = new CSSParser();
569 | parser._init();
570 | parser.mPreserveWS = false;
571 | parser.mPreserveComments = false;
572 | parser.mPreservedTokens = [];
573 | parser.mScanner.init(aString);
574 |
575 | var shadows = [];
576 | var token = parser.getToken(true, true);
577 | var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px", spreadRadius = "0px";
578 | var inset = false;
579 | while (token.isNotNull()) {
580 | if (token.isIdent("none")) {
581 | shadows.push( { none: true } );
582 | token = parser.getToken(true, true);
583 | }
584 | else {
585 | if (token.isIdent('inset')) {
586 | inset = true;
587 | token = parser.getToken(true, true);
588 | }
589 |
590 | if (token.isPercentage() ||
591 | token.isDimensionOfUnit("cm") ||
592 | token.isDimensionOfUnit("mm") ||
593 | token.isDimensionOfUnit("in") ||
594 | token.isDimensionOfUnit("pc") ||
595 | token.isDimensionOfUnit("px") ||
596 | token.isDimensionOfUnit("em") ||
597 | token.isDimensionOfUnit("ex") ||
598 | token.isDimensionOfUnit("pt")) {
599 | var offsetX = token.value;
600 | token = parser.getToken(true, true);
601 | }
602 | else
603 | return [];
604 |
605 | if (!inset && token.isIdent('inset')) {
606 | inset = true;
607 | token = parser.getToken(true, true);
608 | }
609 |
610 | if (token.isPercentage() ||
611 | token.isDimensionOfUnit("cm") ||
612 | token.isDimensionOfUnit("mm") ||
613 | token.isDimensionOfUnit("in") ||
614 | token.isDimensionOfUnit("pc") ||
615 | token.isDimensionOfUnit("px") ||
616 | token.isDimensionOfUnit("em") ||
617 | token.isDimensionOfUnit("ex") ||
618 | token.isDimensionOfUnit("pt")) {
619 | var offsetX = token.value;
620 | token = parser.getToken(true, true);
621 | }
622 | else
623 | return [];
624 |
625 | if (!inset && token.isIdent('inset')) {
626 | inset = true;
627 | token = parser.getToken(true, true);
628 | }
629 |
630 | if (token.isPercentage() ||
631 | token.isDimensionOfUnit("cm") ||
632 | token.isDimensionOfUnit("mm") ||
633 | token.isDimensionOfUnit("in") ||
634 | token.isDimensionOfUnit("pc") ||
635 | token.isDimensionOfUnit("px") ||
636 | token.isDimensionOfUnit("em") ||
637 | token.isDimensionOfUnit("ex") ||
638 | token.isDimensionOfUnit("pt")) {
639 | var blurRadius = token.value;
640 | token = parser.getToken(true, true);
641 | }
642 |
643 | if (!inset && token.isIdent('inset')) {
644 | inset = true;
645 | token = parser.getToken(true, true);
646 | }
647 |
648 | if (token.isPercentage() ||
649 | token.isDimensionOfUnit("cm") ||
650 | token.isDimensionOfUnit("mm") ||
651 | token.isDimensionOfUnit("in") ||
652 | token.isDimensionOfUnit("pc") ||
653 | token.isDimensionOfUnit("px") ||
654 | token.isDimensionOfUnit("em") ||
655 | token.isDimensionOfUnit("ex") ||
656 | token.isDimensionOfUnit("pt")) {
657 | var spreadRadius = token.value;
658 | token = parser.getToken(true, true);
659 | }
660 |
661 | if (!inset && token.isIdent('inset')) {
662 | inset = true;
663 | token = parser.getToken(true, true);
664 | }
665 |
666 | if (token.isFunction("rgb(") ||
667 | token.isFunction("rgba(") ||
668 | token.isFunction("hsl(") ||
669 | token.isFunction("hsla(") ||
670 | token.isSymbol("#") ||
671 | token.isIdent()) {
672 | var color = parser.parseColor(token);
673 | token = parser.getToken(true, true);
674 | }
675 |
676 | if (!inset && token.isIdent('inset')) {
677 | inset = true;
678 | token = parser.getToken(true, true);
679 | }
680 |
681 | shadows.push( { none: false,
682 | color: color,
683 | offsetX: offsetX, offsetY: offsetY,
684 | blurRadius: blurRadius,
685 | spreadRadius: spreadRadius } );
686 |
687 | if (token.isSymbol(",")) {
688 | inset = false;
689 | color = "";
690 | blurRadius = "0px";
691 | spreadRadius = "0px"
692 | offsetX = "0px";
693 | offsetY = "0px";
694 | token = parser.getToken(true, true);
695 | }
696 | else if (!token.isNotNull())
697 | return shadows;
698 | else
699 | return [];
700 | }
701 | }
702 | return shadows;
703 | },
704 |
705 | parseTextShadows: function(aString)
706 | {
707 | var parser = new CSSParser();
708 | parser._init();
709 | parser.mPreserveWS = false;
710 | parser.mPreserveComments = false;
711 | parser.mPreservedTokens = [];
712 | parser.mScanner.init(aString);
713 |
714 | var shadows = [];
715 | var token = parser.getToken(true, true);
716 | var color = "", blurRadius = "0px", offsetX = "0px", offsetY = "0px";
717 | while (token.isNotNull()) {
718 | if (token.isIdent("none")) {
719 | shadows.push( { none: true } );
720 | token = parser.getToken(true, true);
721 | }
722 | else {
723 | if (token.isFunction("rgb(") ||
724 | token.isFunction("rgba(") ||
725 | token.isFunction("hsl(") ||
726 | token.isFunction("hsla(") ||
727 | token.isSymbol("#") ||
728 | token.isIdent()) {
729 | var color = parser.parseColor(token);
730 | token = parser.getToken(true, true);
731 | }
732 | if (token.isPercentage() ||
733 | token.isDimensionOfUnit("cm") ||
734 | token.isDimensionOfUnit("mm") ||
735 | token.isDimensionOfUnit("in") ||
736 | token.isDimensionOfUnit("pc") ||
737 | token.isDimensionOfUnit("px") ||
738 | token.isDimensionOfUnit("em") ||
739 | token.isDimensionOfUnit("ex") ||
740 | token.isDimensionOfUnit("pt")) {
741 | var offsetX = token.value;
742 | token = parser.getToken(true, true);
743 | }
744 | else
745 | return [];
746 | if (token.isPercentage() ||
747 | token.isDimensionOfUnit("cm") ||
748 | token.isDimensionOfUnit("mm") ||
749 | token.isDimensionOfUnit("in") ||
750 | token.isDimensionOfUnit("pc") ||
751 | token.isDimensionOfUnit("px") ||
752 | token.isDimensionOfUnit("em") ||
753 | token.isDimensionOfUnit("ex") ||
754 | token.isDimensionOfUnit("pt")) {
755 | var offsetY = token.value;
756 | token = parser.getToken(true, true);
757 | }
758 | else
759 | return [];
760 | if (token.isPercentage() ||
761 | token.isDimensionOfUnit("cm") ||
762 | token.isDimensionOfUnit("mm") ||
763 | token.isDimensionOfUnit("in") ||
764 | token.isDimensionOfUnit("pc") ||
765 | token.isDimensionOfUnit("px") ||
766 | token.isDimensionOfUnit("em") ||
767 | token.isDimensionOfUnit("ex") ||
768 | token.isDimensionOfUnit("pt")) {
769 | var blurRadius = token.value;
770 | token = parser.getToken(true, true);
771 | }
772 | if (!color &&
773 | (token.isFunction("rgb(") ||
774 | token.isFunction("rgba(") ||
775 | token.isFunction("hsl(") ||
776 | token.isFunction("hsla(") ||
777 | token.isSymbol("#") ||
778 | token.isIdent())) {
779 | var color = parser.parseColor(token);
780 | token = parser.getToken(true, true);
781 | }
782 |
783 | shadows.push( { none: false,
784 | color: color,
785 | offsetX: offsetX, offsetY: offsetY,
786 | blurRadius: blurRadius } );
787 |
788 | if (token.isSymbol(",")) {
789 | color = "";
790 | blurRadius = "0px";
791 | offsetX = "0px";
792 | offsetY = "0px";
793 | token = parser.getToken(true, true);
794 | }
795 | else if (!token.isNotNull())
796 | return shadows;
797 | else
798 | return [];
799 | }
800 | }
801 | return shadows;
802 | },
803 |
804 | parseBackgroundImages: function(aString)
805 | {
806 | var parser = new CSSParser();
807 | parser._init();
808 | parser.mPreserveWS = false;
809 | parser.mPreserveComments = false;
810 | parser.mPreservedTokens = [];
811 | parser.mScanner.init(aString);
812 |
813 | var backgrounds = [];
814 | var token = parser.getToken(true, true);
815 | while (token.isNotNull()) {
816 | /*if (token.isFunction("rgb(") ||
817 | token.isFunction("rgba(") ||
818 | token.isFunction("hsl(") ||
819 | token.isFunction("hsla(") ||
820 | token.isSymbol("#") ||
821 | token.isIdent()) {
822 | var color = parser.parseColor(token);
823 | backgrounds.push( { type: "color", value: color });
824 | token = parser.getToken(true, true);
825 | }
826 | else */
827 | if (token.isFunction("url(")) {
828 | token = parser.getToken(true, true);
829 | var urlContent = parser.parseURL(token);
830 | backgrounds.push( { type: "image", value: "url(" + urlContent });
831 | token = parser.getToken(true, true);
832 | }
833 | else if (token.isFunction("-moz-linear-gradient(") ||
834 | token.isFunction("-moz-radial-gradient(") ||
835 | token.isFunction("-moz-repeating-linear-gradient(") ||
836 | token.isFunction("-moz-repeating-radial-gradient(")) {
837 | var gradient = this.parseGradient(parser, token);
838 | backgrounds.push( { type: gradient.isRadial ? "radial-gradient" : "linear-gradient", value: gradient });
839 | token = parser.getToken(true, true);
840 | }
841 | else
842 | return null;
843 | if (token.isSymbol(",")) {
844 | token = parser.getToken(true, true);
845 | if (!token.isNotNull())
846 | return null;
847 | }
848 | }
849 | return backgrounds;
850 | },
851 |
852 | serializeGradient: function(gradient)
853 | {
854 | var s = gradient.isRadial
855 | ? (gradient.isRepeating ? "-moz-repeating-radial-gradient(" : "-moz-radial-gradient(" )
856 | : (gradient.isRepeating ? "-moz-repeating-linear-gradient(" : "-moz-linear-gradient(" );
857 | if (gradient.angle || gradient.position)
858 | s += (gradient.angle ? gradient.angle + " ": "") +
859 | (gradient.position ? gradient.position : "") +
860 | ", ";
861 | if (gradient.isRadial && (gradient.shape || gradient.size))
862 | s += (gradient.shape ? gradient.shape : "") +
863 | " " +
864 | (gradient.size ? gradient.size : "") +
865 | ", ";
866 | for (var i = 0; i < gradient.stops.length; i++) {
867 | var colorstop = gradient.stops[i];
868 | s += colorstop.color + (colorstop.position ? " " + colorstop.position : "");
869 | if (i != gradient.stops.length -1)
870 | s += ", ";
871 | }
872 | s += ")";
873 | return s;
874 | },
875 |
876 | parseBorderImage: function(aString)
877 | {
878 | var parser = new CSSParser();
879 | parser._init();
880 | parser.mPreserveWS = false;
881 | parser.mPreserveComments = false;
882 | parser.mPreservedTokens = [];
883 | parser.mScanner.init(aString);
884 |
885 | var borderImage = {url: "", offsets: [], widths: [], sizes: []};
886 | var token = parser.getToken(true, true);
887 | if (token.isFunction("url(")) {
888 | token = parser.getToken(true, true);
889 | var urlContent = parser.parseURL(token);
890 | if (urlContent) {
891 | borderImage.url = urlContent.substr(0, urlContent.length - 1).trim();
892 | if ((borderImage.url[0] == '"' && borderImage.url[borderImage.url.length - 1] == '"') ||
893 | (borderImage.url[0] == "'" && borderImage.url[borderImage.url.length - 1] == "'"))
894 | borderImage.url = borderImage.url.substr(1, borderImage.url.length - 2);
895 | }
896 | else
897 | return null;
898 | }
899 | else
900 | return null;
901 |
902 | token = parser.getToken(true, true);
903 | if (token.isNumber() || token.isPercentage())
904 | borderImage.offsets.push(token.value);
905 | else
906 | return null;
907 | var i;
908 | for (i= 0; i < 3; i++) {
909 | token = parser.getToken(true, true);
910 | if (token.isNumber() || token.isPercentage())
911 | borderImage.offsets.push(token.value);
912 | else
913 | break;
914 | }
915 | if (i == 3)
916 | token = parser.getToken(true, true);
917 |
918 | if (token.isSymbol("/")) {
919 | token = parser.getToken(true, true);
920 | if (token.isDimension()
921 | || token.isNumber("0")
922 | || (token.isIdent() && token.value in parser.kBORDER_WIDTH_NAMES))
923 | borderImage.widths.push(token.value);
924 | else
925 | return null;
926 |
927 | for (var i = 0; i < 3; i++) {
928 | token = parser.getToken(true, true);
929 | if (token.isDimension()
930 | || token.isNumber("0")
931 | || (token.isIdent() && token.value in parser.kBORDER_WIDTH_NAMES))
932 | borderImage.widths.push(token.value);
933 | else
934 | break;
935 | }
936 | if (i == 3)
937 | token = parser.getToken(true, true);
938 | }
939 |
940 | for (var i = 0; i < 2; i++) {
941 | if (token.isIdent("stretch")
942 | || token.isIdent("repeat")
943 | || token.isIdent("round"))
944 | borderImage.sizes.push(token.value);
945 | else if (!token.isNotNull())
946 | return borderImage;
947 | else
948 | return null;
949 | token = parser.getToken(true, true);
950 | }
951 | if (!token.isNotNull())
952 | return borderImage;
953 |
954 | return null;
955 | },
956 |
957 | parseMediaQuery: function(aString)
958 | {
959 | const kCONSTRAINTS = {
960 | "width": true,
961 | "min-width": true,
962 | "max-width": true,
963 | "height": true,
964 | "min-height": true,
965 | "max-height": true,
966 | "device-width": true,
967 | "min-device-width": true,
968 | "max-device-width": true,
969 | "device-height": true,
970 | "min-device-height": true,
971 | "max-device-height": true,
972 | "orientation": true,
973 | "aspect-ratio": true,
974 | "min-aspect-ratio": true,
975 | "max-aspect-ratio": true,
976 | "device-aspect-ratio": true,
977 | "min-device-aspect-ratio": true,
978 | "max-device-aspect-ratio": true,
979 | "color": true,
980 | "min-color": true,
981 | "max-color": true,
982 | "color-index": true,
983 | "min-color-index": true,
984 | "max-color-index": true,
985 | "monochrome": true,
986 | "min-monochrome": true,
987 | "max-monochrome": true,
988 | "resolution": true,
989 | "min-resolution": true,
990 | "max-resolution": true,
991 | "scan": true,
992 | "grid": true
993 | };
994 | var parser = new CSSParser();
995 | parser._init();
996 | parser.mPreserveWS = false;
997 | parser.mPreserveComments = false;
998 | parser.mPreservedTokens = [];
999 | parser.mScanner.init(aString);
1000 |
1001 | var m = {amplifier: "", medium: "", constraints: []};
1002 | var token = parser.getToken(true, true);
1003 |
1004 | if (token.isIdent("all") ||
1005 | token.isIdent("aural") ||
1006 | token.isIdent("braille") ||
1007 | token.isIdent("handheld") ||
1008 | token.isIdent("print") ||
1009 | token.isIdent("projection") ||
1010 | token.isIdent("screen") ||
1011 | token.isIdent("tty") ||
1012 | token.isIdent("tv")) {
1013 | m.medium = token.value;
1014 | token = parser.getToken(true, true);
1015 | }
1016 | else if (token.isIdent("not") || token.isIdent("only")) {
1017 | m.amplifier = token.value;
1018 | token = parser.getToken(true, true);
1019 | if (token.isIdent("all") ||
1020 | token.isIdent("aural") ||
1021 | token.isIdent("braille") ||
1022 | token.isIdent("handheld") ||
1023 | token.isIdent("print") ||
1024 | token.isIdent("projection") ||
1025 | token.isIdent("screen") ||
1026 | token.isIdent("tty") ||
1027 | token.isIdent("tv")) {
1028 | m.medium = token.value;
1029 | token = parser.getToken(true, true);
1030 | }
1031 | else
1032 | return null;
1033 | }
1034 |
1035 | if (m.medium) {
1036 | if (!token.isNotNull())
1037 | return m;
1038 | if (token.isIdent("and")) {
1039 | token = parser.getToken(true, true);
1040 | }
1041 | else
1042 | return null;
1043 | }
1044 |
1045 | while (token.isSymbol("(")) {
1046 | token = parser.getToken(true, true);
1047 | if (token.isIdent() && (token.value in kCONSTRAINTS)) {
1048 | var constraint = token.value;
1049 | token = parser.getToken(true, true);
1050 | if (token.isSymbol(":")) {
1051 | token = parser.getToken(true, true);
1052 | var values = [];
1053 | while (!token.isSymbol(")")) {
1054 | values.push(token.value);
1055 | token = parser.getToken(true, true);
1056 | }
1057 | if (token.isSymbol(")")) {
1058 | m.constraints.push({constraint: constraint, value: values});
1059 | token = parser.getToken(true, true);
1060 | if (token.isNotNull()) {
1061 | if (token.isIdent("and")) {
1062 | token = parser.getToken(true, true);
1063 | }
1064 | else
1065 | return null;
1066 | }
1067 | else
1068 | return m;
1069 | }
1070 | else
1071 | return null;
1072 | }
1073 | else if (token.isSymbol(")")) {
1074 | m.constraints.push({constraint: constraint, value: null});
1075 | token = parser.getToken(true, true);
1076 | if (token.isNotNull()) {
1077 | if (token.isIdent("and")) {
1078 | token = parser.getToken(true, true);
1079 | }
1080 | else
1081 | return null;
1082 | }
1083 | else
1084 | return m;
1085 | }
1086 | else
1087 | return null;
1088 | }
1089 | else
1090 | return null;
1091 | }
1092 | return m;
1093 | }
1094 |
1095 | };
1096 |
1097 |
1098 | /************************************************************/
1099 | /************************** JSCSSP **************************/
1100 | /************************************************************/
1101 |
1102 | var CSS_ESCAPE = '\\';
1103 |
1104 | var IS_HEX_DIGIT = 1;
1105 | var START_IDENT = 2;
1106 | var IS_IDENT = 4;
1107 | var IS_WHITESPACE = 8;
1108 |
1109 | var W = IS_WHITESPACE;
1110 | var I = IS_IDENT;
1111 | var S = START_IDENT;
1112 | var SI = IS_IDENT|START_IDENT;
1113 | var XI = IS_IDENT |IS_HEX_DIGIT;
1114 | var XSI = IS_IDENT|START_IDENT|IS_HEX_DIGIT;
1115 |
1116 | function CSSScanner(aString)
1117 | {
1118 | this.init(aString);
1119 | }
1120 |
1121 | CSSScanner.prototype = {
1122 |
1123 | kLexTable: [
1124 | // TAB LF FF CR
1125 | 0, 0, 0, 0, 0, 0, 0, 0, 0, W, W, 0, W, W, 0, 0,
1126 | //
1127 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1128 | // SPC ! " # $ % & ' ( ) * + , - . /
1129 | W, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, I, 0, 0,
1130 | // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
1131 | XI, XI, XI, XI, XI, XI, XI, XI, XI, XI, 0, 0, 0, 0, 0, 0,
1132 | // @ A B C D E F G H I J K L M N O
1133 | 0, XSI,XSI,XSI,XSI,XSI,XSI,SI, SI, SI, SI, SI, SI, SI, SI, SI,
1134 | // P Q R S T U V W X Y Z [ \ ] ^ _
1135 | SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, 0, S, 0, 0, SI,
1136 | // ` a b c d e f g h i j k l m n o
1137 | 0, XSI,XSI,XSI,XSI,XSI,XSI,SI, SI, SI, SI, SI, SI, SI, SI, SI,
1138 | // p q r s t u v w x y z { | } ~
1139 | SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, 0, 0, 0, 0, 0,
1140 | //
1141 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1142 | //
1143 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1144 | // ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ® ¯
1145 | 0, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI,
1146 | // ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿
1147 | SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI,
1148 | // À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï
1149 | SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI,
1150 | // Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß
1151 | SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI,
1152 | // à á â ã ä å æ ç è é ê ë ì í î ï
1153 | SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI,
1154 | // ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ
1155 | SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI, SI
1156 | ],
1157 |
1158 | kHexValues: {
1159 | "0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9,
1160 | "a": 10, "b": 11, "c": 12, "d": 13, "e": 14, "f": 15
1161 | },
1162 |
1163 | mString : "",
1164 | mPos : 0,
1165 | mPreservedPos : [],
1166 |
1167 | init: function(aString) {
1168 | this.mString = aString;
1169 | this.mPos = 0;
1170 | this.mPreservedPos = [];
1171 | },
1172 |
1173 | getCurrentPos: function() {
1174 | return this.mPos;
1175 | },
1176 |
1177 | getAlreadyScanned: function()
1178 | {
1179 | return this.mString.substr(0, this.mPos);
1180 | },
1181 |
1182 | preserveState: function() {
1183 | this.mPreservedPos.push(this.mPos);
1184 | },
1185 |
1186 | restoreState: function() {
1187 | if (this.mPreservedPos.length) {
1188 | this.mPos = this.mPreservedPos.pop();
1189 | }
1190 | },
1191 |
1192 | forgetState: function() {
1193 | if (this.mPreservedPos.length) {
1194 | this.mPreservedPos.pop();
1195 | }
1196 | },
1197 |
1198 | read: function() {
1199 | if (this.mPos < this.mString.length)
1200 | return this.mString.charAt(this.mPos++);
1201 | return -1;
1202 | },
1203 |
1204 | peek: function() {
1205 | if (this.mPos < this.mString.length)
1206 | return this.mString.charAt(this.mPos);
1207 | return -1;
1208 | },
1209 |
1210 | isHexDigit: function(c) {
1211 | var code = c.charCodeAt(0);
1212 | return (code < 256 && (this.kLexTable[code] & IS_HEX_DIGIT) != 0);
1213 | },
1214 |
1215 | isIdentStart: function(c) {
1216 | var code = c.charCodeAt(0);
1217 | return (code >= 256 || (this.kLexTable[code] & START_IDENT) != 0);
1218 | },
1219 |
1220 | startsWithIdent: function(aFirstChar, aSecondChar) {
1221 | var code = aFirstChar.charCodeAt(0);
1222 | return this.isIdentStart(aFirstChar) ||
1223 | (aFirstChar == "-" && this.isIdentStart(aSecondChar));
1224 | },
1225 |
1226 | isIdent: function(c) {
1227 | var code = c.charCodeAt(0);
1228 | return (code >= 256 || (this.kLexTable[code] & IS_IDENT) != 0);
1229 | },
1230 |
1231 | pushback: function() {
1232 | this.mPos--;
1233 | },
1234 |
1235 | nextHexValue: function() {
1236 | var c = this.read();
1237 | if (c == -1 || !this.isHexDigit(c))
1238 | return new jscsspToken(jscsspToken.NULL_TYPE, null);
1239 | var s = c;
1240 | c = this.read();
1241 | while (c != -1 && this.isHexDigit(c)) {
1242 | s += c;
1243 | c = this.read();
1244 | }
1245 | if (c != -1)
1246 | this.pushback();
1247 | return new jscsspToken(jscsspToken.HEX_TYPE, s);
1248 | },
1249 |
1250 | gatherEscape: function() {
1251 | var c = this.peek();
1252 | if (c == -1)
1253 | return "";
1254 | if (this.isHexDigit(c)) {
1255 | var code = 0;
1256 | for (var i = 0; i < 6; i++) {
1257 | c = this.read();
1258 | if (this.isHexDigit(c))
1259 | code = code * 16 + this.kHexValues[c.toLowerCase()];
1260 | else if (!this.isHexDigit(c) && !this.isWhiteSpace(c)) {
1261 | this.pushback();
1262 | break;
1263 | }
1264 | else
1265 | break;
1266 | }
1267 | if (i == 6) {
1268 | c = this.peek();
1269 | if (this.isWhiteSpace(c))
1270 | this.read();
1271 | }
1272 | return String.fromCharCode(code);
1273 | }
1274 | c = this.read();
1275 | if (c != "\n")
1276 | return c;
1277 | return "";
1278 | },
1279 |
1280 | gatherIdent: function(c) {
1281 | var s = "";
1282 | if (c == CSS_ESCAPE)
1283 | s += this.gatherEscape();
1284 | else
1285 | s += c;
1286 | c = this.read();
1287 | while (c != -1
1288 | && (this.isIdent(c) || c == CSS_ESCAPE)) {
1289 | if (c == CSS_ESCAPE)
1290 | s += this.gatherEscape();
1291 | else
1292 | s += c;
1293 | c = this.read();
1294 | }
1295 | if (c != -1)
1296 | this.pushback();
1297 | return s;
1298 | },
1299 |
1300 | parseIdent: function(c) {
1301 | var value = this.gatherIdent(c);
1302 | var nextChar = this.peek();
1303 | if (nextChar == "(") {
1304 | value += this.read();
1305 | return new jscsspToken(jscsspToken.FUNCTION_TYPE, value);
1306 | }
1307 | return new jscsspToken(jscsspToken.IDENT_TYPE, value);
1308 | },
1309 |
1310 | isDigit: function(c) {
1311 | return (c >= '0') && (c <= '9');
1312 | },
1313 |
1314 | parseComment: function(c) {
1315 | var s = c;
1316 | while ((c = this.read()) != -1) {
1317 | s += c;
1318 | if (c == "*") {
1319 | c = this.read();
1320 | if (c == -1)
1321 | break;
1322 | if (c == "/") {
1323 | s += c;
1324 | break;
1325 | }
1326 | this.pushback();
1327 | }
1328 | }
1329 | return new jscsspToken(jscsspToken.COMMENT_TYPE, s);
1330 | },
1331 |
1332 | parseNumber: function(c) {
1333 | var s = c;
1334 | var foundDot = false;
1335 | while ((c = this.read()) != -1) {
1336 | if (c == ".") {
1337 | if (foundDot)
1338 | break;
1339 | else {
1340 | s += c;
1341 | foundDot = true;
1342 | }
1343 | } else if (this.isDigit(c))
1344 | s += c;
1345 | else
1346 | break;
1347 | }
1348 |
1349 | if (c != -1 && this.startsWithIdent(c, this.peek())) { // DIMENSION
1350 | var unit = this.gatherIdent(c);
1351 | s += unit;
1352 | return new jscsspToken(jscsspToken.DIMENSION_TYPE, s, unit);
1353 | }
1354 | else if (c == "%") {
1355 | s += "%";
1356 | return new jscsspToken(jscsspToken.PERCENTAGE_TYPE, s);
1357 | }
1358 | else if (c != -1)
1359 | this.pushback();
1360 | return new jscsspToken(jscsspToken.NUMBER_TYPE, s);
1361 | },
1362 |
1363 | parseString: function(aStop) {
1364 | var s = aStop;
1365 | var previousChar = aStop;
1366 | var c;
1367 | while ((c = this.read()) != -1) {
1368 | if (c == aStop && previousChar != CSS_ESCAPE) {
1369 | s += c;
1370 | break;
1371 | }
1372 | else if (c == CSS_ESCAPE) {
1373 | c = this.peek();
1374 | if (c == -1)
1375 | break;
1376 | else if (c == "\n" || c == "\r" || c == "\f") {
1377 | d = c;
1378 | c = this.read();
1379 | // special for Opera that preserves \r\n...
1380 | if (d == "\r") {
1381 | c = this.peek();
1382 | if (c == "\n")
1383 | c = this.read();
1384 | }
1385 | }
1386 | else {
1387 | s += this.gatherEscape();
1388 | c = this.peek();
1389 | }
1390 | }
1391 | else if (c == "\n" || c == "\r" || c == "\f") {
1392 | break;
1393 | }
1394 | else
1395 | s += c;
1396 |
1397 | previousChar = c;
1398 | }
1399 | return new jscsspToken(jscsspToken.STRING_TYPE, s);
1400 | },
1401 |
1402 | isWhiteSpace: function(c) {
1403 | var code = c.charCodeAt(0);
1404 | return code < 256 && (this.kLexTable[code] & IS_WHITESPACE) != 0;
1405 | },
1406 |
1407 | eatWhiteSpace: function(c) {
1408 | var s = c;
1409 | while ((c = this.read()) != -1) {
1410 | if (!this.isWhiteSpace(c))
1411 | break;
1412 | s += c;
1413 | }
1414 | if (c != -1)
1415 | this.pushback();
1416 | return s;
1417 | },
1418 |
1419 | parseAtKeyword: function(c) {
1420 | return new jscsspToken(jscsspToken.ATRULE_TYPE, this.gatherIdent(c));
1421 | },
1422 |
1423 | nextToken: function() {
1424 | var c = this.read();
1425 | if (c == -1)
1426 | return new jscsspToken(jscsspToken.NULL_TYPE, null);
1427 |
1428 | if (this.startsWithIdent(c, this.peek()))
1429 | return this.parseIdent(c);
1430 |
1431 | if (c == '@') {
1432 | var nextChar = this.read();
1433 | if (nextChar != -1) {
1434 | var followingChar = this.peek();
1435 | this.pushback();
1436 | if (this.startsWithIdent(nextChar, followingChar))
1437 | return this.parseAtKeyword(c);
1438 | }
1439 | }
1440 |
1441 | if (c == "." || c == "+" || c == "-") {
1442 | var nextChar = this.peek();
1443 | if (this.isDigit(nextChar))
1444 | return this.parseNumber(c);
1445 | else if (nextChar == "." && c != ".") {
1446 | firstChar = this.read();
1447 | var secondChar = this.peek();
1448 | this.pushback();
1449 | if (this.isDigit(secondChar))
1450 | return this.parseNumber(c);
1451 | }
1452 | }
1453 | if (this.isDigit(c)) {
1454 | return this.parseNumber(c);
1455 | }
1456 |
1457 | if (c == "'" || c == '"')
1458 | return this.parseString(c);
1459 |
1460 | if (this.isWhiteSpace(c)) {
1461 | var s = this.eatWhiteSpace(c);
1462 |
1463 | return new jscsspToken(jscsspToken.WHITESPACE_TYPE, s);
1464 | }
1465 |
1466 | if (c == "|" || c == "~" || c == "^" || c == "$" || c == "*") {
1467 | var nextChar = this.read();
1468 | if (nextChar == "=") {
1469 | switch (c) {
1470 | case "~" :
1471 | return new jscsspToken(jscsspToken.INCLUDES_TYPE, "~=");
1472 | case "|" :
1473 | return new jscsspToken(jscsspToken.DASHMATCH_TYPE, "|=");
1474 | case "^" :
1475 | return new jscsspToken(jscsspToken.BEGINSMATCH_TYPE, "^=");
1476 | case "$" :
1477 | return new jscsspToken(jscsspToken.ENDSMATCH_TYPE, "$=");
1478 | case "*" :
1479 | return new jscsspToken(jscsspToken.CONTAINSMATCH_TYPE, "*=");
1480 | default :
1481 | break;
1482 | }
1483 | } else if (nextChar != -1)
1484 | this.pushback();
1485 | }
1486 |
1487 | if (c == "/" && this.peek() == "*")
1488 | return this.parseComment(c);
1489 |
1490 | return new jscsspToken(jscsspToken.SYMBOL_TYPE, c);
1491 | }
1492 | };
1493 |
1494 | function CSSParser(aString)
1495 | {
1496 | this.mToken = null;
1497 | this.mLookAhead = null;
1498 | this.mScanner = new CSSScanner(aString);
1499 |
1500 | this.mPreserveWS = true;
1501 | this.mPreserveComments = true;
1502 |
1503 | this.mPreservedTokens = [];
1504 |
1505 | this.mError = null;
1506 | }
1507 |
1508 | CSSParser.prototype = {
1509 |
1510 | _init:function() {
1511 | this.mToken = null;
1512 | this.mLookAhead = null;
1513 | },
1514 |
1515 | kINHERIT: "inherit",
1516 |
1517 | kBORDER_WIDTH_NAMES: {
1518 | "thin": true,
1519 | "medium": true,
1520 | "thick": true
1521 | },
1522 |
1523 | kBORDER_STYLE_NAMES: {
1524 | "none": true,
1525 | "hidden": true,
1526 | "dotted": true,
1527 | "dashed": true,
1528 | "solid": true,
1529 | "double": true,
1530 | "groove": true,
1531 | "ridge": true,
1532 | "inset": true,
1533 | "outset": true
1534 | },
1535 |
1536 | kCOLOR_NAMES: {
1537 | "transparent": true,
1538 |
1539 | "black": true,
1540 | "silver": true,
1541 | "gray": true,
1542 | "white": true,
1543 | "maroon": true,
1544 | "red": true,
1545 | "purple": true,
1546 | "fuchsia": true,
1547 | "green": true,
1548 | "lime": true,
1549 | "olive": true,
1550 | "yellow": true,
1551 | "navy": true,
1552 | "blue": true,
1553 | "teal": true,
1554 | "aqua": true,
1555 |
1556 | "aliceblue": true,
1557 | "antiquewhite": true,
1558 | "aqua": true,
1559 | "aquamarine": true,
1560 | "azure": true,
1561 | "beige": true,
1562 | "bisque": true,
1563 | "black": true,
1564 | "blanchedalmond": true,
1565 | "blue": true,
1566 | "blueviolet": true,
1567 | "brown": true,
1568 | "burlywood": true,
1569 | "cadetblue": true,
1570 | "chartreuse": true,
1571 | "chocolate": true,
1572 | "coral": true,
1573 | "cornflowerblue": true,
1574 | "cornsilk": true,
1575 | "crimson": true,
1576 | "cyan": true,
1577 | "darkblue": true,
1578 | "darkcyan": true,
1579 | "darkgoldenrod": true,
1580 | "darkgray": true,
1581 | "darkgreen": true,
1582 | "darkgrey": true,
1583 | "darkkhaki": true,
1584 | "darkmagenta": true,
1585 | "darkolivegreen": true,
1586 | "darkorange": true,
1587 | "darkorchid": true,
1588 | "darkred": true,
1589 | "darksalmon": true,
1590 | "darkseagreen": true,
1591 | "darkslateblue": true,
1592 | "darkslategray": true,
1593 | "darkslategrey": true,
1594 | "darkturquoise": true,
1595 | "darkviolet": true,
1596 | "deeppink": true,
1597 | "deepskyblue": true,
1598 | "dimgray": true,
1599 | "dimgrey": true,
1600 | "dodgerblue": true,
1601 | "firebrick": true,
1602 | "floralwhite": true,
1603 | "forestgreen": true,
1604 | "fuchsia": true,
1605 | "gainsboro": true,
1606 | "ghostwhite": true,
1607 | "gold": true,
1608 | "goldenrod": true,
1609 | "gray": true,
1610 | "green": true,
1611 | "greenyellow": true,
1612 | "grey": true,
1613 | "honeydew": true,
1614 | "hotpink": true,
1615 | "indianred": true,
1616 | "indigo": true,
1617 | "ivory": true,
1618 | "khaki": true,
1619 | "lavender": true,
1620 | "lavenderblush": true,
1621 | "lawngreen": true,
1622 | "lemonchiffon": true,
1623 | "lightblue": true,
1624 | "lightcoral": true,
1625 | "lightcyan": true,
1626 | "lightgoldenrodyellow": true,
1627 | "lightgray": true,
1628 | "lightgreen": true,
1629 | "lightgrey": true,
1630 | "lightpink": true,
1631 | "lightsalmon": true,
1632 | "lightseagreen": true,
1633 | "lightskyblue": true,
1634 | "lightslategray": true,
1635 | "lightslategrey": true,
1636 | "lightsteelblue": true,
1637 | "lightyellow": true,
1638 | "lime": true,
1639 | "limegreen": true,
1640 | "linen": true,
1641 | "magenta": true,
1642 | "maroon": true,
1643 | "mediumaquamarine": true,
1644 | "mediumblue": true,
1645 | "mediumorchid": true,
1646 | "mediumpurple": true,
1647 | "mediumseagreen": true,
1648 | "mediumslateblue": true,
1649 | "mediumspringgreen": true,
1650 | "mediumturquoise": true,
1651 | "mediumvioletred": true,
1652 | "midnightblue": true,
1653 | "mintcream": true,
1654 | "mistyrose": true,
1655 | "moccasin": true,
1656 | "navajowhite": true,
1657 | "navy": true,
1658 | "oldlace": true,
1659 | "olive": true,
1660 | "olivedrab": true,
1661 | "orange": true,
1662 | "orangered": true,
1663 | "orchid": true,
1664 | "palegoldenrod": true,
1665 | "palegreen": true,
1666 | "paleturquoise": true,
1667 | "palevioletred": true,
1668 | "papayawhip": true,
1669 | "peachpuff": true,
1670 | "peru": true,
1671 | "pink": true,
1672 | "plum": true,
1673 | "powderblue": true,
1674 | "purple": true,
1675 | "red": true,
1676 | "rosybrown": true,
1677 | "royalblue": true,
1678 | "saddlebrown": true,
1679 | "salmon": true,
1680 | "sandybrown": true,
1681 | "seagreen": true,
1682 | "seashell": true,
1683 | "sienna": true,
1684 | "silver": true,
1685 | "skyblue": true,
1686 | "slateblue": true,
1687 | "slategray": true,
1688 | "slategrey": true,
1689 | "snow": true,
1690 | "springgreen": true,
1691 | "steelblue": true,
1692 | "tan": true,
1693 | "teal": true,
1694 | "thistle": true,
1695 | "tomato": true,
1696 | "turquoise": true,
1697 | "violet": true,
1698 | "wheat": true,
1699 | "white": true,
1700 | "whitesmoke": true,
1701 | "yellow": true,
1702 | "yellowgreen": true,
1703 |
1704 | "activeborder": true,
1705 | "activecaption": true,
1706 | "appworkspace": true,
1707 | "background": true,
1708 | "buttonface": true,
1709 | "buttonhighlight": true,
1710 | "buttonshadow": true,
1711 | "buttontext": true,
1712 | "captiontext": true,
1713 | "graytext": true,
1714 | "highlight": true,
1715 | "highlighttext": true,
1716 | "inactiveborder": true,
1717 | "inactivecaption": true,
1718 | "inactivecaptiontext": true,
1719 | "infobackground": true,
1720 | "infotext": true,
1721 | "menu": true,
1722 | "menutext": true,
1723 | "scrollbar": true,
1724 | "threeddarkshadow": true,
1725 | "threedface": true,
1726 | "threedhighlight": true,
1727 | "threedlightshadow": true,
1728 | "threedshadow": true,
1729 | "window": true,
1730 | "windowframe": true,
1731 | "windowtext": true
1732 | },
1733 |
1734 | kLIST_STYLE_TYPE_NAMES: {
1735 | "decimal": true,
1736 | "decimal-leading-zero": true,
1737 | "lower-roman": true,
1738 | "upper-roman": true,
1739 | "georgian": true,
1740 | "armenian": true,
1741 | "lower-latin": true,
1742 | "lower-alpha": true,
1743 | "upper-latin": true,
1744 | "upper-alpha": true,
1745 | "lower-greek": true,
1746 |
1747 | "disc": true,
1748 | "circle": true,
1749 | "square": true,
1750 | "none": true,
1751 |
1752 | /* CSS 3 */
1753 | "box": true,
1754 | "check": true,
1755 | "diamond": true,
1756 | "hyphen": true,
1757 |
1758 | "lower-armenian": true,
1759 | "cjk-ideographic": true,
1760 | "ethiopic-numeric": true,
1761 | "hebrew": true,
1762 | "japanese-formal": true,
1763 | "japanese-informal": true,
1764 | "simp-chinese-formal": true,
1765 | "simp-chinese-informal": true,
1766 | "syriac": true,
1767 | "tamil": true,
1768 | "trad-chinese-formal": true,
1769 | "trad-chinese-informal": true,
1770 | "upper-armenian": true,
1771 | "arabic-indic": true,
1772 | "binary": true,
1773 | "bengali": true,
1774 | "cambodian": true,
1775 | "khmer": true,
1776 | "devanagari": true,
1777 | "gujarati": true,
1778 | "gurmukhi": true,
1779 | "kannada": true,
1780 | "lower-hexadecimal": true,
1781 | "lao": true,
1782 | "malayalam": true,
1783 | "mongolian": true,
1784 | "myanmar": true,
1785 | "octal": true,
1786 | "oriya": true,
1787 | "persian": true,
1788 | "urdu": true,
1789 | "telugu": true,
1790 | "tibetan": true,
1791 | "upper-hexadecimal": true,
1792 | "afar": true,
1793 | "ethiopic-halehame-aa-et": true,
1794 | "ethiopic-halehame-am-et": true,
1795 | "amharic-abegede": true,
1796 | "ehiopic-abegede-am-et": true,
1797 | "cjk-earthly-branch": true,
1798 | "cjk-heavenly-stem": true,
1799 | "ethiopic": true,
1800 | "ethiopic-abegede": true,
1801 | "ethiopic-abegede-gez": true,
1802 | "hangul-consonant": true,
1803 | "hangul": true,
1804 | "hiragana-iroha": true,
1805 | "hiragana": true,
1806 | "katakana-iroha": true,
1807 | "katakana": true,
1808 | "lower-norwegian": true,
1809 | "oromo": true,
1810 | "ethiopic-halehame-om-et": true,
1811 | "sidama": true,
1812 | "ethiopic-halehame-sid-et": true,
1813 | "somali": true,
1814 | "ethiopic-halehame-so-et": true,
1815 | "tigre": true,
1816 | "ethiopic-halehame-tig": true,
1817 | "tigrinya-er-abegede": true,
1818 | "ethiopic-abegede-ti-er": true,
1819 | "tigrinya-et": true,
1820 | "ethiopic-halehame-ti-et": true,
1821 | "upper-greek": true,
1822 | "asterisks": true,
1823 | "footnotes": true,
1824 | "circled-decimal": true,
1825 | "circled-lower-latin": true,
1826 | "circled-upper-latin": true,
1827 | "dotted-decimal": true,
1828 | "double-circled-decimal": true,
1829 | "filled-circled-decimal": true,
1830 | "parenthesised-decimal": true,
1831 | "parenthesised-lower-latin": true
1832 | },
1833 |
1834 | reportError: function(aMsg) {
1835 | this.mError = aMsg;
1836 | },
1837 |
1838 | consumeError: function() {
1839 | var e = this.mError;
1840 | this.mError = null;
1841 | return e;
1842 | },
1843 |
1844 | currentToken: function() {
1845 | return this.mToken;
1846 | },
1847 |
1848 | getHexValue: function() {
1849 | this.mToken = this.mScanner.nextHexValue();
1850 | return this.mToken;
1851 | },
1852 |
1853 | getToken: function(aSkipWS, aSkipComment) {
1854 | if (this.mLookAhead) {
1855 | this.mToken = this.mLookAhead;
1856 | this.mLookAhead = null;
1857 | return this.mToken;
1858 | }
1859 |
1860 | this.mToken = this.mScanner.nextToken();
1861 | while (this.mToken &&
1862 | ((aSkipWS && this.mToken.isWhiteSpace()) ||
1863 | (aSkipComment && this.mToken.isComment())))
1864 | this.mToken = this.mScanner.nextToken();
1865 | return this.mToken;
1866 | },
1867 |
1868 | lookAhead: function(aSkipWS, aSkipComment) {
1869 | var preservedToken = this.mToken;
1870 | this.mScanner.preserveState();
1871 | var token = this.getToken(aSkipWS, aSkipComment);
1872 | this.mScanner.restoreState();
1873 | this.mToken = preservedToken;
1874 |
1875 | return token;
1876 | },
1877 |
1878 | ungetToken: function() {
1879 | this.mLookAhead = this.mToken;
1880 | },
1881 |
1882 | addUnknownAtRule: function(aSheet, aString) {
1883 | var currentLine = CountLF(this.mScanner.getAlreadyScanned());
1884 | var blocks = [];
1885 | var token = this.getToken(false, false);
1886 | while (token.isNotNull()) {
1887 | aString += token.value;
1888 | if (token.isSymbol(";") && !blocks.length)
1889 | break;
1890 | else if (token.isSymbol("{")
1891 | || token.isSymbol("(")
1892 | || token.isSymbol("[")
1893 | || token.type == "function") {
1894 | blocks.push(token.isFunction() ? "(" : token.value);
1895 | } else if (token.isSymbol("}")
1896 | || token.isSymbol(")")
1897 | || token.isSymbol("]")) {
1898 | if (blocks.length) {
1899 | var ontop = blocks[blocks.length - 1];
1900 | if ((token.isSymbol("}") && ontop == "{")
1901 | || (token.isSymbol(")") && ontop == "(")
1902 | || (token.isSymbol("]") && ontop == "[")) {
1903 | blocks.pop();
1904 | if (!blocks.length && token.isSymbol("}"))
1905 | break;
1906 | }
1907 | }
1908 | }
1909 | token = this.getToken(false, false);
1910 | }
1911 |
1912 | this.addUnknownRule(aSheet, aString, currentLine);
1913 | },
1914 |
1915 | addUnknownRule: function(aSheet, aString, aCurrentLine) {
1916 | var errorMsg = this.consumeError();
1917 | var rule = new jscsspErrorRule(errorMsg);
1918 | rule.currentLine = aCurrentLine;
1919 | rule.parsedCssText = aString;
1920 | rule.parentStyleSheet = aSheet;
1921 | aSheet.cssRules.push(rule);
1922 | },
1923 |
1924 | addWhitespace: function(aSheet, aString) {
1925 | var rule = new jscsspWhitespace();
1926 | rule.parsedCssText = aString;
1927 | rule.parentStyleSheet = aSheet;
1928 | aSheet.cssRules.push(rule);
1929 | },
1930 |
1931 | addComment: function(aSheet, aString) {
1932 | var rule = new jscsspComment();
1933 | rule.parsedCssText = aString;
1934 | rule.parentStyleSheet = aSheet;
1935 | aSheet.cssRules.push(rule);
1936 | },
1937 |
1938 | parseCharsetRule: function(aToken, aSheet) {
1939 | var s = aToken.value;
1940 | var token = this.getToken(false, false);
1941 | s += token.value;
1942 | if (token.isWhiteSpace(" ")) {
1943 | token = this.getToken(false, false);
1944 | s += token.value;
1945 | if (token.isString()) {
1946 | var encoding = token.value;
1947 | token = this.getToken(false, false);
1948 | s += token.value;
1949 | if (token.isSymbol(";")) {
1950 | var rule = new jscsspCharsetRule();
1951 | rule.encoding = encoding;
1952 | rule.parsedCssText = s;
1953 | rule.parentStyleSheet = aSheet;
1954 | aSheet.cssRules.push(rule);
1955 | return true;
1956 | }
1957 | else
1958 | this.reportError(kCHARSET_RULE_MISSING_SEMICOLON);
1959 | }
1960 | else
1961 | this.reportError(kCHARSET_RULE_CHARSET_IS_STRING);
1962 | }
1963 | else
1964 | this.reportError(kCHARSET_RULE_MISSING_WS);
1965 |
1966 | this.addUnknownAtRule(aSheet, s);
1967 | return false;
1968 | },
1969 |
1970 | parseImportRule: function(aToken, aSheet) {
1971 | var currentLine = CountLF(this.mScanner.getAlreadyScanned());
1972 | var s = aToken.value;
1973 | this.preserveState();
1974 | var token = this.getToken(true, true);
1975 | var media = [];
1976 | var href = "";
1977 | if (token.isString()) {
1978 | href = token.value;
1979 | s += " " + href;
1980 | }
1981 | else if (token.isFunction("url(")) {
1982 | token = this.getToken(true, true);
1983 | var urlContent = this.parseURL(token);
1984 | if (urlContent) {
1985 | href = "url(" + urlContent;
1986 | s += " " + href;
1987 | }
1988 | }
1989 | else
1990 | this.reportError(kIMPORT_RULE_MISSING_URL);
1991 |
1992 | if (href) {
1993 | token = this.getToken(true, true);
1994 | while (token.isIdent()) {
1995 | s += " " + token.value;
1996 | media.push(token.value);
1997 | token = this.getToken(true, true);
1998 | if (!token)
1999 | break;
2000 | if (token.isSymbol(",")) {
2001 | s += ",";
2002 | } else if (token.isSymbol(";")) {
2003 | break;
2004 | } else
2005 | break;
2006 | token = this.getToken(true, true);
2007 | }
2008 |
2009 | if (!media.length) {
2010 | media.push("all");
2011 | }
2012 |
2013 | if (token.isSymbol(";")) {
2014 | s += ";"
2015 | this.forgetState();
2016 | var rule = new jscsspImportRule();
2017 | rule.currentLine = currentLine;
2018 | rule.parsedCssText = s;
2019 | rule.href = href;
2020 | rule.media = media;
2021 | rule.parentStyleSheet = aSheet;
2022 | aSheet.cssRules.push(rule);
2023 | return true;
2024 | }
2025 | }
2026 |
2027 | this.restoreState();
2028 | this.addUnknownAtRule(aSheet, "@import");
2029 | return false;
2030 | },
2031 |
2032 | parseVariablesRule: function(token, aSheet) {
2033 | var currentLine = CountLF(this.mScanner.getAlreadyScanned());
2034 | var s = token.value;
2035 | var declarations = [];
2036 | var valid = false;
2037 | this.preserveState();
2038 | token = this.getToken(true, true);
2039 | var media = [];
2040 | var foundMedia = false;
2041 | while (token.isNotNull()) {
2042 | if (token.isIdent()) {
2043 | foundMedia = true;
2044 | s += " " + token.value;
2045 | media.push(token.value);
2046 | token = this.getToken(true, true);
2047 | if (token.isSymbol(",")) {
2048 | s += ",";
2049 | } else {
2050 | if (token.isSymbol("{"))
2051 | this.ungetToken();
2052 | else {
2053 | // error...
2054 | token.type = jscsspToken.NULL_TYPE;
2055 | break;
2056 | }
2057 | }
2058 | } else if (token.isSymbol("{"))
2059 | break;
2060 | else if (foundMedia) {
2061 | token.type = jscsspToken.NULL_TYPE;
2062 | // not a media list
2063 | break;
2064 | }
2065 | token = this.getToken(true, true);
2066 | }
2067 |
2068 | if (token.isSymbol("{")) {
2069 | s += " {";
2070 | token = this.getToken(true, true);
2071 | while (true) {
2072 | if (!token.isNotNull()) {
2073 | valid = true;
2074 | break;
2075 | }
2076 | if (token.isSymbol("}")) {
2077 | s += "}";
2078 | valid = true;
2079 | break;
2080 | } else {
2081 | var d = this.parseDeclaration(token, declarations, true, false, aSheet);
2082 | s += ((d && declarations.length) ? " " : "") + d;
2083 | }
2084 | token = this.getToken(true, false);
2085 | }
2086 | }
2087 | if (valid) {
2088 | this.forgetState();
2089 | var rule = new jscsspVariablesRule();
2090 | rule.currentLine = currentLine;
2091 | rule.parsedCssText = s;
2092 | rule.declarations = declarations;
2093 | rule.media = media;
2094 | rule.parentStyleSheet = aSheet;
2095 | aSheet.cssRules.push(rule)
2096 | return true;
2097 | }
2098 | this.restoreState();
2099 | return false;
2100 | },
2101 |
2102 | parseNamespaceRule: function(aToken, aSheet) {
2103 | var currentLine = CountLF(this.mScanner.getAlreadyScanned());
2104 | var s = aToken.value;
2105 | var valid = false;
2106 | this.preserveState();
2107 | var token = this.getToken(true, true);
2108 | if (token.isNotNull()) {
2109 | var prefix = "";
2110 | var url = "";
2111 | if (token.isIdent()) {
2112 | prefix = token.value;
2113 | s += " " + prefix;
2114 | token = this.getToken(true, true);
2115 | }
2116 | if (token) {
2117 | var foundURL = false;
2118 | if (token.isString()) {
2119 | foundURL = true;
2120 | url = token.value;
2121 | s += " " + url;
2122 | } else if (token.isFunction("url(")) {
2123 | // get a url here...
2124 | token = this.getToken(true, true);
2125 | var urlContent = this.parseURL(token);
2126 | if (urlContent) {
2127 | url += "url(" + urlContent;
2128 | foundURL = true;
2129 | s += " " + urlContent;
2130 | }
2131 | }
2132 | }
2133 | if (foundURL) {
2134 | token = this.getToken(true, true);
2135 | if (token.isSymbol(";")) {
2136 | s += ";";
2137 | this.forgetState();
2138 | var rule = new jscsspNamespaceRule();
2139 | rule.currentLine = currentLine;
2140 | rule.parsedCssText = s;
2141 | rule.prefix = prefix;
2142 | rule.url = url;
2143 | rule.parentStyleSheet = aSheet;
2144 | aSheet.cssRules.push(rule);
2145 | return true;
2146 | }
2147 | }
2148 |
2149 | }
2150 | this.restoreState();
2151 | this.addUnknownAtRule(aSheet, "@namespace");
2152 | return false;
2153 | },
2154 |
2155 | parseFontFaceRule: function(aToken, aSheet) {
2156 | var currentLine = CountLF(this.mScanner.getAlreadyScanned());
2157 | var s = aToken.value;
2158 | var valid = false;
2159 | var descriptors = [];
2160 | this.preserveState();
2161 | var token = this.getToken(true, true);
2162 | if (token.isNotNull()) {
2163 | // expecting block start
2164 | if (token.isSymbol("{")) {
2165 | s += " " + token.value;
2166 | var token = this.getToken(true, false);
2167 | while (true) {
2168 | if (token.isSymbol("}")) {
2169 | s += "}";
2170 | valid = true;
2171 | break;
2172 | } else {
2173 | var d = this.parseDeclaration(token, descriptors, false, false, aSheet);
2174 | s += ((d && descriptors.length) ? " " : "") + d;
2175 | }
2176 | token = this.getToken(true, false);
2177 | }
2178 | }
2179 | }
2180 | if (valid) {
2181 | this.forgetState();
2182 | var rule = new jscsspFontFaceRule();
2183 | rule.currentLine = currentLine;
2184 | rule.parsedCssText = s;
2185 | rule.descriptors = descriptors;
2186 | rule.parentStyleSheet = aSheet;
2187 | aSheet.cssRules.push(rule)
2188 | return true;
2189 | }
2190 | this.restoreState();
2191 | return false;
2192 | },
2193 |
2194 | parsePageRule: function(aToken, aSheet) {
2195 | var currentLine = CountLF(this.mScanner.getAlreadyScanned());
2196 | var s = aToken.value;
2197 | var valid = false;
2198 | var declarations = [];
2199 | this.preserveState();
2200 | var token = this.getToken(true, true);
2201 | var pageSelector = "";
2202 | if (token.isSymbol(":") || token.isIdent()) {
2203 | if (token.isSymbol(":")) {
2204 | pageSelector = ":";
2205 | token = this.getToken(false, false);
2206 | }
2207 | if (token.isIdent()) {
2208 | pageSelector += token.value;
2209 | s += " " + pageSelector;
2210 | token = this.getToken(true, true);
2211 | }
2212 | }
2213 | if (token.isNotNull()) {
2214 | // expecting block start
2215 | if (token.isSymbol("{")) {
2216 | s += " " + token.value;
2217 | var token = this.getToken(true, false);
2218 | while (true) {
2219 | if (token.isSymbol("}")) {
2220 | s += "}";
2221 | valid = true;
2222 | break;
2223 | } else {
2224 | var d = this.parseDeclaration(token, declarations, true, true, aSheet);
2225 | s += ((d && declarations.length) ? " " : "") + d;
2226 | }
2227 | token = this.getToken(true, false);
2228 | }
2229 | }
2230 | }
2231 | if (valid) {
2232 | this.forgetState();
2233 | var rule = new jscsspPageRule();
2234 | rule.currentLine = currentLine;
2235 | rule.parsedCssText = s;
2236 | rule.pageSelector = pageSelector;
2237 | rule.declarations = declarations;
2238 | rule.parentStyleSheet = aSheet;
2239 | aSheet.cssRules.push(rule)
2240 | return true;
2241 | }
2242 | this.restoreState();
2243 | return false;
2244 | },
2245 |
2246 | parseDefaultPropertyValue: function(token, aDecl, aAcceptPriority, descriptor, aSheet) {
2247 | var valueText = "";
2248 | var blocks = [];
2249 | var foundPriority = false;
2250 | var values = [];
2251 | while (token.isNotNull()) {
2252 |
2253 | if ((token.isSymbol(";")
2254 | || token.isSymbol("}")
2255 | || token.isSymbol("!"))
2256 | && !blocks.length) {
2257 | if (token.isSymbol("}"))
2258 | this.ungetToken();
2259 | break;
2260 | }
2261 |
2262 | if (token.isIdent(this.kINHERIT)) {
2263 | if (values.length) {
2264 | return "";
2265 | }
2266 | else {
2267 | valueText = this.kINHERIT;
2268 | var value = new jscsspVariable(kJscsspINHERIT_VALUE, aSheet);
2269 | values.push(value);
2270 | token = this.getToken(true, true);
2271 | break;
2272 | }
2273 | }
2274 | else if (token.isSymbol("{")
2275 | || token.isSymbol("(")
2276 | || token.isSymbol("[")) {
2277 | blocks.push(token.value);
2278 | }
2279 | else if (token.isSymbol("}")
2280 | || token.isSymbol("]")) {
2281 | if (blocks.length) {
2282 | var ontop = blocks[blocks.length - 1];
2283 | if ((token.isSymbol("}") && ontop == "{")
2284 | || (token.isSymbol(")") && ontop == "(")
2285 | || (token.isSymbol("]") && ontop == "[")) {
2286 | blocks.pop();
2287 | }
2288 | }
2289 | }
2290 | // XXX must find a better way to store individual values
2291 | // probably a |values: []| field holding dimensions, percentages
2292 | // functions, idents, numbers and symbols, in that order.
2293 | if (token.isFunction()) {
2294 | if (token.isFunction("var(")) {
2295 | token = this.getToken(true, true);
2296 | if (token.isIdent()) {
2297 | var name = token.value;
2298 | token = this.getToken(true, true);
2299 | if (token.isSymbol(")")) {
2300 | var value = new jscsspVariable(kJscsspVARIABLE_VALUE, aSheet);
2301 | valueText += "var(" + name + ")";
2302 | value.name = name;
2303 | values.push(value);
2304 | }
2305 | else
2306 | return "";
2307 | }
2308 | else
2309 | return "";
2310 | }
2311 | else {
2312 | var fn = token.value;
2313 | token = this.getToken(false, true);
2314 | var arg = this.parseFunctionArgument(token);
2315 | if (arg) {
2316 | valueText += fn + arg;
2317 | var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet);
2318 | value.value = fn + arg;
2319 | values.push(value);
2320 | }
2321 | else
2322 | return "";
2323 | }
2324 | }
2325 | else if (token.isSymbol("#")) {
2326 | var color = this.parseColor(token);
2327 | if (color) {
2328 | valueText += color;
2329 | var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet);
2330 | value.value = color;
2331 | values.push(value);
2332 | }
2333 | else
2334 | return "";
2335 | }
2336 | else if (!token.isWhiteSpace() && !token.isSymbol(",")) {
2337 | var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, aSheet);
2338 | value.value = token.value;
2339 | values.push(value);
2340 | valueText += token.value;
2341 | }
2342 | else
2343 | valueText += token.value;
2344 | token = this.getToken(false, true);
2345 | }
2346 | if (values.length && valueText) {
2347 | this.forgetState();
2348 | aDecl.push(this._createJscsspDeclarationFromValuesArray(descriptor, values, valueText));
2349 | return valueText;
2350 | }
2351 | return "";
2352 | },
2353 |
2354 | parseMarginOrPaddingShorthand: function(token, aDecl, aAcceptPriority, aProperty)
2355 | {
2356 | var top = null;
2357 | var bottom = null;
2358 | var left = null;
2359 | var right = null;
2360 |
2361 | var values = [];
2362 | while (true) {
2363 |
2364 | if (!token.isNotNull())
2365 | break;
2366 |
2367 | if (token.isSymbol(";")
2368 | || (aAcceptPriority && token.isSymbol("!"))
2369 | || token.isSymbol("}")) {
2370 | if (token.isSymbol("}"))
2371 | this.ungetToken();
2372 | break;
2373 | }
2374 |
2375 | else if (!values.length && token.isIdent(this.kINHERIT)) {
2376 | values.push(token.value);
2377 | token = this.getToken(true, true);
2378 | break;
2379 | }
2380 |
2381 | else if (token.isDimension()
2382 | || token.isNumber("0")
2383 | || token.isPercentage()
2384 | || token.isIdent("auto")) {
2385 | values.push(token.value);
2386 | }
2387 | else
2388 | return "";
2389 |
2390 | token = this.getToken(true, true);
2391 | }
2392 |
2393 | var count = values.length;
2394 | switch (count) {
2395 | case 1:
2396 | top = values[0];
2397 | bottom = top;
2398 | left = top;
2399 | right = top;
2400 | break;
2401 | case 2:
2402 | top = values[0];
2403 | bottom = top;
2404 | left = values[1];
2405 | right = left;
2406 | break;
2407 | case 3:
2408 | top = values[0];
2409 | left = values[1];
2410 | right = left;
2411 | bottom = values[2];
2412 | break;
2413 | case 4:
2414 | top = values[0];
2415 | right = values[1];
2416 | bottom = values[2];
2417 | left = values[3];
2418 | break;
2419 | default:
2420 | return "";
2421 | }
2422 | this.forgetState();
2423 | aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-top", top));
2424 | aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-right", right));
2425 | aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-bottom", bottom));
2426 | aDecl.push(this._createJscsspDeclarationFromValue(aProperty + "-left", left));
2427 | return top + " " + right + " " + bottom + " " + left;
2428 | },
2429 |
2430 | parseBorderColorShorthand: function(token, aDecl, aAcceptPriority)
2431 | {
2432 | var top = null;
2433 | var bottom = null;
2434 | var left = null;
2435 | var right = null;
2436 |
2437 | var values = [];
2438 | while (true) {
2439 |
2440 | if (!token.isNotNull())
2441 | break;
2442 |
2443 | if (token.isSymbol(";")
2444 | || (aAcceptPriority && token.isSymbol("!"))
2445 | || token.isSymbol("}")) {
2446 | if (token.isSymbol("}"))
2447 | this.ungetToken();
2448 | break;
2449 | }
2450 |
2451 | else if (!values.length && token.isIdent(this.kINHERIT)) {
2452 | values.push(token.value);
2453 | token = this.getToken(true, true);
2454 | break;
2455 | }
2456 |
2457 | else {
2458 | var color = this.parseColor(token);
2459 | if (color)
2460 | values.push(color);
2461 | else
2462 | return "";
2463 | }
2464 |
2465 | token = this.getToken(true, true);
2466 | }
2467 |
2468 | var count = values.length;
2469 | switch (count) {
2470 | case 1:
2471 | top = values[0];
2472 | bottom = top;
2473 | left = top;
2474 | right = top;
2475 | break;
2476 | case 2:
2477 | top = values[0];
2478 | bottom = top;
2479 | left = values[1];
2480 | right = left;
2481 | break;
2482 | case 3:
2483 | top = values[0];
2484 | left = values[1];
2485 | right = left;
2486 | bottom = values[2];
2487 | break;
2488 | case 4:
2489 | top = values[0];
2490 | right = values[1];
2491 | bottom = values[2];
2492 | left = values[3];
2493 | break;
2494 | default:
2495 | return "";
2496 | }
2497 | this.forgetState();
2498 | aDecl.push(this._createJscsspDeclarationFromValue("border-top-color", top));
2499 | aDecl.push(this._createJscsspDeclarationFromValue("border-right-color", right));
2500 | aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-color", bottom));
2501 | aDecl.push(this._createJscsspDeclarationFromValue("border-left-color", left));
2502 | return top + " " + right + " " + bottom + " " + left;
2503 | },
2504 |
2505 | parseCueShorthand: function(token, declarations, aAcceptPriority)
2506 | {
2507 | var before = "";
2508 | var after = "";
2509 |
2510 | var values = [];
2511 | var values = [];
2512 | while (true) {
2513 |
2514 | if (!token.isNotNull())
2515 | break;
2516 |
2517 | if (token.isSymbol(";")
2518 | || (aAcceptPriority && token.isSymbol("!"))
2519 | || token.isSymbol("}")) {
2520 | if (token.isSymbol("}"))
2521 | this.ungetToken();
2522 | break;
2523 | }
2524 |
2525 | else if (!values.length && token.isIdent(this.kINHERIT)) {
2526 | values.push(token.value);
2527 | }
2528 |
2529 | else if (token.isIdent("none"))
2530 | values.push(token.value);
2531 |
2532 | else if (token.isFunction("url(")) {
2533 | var token = this.getToken(true, true);
2534 | var urlContent = this.parseURL(token);
2535 | if (urlContent)
2536 | values.push("url(" + urlContent);
2537 | else
2538 | return "";
2539 | }
2540 | else
2541 | return "";
2542 |
2543 | token = this.getToken(true, true);
2544 | }
2545 |
2546 | var count = values.length;
2547 | switch (count) {
2548 | case 1:
2549 | before = values[0];
2550 | after = before;
2551 | break;
2552 | case 2:
2553 | before = values[0];
2554 | after = values[1];
2555 | break;
2556 | default:
2557 | return "";
2558 | }
2559 | this.forgetState();
2560 | aDecl.push(this._createJscsspDeclarationFromValue("cue-before", before));
2561 | aDecl.push(this._createJscsspDeclarationFromValue("cue-after", after));
2562 | return before + " " + after;
2563 | },
2564 |
2565 | parsePauseShorthand: function(token, declarations, aAcceptPriority)
2566 | {
2567 | var before = "";
2568 | var after = "";
2569 |
2570 | var values = [];
2571 | var values = [];
2572 | while (true) {
2573 |
2574 | if (!token.isNotNull())
2575 | break;
2576 |
2577 | if (token.isSymbol(";")
2578 | || (aAcceptPriority && token.isSymbol("!"))
2579 | || token.isSymbol("}")) {
2580 | if (token.isSymbol("}"))
2581 | this.ungetToken();
2582 | break;
2583 | }
2584 |
2585 | else if (!values.length && token.isIdent(this.kINHERIT)) {
2586 | values.push(token.value);
2587 | }
2588 |
2589 | else if (token.isDimensionOfUnit("ms")
2590 | || token.isDimensionOfUnit("s")
2591 | || token.isPercentage()
2592 | || token.isNumber("0"))
2593 | values.push(token.value);
2594 | else
2595 | return "";
2596 |
2597 | token = this.getToken(true, true);
2598 | }
2599 |
2600 | var count = values.length;
2601 | switch (count) {
2602 | case 1:
2603 | before = values[0];
2604 | after = before;
2605 | break;
2606 | case 2:
2607 | before = values[0];
2608 | after = values[1];
2609 | break;
2610 | default:
2611 | return "";
2612 | }
2613 | this.forgetState();
2614 | aDecl.push(this._createJscsspDeclarationFromValue("pause-before", before));
2615 | aDecl.push(this._createJscsspDeclarationFromValue("pause-after", after));
2616 | return before + " " + after;
2617 | },
2618 |
2619 | parseBorderWidthShorthand: function(token, aDecl, aAcceptPriority)
2620 | {
2621 | var top = null;
2622 | var bottom = null;
2623 | var left = null;
2624 | var right = null;
2625 |
2626 | var values = [];
2627 | while (true) {
2628 |
2629 | if (!token.isNotNull())
2630 | break;
2631 |
2632 | if (token.isSymbol(";")
2633 | || (aAcceptPriority && token.isSymbol("!"))
2634 | || token.isSymbol("}")) {
2635 | if (token.isSymbol("}"))
2636 | this.ungetToken();
2637 | break;
2638 | }
2639 |
2640 | else if (!values.length && token.isIdent(this.kINHERIT)) {
2641 | values.push(token.value);
2642 | }
2643 |
2644 | else if (token.isDimension()
2645 | || token.isNumber("0")
2646 | || (token.isIdent() && token.value in this.kBORDER_WIDTH_NAMES)) {
2647 | values.push(token.value);
2648 | }
2649 | else
2650 | return "";
2651 |
2652 | token = this.getToken(true, true);
2653 | }
2654 |
2655 | var count = values.length;
2656 | switch (count) {
2657 | case 1:
2658 | top = values[0];
2659 | bottom = top;
2660 | left = top;
2661 | right = top;
2662 | break;
2663 | case 2:
2664 | top = values[0];
2665 | bottom = top;
2666 | left = values[1];
2667 | right = left;
2668 | break;
2669 | case 3:
2670 | top = values[0];
2671 | left = values[1];
2672 | right = left;
2673 | bottom = values[2];
2674 | break;
2675 | case 4:
2676 | top = values[0];
2677 | right = values[1];
2678 | bottom = values[2];
2679 | left = values[3];
2680 | break;
2681 | default:
2682 | return "";
2683 | }
2684 | this.forgetState();
2685 | aDecl.push(this._createJscsspDeclarationFromValue("border-top-width", top));
2686 | aDecl.push(this._createJscsspDeclarationFromValue("border-right-width", right));
2687 | aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-width", bottom));
2688 | aDecl.push(this._createJscsspDeclarationFromValue("border-left-width", left));
2689 | return top + " " + right + " " + bottom + " " + left;
2690 | },
2691 |
2692 | parseBorderStyleShorthand: function(token, aDecl, aAcceptPriority)
2693 | {
2694 | var top = null;
2695 | var bottom = null;
2696 | var left = null;
2697 | var right = null;
2698 |
2699 | var values = [];
2700 | while (true) {
2701 |
2702 | if (!token.isNotNull())
2703 | break;
2704 |
2705 | if (token.isSymbol(";")
2706 | || (aAcceptPriority && token.isSymbol("!"))
2707 | || token.isSymbol("}")) {
2708 | if (token.isSymbol("}"))
2709 | this.ungetToken();
2710 | break;
2711 | }
2712 |
2713 | else if (!values.length && token.isIdent(this.kINHERIT)) {
2714 | values.push(token.value);
2715 | }
2716 |
2717 | else if (token.isIdent() && token.value in this.kBORDER_STYLE_NAMES) {
2718 | values.push(token.value);
2719 | }
2720 | else
2721 | return "";
2722 |
2723 | token = this.getToken(true, true);
2724 | }
2725 |
2726 | var count = values.length;
2727 | switch (count) {
2728 | case 1:
2729 | top = values[0];
2730 | bottom = top;
2731 | left = top;
2732 | right = top;
2733 | break;
2734 | case 2:
2735 | top = values[0];
2736 | bottom = top;
2737 | left = values[1];
2738 | right = left;
2739 | break;
2740 | case 3:
2741 | top = values[0];
2742 | left = values[1];
2743 | right = left;
2744 | bottom = values[2];
2745 | break;
2746 | case 4:
2747 | top = values[0];
2748 | right = values[1];
2749 | bottom = values[2];
2750 | left = values[3];
2751 | break;
2752 | default:
2753 | return "";
2754 | }
2755 | this.forgetState();
2756 | aDecl.push(this._createJscsspDeclarationFromValue("border-top-style", top));
2757 | aDecl.push(this._createJscsspDeclarationFromValue("border-right-style", right));
2758 | aDecl.push(this._createJscsspDeclarationFromValue("border-bottom-style", bottom));
2759 | aDecl.push(this._createJscsspDeclarationFromValue("border-left-style", left));
2760 | return top + " " + right + " " + bottom + " " + left;
2761 | },
2762 |
2763 | parseBorderEdgeOrOutlineShorthand: function(token, aDecl, aAcceptPriority, aProperty)
2764 | {
2765 | var bWidth = null;
2766 | var bStyle = null;
2767 | var bColor = null;
2768 |
2769 | while (true) {
2770 | if (!token.isNotNull())
2771 | break;
2772 |
2773 | if (token.isSymbol(";")
2774 | || (aAcceptPriority && token.isSymbol("!"))
2775 | || token.isSymbol("}")) {
2776 | if (token.isSymbol("}"))
2777 | this.ungetToken();
2778 | break;
2779 | }
2780 |
2781 | else if (!bWidth && !bStyle && !bColor
2782 | && token.isIdent(this.kINHERIT)) {
2783 | bWidth = this.kINHERIT;
2784 | bStyle = this.kINHERIT;
2785 | bColor = this.kINHERIT;
2786 | }
2787 |
2788 | else if (!bWidth &&
2789 | (token.isDimension()
2790 | || (token.isIdent() && token.value in this.kBORDER_WIDTH_NAMES)
2791 | || token.isNumber("0"))) {
2792 | bWidth = token.value;
2793 | }
2794 |
2795 | else if (!bStyle &&
2796 | (token.isIdent() && token.value in this.kBORDER_STYLE_NAMES)) {
2797 | bStyle = token.value;
2798 | }
2799 |
2800 | else {
2801 | var color = (aProperty == "outline" && token.isIdent("invert"))
2802 | ? "invert" : this.parseColor(token);
2803 | if (!bColor && color)
2804 | bColor = color;
2805 | else
2806 | return "";
2807 | }
2808 | token = this.getToken(true, true);
2809 | }
2810 |
2811 | // create the declarations
2812 | this.forgetState();
2813 | bWidth = bWidth ? bWidth : "medium";
2814 | bStyle = bStyle ? bStyle : "none";
2815 | bColor = bColor ? bColor : "-moz-initial";
2816 |
2817 | function addPropertyToDecl(aSelf, aDecl, property, w, s, c) {
2818 | aDecl.push(aSelf._createJscsspDeclarationFromValue(property + "-width", w));
2819 | aDecl.push(aSelf._createJscsspDeclarationFromValue(property + "-style", s));
2820 | aDecl.push(aSelf._createJscsspDeclarationFromValue(property + "-color", c));
2821 | }
2822 |
2823 | if (aProperty == "border") {
2824 | addPropertyToDecl(this, aDecl, "border-top", bWidth, bStyle, bColor);
2825 | addPropertyToDecl(this, aDecl, "border-right", bWidth, bStyle, bColor);
2826 | addPropertyToDecl(this, aDecl, "border-bottom", bWidth, bStyle, bColor);
2827 | addPropertyToDecl(this, aDecl, "border-left", bWidth, bStyle, bColor);
2828 | }
2829 | else
2830 | addPropertyToDecl(this, aDecl, aProperty, bWidth, bStyle, bColor);
2831 | return bWidth + " " + bStyle + " " + bColor;
2832 | },
2833 |
2834 | parseBackgroundShorthand: function(token, aDecl, aAcceptPriority)
2835 | {
2836 | var kHPos = {"left": true, "right": true };
2837 | var kVPos = {"top": true, "bottom": true };
2838 | var kPos = {"left": true, "right": true, "top": true, "bottom": true, "center": true};
2839 |
2840 | var bgColor = null;
2841 | var bgRepeat = null;
2842 | var bgAttachment = null;
2843 | var bgImage = null;
2844 | var bgPosition = null;
2845 |
2846 | while (true) {
2847 |
2848 | if (!token.isNotNull())
2849 | break;
2850 |
2851 | if (token.isSymbol(";")
2852 | || (aAcceptPriority && token.isSymbol("!"))
2853 | || token.isSymbol("}")) {
2854 | if (token.isSymbol("}"))
2855 | this.ungetToken();
2856 | break;
2857 | }
2858 |
2859 | else if (!bgColor && !bgRepeat && !bgAttachment && !bgImage && !bgPosition
2860 | && token.isIdent(this.kINHERIT)) {
2861 | bgColor = this.kINHERIT;
2862 | bgRepeat = this.kINHERIT;
2863 | bgAttachment = this.kINHERIT;
2864 | bgImage = this.kINHERIT;
2865 | bgPosition = this.kINHERIT;
2866 | }
2867 |
2868 | else {
2869 | if (!bgAttachment &&
2870 | (token.isIdent("scroll")
2871 | || token.isIdent("fixed"))) {
2872 | bgAttachment = token.value;
2873 | }
2874 |
2875 | else if (!bgPosition &&
2876 | ((token.isIdent() && token.value in kPos)
2877 | || token.isDimension()
2878 | || token.isNumber("0")
2879 | || token.isPercentage())) {
2880 | bgPosition = token.value;
2881 | token = this.getToken(true, true);
2882 | if (token.isDimension() || token.isNumber("0") || token.isPercentage()) {
2883 | bgPosition += " " + token.value;
2884 | }
2885 | else if (token.isIdent() && token.value in kPos) {
2886 | if ((bgPosition in kHPos && token.value in kHPos) ||
2887 | (bgPosition in kVPos && token.value in kVPos))
2888 | return "";
2889 | bgPosition += " " + token.value;
2890 | }
2891 | else {
2892 | this.ungetToken();
2893 | bgPosition += " center";
2894 | }
2895 | }
2896 |
2897 | else if (!bgRepeat &&
2898 | (token.isIdent("repeat")
2899 | || token.isIdent("repeat-x")
2900 | || token.isIdent("repeat-y")
2901 | || token.isIdent("no-repeat"))) {
2902 | bgRepeat = token.value;
2903 | }
2904 |
2905 | else if (!bgImage &&
2906 | (token.isFunction("url(")
2907 | || token.isIdent("none"))) {
2908 | bgImage = token.value;
2909 | if (token.isFunction("url(")) {
2910 | token = this.getToken(true, true);
2911 | var url = this.parseURL(token); // TODO
2912 | if (url)
2913 | bgImage += url;
2914 | else
2915 | return "";
2916 | }
2917 | }
2918 |
2919 | else if (!bgImage &&
2920 | (token.isFunction("-moz-linear-gradient(")
2921 | || token.isFunction("-moz-radial-gradient(")
2922 | || token.isFunction("-moz-repeating-linear-gradient(")
2923 | || token.isFunction("-moz-repeating-radial-gradient("))) {
2924 | var gradient = CssInspector.parseGradient(this, token);
2925 | if (gradient)
2926 | bgImage = CssInspector.serializeGradient(gradient);
2927 | else
2928 | return "";
2929 | }
2930 |
2931 | else {
2932 | var color = this.parseColor(token);
2933 | if (!bgColor && color)
2934 | bgColor = color;
2935 | else
2936 | return "";
2937 | }
2938 |
2939 | }
2940 |
2941 | token = this.getToken(true, true);
2942 | }
2943 |
2944 | // create the declarations
2945 | this.forgetState();
2946 | bgColor = bgColor ? bgColor : "transparent";
2947 | bgImage = bgImage ? bgImage : "none";
2948 | bgRepeat = bgRepeat ? bgRepeat : "repeat";
2949 | bgAttachment = bgAttachment ? bgAttachment : "scroll";
2950 | bgPosition = bgPosition ? bgPosition : "top left";
2951 |
2952 | aDecl.push(this._createJscsspDeclarationFromValue("background-color", bgColor));
2953 | aDecl.push(this._createJscsspDeclarationFromValue("background-image", bgImage));
2954 | aDecl.push(this._createJscsspDeclarationFromValue("background-repeat", bgRepeat));
2955 | aDecl.push(this._createJscsspDeclarationFromValue("background-attachment", bgAttachment));
2956 | aDecl.push(this._createJscsspDeclarationFromValue("background-position", bgPosition));
2957 | return bgColor + " " + bgImage + " " + bgRepeat + " " + bgAttachment + " " + bgPosition;
2958 | },
2959 |
2960 | parseListStyleShorthand: function(token, aDecl, aAcceptPriority)
2961 | {
2962 | var kPosition = { "inside": true, "outside": true };
2963 |
2964 | var lType = null;
2965 | var lPosition = null;
2966 | var lImage = null;
2967 |
2968 | while (true) {
2969 |
2970 | if (!token.isNotNull())
2971 | break;
2972 |
2973 | if (token.isSymbol(";")
2974 | || (aAcceptPriority && token.isSymbol("!"))
2975 | || token.isSymbol("}")) {
2976 | if (token.isSymbol("}"))
2977 | this.ungetToken();
2978 | break;
2979 | }
2980 |
2981 | else if (!lType && !lPosition && ! lImage
2982 | && token.isIdent(this.kINHERIT)) {
2983 | lType = this.kINHERIT;
2984 | lPosition = this.kINHERIT;
2985 | lImage = this.kINHERIT;
2986 | }
2987 |
2988 | else if (!lType &&
2989 | (token.isIdent() && token.value in this.kLIST_STYLE_TYPE_NAMES)) {
2990 | lType = token.value;
2991 | }
2992 |
2993 | else if (!lPosition &&
2994 | (token.isIdent() && token.value in kPosition)) {
2995 | lPosition = token.value;
2996 | }
2997 |
2998 | else if (!lImage && token.isFunction("url")) {
2999 | token = this.getToken(true, true);
3000 | var urlContent = this.parseURL(token);
3001 | if (urlContent) {
3002 | lImage = "url(" + urlContent;
3003 | }
3004 | else
3005 | return "";
3006 | }
3007 | else if (!token.isIdent("none"))
3008 | return "";
3009 |
3010 | token = this.getToken(true, true);
3011 | }
3012 |
3013 | // create the declarations
3014 | this.forgetState();
3015 | lType = lType ? lType : "none";
3016 | lImage = lImage ? lImage : "none";
3017 | lPosition = lPosition ? lPosition : "outside";
3018 |
3019 | aDecl.push(this._createJscsspDeclarationFromValue("list-style-type", lType));
3020 | aDecl.push(this._createJscsspDeclarationFromValue("list-style-position", lPosition));
3021 | aDecl.push(this._createJscsspDeclarationFromValue("list-style-image", lImage));
3022 | return lType + " " + lPosition + " " + lImage;
3023 | },
3024 |
3025 | parseFontShorthand: function(token, aDecl, aAcceptPriority)
3026 | {
3027 | var kStyle = {"italic": true, "oblique": true };
3028 | var kVariant = {"small-caps": true };
3029 | var kWeight = { "bold": true, "bolder": true, "lighter": true,
3030 | "100": true, "200": true, "300": true, "400": true,
3031 | "500": true, "600": true, "700": true, "800": true,
3032 | "900": true };
3033 | var kSize = { "xx-small": true, "x-small": true, "small": true, "medium": true,
3034 | "large": true, "x-large": true, "xx-large": true,
3035 | "larger": true, "smaller": true };
3036 | var kValues = { "caption": true, "icon": true, "menu": true, "message-box": true, "small-caption": true, "status-bar": true };
3037 | var kFamily = { "serif": true, "sans-serif": true, "cursive": true, "fantasy": true, "monospace": true };
3038 |
3039 | var fStyle = null;
3040 | var fVariant = null;
3041 | var fWeight = null;
3042 | var fSize = null;
3043 | var fLineHeight = null;
3044 | var fFamily = "";
3045 | var fSystem = null;
3046 | var fFamilyValues = [];
3047 |
3048 | var normalCount = 0;
3049 | while (true) {
3050 |
3051 | if (!token.isNotNull())
3052 | break;
3053 |
3054 | if (token.isSymbol(";")
3055 | || (aAcceptPriority && token.isSymbol("!"))
3056 | || token.isSymbol("}")) {
3057 | if (token.isSymbol("}"))
3058 | this.ungetToken();
3059 | break;
3060 | }
3061 |
3062 | else if (!fStyle && !fVariant && !fWeight
3063 | && !fSize && !fLineHeight && !fFamily
3064 | && !fSystem
3065 | && token.isIdent(this.kINHERIT)) {
3066 | fStyle = this.kINHERIT;
3067 | fVariant = this.kINHERIT;
3068 | fWeight = this.kINHERIT;
3069 | fSize = this.kINHERIT;
3070 | fLineHeight = this.kINHERIT;
3071 | fFamily = this.kINHERIT;
3072 | fSystem = this.kINHERIT;
3073 | }
3074 |
3075 | else {
3076 | if (!fSystem && (token.isIdent() && token.value in kValues)) {
3077 | fSystem = token.value;
3078 | break;
3079 | }
3080 |
3081 | else {
3082 | if (!fStyle
3083 | && token.isIdent()
3084 | && (token.value in kStyle)) {
3085 | fStyle = token.value;
3086 | }
3087 |
3088 | else if (!fVariant
3089 | && token.isIdent()
3090 | && (token.value in kVariant)) {
3091 | fVariant = token.value;
3092 | }
3093 |
3094 | else if (!fWeight
3095 | && (token.isIdent() || token.isNumber())
3096 | && (token.value in kWeight)) {
3097 | fWeight = token.value;
3098 | }
3099 |
3100 | else if (!fSize
3101 | && ((token.isIdent() && (token.value in kSize))
3102 | || token.isDimension()
3103 | || token.isPercentage())) {
3104 | fSize = token.value;
3105 | var token = this.getToken(false, false);
3106 | if (token.isSymbol("/")) {
3107 | token = this.getToken(false, false);
3108 | if (!fLineHeight &&
3109 | (token.isDimension() || token.isNumber() || token.isPercentage())) {
3110 | fLineHeight = token.value;
3111 | }
3112 | else
3113 | return "";
3114 | }
3115 | else
3116 | this.ungetToken();
3117 | }
3118 |
3119 | else if (token.isIdent("normal")) {
3120 | normalCount++;
3121 | if (normalCount > 3)
3122 | return "";
3123 | }
3124 |
3125 | else if (!fFamily && // *MUST* be last to be tested here
3126 | (token.isString()
3127 | || token.isIdent())) {
3128 | var lastWasComma = false;
3129 | while (true) {
3130 | if (!token.isNotNull())
3131 | break;
3132 | else if (token.isSymbol(";")
3133 | || (aAcceptPriority && token.isSymbol("!"))
3134 | || token.isSymbol("}")) {
3135 | this.ungetToken();
3136 | break;
3137 | }
3138 | else if (token.isIdent() && token.value in kFamily) {
3139 | var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, null);
3140 | value.value = token.value;
3141 | fFamilyValues.push(value);
3142 | fFamily += token.value;
3143 | break;
3144 | }
3145 | else if (token.isString() || token.isIdent()) {
3146 | var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, null);
3147 | value.value = token.value;
3148 | fFamilyValues.push(value);
3149 | fFamily += token.value;
3150 | lastWasComma = false;
3151 | }
3152 | else if (!lastWasComma && token.isSymbol(",")) {
3153 | fFamily += ", ";
3154 | lastWasComma = true;
3155 | }
3156 | else
3157 | return "";
3158 | token = this.getToken(true, true);
3159 | }
3160 | }
3161 |
3162 | else {
3163 | return "";
3164 | }
3165 | }
3166 |
3167 | }
3168 |
3169 | token = this.getToken(true, true);
3170 | }
3171 |
3172 | // create the declarations
3173 | this.forgetState();
3174 | if (fSystem) {
3175 | aDecl.push(this._createJscsspDeclarationFromValue("font", fSystem));
3176 | return fSystem;
3177 | }
3178 | fStyle = fStyle ? fStyle : "normal";
3179 | fVariant = fVariant ? fVariant : "normal";
3180 | fWeight = fWeight ? fWeight : "normal";
3181 | fSize = fSize ? fSize : "medium";
3182 | fLineHeight = fLineHeight ? fLineHeight : "normal";
3183 | fFamily = fFamily ? fFamily : "-moz-initial";
3184 |
3185 | aDecl.push(this._createJscsspDeclarationFromValue("font-style", fStyle));
3186 | aDecl.push(this._createJscsspDeclarationFromValue("font-variant", fVariant));
3187 | aDecl.push(this._createJscsspDeclarationFromValue("font-weight", fWeight));
3188 | aDecl.push(this._createJscsspDeclarationFromValue("font-size", fSize));
3189 | aDecl.push(this._createJscsspDeclarationFromValue("line-height", fLineHeight));
3190 | aDecl.push(this._createJscsspDeclarationFromValuesArray("font-family", fFamilyValues, fFamily));
3191 | return fStyle + " " + fVariant + " " + fWeight + " " + fSize + "/" + fLineHeight + " " + fFamily;
3192 | },
3193 |
3194 | _createJscsspDeclaration: function(property, value)
3195 | {
3196 | var decl = new jscsspDeclaration();
3197 | decl.property = property;
3198 | decl.value = this.trim11(value);
3199 | decl.parsedCssText = property + ": " + value + ";";
3200 | return decl;
3201 | },
3202 |
3203 | _createJscsspDeclarationFromValue: function(property, valueText)
3204 | {
3205 | var decl = new jscsspDeclaration();
3206 | decl.property = property;
3207 | var value = new jscsspVariable(kJscsspPRIMITIVE_VALUE, null);
3208 | value.value = valueText;
3209 | decl.values = [value];
3210 | decl.valueText = valueText;
3211 | decl.parsedCssText = property + ": " + valueText + ";";
3212 | return decl;
3213 | },
3214 |
3215 | _createJscsspDeclarationFromValuesArray: function(property, values, valueText)
3216 | {
3217 | var decl = new jscsspDeclaration();
3218 | decl.property = property;
3219 | decl.values = values;
3220 | decl.valueText = valueText;
3221 | decl.parsedCssText = property + ": " + valueText + ";";
3222 | return decl;
3223 | },
3224 |
3225 | parseURL: function(token)
3226 | {
3227 | var value = "";
3228 | if (token.isString())
3229 | {
3230 | value += token.value;
3231 | token = this.getToken(true, true);
3232 | }
3233 | else
3234 | while (true)
3235 | {
3236 | if (!token.isNotNull()) {
3237 | this.reportError(kURL_EOF);
3238 | return "";
3239 | }
3240 | if (token.isWhiteSpace()) {
3241 | nextToken = this.lookAhead(true, true);
3242 | // if next token is not a closing parenthesis, that's an error
3243 | if (!nextToken.isSymbol(")")) {
3244 | this.reportError(kURL_WS_INSIDE);
3245 | token = this.currentToken();
3246 | break;
3247 | }
3248 | }
3249 | if (token.isSymbol(")")) {
3250 | break;
3251 | }
3252 | value += token.value;
3253 | token = this.getToken(false, false);
3254 | }
3255 |
3256 | if (token.isSymbol(")")) {
3257 | return value + ")";
3258 | }
3259 | return "";
3260 | },
3261 |
3262 | parseFunctionArgument: function(token)
3263 | {
3264 | var value = "";
3265 | if (token.isString())
3266 | {
3267 | value += token.value;
3268 | token = this.getToken(true, true);
3269 | }
3270 | else {
3271 | var parenthesis = 1;
3272 | while (true)
3273 | {
3274 | if (!token.isNotNull())
3275 | return "";
3276 | if (token.isFunction() || token.isSymbol("("))
3277 | parenthesis++;
3278 | if (token.isSymbol(")")) {
3279 | parenthesis--;
3280 | if (!parenthesis)
3281 | break;
3282 | }
3283 | value += token.value;
3284 | token = this.getToken(false, false);
3285 | }
3286 | }
3287 |
3288 | if (token.isSymbol(")"))
3289 | return value + ")";
3290 | return "";
3291 | },
3292 |
3293 | parseColor: function(token)
3294 | {
3295 | var color = "";
3296 | if (token.isFunction("rgb(")
3297 | || token.isFunction("rgba(")) {
3298 | color = token.value;
3299 | var isRgba = token.isFunction("rgba(")
3300 | token = this.getToken(true, true);
3301 | if (!token.isNumber() && !token.isPercentage())
3302 | return "";
3303 | color += token.value;
3304 | token = this.getToken(true, true);
3305 | if (!token.isSymbol(","))
3306 | return "";
3307 | color += ", ";
3308 |
3309 | token = this.getToken(true, true);
3310 | if (!token.isNumber() && !token.isPercentage())
3311 | return "";
3312 | color += token.value;
3313 | token = this.getToken(true, true);
3314 | if (!token.isSymbol(","))
3315 | return "";
3316 | color += ", ";
3317 |
3318 | token = this.getToken(true, true);
3319 | if (!token.isNumber() && !token.isPercentage())
3320 | return "";
3321 | color += token.value;
3322 |
3323 | if (isRgba) {
3324 | token = this.getToken(true, true);
3325 | if (!token.isSymbol(","))
3326 | return "";
3327 | color += ", ";
3328 |
3329 | token = this.getToken(true, true);
3330 | if (!token.isNumber())
3331 | return "";
3332 | color += token.value;
3333 | }
3334 |
3335 | token = this.getToken(true, true);
3336 | if (!token.isSymbol(")"))
3337 | return "";
3338 | color += token.value;
3339 | }
3340 |
3341 | else if (token.isFunction("hsl(")
3342 | || token.isFunction("hsla(")) {
3343 | color = token.value;
3344 | var isHsla = token.isFunction("hsla(")
3345 | token = this.getToken(true, true);
3346 | if (!token.isNumber())
3347 | return "";
3348 | color += token.value;
3349 | token = this.getToken(true, true);
3350 | if (!token.isSymbol(","))
3351 | return "";
3352 | color += ", ";
3353 |
3354 | token = this.getToken(true, true);
3355 | if (!token.isPercentage())
3356 | return "";
3357 | color += token.value;
3358 | token = this.getToken(true, true);
3359 | if (!token.isSymbol(","))
3360 | return "";
3361 | color += ", ";
3362 |
3363 | token = this.getToken(true, true);
3364 | if (!token.isPercentage())
3365 | return "";
3366 | color += token.value;
3367 |
3368 | if (isHsla) {
3369 | token = this.getToken(true, true);
3370 | if (!token.isSymbol(","))
3371 | return "";
3372 | color += ", ";
3373 |
3374 | token = this.getToken(true, true);
3375 | if (!token.isNumber())
3376 | return "";
3377 | color += token.value;
3378 | }
3379 |
3380 | token = this.getToken(true, true);
3381 | if (!token.isSymbol(")"))
3382 | return "";
3383 | color += token.value;
3384 | }
3385 |
3386 | else if (token.isIdent()
3387 | && (token.value in this.kCOLOR_NAMES))
3388 | color = token.value;
3389 |
3390 | else if (token.isSymbol("#")) {
3391 | token = this.getHexValue();
3392 | if (!token.isHex())
3393 | return "";
3394 | var length = token.value.length;
3395 | if (length != 3 && length != 6)
3396 | return "";
3397 | if (token.value.match( /[a-fA-F0-9]/g ).length != length)
3398 | return "";
3399 | color = "#" + token.value;
3400 | }
3401 | return color;
3402 | },
3403 |
3404 | parseDeclaration: function(aToken, aDecl, aAcceptPriority, aExpandShorthands, aSheet) {
3405 | this.preserveState();
3406 | var blocks = [];
3407 | if (aToken.isIdent()) {
3408 | var descriptor = aToken.value.toLowerCase();
3409 | var token = this.getToken(true, true);
3410 | if (token.isSymbol(":")) {
3411 | var token = this.getToken(true, true);
3412 |
3413 | var value = "";
3414 | var declarations = [];
3415 | if (aExpandShorthands)
3416 | switch (descriptor) {
3417 | case "background":
3418 | value = this.parseBackgroundShorthand(token, declarations, aAcceptPriority);
3419 | break;
3420 | case "margin":
3421 | case "padding":
3422 | value = this.parseMarginOrPaddingShorthand(token, declarations, aAcceptPriority, descriptor);
3423 | break;
3424 | case "border-color":
3425 | value = this.parseBorderColorShorthand(token, declarations, aAcceptPriority);
3426 | break;
3427 | case "border-style":
3428 | value = this.parseBorderStyleShorthand(token, declarations, aAcceptPriority);
3429 | break;
3430 | case "border-width":
3431 | value = this.parseBorderWidthShorthand(token, declarations, aAcceptPriority);
3432 | break;
3433 | case "border-top":
3434 | case "border-right":
3435 | case "border-bottom":
3436 | case "border-left":
3437 | case "border":
3438 | case "outline":
3439 | value = this.parseBorderEdgeOrOutlineShorthand(token, declarations, aAcceptPriority, descriptor);
3440 | break;
3441 | case "cue":
3442 | value = this.parseCueShorthand(token, declarations, aAcceptPriority);
3443 | break;
3444 | case "pause":
3445 | value = this.parsePauseShorthand(token, declarations, aAcceptPriority);
3446 | break;
3447 | case "font":
3448 | value = this.parseFontShorthand(token, declarations, aAcceptPriority);
3449 | break;
3450 | case "list-style":
3451 | value = this.parseListStyleShorthand(token, declarations, aAcceptPriority);
3452 | break;
3453 | default:
3454 | value = this.parseDefaultPropertyValue(token, declarations, aAcceptPriority, descriptor, aSheet);
3455 | break;
3456 | }
3457 | else
3458 | value = this.parseDefaultPropertyValue(token, declarations, aAcceptPriority, descriptor, aSheet);
3459 | token = this.currentToken();
3460 | if (value) // no error above
3461 | {
3462 | var priority = false;
3463 | if (token.isSymbol("!")) {
3464 | token = this.getToken(true, true);
3465 | if (token.isIdent("important")) {
3466 | priority = true;
3467 | token = this.getToken(true, true);
3468 | if (token.isSymbol(";") || token.isSymbol("}")) {
3469 | if (token.isSymbol("}"))
3470 | this.ungetToken();
3471 | }
3472 | else return "";
3473 | }
3474 | else return "";
3475 | }
3476 | else if (token.isNotNull() && !token.isSymbol(";") && !token.isSymbol("}"))
3477 | return "";
3478 | for (var i = 0; i < declarations.length; i++) {
3479 | declarations[i].priority = priority;
3480 | aDecl.push(declarations[i]);
3481 | }
3482 | return descriptor + ": " + value + ";";
3483 | }
3484 | }
3485 | }
3486 | else if (aToken.isComment()) {
3487 | if (this.mPreserveComments) {
3488 | this.forgetState();
3489 | var comment = new jscsspComment();
3490 | comment.parsedCssText = aToken.value;
3491 | aDecl.push(comment);
3492 | }
3493 | return aToken.value;
3494 | }
3495 |
3496 | // we have an error here, let's skip it
3497 | this.restoreState();
3498 | var s = aToken.value;
3499 | blocks = [];
3500 | var token = this.getToken(false, false);
3501 | while (token.isNotNull()) {
3502 | s += token.value;
3503 | if ((token.isSymbol(";") || token.isSymbol("}")) && !blocks.length) {
3504 | if (token.isSymbol("}"))
3505 | this.ungetToken();
3506 | break;
3507 | } else if (token.isSymbol("{")
3508 | || token.isSymbol("(")
3509 | || token.isSymbol("[")
3510 | || token.isFunction()) {
3511 | blocks.push(token.isFunction() ? "(" : token.value);
3512 | } else if (token.isSymbol("}")
3513 | || token.isSymbol(")")
3514 | || token.isSymbol("]")) {
3515 | if (blocks.length) {
3516 | var ontop = blocks[blocks.length - 1];
3517 | if ((token.isSymbol("}") && ontop == "{")
3518 | || (token.isSymbol(")") && ontop == "(")
3519 | || (token.isSymbol("]") && ontop == "[")) {
3520 | blocks.pop();
3521 | }
3522 | }
3523 | }
3524 | token = this.getToken(false, false);
3525 | }
3526 | return "";
3527 | },
3528 |
3529 | parseKeyframesRule: function(aToken, aSheet) {
3530 | var currentLine = CountLF(this.mScanner.getAlreadyScanned());
3531 | var s = aToken.value;
3532 | var valid = false;
3533 | var keyframesRule = new jscsspKeyframesRule();
3534 | keyframesRule.currentLine = currentLine;
3535 | this.preserveState();
3536 | var token = this.getToken(true, true);
3537 | var foundName = false;
3538 | while (token.isNotNull()) {
3539 | if (token.isIdent()) {
3540 | // should be the keyframes' name
3541 | foundName = true;
3542 | s += " " + token.value;
3543 | keyframesRule.name = token.value;
3544 | token = this.getToken(true, true);
3545 | if (token.isSymbol("{"))
3546 | this.ungetToken();
3547 | else {
3548 | // error...
3549 | token.type = jscsspToken.NULL_TYPE;
3550 | break;
3551 | }
3552 | }
3553 | else if (token.isSymbol("{")) {
3554 | if (!foundName) {
3555 | token.type = jscsspToken.NULL_TYPE;
3556 | // not a valid keyframes at-rule
3557 | }
3558 | break;
3559 | }
3560 | else {
3561 | token.type = jscsspToken.NULL_TYPE;
3562 | // not a valid keyframes at-rule
3563 | break;
3564 | }
3565 | token = this.getToken(true, true);
3566 | }
3567 |
3568 | if (token.isSymbol("{") && keyframesRule.name) {
3569 | // ok let's parse keyframe rules now...
3570 | s += " { ";
3571 | token = this.getToken(true, false);
3572 | while (token.isNotNull()) {
3573 | if (token.isComment() && this.mPreserveComments) {
3574 | s += " " + token.value;
3575 | var comment = new jscsspComment();
3576 | comment.parsedCssText = token.value;
3577 | keyframesRule.cssRules.push(comment);
3578 | } else if (token.isSymbol("}")) {
3579 | valid = true;
3580 | break;
3581 | } else {
3582 | var r = this.parseKeyframeRule(token, keyframesRule, true);
3583 | if (r)
3584 | s += r;
3585 | }
3586 | token = this.getToken(true, false);
3587 | }
3588 | }
3589 | if (valid) {
3590 | this.forgetState();
3591 | keyframesRule.currentLine = currentLine;
3592 | keyframesRule.parsedCssText = s;
3593 | aSheet.cssRules.push(keyframesRule);
3594 | return true;
3595 | }
3596 | this.restoreState();
3597 | return false;
3598 | },
3599 |
3600 | parseKeyframeRule: function(aToken, aOwner) {
3601 | var currentLine = CountLF(this.mScanner.getAlreadyScanned());
3602 | this.preserveState();
3603 | var token = aToken;
3604 |
3605 | // find the keyframe keys
3606 | var key = "";
3607 | while (token.isNotNull()) {
3608 | if (token.isIdent() || token.isPercentage()) {
3609 | if (token.isIdent()
3610 | && !token.isIdent("from")
3611 | && !token.isIdent("to")) {
3612 | key = "";
3613 | break;
3614 | }
3615 | key += token.value;
3616 | token = this.getToken(true, true);
3617 | if (token.isSymbol("{")) {
3618 | this.ungetToken();
3619 | break;
3620 | }
3621 | else
3622 | if (token.isSymbol(",")) {
3623 | key += ", ";
3624 | }
3625 | else {
3626 | key = "";
3627 | break;
3628 | }
3629 | }
3630 | else {
3631 | key = "";
3632 | break;
3633 | }
3634 | token = this.getToken(true, true);
3635 | }
3636 |
3637 | var valid = false;
3638 | var declarations = [];
3639 | if (key) {
3640 | var s = key;
3641 | token = this.getToken(true, true);
3642 | if (token.isSymbol("{")) {
3643 | s += " { ";
3644 | token = this.getToken(true, false);
3645 | while (true) {
3646 | if (!token.isNotNull()) {
3647 | valid = true;
3648 | break;
3649 | }
3650 | if (token.isSymbol("}")) {
3651 | s += "}";
3652 | valid = true;
3653 | break;
3654 | } else {
3655 | var d = this.parseDeclaration(token, declarations, true, true, aOwner);
3656 | s += ((d && declarations.length) ? " " : "") + d;
3657 | }
3658 | token = this.getToken(true, false);
3659 | }
3660 | }
3661 | }
3662 | else {
3663 | // key is invalid so the whole rule is invalid with it
3664 | }
3665 |
3666 | if (valid) {
3667 | var rule = new jscsspKeyframeRule();
3668 | rule.currentLine = currentLine;
3669 | rule.parsedCssText = s;
3670 | rule.declarations = declarations;
3671 | rule.keyText = key;
3672 | rule.parentRule = aOwner;
3673 | aOwner.cssRules.push(rule);
3674 | return s;
3675 | }
3676 | this.restoreState();
3677 | s = this.currentToken().value;
3678 | this.addUnknownAtRule(aOwner, s);
3679 | return "";
3680 | },
3681 |
3682 | parseMediaRule: function(aToken, aSheet) {
3683 | var currentLine = CountLF(this.mScanner.getAlreadyScanned());
3684 | var s = aToken.value;
3685 | var valid = false;
3686 | var mediaRule = new jscsspMediaRule();
3687 | mediaRule.currentLine = currentLine;
3688 | this.preserveState();
3689 | var token = this.getToken(true, true);
3690 | var foundMedia = false;
3691 | while (token.isNotNull()) {
3692 | if (token.isIdent()) {
3693 | foundMedia = true;
3694 | s += " " + token.value;
3695 | mediaRule.media.push(token.value);
3696 | token = this.getToken(true, true);
3697 | if (token.isSymbol(",")) {
3698 | s += ",";
3699 | } else {
3700 | if (token.isSymbol("{"))
3701 | this.ungetToken();
3702 | else {
3703 | // error...
3704 | token.type = jscsspToken.NULL_TYPE;
3705 | break;
3706 | }
3707 | }
3708 | }
3709 | else if (token.isSymbol("{"))
3710 | break;
3711 | else if (foundMedia) {
3712 | token.type = jscsspToken.NULL_TYPE;
3713 | // not a media list
3714 | break;
3715 | }
3716 | token = this.getToken(true, true);
3717 | }
3718 | if (token.isSymbol("{") && mediaRule.media.length) {
3719 | // ok let's parse style rules now...
3720 | s += " { ";
3721 | token = this.getToken(true, false);
3722 | while (token.isNotNull()) {
3723 | if (token.isComment() && this.mPreserveComments) {
3724 | s += " " + token.value;
3725 | var comment = new jscsspComment();
3726 | comment.parsedCssText = token.value;
3727 | mediaRule.cssRules.push(comment);
3728 | } else if (token.isSymbol("}")) {
3729 | valid = true;
3730 | break;
3731 | } else {
3732 | var r = this.parseStyleRule(token, mediaRule, true);
3733 | if (r)
3734 | s += r;
3735 | }
3736 | token = this.getToken(true, false);
3737 | }
3738 | }
3739 | if (valid) {
3740 | this.forgetState();
3741 | mediaRule.parsedCssText = s;
3742 | aSheet.cssRules.push(mediaRule);
3743 | return true;
3744 | }
3745 | this.restoreState();
3746 | return false;
3747 | },
3748 |
3749 | trim11: function(str) {
3750 | str = str.replace(/^\s+/, '');
3751 | for (var i = str.length - 1; i >= 0; i--) {
3752 | if (/\S/.test( str.charAt(i) )) { // XXX charat
3753 | str = str.substring(0, i + 1);
3754 | break;
3755 | }
3756 | }
3757 | return str;
3758 | },
3759 |
3760 | parseStyleRule: function(aToken, aOwner, aIsInsideMediaRule)
3761 | {
3762 | var currentLine = CountLF(this.mScanner.getAlreadyScanned());
3763 | this.preserveState();
3764 | // first let's see if we have a selector here...
3765 | var selector = this.parseSelector(aToken, false);
3766 | var valid = false;
3767 | var declarations = [];
3768 | if (selector) {
3769 | selector = this.trim11(selector.selector);
3770 | var s = selector;
3771 | var token = this.getToken(true, true);
3772 | if (token.isSymbol("{")) {
3773 | s += " { ";
3774 | var token = this.getToken(true, false);
3775 | while (true) {
3776 | if (!token.isNotNull()) {
3777 | valid = true;
3778 | break;
3779 | }
3780 | if (token.isSymbol("}")) {
3781 | s += "}";
3782 | valid = true;
3783 | break;
3784 | } else {
3785 | var d = this.parseDeclaration(token, declarations, true, true, aOwner);
3786 | s += ((d && declarations.length) ? " " : "") + d;
3787 | }
3788 | token = this.getToken(true, false);
3789 | }
3790 | }
3791 | }
3792 | else {
3793 | // selector is invalid so the whole rule is invalid with it
3794 | }
3795 |
3796 | if (valid) {
3797 | var rule = new jscsspStyleRule();
3798 | rule.currentLine = currentLine;
3799 | rule.parsedCssText = s;
3800 | rule.declarations = declarations;
3801 | rule.mSelectorText = selector;
3802 | if (aIsInsideMediaRule)
3803 | rule.parentRule = aOwner;
3804 | else
3805 | rule.parentStyleSheet = aOwner;
3806 | aOwner.cssRules.push(rule);
3807 | return s;
3808 | }
3809 | this.restoreState();
3810 | s = this.currentToken().value;
3811 | this.addUnknownAtRule(aOwner, s);
3812 | return "";
3813 | },
3814 |
3815 | parseSelector: function(aToken, aParseSelectorOnly) {
3816 | var s = "";
3817 | var specificity = {a: 0, b: 0, c: 0, d: 0}; // CSS 2.1 section 6.4.3
3818 | var isFirstInChain = true;
3819 | var token = aToken;
3820 | var valid = false;
3821 | var combinatorFound = false;
3822 | while (true) {
3823 | if (!token.isNotNull()) {
3824 | if (aParseSelectorOnly)
3825 | return {selector: s, specificity: specificity };
3826 | return "";
3827 | }
3828 |
3829 | if (!aParseSelectorOnly && token.isSymbol("{")) {
3830 | // end of selector
3831 | valid = !combinatorFound;
3832 | if (valid) this.ungetToken();
3833 | break;
3834 | }
3835 |
3836 | if (token.isSymbol(",")) { // group of selectors
3837 | s += token.value;
3838 | isFirstInChain = true;
3839 | combinatorFound = false;
3840 | token = this.getToken(false, true);
3841 | continue;
3842 | }
3843 | // now combinators and grouping...
3844 | else if (!combinatorFound
3845 | && (token.isWhiteSpace()
3846 | || token.isSymbol(">")
3847 | || token.isSymbol("+")
3848 | || token.isSymbol("~"))) {
3849 | if (token.isWhiteSpace()) {
3850 | s += " ";
3851 | var nextToken = this.lookAhead(true, true);
3852 | if (!nextToken.isNotNull()) {
3853 | if (aParseSelectorOnly)
3854 | return {selector: s, specificity: specificity };
3855 | return "";
3856 | }
3857 | if (nextToken.isSymbol(">")
3858 | || nextToken.isSymbol("+")
3859 | || nextToken.isSymbol("~")) {
3860 | token = this.getToken(true, true);
3861 | s += token.value + " ";
3862 | combinatorFound = true;
3863 | }
3864 | }
3865 | else {
3866 | s += token.value;
3867 | combinatorFound = true;
3868 | }
3869 | isFirstInChain = true;
3870 | token = this.getToken(true, true);
3871 | continue;
3872 | }
3873 | else {
3874 | var simpleSelector = this.parseSimpleSelector(token, isFirstInChain, true);
3875 | if (!simpleSelector)
3876 | break; // error
3877 | s += simpleSelector.selector;
3878 | specificity.b += simpleSelector.specificity.b;
3879 | specificity.c += simpleSelector.specificity.c;
3880 | specificity.d += simpleSelector.specificity.d;
3881 | isFirstInChain = false;
3882 | combinatorFound = false;
3883 | }
3884 |
3885 | token = this.getToken(false, true);
3886 | }
3887 |
3888 | if (valid) {
3889 | return {selector: s, specificity: specificity };
3890 | }
3891 | return "";
3892 | },
3893 |
3894 | isPseudoElement: function(aIdent)
3895 | {
3896 | switch (aIdent) {
3897 | case "first-letter":
3898 | case "first-line":
3899 | case "before":
3900 | case "after":
3901 | case "marker":
3902 | return true;
3903 | break;
3904 | default: return false;
3905 | break;
3906 | }
3907 | },
3908 |
3909 | parseSimpleSelector: function(token, isFirstInChain, canNegate)
3910 | {
3911 | var s = "";
3912 | var specificity = {a: 0, b: 0, c: 0, d: 0}; // CSS 2.1 section 6.4.3
3913 |
3914 | if (isFirstInChain
3915 | && (token.isSymbol("*") || token.isSymbol("|") || token.isIdent())) {
3916 | // type or universal selector
3917 | if (token.isSymbol("*") || token.isIdent()) {
3918 | // we don't know yet if it's a prefix or a universal
3919 | // selector
3920 | s += token.value;
3921 | var isIdent = token.isIdent();
3922 | token = this.getToken(false, true);
3923 | if (token.isSymbol("|")) {
3924 | // it's a prefix
3925 | s += token.value;
3926 | token = this.getToken(false, true);
3927 | if (token.isIdent() || token.isSymbol("*")) {
3928 | // ok we now have a type element or universal
3929 | // selector
3930 | s += token.value;
3931 | if (token.isIdent())
3932 | specificity.d++;
3933 | } else
3934 | // oops that's an error...
3935 | return null;
3936 | } else {
3937 | this.ungetToken();
3938 | if (isIdent)
3939 | specificity.d++;
3940 | }
3941 | } else if (token.isSymbol("|")) {
3942 | s += token.value;
3943 | token = this.getToken(false, true);
3944 | if (token.isIdent() || token.isSymbol("*")) {
3945 | s += token.value;
3946 | if (token.isIdent())
3947 | specificity.d++;
3948 | } else
3949 | // oops that's an error
3950 | return null;
3951 | }
3952 | }
3953 |
3954 | else if (token.isSymbol(".") || token.isSymbol("#")) {
3955 | var isClass = token.isSymbol(".");
3956 | s += token.value;
3957 | token = this.getToken(false, true);
3958 | if (token.isIdent()) {
3959 | s += token.value;
3960 | if (isClass)
3961 | specificity.c++;
3962 | else
3963 | specificity.b++;
3964 | }
3965 | else
3966 | return null;
3967 | }
3968 |
3969 | else if (token.isSymbol(":")) {
3970 | s += token.value;
3971 | token = this.getToken(false, true);
3972 | if (token.isSymbol(":")) {
3973 | s += token.value;
3974 | token = this.getToken(false, true);
3975 | }
3976 | if (token.isIdent()) {
3977 | s += token.value;
3978 | if (this.isPseudoElement(token.value))
3979 | specificity.d++;
3980 | else
3981 | specificity.c++;
3982 | }
3983 | else if (token.isFunction()) {
3984 | s += token.value;
3985 | if (token.isFunction(":not(")) {
3986 | if (!canNegate)
3987 | return null;
3988 | token = this.getToken(true, true);
3989 | var simpleSelector = this.parseSimpleSelector(token, isFirstInChain, false);
3990 | if (!simpleSelector)
3991 | return null;
3992 | else {
3993 | s += simpleSelector.selector;
3994 | token = this.getToken(true, true);
3995 | if (token.isSymbol(")"))
3996 | s += ")";
3997 | else
3998 | return null;
3999 | }
4000 | specificity.c++;
4001 | }
4002 | else {
4003 | while (true) {
4004 | token = this.getToken(false, true);
4005 | if (token.isSymbol(")")) {
4006 | s += ")";
4007 | break;
4008 | } else
4009 | s += token.value;
4010 | }
4011 | specificity.c++;
4012 | }
4013 | } else
4014 | return null;
4015 |
4016 | } else if (token.isSymbol("[")) {
4017 | s += "[";
4018 | token = this.getToken(true, true);
4019 | if (token.isIdent() || token.isSymbol("*")) {
4020 | s += token.value;
4021 | var nextToken = this.getToken(true, true);
4022 | if (token.isSymbol("|")) {
4023 | s += "|";
4024 | token = this.getToken(true, true);
4025 | if (token.isIdent())
4026 | s += token.value;
4027 | else
4028 | return null;
4029 | } else
4030 | this.ungetToken();
4031 | } else if (token.isSymbol("|")) {
4032 | s += "|";
4033 | token = this.getToken(true, true);
4034 | if (token.isIdent())
4035 | s += token.value;
4036 | else
4037 | return null;
4038 | }
4039 | else
4040 | return null;
4041 |
4042 | // nothing, =, *=, $=, ^=, |=
4043 | token = this.getToken(true, true);
4044 | if (token.isIncludes()
4045 | || token.isDashmatch()
4046 | || token.isBeginsmatch()
4047 | || token.isEndsmatch()
4048 | || token.isContainsmatch()
4049 | || token.isSymbol("=")) {
4050 | s += token.value;
4051 | token = this.getToken(true, true);
4052 | if (token.isString() || token.isIdent()) {
4053 | s += token.value;
4054 | token = this.getToken(true, true);
4055 | }
4056 | else
4057 | return null;
4058 |
4059 | if (token.isSymbol("]")) {
4060 | s += token.value;
4061 | specificity.c++;
4062 | }
4063 | else
4064 | return null;
4065 | }
4066 | else if (token.isSymbol("]")) {
4067 | s += token.value;
4068 | specificity.c++;
4069 | }
4070 | else
4071 | return null;
4072 |
4073 | }
4074 | else if (token.isWhiteSpace()) {
4075 | var t = this.lookAhead(true, true);
4076 | if (t.isSymbol('{'))
4077 | return ""
4078 | }
4079 | if (s)
4080 | return {selector: s, specificity: specificity };
4081 | return null;
4082 | },
4083 |
4084 | preserveState: function() {
4085 | this.mPreservedTokens.push(this.currentToken());
4086 | this.mScanner.preserveState();
4087 | },
4088 |
4089 | restoreState: function() {
4090 | if (this.mPreservedTokens.length) {
4091 | this.mScanner.restoreState();
4092 | this.mToken = this.mPreservedTokens.pop();
4093 | }
4094 | },
4095 |
4096 | forgetState: function() {
4097 | if (this.mPreservedTokens.length) {
4098 | this.mScanner.forgetState();
4099 | this.mPreservedTokens.pop();
4100 | }
4101 | },
4102 |
4103 | parse: function(aString, aTryToPreserveWhitespaces, aTryToPreserveComments) {
4104 | if (!aString)
4105 | return null; // early way out if we can
4106 |
4107 | this.mPreserveWS = aTryToPreserveWhitespaces;
4108 | this.mPreserveComments = aTryToPreserveComments;
4109 | this.mPreservedTokens = [];
4110 | this.mScanner.init(aString);
4111 | var sheet = new jscsspStylesheet();
4112 |
4113 | // @charset can only appear at first char of the stylesheet
4114 | var token = this.getToken(false, false);
4115 | if (!token.isNotNull())
4116 | return;
4117 | if (token.isAtRule("@charset")) {
4118 | this.parseCharsetRule(token, sheet);
4119 | token = this.getToken(false, false);
4120 | }
4121 |
4122 | var foundStyleRules = false;
4123 | var foundImportRules = false;
4124 | var foundNameSpaceRules = false;
4125 | while (true) {
4126 | if (!token.isNotNull())
4127 | break;
4128 | if (token.isWhiteSpace())
4129 | {
4130 | if (aTryToPreserveWhitespaces)
4131 | this.addWhitespace(sheet, token.value);
4132 | }
4133 |
4134 | else if (token.isComment())
4135 | {
4136 | if (this.mPreserveComments)
4137 | this.addComment(sheet, token.value);
4138 | }
4139 |
4140 | else if (token.isAtRule()) {
4141 | if (token.isAtRule("@variables")) {
4142 | if (!foundImportRules && !foundStyleRules)
4143 | this.parseVariablesRule(token, sheet);
4144 | else {
4145 | this.reportError(kVARIABLES_RULE_POSITION);
4146 | this.addUnknownAtRule(sheet, token.value);
4147 | }
4148 | }
4149 | else if (token.isAtRule("@import")) {
4150 | // @import rules MUST occur before all style and namespace
4151 | // rules
4152 | if (!foundStyleRules && !foundNameSpaceRules)
4153 | foundImportRules = this.parseImportRule(token, sheet);
4154 | else {
4155 | this.reportError(kIMPORT_RULE_POSITION);
4156 | this.addUnknownAtRule(sheet, token.value);
4157 | }
4158 | }
4159 | else if (token.isAtRule("@namespace")) {
4160 | // @namespace rules MUST occur before all style rule and
4161 | // after all @import rules
4162 | if (!foundStyleRules)
4163 | foundNameSpaceRules = this.parseNamespaceRule(token, sheet);
4164 | else {
4165 | this.reportError(kNAMESPACE_RULE_POSITION);
4166 | this.addUnknownAtRule(sheet, token.value);
4167 | }
4168 | }
4169 | else if (token.isAtRule("@font-face")) {
4170 | if (this.parseFontFaceRule(token, sheet))
4171 | foundStyleRules = true;
4172 | else
4173 | this.addUnknownAtRule(sheet, token.value);
4174 | }
4175 | else if (token.isAtRule("@page")) {
4176 | if (this.parsePageRule(token, sheet))
4177 | foundStyleRules = true;
4178 | else
4179 | this.addUnknownAtRule(sheet, token.value);
4180 | }
4181 | else if (token.isAtRule("@media")) {
4182 | if (this.parseMediaRule(token, sheet))
4183 | foundStyleRules = true;
4184 | else
4185 | this.addUnknownAtRule(sheet, token.value);
4186 | }
4187 | else if (token.isAtRule("@keyframes")) {
4188 | if (!this.parseKeyframesRule(token, sheet))
4189 | this.addUnknownAtRule(sheet, token.value);
4190 | }
4191 | else if (token.isAtRule("@charset")) {
4192 | this.reportError(kCHARSET_RULE_CHARSET_SOF);
4193 | this.addUnknownAtRule(sheet, token.value);
4194 | }
4195 | else {
4196 | this.reportError(kUNKNOWN_AT_RULE);
4197 | this.addUnknownAtRule(sheet, token.value);
4198 | }
4199 | }
4200 |
4201 | else // plain style rules
4202 | {
4203 | var ruleText = this.parseStyleRule(token, sheet, false);
4204 | if (ruleText)
4205 | foundStyleRules = true;
4206 | }
4207 | token = this.getToken(false);
4208 | }
4209 |
4210 | return sheet;
4211 | }
4212 |
4213 | };
4214 |
4215 |
4216 | function jscsspToken(aType, aValue, aUnit)
4217 | {
4218 | this.type = aType;
4219 | this.value = aValue;
4220 | this.unit = aUnit;
4221 | }
4222 |
4223 | jscsspToken.NULL_TYPE = 0;
4224 |
4225 | jscsspToken.WHITESPACE_TYPE = 1;
4226 | jscsspToken.STRING_TYPE = 2;
4227 | jscsspToken.COMMENT_TYPE = 3;
4228 | jscsspToken.NUMBER_TYPE = 4;
4229 | jscsspToken.IDENT_TYPE = 5;
4230 | jscsspToken.FUNCTION_TYPE = 6;
4231 | jscsspToken.ATRULE_TYPE = 7;
4232 | jscsspToken.INCLUDES_TYPE = 8;
4233 | jscsspToken.DASHMATCH_TYPE = 9;
4234 | jscsspToken.BEGINSMATCH_TYPE = 10;
4235 | jscsspToken.ENDSMATCH_TYPE = 11;
4236 | jscsspToken.CONTAINSMATCH_TYPE = 12;
4237 | jscsspToken.SYMBOL_TYPE = 13;
4238 | jscsspToken.DIMENSION_TYPE = 14;
4239 | jscsspToken.PERCENTAGE_TYPE = 15;
4240 | jscsspToken.HEX_TYPE = 16;
4241 |
4242 | jscsspToken.prototype = {
4243 |
4244 | isNotNull: function ()
4245 | {
4246 | return this.type;
4247 | },
4248 |
4249 | _isOfType: function (aType, aValue)
4250 | {
4251 | return (this.type == aType && (!aValue || this.value.toLowerCase() == aValue));
4252 | },
4253 |
4254 | isWhiteSpace: function(w)
4255 | {
4256 | return this._isOfType(jscsspToken.WHITESPACE_TYPE, w);
4257 | },
4258 |
4259 | isString: function()
4260 | {
4261 | return this._isOfType(jscsspToken.STRING_TYPE);
4262 | },
4263 |
4264 | isComment: function()
4265 | {
4266 | return this._isOfType(jscsspToken.COMMENT_TYPE);
4267 | },
4268 |
4269 | isNumber: function(n)
4270 | {
4271 | return this._isOfType(jscsspToken.NUMBER_TYPE, n);
4272 | },
4273 |
4274 | isSymbol: function(c)
4275 | {
4276 | return this._isOfType(jscsspToken.SYMBOL_TYPE, c);
4277 | },
4278 |
4279 | isIdent: function(i)
4280 | {
4281 | return this._isOfType(jscsspToken.IDENT_TYPE, i);
4282 | },
4283 |
4284 | isFunction: function(f)
4285 | {
4286 | return this._isOfType(jscsspToken.FUNCTION_TYPE, f);
4287 | },
4288 |
4289 | isAtRule: function(a)
4290 | {
4291 | return this._isOfType(jscsspToken.ATRULE_TYPE, a);
4292 | },
4293 |
4294 | isIncludes: function()
4295 | {
4296 | return this._isOfType(jscsspToken.INCLUDES_TYPE);
4297 | },
4298 |
4299 | isDashmatch: function()
4300 | {
4301 | return this._isOfType(jscsspToken.DASHMATCH_TYPE);
4302 | },
4303 |
4304 | isBeginsmatch: function()
4305 | {
4306 | return this._isOfType(jscsspToken.BEGINSMATCH_TYPE);
4307 | },
4308 |
4309 | isEndsmatch: function()
4310 | {
4311 | return this._isOfType(jscsspToken.ENDSMATCH_TYPE);
4312 | },
4313 |
4314 | isContainsmatch: function()
4315 | {
4316 | return this._isOfType(jscsspToken.CONTAINSMATCH_TYPE);
4317 | },
4318 |
4319 | isSymbol: function(c)
4320 | {
4321 | return this._isOfType(jscsspToken.SYMBOL_TYPE, c);
4322 | },
4323 |
4324 | isDimension: function()
4325 | {
4326 | return this._isOfType(jscsspToken.DIMENSION_TYPE);
4327 | },
4328 |
4329 | isPercentage: function()
4330 | {
4331 | return this._isOfType(jscsspToken.PERCENTAGE_TYPE);
4332 | },
4333 |
4334 | isHex: function()
4335 | {
4336 | return this._isOfType(jscsspToken.HEX_TYPE);
4337 | },
4338 |
4339 | isDimensionOfUnit: function(aUnit)
4340 | {
4341 | return (this.isDimension() && this.unit == aUnit);
4342 | },
4343 |
4344 | isLength: function()
4345 | {
4346 | return (this.isPercentage() ||
4347 | this.isDimensionOfUnit("cm") ||
4348 | this.isDimensionOfUnit("mm") ||
4349 | this.isDimensionOfUnit("in") ||
4350 | this.isDimensionOfUnit("pc") ||
4351 | this.isDimensionOfUnit("px") ||
4352 | this.isDimensionOfUnit("em") ||
4353 | this.isDimensionOfUnit("ex") ||
4354 | this.isDimensionOfUnit("pt"));
4355 | },
4356 |
4357 | isAngle: function()
4358 | {
4359 | return (this.isDimensionOfUnit("deg") ||
4360 | this.isDimensionOfUnit("rad") ||
4361 | this.isDimensionOfUnit("grad"));
4362 | }
4363 | }
4364 |
4365 | var kJscsspUNKNOWN_RULE = 0;
4366 | var kJscsspSTYLE_RULE = 1
4367 | var kJscsspCHARSET_RULE = 2;
4368 | var kJscsspIMPORT_RULE = 3;
4369 | var kJscsspMEDIA_RULE = 4;
4370 | var kJscsspFONT_FACE_RULE = 5;
4371 | var kJscsspPAGE_RULE = 6;
4372 |
4373 | var kJscsspKEYFRAMES_RULE = 7;
4374 | var kJscsspKEYFRAME_RULE = 8;
4375 |
4376 | var kJscsspNAMESPACE_RULE = 100;
4377 | var kJscsspCOMMENT = 101;
4378 | var kJscsspWHITE_SPACE = 102;
4379 |
4380 | var kJscsspVARIABLES_RULE = 200;
4381 |
4382 | var kJscsspSTYLE_DECLARATION = 1000;
4383 |
4384 | var gTABS = "";
4385 |
4386 | function jscsspStylesheet()
4387 | {
4388 | this.cssRules = [];
4389 | this.variables = {};
4390 | }
4391 |
4392 | jscsspStylesheet.prototype = {
4393 | insertRule: function(aRule, aIndex) {
4394 | try {
4395 | this.cssRules.splice(aIndex, 1, aRule);
4396 | }
4397 | catch(e) {
4398 | }
4399 | },
4400 |
4401 | deleteRule: function(aIndex) {
4402 | try {
4403 | this.cssRules.splice(aIndex);
4404 | }
4405 | catch(e) {
4406 | }
4407 | },
4408 |
4409 | cssText: function() {
4410 | var rv = "";
4411 | for (var i = 0; i < this.cssRules.length; i++)
4412 | rv += this.cssRules[i].cssText() + "\n";
4413 | return rv;
4414 | },
4415 |
4416 | resolveVariables: function(aMedium) {
4417 |
4418 | function ItemFoundInArray(aArray, aItem) {
4419 | for (var i = 0; i < aArray.length; i++)
4420 | if (aItem == aArray[i])
4421 | return true;
4422 | return false;
4423 | }
4424 |
4425 | for (var i = 0; i < this.cssRules.length; i++)
4426 | {
4427 | var rule = this.cssRules[i];
4428 | if (rule.type == kJscsspSTYLE_RULE || rule.type == kJscsspIMPORT_RULE)
4429 | break;
4430 | else if (rule.type == kJscsspVARIABLES_RULE &&
4431 | (!rule.media.length || ItemFoundInArray(rule.media, aMedium))) {
4432 |
4433 | for (var j = 0; j < rule.declarations.length; j++) {
4434 | var valueText = "";
4435 | for (var k = 0; k < rule.declarations[j].values.length; k++)
4436 | valueText += (k ? " " : "") + rule.declarations[j].values[k].value;
4437 | this.variables[rule.declarations[j].property] = valueText;
4438 | }
4439 | }
4440 | }
4441 | }
4442 | };
4443 |
4444 | /* kJscsspCHARSET_RULE */
4445 |
4446 | function jscsspCharsetRule()
4447 | {
4448 | this.type = kJscsspCHARSET_RULE;
4449 | this.encoding = null;
4450 | this.parsedCssText = null;
4451 | this.parentStyleSheet = null;
4452 | this.parentRule = null;
4453 | }
4454 |
4455 | jscsspCharsetRule.prototype = {
4456 |
4457 | cssText: function() {
4458 | return "@charset " + this.encoding + ";";
4459 | },
4460 |
4461 | setCssText: function(val) {
4462 | var sheet = {cssRules: []};
4463 | var parser = new CSSParser(val);
4464 | var token = parser.getToken(false, false);
4465 | if (token.isAtRule("@charset")) {
4466 | if (parser.parseCharsetRule(token, sheet)) {
4467 | var newRule = sheet.cssRules[0];
4468 | this.encoding = newRule.encoding;
4469 | this.parsedCssText = newRule.parsedCssText;
4470 | return;
4471 | }
4472 | }
4473 | throw DOMException.SYNTAX_ERR;
4474 | }
4475 | };
4476 |
4477 | /* kJscsspUNKNOWN_RULE */
4478 |
4479 | function jscsspErrorRule(aErrorMsg)
4480 | {
4481 | this.error = aErrorMsg ? aErrorMsg : "INVALID";
4482 | this.type = kJscsspUNKNOWN_RULE;
4483 | this.parsedCssText = null;
4484 | this.parentStyleSheet = null;
4485 | this.parentRule = null;
4486 | }
4487 |
4488 | jscsspErrorRule.prototype = {
4489 | cssText: function() {
4490 | return this.parsedCssText;
4491 | }
4492 | };
4493 |
4494 | /* kJscsspCOMMENT */
4495 |
4496 | function jscsspComment()
4497 | {
4498 | this.type = kJscsspCOMMENT;
4499 | this.parsedCssText = null;
4500 | this.parentStyleSheet = null;
4501 | this.parentRule = null;
4502 | }
4503 |
4504 | jscsspComment.prototype = {
4505 | cssText: function() {
4506 | return this.parsedCssText;
4507 | },
4508 |
4509 | setCssText: function(val) {
4510 | var parser = new CSSParser(val);
4511 | var token = parser.getToken(true, false);
4512 | if (token.isComment())
4513 | this.parsedCssText = token.value;
4514 | else
4515 | throw DOMException.SYNTAX_ERR;
4516 | }
4517 | };
4518 |
4519 | /* kJscsspWHITE_SPACE */
4520 |
4521 | function jscsspWhitespace()
4522 | {
4523 | this.type = kJscsspWHITE_SPACE;
4524 | this.parsedCssText = null;
4525 | this.parentStyleSheet = null;
4526 | this.parentRule = null;
4527 | }
4528 |
4529 | jscsspWhitespace.prototype = {
4530 | cssText: function() {
4531 | return this.parsedCssText;
4532 | }
4533 | };
4534 |
4535 | /* kJscsspIMPORT_RULE */
4536 |
4537 | function jscsspImportRule()
4538 | {
4539 | this.type = kJscsspIMPORT_RULE;
4540 | this.parsedCssText = null;
4541 | this.href = null;
4542 | this.media = [];
4543 | this.parentStyleSheet = null;
4544 | this.parentRule = null;
4545 | }
4546 |
4547 | jscsspImportRule.prototype = {
4548 | cssText: function() {
4549 | var mediaString = this.media.join(", ");
4550 | return "@import " + this.href
4551 | + ((mediaString && mediaString != "all") ? mediaString + " " : "")
4552 | + ";";
4553 | },
4554 |
4555 | setCssText: function(val) {
4556 | var sheet = {cssRules: []};
4557 | var parser = new CSSParser(val);
4558 | var token = parser.getToken(true, true);
4559 | if (token.isAtRule("@import")) {
4560 | if (parser.parseImportRule(token, sheet)) {
4561 | var newRule = sheet.cssRules[0];
4562 | this.href = newRule.href;
4563 | this.media = newRule.media;
4564 | this.parsedCssText = newRule.parsedCssText;
4565 | return;
4566 | }
4567 | }
4568 | throw DOMException.SYNTAX_ERR;
4569 | }
4570 | };
4571 |
4572 | /* kJscsspNAMESPACE_RULE */
4573 |
4574 | function jscsspNamespaceRule()
4575 | {
4576 | this.type = kJscsspNAMESPACE_RULE;
4577 | this.parsedCssText = null;
4578 | this.prefix = null;
4579 | this.url = null;
4580 | this.parentStyleSheet = null;
4581 | this.parentRule = null;
4582 | }
4583 |
4584 | jscsspNamespaceRule.prototype = {
4585 | cssText: function() {
4586 | return "@namespace " + (this.prefix ? this.prefix + " ": "")
4587 | + this.url
4588 | + ";";
4589 | },
4590 |
4591 | setCssText: function(val) {
4592 | var sheet = {cssRules: []};
4593 | var parser = new CSSParser(val);
4594 | var token = parser.getToken(true, true);
4595 | if (token.isAtRule("@namespace")) {
4596 | if (parser.parseNamespaceRule(token, sheet)) {
4597 | var newRule = sheet.cssRules[0];
4598 | this.url = newRule.url;
4599 | this.prefix = newRule.prefix;
4600 | this.parsedCssText = newRule.parsedCssText;
4601 | return;
4602 | }
4603 | }
4604 | throw DOMException.SYNTAX_ERR;
4605 | }
4606 | };
4607 |
4608 | /* kJscsspSTYLE_DECLARATION */
4609 |
4610 | function jscsspDeclaration()
4611 | {
4612 | this.type = kJscsspSTYLE_DECLARATION;
4613 | this.property = null;
4614 | this.values = [];
4615 | this.valueText = null;
4616 | this.priority = null;
4617 | this.parsedCssText = null;
4618 | this.parentStyleSheet = null;
4619 | this.parentRule = null;
4620 | }
4621 |
4622 | jscsspDeclaration.prototype = {
4623 | kCOMMA_SEPARATED: {
4624 | "cursor": true,
4625 | "font-family": true,
4626 | "voice-family": true,
4627 | "background-image": true
4628 | },
4629 |
4630 | kUNMODIFIED_COMMA_SEPARATED_PROPERTIES: {
4631 | "text-shadow": true,
4632 | "box-shadow": true,
4633 | "-moz-transition": true,
4634 | "-moz-transition-property": true,
4635 | "-moz-transition-duration": true,
4636 | "-moz-transition-timing-function": true,
4637 | "-moz-transition-delay": true
4638 | },
4639 |
4640 | cssText: function() {
4641 | var prefixes = CssInspector.prefixesForProperty(this.property);
4642 |
4643 | if (this.property in this.kUNMODIFIED_COMMA_SEPARATED_PROPERTIES) {
4644 | if (prefixes) {
4645 | var rv = "";
4646 | for (var propertyIndex = 0; propertyIndex < prefixes.length; propertyIndex++) {
4647 | var property = prefixes[propertyIndex];
4648 | rv += (propertyIndex ? gTABS : "") + property + ": ";
4649 | rv += this.valueText + (this.priority ? " !important" : "") + ";";
4650 | rv += ((prefixes.length > 1 && propertyIndex != prefixes.length -1) ? "\n" : "");
4651 | }
4652 | return rv;
4653 | }
4654 | return this.property + ": " + this.valueText +
4655 | (this.priority ? " !important" : "") + ";"
4656 | }
4657 |
4658 | if (prefixes) {
4659 | var rv = "";
4660 | for (var propertyIndex = 0; propertyIndex < prefixes.length; propertyIndex++) {
4661 | var property = prefixes[propertyIndex];
4662 | rv += (propertyIndex ? gTABS : "") + property + ": ";
4663 | var separator = (property in this.kCOMMA_SEPARATED) ? ", " : " ";
4664 | for (var i = 0; i < this.values.length; i++)
4665 | if (this.values[i].cssText() != null)
4666 | rv += (i ? separator : "") + this.values[i].cssText();
4667 | else
4668 | return null;
4669 | rv += (this.priority ? " !important" : "") + ";" +
4670 | ((prefixes.length > 1 && propertyIndex != prefixes.length -1) ? "\n" : "");
4671 | }
4672 | return rv;
4673 | }
4674 |
4675 | var rv = this.property + ": ";
4676 | var separator = (this.property in this.kCOMMA_SEPARATED) ? ", " : " ";
4677 | var extras = {"webkit": false, "presto": false, "trident": false, "generic": false }
4678 | for (var i = 0; i < this.values.length; i++) {
4679 | var v = this.values[i].cssText();
4680 | if (v != null) {
4681 | var paren = v.indexOf("(");
4682 | var kwd = v;
4683 | if (paren != -1)
4684 | kwd = v.substr(0, paren);
4685 | if (kwd in kCSS_VENDOR_VALUES) {
4686 | for (var j in kCSS_VENDOR_VALUES[kwd]) {
4687 | extras[j] = extras[j] || (kCSS_VENDOR_VALUES[kwd][j] != "");
4688 | }
4689 | }
4690 | rv += (i ? separator : "") + v;
4691 | }
4692 | else
4693 | return null;
4694 | }
4695 | rv += (this.priority ? " !important" : "") + ";";
4696 |
4697 | for (var j in extras) {
4698 | if (extras[j]) {
4699 | var str = "\n" + gTABS + this.property + ": ";
4700 | for (var i = 0; i < this.values.length; i++) {
4701 | var v = this.values[i].cssText();
4702 | if (v != null) {
4703 | var paren = v.indexOf("(");
4704 | var kwd = v;
4705 | if (paren != -1)
4706 | kwd = v.substr(0, paren);
4707 | if (kwd in kCSS_VENDOR_VALUES) {
4708 | functor = kCSS_VENDOR_VALUES[kwd][j];
4709 | if (functor) {
4710 | v = (typeof functor == "string") ? functor : functor(v, j);
4711 | if (!v) {
4712 | str = null;
4713 | break;
4714 | }
4715 | }
4716 | }
4717 | str += (i ? separator : "") + v;
4718 | }
4719 | else
4720 | return null;
4721 | }
4722 | if (str)
4723 | rv += str + ";"
4724 | else
4725 | rv += "\n" + gTABS + "/* Impossible to translate property " + this.property + " for " + j + " */";
4726 | }
4727 | }
4728 | return rv;
4729 | },
4730 |
4731 | setCssText: function(val) {
4732 | var declarations = [];
4733 | var parser = new CSSParser(val);
4734 | var token = parser.getToken(true, true);
4735 | if (parser.parseDeclaration(token, declarations, true, true, null)
4736 | && declarations.length
4737 | && declarations[0].type == kJscsspSTYLE_DECLARATION) {
4738 | var newDecl = declarations.cssRules[0];
4739 | this.property = newDecl.property;
4740 | this.value = newDecl.value;
4741 | this.priority = newDecl.priority;
4742 | this.parsedCssText = newRule.parsedCssText;
4743 | return;
4744 | }
4745 | throw DOMException.SYNTAX_ERR;
4746 | }
4747 | };
4748 |
4749 | /* kJscsspFONT_FACE_RULE */
4750 |
4751 | function jscsspFontFaceRule()
4752 | {
4753 | this.type = kJscsspFONT_FACE_RULE;
4754 | this.parsedCssText = null;
4755 | this.descriptors = [];
4756 | this.parentStyleSheet = null;
4757 | this.parentRule = null;
4758 | }
4759 |
4760 | jscsspFontFaceRule.prototype = {
4761 | cssText: function() {
4762 | var rv = gTABS + "@font-face {\n";
4763 | var preservedGTABS = gTABS;
4764 | gTABS += " ";
4765 | for (var i = 0; i < this.descriptors.length; i++)
4766 | rv += gTABS + this.descriptors[i].cssText() + "\n";
4767 | gTABS = preservedGTABS;
4768 | return rv + gTABS + "}";
4769 | },
4770 |
4771 | setCssText: function(val) {
4772 | var sheet = {cssRules: []};
4773 | var parser = new CSSParser(val);
4774 | var token = parser.getToken(true, true);
4775 | if (token.isAtRule("@font-face")) {
4776 | if (parser.parseFontFaceRule(token, sheet)) {
4777 | var newRule = sheet.cssRules[0];
4778 | this.descriptors = newRule.descriptors;
4779 | this.parsedCssText = newRule.parsedCssText;
4780 | return;
4781 | }
4782 | }
4783 | throw DOMException.SYNTAX_ERR;
4784 | }
4785 | };
4786 |
4787 | /* kJscsspKEYFRAMES_RULE */
4788 | function jscsspKeyframesRule()
4789 | {
4790 | this.type = kJscsspKEYFRAMES_RULE;
4791 | this.parsedCssText = null;
4792 | this.cssRules = [];
4793 | this.name = null;
4794 | this.parentStyleSheet = null;
4795 | this.parentRule = null;
4796 | }
4797 |
4798 | jscsspKeyframesRule.prototype = {
4799 | cssText: function() {
4800 | var rv = gTABS
4801 | + "@keyframes "
4802 | + this.name + " {\n";
4803 | var preservedGTABS = gTABS;
4804 | gTABS += " ";
4805 | for (var i = 0; i < this.cssRules.length; i++)
4806 | rv += gTABS + this.cssRules[i].cssText() + "\n";
4807 | gTABS = preservedGTABS;
4808 | rv += gTABS + "}\n";
4809 | return rv;
4810 | },
4811 |
4812 | setCssText: function(val) {
4813 | var sheet = {cssRules: []};
4814 | var parser = new CSSParser(val);
4815 | var token = parser.getToken(true, true);
4816 | if (token.isAtRule("@keyframes")) {
4817 | if (parser.parseKeyframesRule(token, sheet)) {
4818 | var newRule = sheet.cssRules[0];
4819 | this.cssRules = newRule.cssRules;
4820 | this.name = newRule.name;
4821 | this.parsedCssText = newRule.parsedCssText;
4822 | return;
4823 | }
4824 | }
4825 | throw DOMException.SYNTAX_ERR;
4826 | }
4827 | };
4828 |
4829 | /* kJscsspKEYFRAME_RULE */
4830 | function jscsspKeyframeRule()
4831 | {
4832 | this.type = kJscsspKEYFRAME_RULE;
4833 | this.parsedCssText = null;
4834 | this.declarations = []
4835 | this.keyText = null;
4836 | this.parentStyleSheet = null;
4837 | this.parentRule = null;
4838 | }
4839 |
4840 | jscsspKeyframeRule.prototype = {
4841 | cssText: function() {
4842 | var rv = this.keyText + " {\n";
4843 | var preservedGTABS = gTABS;
4844 | gTABS += " ";
4845 | for (var i = 0; i < this.declarations.length; i++) {
4846 | var declText = this.declarations[i].cssText();
4847 | if (declText)
4848 | rv += gTABS + this.declarations[i].cssText() + "\n";
4849 | }
4850 | gTABS = preservedGTABS;
4851 | return rv + gTABS + "}";
4852 | },
4853 |
4854 | setCssText: function(val) {
4855 | var sheet = {cssRules: []};
4856 | var parser = new CSSParser(val);
4857 | var token = parser.getToken(true, true);
4858 | if (!token.isNotNull()) {
4859 | if (parser.parseKeyframeRule(token, sheet, false)) {
4860 | var newRule = sheet.cssRules[0];
4861 | this.keyText = newRule.keyText;
4862 | this.declarations = newRule.declarations;
4863 | this.parsedCssText = newRule.parsedCssText;
4864 | return;
4865 | }
4866 | }
4867 | throw DOMException.SYNTAX_ERR;
4868 | }
4869 | };
4870 |
4871 | /* kJscsspMEDIA_RULE */
4872 |
4873 | function jscsspMediaRule()
4874 | {
4875 | this.type = kJscsspMEDIA_RULE;
4876 | this.parsedCssText = null;
4877 | this.cssRules = [];
4878 | this.media = [];
4879 | this.parentStyleSheet = null;
4880 | this.parentRule = null;
4881 | }
4882 |
4883 | jscsspMediaRule.prototype = {
4884 | cssText: function() {
4885 | var rv = gTABS + "@media " + this.media.join(", ") + " {\n";
4886 | var preservedGTABS = gTABS;
4887 | gTABS += " ";
4888 | for (var i = 0; i < this.cssRules.length; i++)
4889 | rv += gTABS + this.cssRules[i].cssText() + "\n";
4890 | gTABS = preservedGTABS;
4891 | return rv + gTABS + "}";
4892 | },
4893 |
4894 | setCssText: function(val) {
4895 | var sheet = {cssRules: []};
4896 | var parser = new CSSParser(val);
4897 | var token = parser.getToken(true, true);
4898 | if (token.isAtRule("@media")) {
4899 | if (parser.parseMediaRule(token, sheet)) {
4900 | var newRule = sheet.cssRules[0];
4901 | this.cssRules = newRule.cssRules;
4902 | this.media = newRule.media;
4903 | this.parsedCssText = newRule.parsedCssText;
4904 | return;
4905 | }
4906 | }
4907 | throw DOMException.SYNTAX_ERR;
4908 | }
4909 | };
4910 |
4911 | /* kJscsspSTYLE_RULE */
4912 |
4913 | function jscsspStyleRule()
4914 | {
4915 | this.type = kJscsspSTYLE_RULE;
4916 | this.parsedCssText = null;
4917 | this.declarations = []
4918 | this.mSelectorText = null;
4919 | this.parentStyleSheet = null;
4920 | this.parentRule = null;
4921 | }
4922 |
4923 | jscsspStyleRule.prototype = {
4924 | cssText: function() {
4925 | var rv = this.mSelectorText + " {\n";
4926 | var preservedGTABS = gTABS;
4927 | gTABS += " ";
4928 | for (var i = 0; i < this.declarations.length; i++) {
4929 | var declText = this.declarations[i].cssText();
4930 | if (declText)
4931 | rv += gTABS + this.declarations[i].cssText() + "\n";
4932 | }
4933 | gTABS = preservedGTABS;
4934 | return rv + gTABS + "}";
4935 | },
4936 |
4937 | setCssText: function(val) {
4938 | var sheet = {cssRules: []};
4939 | var parser = new CSSParser(val);
4940 | var token = parser.getToken(true, true);
4941 | if (!token.isNotNull()) {
4942 | if (parser.parseStyleRule(token, sheet, false)) {
4943 | var newRule = sheet.cssRules[0];
4944 | this.mSelectorText = newRule.mSelectorText;
4945 | this.declarations = newRule.declarations;
4946 | this.parsedCssText = newRule.parsedCssText;
4947 | return;
4948 | }
4949 | }
4950 | throw DOMException.SYNTAX_ERR;
4951 | },
4952 |
4953 | selectorText: function() {
4954 | return this.mSelectorText;
4955 | },
4956 |
4957 | setSelectorText: function(val) {
4958 | var parser = new CSSParser(val);
4959 | var token = parser.getToken(true, true);
4960 | if (!token.isNotNull()) {
4961 | var s = parser.parseSelector(token, true);
4962 | if (s) {
4963 | this.mSelectorText = s.selector;
4964 | return;
4965 | }
4966 | }
4967 | throw DOMException.SYNTAX_ERR;
4968 | }
4969 | };
4970 |
4971 | /* kJscsspPAGE_RULE */
4972 |
4973 | function jscsspPageRule()
4974 | {
4975 | this.type = kJscsspPAGE_RULE;
4976 | this.parsedCssText = null;
4977 | this.pageSelector = null;
4978 | this.declarations = [];
4979 | this.parentStyleSheet = null;
4980 | this.parentRule = null;
4981 | }
4982 |
4983 | jscsspPageRule.prototype = {
4984 | cssText: function() {
4985 | var rv = gTABS + "@page "
4986 | + (this.pageSelector ? this.pageSelector + " ": "")
4987 | + "{\n";
4988 | var preservedGTABS = gTABS;
4989 | gTABS += " ";
4990 | for (var i = 0; i < this.declarations.length; i++)
4991 | rv += gTABS + this.declarations[i].cssText() + "\n";
4992 | gTABS = preservedGTABS;
4993 | return rv + gTABS + "}";
4994 | },
4995 |
4996 | setCssText: function(val) {
4997 | var sheet = {cssRules: []};
4998 | var parser = new CSSParser(val);
4999 | var token = parser.getToken(true, true);
5000 | if (token.isAtRule("@page")) {
5001 | if (parser.parsePageRule(token, sheet)) {
5002 | var newRule = sheet.cssRules[0];
5003 | this.pageSelector = newRule.pageSelector;
5004 | this.declarations = newRule.declarations;
5005 | this.parsedCssText = newRule.parsedCssText;
5006 | return;
5007 | }
5008 | }
5009 | throw DOMException.SYNTAX_ERR;
5010 | }
5011 | };
5012 |
5013 | /* kJscsspVARIABLES_RULE */
5014 |
5015 | function jscsspVariablesRule()
5016 | {
5017 | this.type = kJscsspVARIABLES_RULE;
5018 | this.parsedCssText = null;
5019 | this.declarations = [];
5020 | this.parentStyleSheet = null;
5021 | this.parentRule = null;
5022 | this.media = null;
5023 | }
5024 |
5025 | jscsspVariablesRule.prototype = {
5026 | cssText: function() {
5027 | var rv = gTABS + "@variables " +
5028 | (this.media.length ? this.media.join(", ") + " " : "") +
5029 | "{\n";
5030 | var preservedGTABS = gTABS;
5031 | gTABS += " ";
5032 | for (var i = 0; i < this.declarations.length; i++)
5033 | rv += gTABS + this.declarations[i].cssText() + "\n";
5034 | gTABS = preservedGTABS;
5035 | return rv + gTABS + "}";
5036 | },
5037 |
5038 | setCssText: function(val) {
5039 | var sheet = {cssRules: []};
5040 | var parser = new CSSParser(val);
5041 | var token = parser.getToken(true, true);
5042 | if (token.isAtRule("@variables")) {
5043 | if (parser.parseVariablesRule(token, sheet)) {
5044 | var newRule = sheet.cssRules[0];
5045 | this.declarations = newRule.declarations;
5046 | this.parsedCssText = newRule.parsedCssText;
5047 | return;
5048 | }
5049 | }
5050 | throw DOMException.SYNTAX_ERR;
5051 | }
5052 | };
5053 |
5054 | var kJscsspINHERIT_VALUE = 0;
5055 | var kJscsspPRIMITIVE_VALUE = 1;
5056 | var kJscsspVARIABLE_VALUE = 4;
5057 |
5058 | function jscsspVariable(aType, aSheet)
5059 | {
5060 | this.value = "";
5061 | this.type = aType;
5062 | this.name = null;
5063 | this.parentRule = null;
5064 | this.parentStyleSheet = aSheet;
5065 | }
5066 |
5067 | jscsspVariable.prototype = {
5068 | cssText: function() {
5069 | if (this.type == kJscsspVARIABLE_VALUE)
5070 | return this.resolveVariable(this.name, this.parentRule, this.parentStyleSheet);
5071 | else
5072 | return this.value;
5073 | },
5074 |
5075 | setCssText: function(val) {
5076 | if (this.type == kJscsspVARIABLE_VALUE)
5077 | throw DOMException.SYNTAX_ERR;
5078 | else
5079 | this.value = val;
5080 | },
5081 |
5082 | resolveVariable: function(aName, aRule, aSheet)
5083 | {
5084 | if (aName.toLowerCase() in aSheet.variables)
5085 | return aSheet.variables[aName.toLowerCase()];
5086 | return null;
5087 | }
5088 | };
5089 |
5090 | function ParseURL(buffer) {
5091 | var result = { };
5092 | result.protocol = "";
5093 | result.user = "";
5094 | result.password = "";
5095 | result.host = "";
5096 | result.port = "";
5097 | result.path = "";
5098 | result.query = "";
5099 |
5100 | var section = "PROTOCOL";
5101 | var start = 0;
5102 | var wasSlash = false;
5103 |
5104 | while(start < buffer.length) {
5105 | if(section == "PROTOCOL") {
5106 | if(buffer.charAt(start) == ':') {
5107 | section = "AFTER_PROTOCOL";
5108 | start++;
5109 | } else if(buffer.charAt(start) == '/' && result.protocol.length() == 0) {
5110 | section = PATH;
5111 | } else {
5112 | result.protocol += buffer.charAt(start++);
5113 | }
5114 | } else if(section == "AFTER_PROTOCOL") {
5115 | if(buffer.charAt(start) == '/') {
5116 | if(!wasSlash) {
5117 | wasSlash = true;
5118 | } else {
5119 | wasSlash = false;
5120 | section = "USER";
5121 | }
5122 | start ++;
5123 | } else {
5124 | throw new ParseException("Protocol shell be separated with 2 slashes");
5125 | }
5126 | } else if(section == "USER") {
5127 | if(buffer.charAt(start) == '/') {
5128 | result.host = result.user;
5129 | result.user = "";
5130 | section = "PATH";
5131 | } else if(buffer.charAt(start) == '?') {
5132 | result.host = result.user;
5133 | result.user = "";
5134 | section = "QUERY";
5135 | start++;
5136 | } else if(buffer.charAt(start) == ':') {
5137 | section = "PASSWORD";
5138 | start++;
5139 | } else if(buffer.charAt(start) == '@') {
5140 | section = "HOST";
5141 | start++;
5142 | } else {
5143 | result.user += buffer.charAt(start++);
5144 | }
5145 | } else if(section == "PASSWORD") {
5146 | if(buffer.charAt(start) == '/') {
5147 | result.host = result.user;
5148 | result.port = result.password;
5149 | result.user = "";
5150 | result.password = "";
5151 | section = "PATH";
5152 | } else if(buffer.charAt(start) == '?') {
5153 | result.host = result.user;
5154 | result.port = result.password;
5155 | result.user = "";
5156 | result.password = "";
5157 | section = "QUERY";
5158 | start ++;
5159 | } else if(buffer.charAt(start) == '@') {
5160 | section = "HOST";
5161 | start++;
5162 | } else {
5163 | result.password += buffer.charAt(start++);
5164 | }
5165 | } else if(section == "HOST") {
5166 | if(buffer.charAt(start) == '/') {
5167 | section = "PATH";
5168 | } else if(buffer.charAt(start) == ':') {
5169 | section = "PORT";
5170 | start++;
5171 | } else if(buffer.charAt(start) == '?') {
5172 | section = "QUERY";
5173 | start++;
5174 | } else {
5175 | result.host += buffer.charAt(start++);
5176 | }
5177 | } else if(section == "PORT") {
5178 | if(buffer.charAt(start) == '/') {
5179 | section = "PATH";
5180 | } else if(buffer.charAt(start) == '?') {
5181 | section = "QUERY";
5182 | start++;
5183 | } else {
5184 | result.port += buffer.charAt(start++);
5185 | }
5186 | } else if(section == "PATH") {
5187 | if(buffer.charAt(start) == '?') {
5188 | section = "QUERY";
5189 | start ++;
5190 | } else {
5191 | result.path += buffer.charAt(start++);
5192 | }
5193 | } else if(section == "QUERY") {
5194 | result.query += buffer.charAt(start++);
5195 | }
5196 | }
5197 |
5198 | if(section == "PROTOCOL") {
5199 | result.host = result.protocol;
5200 | result.protocol = "http";
5201 | } else if(section == "AFTER_PROTOCOL") {
5202 | throw new ParseException("Invalid url");
5203 | } else if(section == "USER") {
5204 | result.host = result.user;
5205 | result.user = "";
5206 | } else if(section == "PASSWORD") {
5207 | result.host = result.user;
5208 | result.port = result.password;
5209 | result.user = "";
5210 | result.password = "";
5211 | }
5212 |
5213 | return result;
5214 | }
5215 |
5216 | function ParseException(description) {
5217 | this.description = description;
5218 | }
5219 |
5220 | function CountLF(s)
5221 | {
5222 | var nCR = s.match( /\n/g );
5223 | return nCR ? nCR.length + 1 : 1;
5224 | }
5225 |
5226 |
5227 | function FilterLinearGradientForOutput(aValue, aEngine)
5228 | {
5229 | if (aEngine == "generic")
5230 | return aValue.substr(5);
5231 |
5232 | if (aEngine == "webkit")
5233 | return aValue.replace( /\-moz\-/g , "-webkit-")
5234 |
5235 | if (aEngine != "webkit20110101")
5236 | return "";
5237 |
5238 | var g = CssInspector.parseBackgroundImages(aValue)[0];
5239 |
5240 | var cancelled = false;
5241 | var str = "-webkit-gradient(linear, ";
5242 | var position = ("position" in g.value) ? g.value.position.toLowerCase() : "";
5243 | var angle = ("angle" in g.value) ? g.value.angle.toLowerCase() : "";
5244 | // normalize angle
5245 | if (angle) {
5246 | var match = angle.match(/^([0-9\-\.\\+]+)([a-z]*)/);
5247 | var angle = parseFloat(match[1]);
5248 | var unit = match[2];
5249 | switch (unit) {
5250 | case "grad": angle = angle * 90 / 100; break;
5251 | case "rad": angle = angle * 180 / Math.PI; break;
5252 | default: break;
5253 | }
5254 | while (angle < 0)
5255 | angle += 360;
5256 | while (angle >= 360)
5257 | angle -= 360;
5258 | }
5259 | // get startpoint w/o keywords
5260 | var startpoint = [];
5261 | var endpoint = [];
5262 | if (position != "") {
5263 | if (position == "center")
5264 | position = "center center";
5265 | startpoint = position.split(" ");
5266 | if (angle == "" && angle != 0) {
5267 | // no angle, then we just turn the point 180 degrees around center
5268 | switch (startpoint[0]) {
5269 | case "left": endpoint.push("right"); break;
5270 | case "center": endpoint.push("center"); break;
5271 | case "right": endpoint.push("left"); break;
5272 | default: {
5273 | var match = startpoint[0].match(/^([0-9\-\.\\+]+)([a-z]*)/);
5274 | var v = parseFloat(match[0]);
5275 | var unit = match[1];
5276 | if (unit == "%") {
5277 | endpoint.push((100-v) + "%");
5278 | }
5279 | else
5280 | cancelled = true;
5281 | }
5282 | break;
5283 | }
5284 | if (!cancelled)
5285 | switch (startpoint[1]) {
5286 | case "top": endpoint.push("bottom"); break;
5287 | case "center": endpoint.push("center"); break;
5288 | case "bottom": endpoint.push("top"); break;
5289 | default: {
5290 | var match = startpoint[1].match(/^([0-9\-\.\\+]+)([a-z]*)/);
5291 | var v = parseFloat(match[0]);
5292 | var unit = match[1];
5293 | if (unit == "%") {
5294 | endpoint.push((100-v) + "%");
5295 | }
5296 | else
5297 | cancelled = true;
5298 | }
5299 | break;
5300 | }
5301 | }
5302 | else {
5303 | switch (angle) {
5304 | case 0: endpoint.push("right"); endpoint.push(startpoint[1]); break;
5305 | case 90: endpoint.push(startpoint[0]); endpoint.push("top"); break;
5306 | case 180: endpoint.push("left"); endpoint.push(startpoint[1]); break;
5307 | case 270: endpoint.push(startpoint[0]); endpoint.push("bottom"); break;
5308 | default: cancelled = true; break;
5309 | }
5310 | }
5311 | }
5312 | else {
5313 | // no position defined, we accept only vertical and horizontal
5314 | if (angle == "")
5315 | angle = 270;
5316 | switch (angle) {
5317 | case 0: startpoint= ["left", "center"]; endpoint = ["right", "center"]; break;
5318 | case 90: startpoint= ["center", "bottom"]; endpoint = ["center", "top"]; break;
5319 | case 180: startpoint= ["right", "center"]; endpoint = ["left", "center"]; break;
5320 | case 270: startpoint= ["center", "top"]; endpoint = ["center", "bottom"]; break;
5321 | default: cancelled = true; break;
5322 | }
5323 | }
5324 |
5325 | if (cancelled)
5326 | return "";
5327 |
5328 | str += startpoint.join(" ") + ", " + endpoint.join(" ");
5329 | if (!g.value.stops[0].position)
5330 | g.value.stops[0].position = "0%";
5331 | if (!g.value.stops[g.value.stops.length-1].position)
5332 | g.value.stops[g.value.stops.length-1].position = "100%";
5333 | var current = 0;
5334 | for (var i = 0; i < g.value.stops.length && !cancelled; i++) {
5335 | var s = g.value.stops[i];
5336 | if (s.position) {
5337 | if (s.position.indexOf("%") == -1) {
5338 | cancelled = true;
5339 | break;
5340 | }
5341 | }
5342 | else {
5343 | var j = i + 1;
5344 | while (j < g.value.stops.length && !g.value.stops[j].position)
5345 | j++;
5346 | var inc = parseFloat(g.value.stops[j].position) - current;
5347 | for (var k = i; k < j; k++) {
5348 | g.value.stops[k].position = (current + inc * (k - i + 1) / (j - i + 1)) + "%";
5349 | }
5350 | }
5351 | current = parseFloat(s.position);
5352 | str += ", color-stop(" + (parseFloat(current) / 100) + ", " + s.color + ")";
5353 | }
5354 |
5355 | if (cancelled)
5356 | return "";
5357 | return str + ")";
5358 | }
5359 |
5360 | function FilterRadialGradientForOutput(aValue, aEngine)
5361 | {
5362 | if (aEngine == "generic")
5363 | return aValue.substr(5);
5364 |
5365 | else if (aEngine == "webkit")
5366 | return aValue.replace( /\-moz\-/g , "-webkit-")
5367 |
5368 | else if (aEngine != "webkit20110101")
5369 | return "";
5370 |
5371 | var g = CssInspector.parseBackgroundImages(aValue)[0];
5372 |
5373 | var shape = ("shape" in g.value) ? g.value.shape : "";
5374 | var size = ("size" in g.value) ? g.value.size : "";
5375 | if (shape != "circle"
5376 | || (size != "farthest-corner" && size != "cover"))
5377 | return "";
5378 |
5379 | if (g.value.stops.length < 2
5380 | || !("position" in g.value.stops[0])
5381 | || !g.value.stops[g.value.stops.length - 1].position
5382 | || !("position" in g.value.stops[0])
5383 | || !g.value.stops[g.value.stops.length - 1].position)
5384 | return "";
5385 |
5386 | for (var i = 0; i < g.value.stops.length; i++) {
5387 | var s = g.value.stops[i];
5388 | if (("position" in s) && s.position && s.position.indexOf("px") == -1)
5389 | return "";
5390 | }
5391 |
5392 | var str = "-webkit-gradient(radial, ";
5393 | var position = ("position" in g.value) ? g.value.position : "center center";
5394 | str += position + ", " + parseFloat(g.value.stops[0].position) + ", ";
5395 | str += position + ", " + parseFloat(g.value.stops[g.value.stops.length - 1].position);
5396 |
5397 | // at this point we're sure to deal with pixels
5398 | var current = parseFloat(g.value.stops[0].position);
5399 | for (var i = 0; i < g.value.stops.length; i++) {
5400 | var s = g.value.stops[i];
5401 | if (!("position" in s) || !s.position) {
5402 | var j = i + 1;
5403 | while (j < g.value.stops.length && !g.value.stops[j].position)
5404 | j++;
5405 | var inc = parseFloat(g.value.stops[j].position) - current;
5406 | for (var k = i; k < j; k++) {
5407 | g.value.stops[k].position = (current + inc * (k - i + 1) / (j - i + 1)) + "px";
5408 | }
5409 | }
5410 | current = parseFloat(s.position);
5411 | var c = (current - parseFloat(g.value.stops[0].position)) /
5412 | (parseFloat(g.value.stops[g.value.stops.length - 1].position) - parseFloat(g.value.stops[0].position));
5413 | str += ", color-stop(" + c + ", " + s.color + ")";
5414 | }
5415 | str += ")"
5416 | return str;
5417 | }
5418 |
5419 | function FilterRepeatingGradientForOutput(aValue, aEngine)
5420 | {
5421 | if (aEngine == "generic")
5422 | return aValue.substr(5);
5423 |
5424 | else if (aEngine == "webkit")
5425 | return aValue.replace( /\-moz\-/g , "-webkit-")
5426 |
5427 | return "";
5428 | }
5429 |
--------------------------------------------------------------------------------
/js/palette.js:
--------------------------------------------------------------------------------
1 | var Color = net.brehaut.Color;
2 |
3 | var Palette = {
4 | colors : [],
5 | bw : [],
6 |
7 | init: function(cssText) {
8 | var parser = new CSSParser();
9 | var sheet = parser.parse(cssText, false, true);
10 | var colorsIndex = {};
11 | var rule;
12 | var declarations;
13 | var color;
14 |
15 | Palette.colors = [];
16 | Palette.bw = [];
17 |
18 | //Parse stylesheet and collect colors
19 | if (sheet && sheet.cssRules) {
20 | for (var i=0,l=sheet.cssRules.length; i c2.lightness) {
79 | return 1;
80 | } else {
81 | return c1.saturation - c2.saturation;
82 | }
83 | } else if (c1.hue < c2.hue) {
84 | return -1
85 | } else {
86 | return 1;
87 | }
88 | }
89 | };
--------------------------------------------------------------------------------