├── LICENSE ├── README.md ├── index.html └── js ├── color.js ├── cssParser.js └── palette.js /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012 Maurice Svay 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 | 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 | }; --------------------------------------------------------------------------------