root/lang/actionscript/ascss/src/css/ASCSS.asy @ 10752

Revision 10752, 95.8 kB (checked in by gyuque, 5 years ago)

supported attribute selector

Line 
1%{
2/*
3 *  Copyright (C) 2002-2003 Lars Knoll (knoll@kde.org)
4 *  Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
5 *  Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
6 *
7 *  This library is free software; you can redistribute it and/or
8 *  modify it under the terms of the GNU Lesser General Public
9 *  License as published by the Free Software Foundation; either
10 *  version 2 of the License, or (at your option) any later version.
11 *
12 *  This library is distributed in the hope that it will be useful,
13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 *  Lesser General Public License for more details.
16 *
17 *  You should have received a copy of the GNU Lesser General Public
18 *  License along with this library; if not, write to the Free Software
19 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20 *
21 */
22
23package css
24{
25        public class ASCSS
26        {
27                private var mParser:ASCSSParser;
28                private var mSheet:StyleList;
29                private var mProgressiveMode:Boolean;
30                private var mListener:IParserListener;
31
32                function ASCSS(aSrc:String, aDebugOut:Object = null, aProgressive:Boolean = false, aListener:IParserListener = null)
33                {
34                        mListener = aListener;
35                        mProgressiveMode = aProgressive;
36                        mSheet = new StyleList(null);
37                        var parser:ASCSSParser = new ASCSSParser(mSheet, aDebugOut, aProgressive, aListener);
38                        var lx:CSSLexer = new CSSLexer(aSrc, parser, aProgressive);
39                        parser.lexer = lx;
40
41                        mParser = parser;
42                }
43
44                public function get restRatio():Number
45                {
46                        return mParser.lexer.restRatio;
47                }
48
49                public function set propertyExtension(x:IPropertyExtension):void
50                {
51                        mParser.propertyExtension = x;
52                }
53
54                public function get sheet():StyleList
55                {
56                        return mSheet;
57                }
58
59                public function parse():void
60                {
61                        mParser.yyparse();
62                        if (mParser.lexer.finished && mListener)
63                        {
64                                mListener.cssParserFinished();
65                        }
66
67                        if (mParser.inShorthand())
68                                throw "parser is still in shorthand scope!";
69                }
70
71                public static function strip(s:String):String
72                {
73                        return s.replace(/^ +/, '').replace(/ +$/, '');
74                }
75               
76                public static function parseURL(url:String):String
77                {
78                        const rxURL:RegExp = /^[uU][rR][lL]\((.*)\)$/
79                        const rxS1:RegExp = /^"(.*)"$/
80                        const rxS2:RegExp = /^'(.*)'$/
81                        var rxres:Object;
82               
83                        url = strip(url);
84               
85                        if (null != (rxres = rxURL.exec(url)))
86                                url = rxres[1];
87               
88                        url = strip(url);
89               
90                        if (null != (rxres = rxS1.exec(url)))
91                                url = rxres[1];
92               
93                        if (null != (rxres = rxS2.exec(url)))
94                                url = rxres[1];
95               
96                        url = strip(url);
97               
98                        var buffer:Array = [];
99                    for (var k:int = 0; k < url.length; k++) {
100                                var c:uint = url.charCodeAt(k);
101                                if (c > 13)
102                                        buffer.push(url.charAt(k));
103                    }
104               
105                    return buffer.join('');
106                }
107        }
108}
109
110class ShadowParseContext
111{
112        import css.*;
113        public var allowX:Boolean = true;
114        public var allowY:Boolean = false;
115        public var allowBlur:Boolean = false;
116        public var allowColor:Boolean = true;
117        public var allowBreak:Boolean = true;
118
119        public var values:CSSValueList = null;
120        public var x:CSSPrimitiveValue = null;
121        public var y:CSSPrimitiveValue = null;
122        public var blur:CSSPrimitiveValue = null;
123        public var color:CSSPrimitiveValue = null;
124
125        public function allowLength():Boolean { return allowX || allowY || allowBlur; }
126
127        public function commitValue():void
128        {
129                // Handle the ,, case gracefully by doing nothing.
130                if (x || y || blur || color) {
131                        if (!values)
132                                values = new CSSValueList();
133                       
134                        // Construct the current shadow value and add it to the list.
135                        values.append(new ShadowValue(x, y, blur, color));
136                }
137               
138                // Now reset for the next shadow value.
139                x = y = blur = color = null;
140                allowX = allowColor = allowBreak = true;
141                allowY = allowBlur = false; 
142        }
143
144        public function commitLength(v:Value):void
145        {
146                var val:CSSPrimitiveValue = CSSPrimitiveValue.newUnitNumber(v.fValue, v.unit);
147
148                if (allowX) {
149                        x = val;
150                        allowX = false; allowY = true; allowColor = false; allowBreak = false;
151                }
152                else if (allowY) {
153                        y = val;
154                        allowY = false; allowBlur = true; allowColor = true; allowBreak = true;
155                }
156                else if (allowBlur) {
157                        blur = val;
158                        allowBlur = false;
159                }
160        }
161
162        public function commitColor(val:CSSPrimitiveValue):void
163        {
164                color = val;
165                allowColor = false;
166                if (allowX)
167                        allowBreak = false;
168                else
169                        allowBlur = false;
170        }
171}
172
173%}
174
175%union {
176    bool Boolean;
177    char character;
178    int integer;
179    double number;
180    ParseString string;
181
182    CSSRule* rule;
183    CSSRuleList* ruleList;
184    CSSSelector* selector;
185    CSSSelector::Relation relation;
186    MediaList* mediaList;
187    MediaQuery* mediaQuery;
188    MediaQuery::Restrictor mediaQueryRestrictor;
189    MediaQueryExp* mediaQueryExp;
190    Value value;
191    ValueList* valueList;
192    Vector<MediaQueryExp*>* mediaQueryExpList;
193}
194
195%expect 42
196
197%left UNIMPORTANT_TOK
198
199%token WHITESPACE SGML_CD
200
201%token INCLUDES
202%token DASHMATCH
203%token BEGINSWITH
204%token ENDSWITH
205%token CONTAINS
206
207%token <string> STRING
208%right <string> IDENT
209%token <string> NTH
210
211%nonassoc <string> HEX
212%nonassoc <string> IDSEL
213%nonassoc ':'
214%nonassoc '.'
215%nonassoc '['
216%nonassoc <string> '*'
217%nonassoc error
218%left '|'
219
220%token IMPORT_SYM
221%token PAGE_SYM
222%token MEDIA_SYM
223%token FONT_FACE_SYM
224%token CHARSET_SYM
225%token NAMESPACE_SYM
226%token WEBKIT_RULE_SYM
227%token WEBKIT_DECLS_SYM
228%token WEBKIT_VALUE_SYM
229%token WEBKIT_MEDIAQUERY_SYM
230
231%token IMPORTANT_SYM
232%token MEDIA_ONLY
233%token MEDIA_NOT
234%token MEDIA_AND
235
236%token <number> QEMS
237%token <number> EMS
238%token <number> EXS
239%token <number> PXS
240%token <number> CMS
241%token <number> MMS
242%token <number> INS
243%token <number> PTS
244%token <number> PCS
245%token <number> DEGS
246%token <number> RADS
247%token <number> GRADS
248%token <number> MSECS
249%token <number> SECS
250%token <number> HERZ
251%token <number> KHERZ
252%token <string> DIMEN
253%token <number> PERCENTAGE
254%token <number> FLOATTOKEN
255%token <number> INTEGER
256
257%token <string> URI
258%token <string> FUNCTION
259%token <string> NOTFUNCTION
260
261%token <string> UNICODERANGE
262
263%type <relation> combinator
264
265%type <rule> charset
266%type <rule> ruleset
267%type <rule> valid_rule_or_import
268%type <rule> media
269%type <rule> import
270%type <rule> page
271%type <rule> font_face
272%type <rule> invalid_rule
273%type <rule> invalid_at
274%type <rule> invalid_import
275%type <rule> rule
276%type <rule> valid_rule
277
278%type <string> maybe_ns_prefix
279
280%type <string> namespace_selector
281
282%type <string> string_or_uri
283%type <string> ident_or_string
284%type <string> medium
285%type <string> hexcolor
286
287%type <string> media_feature
288%type <mediaList> media_list
289%type <mediaList> maybe_media_list
290%type <mediaQuery> media_query
291%type <mediaQueryRestrictor> maybe_media_restrictor
292%type <valueList> maybe_media_value
293%type <mediaQueryExp> media_query_exp
294%type <mediaQueryExpList> media_query_exp_list
295%type <mediaQueryExpList> maybe_and_media_query_exp_list
296
297%type <ruleList> ruleset_list
298
299%type <integer> property
300
301%type <selector> specifier
302%type <selector> specifier_list
303%type <selector> simple_selector
304%type <selector> selector
305%type <selector> selector_list
306%type <selector> selector_with_trailing_whitespace
307%type <selector> class
308%type <selector> attrib
309%type <selector> pseudo
310
311%type <boolean> declaration_list
312%type <boolean> decl_list
313%type <boolean> declaration
314
315%type <boolean> prio
316
317%type <integer> match
318%type <integer> unary_operator
319%type <character> operator
320
321%type <valueList> expr
322%type <value> term
323%type <value> unary_term
324%type <value> function
325
326%type <string> element_name
327%type <string> attr_name
328
329%%
330
331stylesheet:
332    maybe_charset maybe_sgml import_list namespace_list rule_list
333  | webkit_rule maybe_space
334  | webkit_decls maybe_space
335  | webkit_value maybe_space
336  | webkit_mediaquery maybe_space
337  ;
338
339valid_rule_or_import:
340    valid_rule
341  | import
342  ;
343
344webkit_rule:
345    WEBKIT_RULE_SYM '{' maybe_space valid_rule_or_import maybe_space '}' {
346        (parser as ASCSSParser /* original: CSSParser */).rule = $4;
347    }
348;
349
350webkit_decls:
351    WEBKIT_DECLS_SYM '{' maybe_space declaration_list '}' {
352        /* can be empty */
353    }
354;
355
356webkit_value:
357    WEBKIT_VALUE_SYM '{' maybe_space expr '}' {
358        var p:ASCSSParser /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
359        if ($4) {
360            p.valueList = p.sinkFloatingValueList($4);
361            var oldParsedProperties:int = p.numParsedProperties;
362            if (!p.parseValue(p.id, p.important))
363                p.rollbackLastProperties(p.numParsedProperties - oldParsedProperties);
364            /* delete p->valueList; */
365            p.valueList = null;
366        }
367    }
368;
369
370webkit_mediaquery:
371     WEBKIT_MEDIAQUERY_SYM WHITESPACE maybe_space media_query '}' {
372         p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
373         p.mediaQuery = p.sinkFloatingMediaQuery($4);
374     }
375;
376
377maybe_space:
378    /* empty */ %prec UNIMPORTANT_TOK
379  | maybe_space WHITESPACE
380  ;
381
382maybe_sgml:
383    /* empty */
384  | maybe_sgml SGML_CD
385  | maybe_sgml WHITESPACE
386  ;
387
388maybe_charset:
389   /* empty */
390  | charset {
391  }
392;
393
394charset:
395  CHARSET_SYM maybe_space STRING maybe_space ';' {
396     markLine();
397     p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
398     $$ = (parser as ASCSSParser /* original: CSSParser */).createCharsetRule($3);
399     if ($$ && p.styleElement && p.styleElement.isCSSStyleSheet())
400         p.styleElement.append($$);
401  }
402  | CHARSET_SYM error invalid_block {
403  }
404  | CHARSET_SYM error ';' {
405  }
406;
407
408import_list:
409 /* empty */
410 | import_list import maybe_sgml {
411     p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
412     if ($2 && p.styleElement && p.styleElement.isCSSStyleSheet())
413         p.styleElement.append($2);
414 }
415 ;
416
417namespace_list:
418/* empty */
419| namespace_list namespace maybe_sgml
420;
421
422rule_list:
423   /* empty */
424 | rule_list rule maybe_sgml {
425     p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
426     if ($2 && p.styleElement && p.styleElement.isCSSStyleSheet())
427         p.styleElement.append($2);
428 }
429 ;
430
431valid_rule:
432    ruleset
433  | media
434  | page
435  | font_face
436  ;
437
438rule:
439    valid_rule
440  | invalid_rule
441  | invalid_at
442  | invalid_import
443  ;
444
445import:
446    IMPORT_SYM maybe_space string_or_uri maybe_space maybe_media_list ';' {
447        $$ = (parser as ASCSSParser /* original: CSSParser */).createImportRule($3, $5);
448    }
449  | IMPORT_SYM error invalid_block {
450        $$ = null /* 0 */;
451    }
452  | IMPORT_SYM error ';' {
453        $$ = null /* 0 */;
454    }
455  ;
456
457namespace:
458NAMESPACE_SYM maybe_space maybe_ns_prefix string_or_uri maybe_space ';' {
459    p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
460    if (p.styleElement && p.styleElement.isCSSStyleSheet())
461        (p.styleElement as CSSStyleSheet).addNamespace(p, $3, $4);
462}
463| NAMESPACE_SYM error invalid_block
464| NAMESPACE_SYM error ';'
465;
466
467maybe_ns_prefix:
468/* empty */ { $$ = null; /* $$.characters = 0; */ }
469| IDENT WHITESPACE { $$ = $1; }
470;
471
472string_or_uri:
473STRING
474| URI
475;
476
477media_feature:
478    IDENT maybe_space {
479        $$ = $1;
480    }
481    ;
482
483maybe_media_value:
484    /*empty*/ {
485        $$ = null /* 0 */;
486    }
487    | ':' maybe_space expr maybe_space {
488        $$ = $3;
489    }
490    ;
491
492media_query_exp:
493    '(' maybe_space media_feature maybe_space maybe_media_value ')' maybe_space {
494        $3.toLowerCase();
495        $$ = (parser as ASCSSParser /* original: CSSParser */).createFloatingMediaQueryExp($3, $5);
496    }
497    ;
498
499media_query_exp_list:
500    media_query_exp {
501        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
502        $$ = p.createFloatingMediaQueryExpList();
503        $$.append(p.sinkFloatingMediaQueryExp($1));
504    }
505    | media_query_exp_list maybe_space MEDIA_AND maybe_space media_query_exp {
506        $$ = $1;
507        $$.append((parser as ASCSSParser /* original: CSSParser */).sinkFloatingMediaQueryExp($5));
508    }
509    ;
510
511maybe_and_media_query_exp_list:
512    /*empty*/ {
513        $$ = (parser as ASCSSParser /* original: CSSParser */).createFloatingMediaQueryExpList();
514    }
515    | MEDIA_AND maybe_space media_query_exp_list {
516        $$ = $3;
517    }
518    ;
519
520maybe_media_restrictor:
521    /*empty*/ {
522        $$ = MediaQuery.None;
523    }
524    | MEDIA_ONLY {
525        $$ = MediaQuery.Only;
526    }
527    | MEDIA_NOT {
528        $$ = MediaQuery.Not;
529    }
530    ;
531
532media_query:
533    media_query_exp_list {
534        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
535        $$ = p.createFloatingMediaQueryWithExprs(p.sinkFloatingMediaQueryExpList($1));
536    }
537    |
538    maybe_media_restrictor maybe_space medium maybe_and_media_query_exp_list {
539        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
540        $3.toLowerCase();
541        $$ = p.createFloatingMediaQuery($1, $3, p.sinkFloatingMediaQueryExpList($4));
542    }
543    ;
544
545maybe_media_list:
546     /* empty */ {
547        $$ = (parser as ASCSSParser /* original: CSSParser */).createMediaList();
548     }
549     | media_list
550     ;
551
552media_list:
553    media_query {
554        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
555        $$ = p.createMediaList();
556        $$.appendMediaQuery(p.sinkFloatingMediaQuery($1));
557    }
558    | media_list ',' maybe_space media_query {
559        $$ = $1;
560        if ($$)
561            $$.appendMediaQuery((parser as ASCSSParser /* original: CSSParser */).sinkFloatingMediaQuery($4));
562    }
563    | media_list error {
564        $$ = null /* 0 */;
565    }
566    ;
567
568media:
569    MEDIA_SYM maybe_space media_list '{' maybe_space ruleset_list '}' {
570        $$ = (parser as ASCSSParser /* original: CSSParser */).createMediaRule($3, $6);
571    }
572    | MEDIA_SYM maybe_space '{' maybe_space ruleset_list '}' {
573        $$ = (parser as ASCSSParser /* original: CSSParser */).createMediaRule(null, $5);
574    }
575    ;
576
577ruleset_list:
578    /* empty */ { $$ = null /* 0 */; }
579    | ruleset_list ruleset maybe_space {
580        $$ = $1;
581        if ($2) {
582            if (!$$)
583                $$ = (parser as ASCSSParser /* original: CSSParser */).createRuleList();
584            $$.append($2);
585        }
586    }
587    ;
588
589medium:
590  IDENT maybe_space {
591      $$ = $1;
592  }
593  ;
594
595/*
596page:
597    PAGE_SYM maybe_space IDENT? pseudo_page? maybe_space
598    '{' maybe_space declaration [ ';' maybe_space declaration ]* '}' maybe_space
599  ;
600
601pseudo_page
602  : ':' IDENT
603  ;
604*/
605
606page:
607    PAGE_SYM error invalid_block {
608      $$ = null /* 0 */;
609    }
610  | PAGE_SYM error ';' {
611      $$ = null /* 0 */;
612    }
613    ;
614
615font_face:
616    FONT_FACE_SYM maybe_space
617    '{' maybe_space declaration_list '}'  maybe_space {
618        $$ = (parser as ASCSSParser /* original: CSSParser */).createFontFaceRule();
619    }
620    | FONT_FACE_SYM error invalid_block {
621      $$ = null /* 0 */;
622    }
623    | FONT_FACE_SYM error ';' {
624      $$ = null /* 0 */;
625    }
626;
627
628combinator:
629    '+' maybe_space { $$ = CSSSelector.DirectAdjacent; }
630  | '~' maybe_space { $$ = CSSSelector.IndirectAdjacent; }
631  | '>' maybe_space { $$ = CSSSelector.Child; }
632  ;
633
634unary_operator:
635    '-' { $$ = -1; }
636  | '+' { $$ = 1; }
637  ;
638
639ruleset:
640    selector_list '{' maybe_space declaration_list '}' {
641        $$ = (parser as ASCSSParser /* original: CSSParser */).createStyleRule($1);
642                pauseIfProgressive();
643    }
644  ;
645
646selector_list:
647    selector %prec UNIMPORTANT_TOK {
648        $$ = $1;
649    }
650    | selector_list ',' maybe_space selector %prec UNIMPORTANT_TOK {
651        if ($1 && $4) {
652            p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
653            $$ = $1;
654            $$.append(p.sinkFloatingSelector($4));
655        } else
656            $$ = null /* 0 */;
657    }
658  | selector_list error {
659        $$ = null /* 0 */;
660    }
661   ;
662
663selector_with_trailing_whitespace:
664    selector WHITESPACE {
665        $$ = $1;
666    }
667    ;
668
669selector:
670    simple_selector {
671        $$ = $1;
672                markLine();
673    }
674    | selector_with_trailing_whitespace
675    {
676        $$ = $1;
677                markLine();
678    }
679    | selector_with_trailing_whitespace simple_selector
680    {
681        $$ = $2;
682        if (!$1)
683            $$ = null /* 0 */;
684        else if ($$) {
685            p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
686            var end:CSSSelector = CSSSelector($$);
687            while (end.m_tagHistory)
688                end = end.m_tagHistory;
689            end.m_relation = CSSSelector.Descendant;
690            end.m_tagHistory = p.sinkFloatingSelector($1);
691            if ((doc = p.document()))
692                doc.setUsesDescendantRules(true);
693        }
694    }
695    | selector combinator simple_selector {
696        $$ = $3;
697        if (!$1)
698            $$ = null /* 0 */;
699        else if ($$) {
700            p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
701            end = CSSSelector($$);
702            while (end.m_tagHistory)
703                end = end.m_tagHistory;
704            end.m_relation = $2;
705            end.m_tagHistory = p.sinkFloatingSelector($1);
706            if ($2 == CSSSelector.Child) {
707                if ((doc = p.document()))
708                    doc.setUsesDescendantRules(true);
709            } else if ($2 == CSSSelector.DirectAdjacent || $2 == CSSSelector.IndirectAdjacent) {
710                if ((doc = p.document()))
711                    doc.setUsesSiblingRules(true);
712            }
713        }
714    }
715    | selector error {
716        $$ = null /* 0 */;
717    }
718    ;
719
720namespace_selector:
721    /* empty */ '|' { $$ = null; /* $$.characters = null; $$.length = 0; */ }
722    | '*' '|' { $$ = star; /* $$.characters = star; $$.length = 1; */ }
723    | IDENT '|' { $$ = $1; }
724;
725   
726simple_selector:
727    element_name {
728        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
729        $$ = p.createFloatingSelector();
730        $$.m_tag = new QualifiedName(null, $1, p.defaultNamespace);
731    }
732    | element_name specifier_list {
733        $$ = $2;
734        if ($$) {
735            p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
736            $$.m_tag = new QualifiedName(null, $1, p.defaultNamespace);
737        }
738    }
739    | specifier_list {
740        $$ = $1;
741        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
742        if ($$ && p.defaultNamespace != '*')
743            $$.m_tag = new QualifiedName(null, '*', p.defaultNamespace);
744    }
745    | namespace_selector element_name {
746        var namespacePrefix:String = $1;
747        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
748        $$ = p.createFloatingSelector();
749        if (p.styleElement && p.styleElement.isCSSStyleSheet()) {
750            $$.m_tag = new QualifiedName(namespacePrefix, $2,
751                                      (p.styleElement as CSSStyleSheet).determineNamespace(namespacePrefix));
752        } else // FIXME: Shouldn't this case be an error?
753            $$.m_tag = new QualifiedName(null, $2, p.defaultNamespace);
754    }
755    | namespace_selector element_name specifier_list {
756        $$ = $3;
757        if ($$) {
758            namespacePrefix = $1;
759            p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
760            if (p.styleElement && p.styleElement.isCSSStyleSheet()) {
761                $$.m_tag = new QualifiedName(namespacePrefix, $2,
762                                          (p.styleElement as CSSStyleSheet).determineNamespace(namespacePrefix));
763            } else // FIXME: Shouldn't this case be an error?
764                $$.m_tag = new QualifiedName(null, $2, p.defaultNamespace);
765        }
766    }
767    | namespace_selector specifier_list {
768        $$ = $2;
769        if ($$) {
770            namespacePrefix = $1;
771            p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
772            if (p.styleElement && p.styleElement.isCSSStyleSheet())
773                $$.m_tag = new QualifiedName(namespacePrefix,
774                                          '*',
775                                          (p.styleElement as CSSStyleSheet).determineNamespace(namespacePrefix));
776        }
777    }
778  ;
779
780element_name:
781    IDENT {
782        var str:String = $1;
783        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
784        var doc:Document = p.document();
785        if (doc && doc.isHTMLDocument())
786            str.toLowerCase();
787        $$ = str;
788    }
789    | '*' {
790        $$ = star;
791    }
792  ;
793
794specifier_list:
795    specifier {
796        $$ = $1;
797    }
798    | specifier_list specifier {
799        if (!$2)
800            $$ = null /* 0 */;
801        else if ($1) {
802            $$ = $1;
803            p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
804            end = $1;
805            while (end.m_tagHistory)
806                end = end.m_tagHistory;
807            end.m_relation = CSSSelector.SubSelector;
808            end.m_tagHistory = p.sinkFloatingSelector($2);
809        }
810    }
811    | specifier_list error {
812        $$ = null /* 0 */;
813    }
814;
815
816specifier:
817    IDSEL {
818        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
819        $$ = p.createFloatingSelector();
820        $$.m_match = CSSSelector.Id;
821        if (!p.strict)
822            $1.toLowerCase();
823        $$.m_attr = QualifiedName.idAttr;
824        $$.m_value = $1;
825    }
826  | HEX {
827        // if ($1.characters[0] >= '0' && $1.characters[0] <= '9') {
828        if ($1.match(/^[0-9]/)) {
829            $$ = null /* 0 */;
830        } else {
831            p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
832            $$ = p.createFloatingSelector();
833            $$.m_match = CSSSelector.Id;
834            if (!p.strict)
835                $1.toLowerCase();
836            $$.m_attr = QualifiedName.idAttr;
837            $$.m_value = $1;
838        }
839    }
840  | class
841  | attrib
842  | pseudo
843    ;
844
845class:
846    '.' IDENT {
847        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
848        $$ = p.createFloatingSelector();
849        $$.m_match = CSSSelector.Class;
850        if (!p.strict)
851            $2.toLowerCase();
852        $$.m_attr = QualifiedName.classAttr;
853        $$.m_value = $2;
854    }
855  ;
856
857attr_name:
858    IDENT maybe_space {
859        str = $1;
860        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
861        doc = p.document();
862        if (doc && doc.isHTMLDocument())
863            str.toLowerCase();
864        $$ = str;
865    }
866    ;
867
868attrib:
869    '[' maybe_space attr_name ']' {
870        $$ = (parser as ASCSSParser /* original: CSSParser */).createFloatingSelector();
871        $$.m_attr = new QualifiedName(null, $3, null);
872        $$.m_match = CSSSelector.Set;
873    }
874    | '[' maybe_space attr_name match maybe_space ident_or_string maybe_space ']' {
875        $$ = (parser as ASCSSParser /* original: CSSParser */).createFloatingSelector();
876        $$.m_attr = new QualifiedName(null, $3, null);
877        $$.m_match = uint($4);
878        $$.m_value = $6;
879    }
880    | '[' maybe_space namespace_selector attr_name ']' {
881        namespacePrefix = $3;
882        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
883        $$ = p.createFloatingSelector();
884        $$.m_attr = new QualifiedName(namespacePrefix, $4,
885                                   (p.styleElement as CSSStyleSheet).determineNamespace(namespacePrefix));
886        $$.m_match = CSSSelector.Set;
887    }
888    | '[' maybe_space namespace_selector attr_name match maybe_space ident_or_string maybe_space ']' {
889        namespacePrefix = $3;
890        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
891        $$ = p.createFloatingSelector();
892        $$.m_attr = new QualifiedName(namespacePrefix, $4,
893                                   (p.styleElement as CSSStyleSheet).determineNamespace(namespacePrefix));
894        $$.m_match = uint($5);
895        $$.m_value = $7;
896    }
897  ;
898
899match:
900    '=' {
901        $$ = CSSSelector.Exact;
902    }
903    | INCLUDES {
904        $$ = CSSSelector.List;
905    }
906    | DASHMATCH {
907        $$ = CSSSelector.Hyphen;
908    }
909    | BEGINSWITH {
910        $$ = CSSSelector.Begin;
911    }
912    | ENDSWITH {
913        $$ = CSSSelector.End;
914    }
915    | CONTAINS {
916        $$ = CSSSelector.Contain;
917    }
918    ;
919
920ident_or_string:
921    IDENT
922  | STRING
923    ;
924
925pseudo:
926    ':' IDENT {
927        $$ = (parser as ASCSSParser /* original: CSSParser */).createFloatingSelector();
928        $$.m_match = CSSSelector.PseudoClass;
929        $2.toLowerCase();
930        $$.m_value = $2;
931        var type:int /* original: PseudoType */ = $$.pseudoType();
932        if (type == CSSSelector.PseudoUnknown)
933            $$ = null /* 0 */;
934        else if (type == CSSSelector.PseudoEmpty ||
935                 type == CSSSelector.PseudoFirstChild ||
936                 type == CSSSelector.PseudoFirstOfType ||
937                 type == CSSSelector.PseudoLastChild ||
938                 type == CSSSelector.PseudoLastOfType ||
939                 type == CSSSelector.PseudoOnlyChild ||
940                 type == CSSSelector.PseudoOnlyOfType) {
941            p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
942            doc = p.document();
943            if (doc)
944                doc.setUsesSiblingRules(true);
945        } else if (type == CSSSelector.PseudoFirstLine) {
946            p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
947            if ((doc = p.document()))
948                doc.setUsesFirstLineRules(true);
949        }
950    }
951    | ':' ':' IDENT {
952        $$ = (parser as ASCSSParser /* original: CSSParser */).createFloatingSelector();
953        $$.m_match = CSSSelector.PseudoElement;
954        $3.toLowerCase();
955        $$.m_value = $3;
956        type /* original: PseudoType */ = $$.pseudoType();
957        if (type == CSSSelector.PseudoUnknown)
958            $$ = null /* 0 */;
959        else if (type == CSSSelector.PseudoFirstLine) {
960            p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
961            if ((doc = p.document()))
962                doc.setUsesFirstLineRules(true);
963        }
964    }
965    // used by :nth-*(ax+b)
966    | ':' FUNCTION NTH ')' {
967        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
968        $$ = p.createFloatingSelector();
969        $$.m_match = CSSSelector.PseudoClass;
970        $$.m_argument = $3;
971        $$.m_value = $2;
972        type /* original: PseudoType */ = $$.pseudoType();
973        if (type == CSSSelector.PseudoUnknown)
974            $$ = null /* 0 */;
975        else if (type == CSSSelector.PseudoNthChild ||
976                 type == CSSSelector.PseudoNthOfType ||
977                 type == CSSSelector.PseudoNthLastChild ||
978                 type == CSSSelector.PseudoNthLastOfType) {
979            if (p.document())
980                p.document().setUsesSiblingRules(true);
981        }
982    }
983    // used by :nth-*
984    | ':' FUNCTION INTEGER ')' {
985        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
986        $$ = p.createFloatingSelector();
987        $$.m_match = CSSSelector.PseudoClass;
988        $$.m_argument = Number($3);
989        $$.m_value = $2;
990        type /* original: PseudoType */ = $$.pseudoType();
991        if (type == CSSSelector.PseudoUnknown)
992            $$ = null /* 0 */;
993        else if (type == CSSSelector.PseudoNthChild ||
994                 type == CSSSelector.PseudoNthOfType ||
995                 type == CSSSelector.PseudoNthLastChild ||
996                 type == CSSSelector.PseudoNthLastOfType) {
997            if (p.document())
998                p.document().setUsesSiblingRules(true);
999        }
1000    }
1001    // used by :nth-*(odd/even) and :lang
1002    | ':' FUNCTION IDENT ')' {
1003        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
1004        $$ = p.createFloatingSelector();
1005        $$.m_match = CSSSelector.PseudoClass;
1006        $$.m_argument = $3;
1007        $2.toLowerCase();
1008        $$.m_value = $2;
1009        type /* original: PseudoType */ = $$.pseudoType();
1010        if (type == CSSSelector.PseudoUnknown)
1011            $$ = null /* 0 */;
1012        else if (type == CSSSelector.PseudoNthChild ||
1013                 type == CSSSelector.PseudoNthOfType ||
1014                 type == CSSSelector.PseudoNthLastChild ||
1015                 type == CSSSelector.PseudoNthLastOfType) {
1016            if (p.document())
1017                p.document().setUsesSiblingRules(true);
1018        }
1019    }
1020    // used by :not
1021    | ':' NOTFUNCTION maybe_space simple_selector maybe_space ')' {
1022        if (!$4)
1023            $$ = null /* 0 */;
1024        else {
1025            p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
1026            $$ = p.createFloatingSelector();
1027            $$.m_match = CSSSelector.PseudoClass;
1028            $$.m_simpleSelector = p.sinkFloatingSelector($4);
1029            $2.toLowerCase();
1030            $$.m_value = $2;
1031        }
1032    }
1033  ;
1034
1035declaration_list:
1036    declaration {
1037        $$ = $1;
1038    }
1039    | decl_list declaration {
1040        $$ = $1;
1041        if ( $2 )
1042            $$ = $2;
1043    }
1044    | decl_list {
1045        $$ = $1;
1046    }
1047    | error invalid_block_list error {
1048        $$ = false;
1049    }
1050    | error {
1051        $$ = false;
1052    }
1053    | decl_list error {
1054        $$ = $1;
1055    }
1056    ;
1057
1058decl_list:
1059    declaration ';' maybe_space {
1060        $$ = $1;
1061    }
1062    | declaration invalid_block_list ';' maybe_space {
1063        $$ = false;
1064    }
1065    | error ';' maybe_space {
1066        $$ = false;
1067    }
1068    | error invalid_block_list error ';' maybe_space {
1069        $$ = false;
1070    }
1071    | decl_list declaration ';' maybe_space {
1072        $$ = $1;
1073        if ($2)
1074            $$ = $2;
1075    }
1076    | decl_list error ';' maybe_space {
1077        $$ = $1;
1078    }
1079    | decl_list error invalid_block_list error ';' maybe_space {
1080        $$ = $1;
1081    }
1082    ;
1083
1084declaration:
1085    property ':' maybe_space expr prio {
1086        $$ = false;
1087        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
1088        if ($1 && $4) {
1089            p.valueList = p.sinkFloatingValueList($4);
1090            oldParsedProperties = p.numParsedProperties;
1091            $$ = p.parseValue($1, $5);
1092            if (!$$)
1093                p.rollbackLastProperties(p.numParsedProperties - oldParsedProperties);
1094            /* delete p->valueList; */
1095            p.valueList = null;
1096        }
1097    }
1098    |
1099    property error {
1100        $$ = false;
1101    }
1102    |
1103    property ':' maybe_space error expr prio {
1104        /* The default movable type template has letter-spacing: .none;  Handle this by looking for
1105        error tokens at the start of an expr, recover the expr and then treat as an error, cleaning
1106        up and deleting the shifted expr.  */
1107        $$ = false;
1108    }
1109    |
1110    IMPORTANT_SYM maybe_space {
1111        /* Handle this case: div { text-align: center; !important } Just reduce away the stray !important. */
1112        $$ = false;
1113    }
1114    |
1115    property ':' maybe_space {
1116        /* div { font-family: } Just reduce away this property with no value. */
1117        $$ = false;
1118    }
1119    |
1120    property ':' maybe_space error {
1121        /* if we come across rules with invalid values like this case: p { weight: *; }, just discard the rule */
1122        $$ = false;
1123    }
1124  ;
1125
1126property:
1127    IDENT maybe_space {
1128        $$ = cssPropertyID($1);
1129    }
1130  ;
1131
1132prio:
1133    IMPORTANT_SYM maybe_space { $$ = true; }
1134    | /* empty */ { $$ = false; }
1135  ;
1136
1137expr:
1138    term {
1139        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
1140        $$ = p.createFloatingValueList();
1141        $$.addValue(p.sinkFloatingValue($1));
1142    }
1143    | expr operator term {
1144        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
1145        $$ = $1;
1146        if ($$) {
1147            if ($2) {
1148                var v:Value = new Value();
1149                v.id = 0;
1150                v.unit = Value.Operator;
1151                v.iValue = $2;
1152                $$.addValue(v);
1153            }
1154            $$.addValue(p.sinkFloatingValue($3));
1155        }
1156    }
1157    | expr error {
1158        $$ = null /* 0 */;
1159    }
1160  ;
1161
1162operator:
1163    '/' maybe_space {
1164        $$ = '/';
1165    }
1166  | ',' maybe_space {
1167        $$ = ',';
1168    }
1169  | /* empty */ {
1170        $$ = null /* 0 */;
1171  }
1172  ;
1173
1174term:
1175  unary_term { $$ = $1; }
1176  | unary_operator unary_term { $$ = new Value(); $$ = $2; $$.fValue *= $1; }
1177  | STRING maybe_space { $$ = new Value(); $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue.CSS_STRING; }
1178  | IDENT maybe_space {
1179      $$ = new Value();
1180      $$.id = cssValueKeywordID($1);
1181      $$.unit = CSSPrimitiveValue.CSS_IDENT;
1182      $$.string = $1;
1183  }
1184  /* We might need to actually parse the number from a dimension, but we can't just put something that uses $$.string into unary_term. */
1185  | DIMEN maybe_space { $$ = new Value(); $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue.CSS_DIMENSION }
1186  | unary_operator DIMEN maybe_space { $$ = new Value(); $$.id = 0; $$.string = $2; $$.unit = CSSPrimitiveValue.CSS_DIMENSION }
1187  | URI maybe_space { $$ = new Value(); $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue.CSS_URI; }
1188  | UNICODERANGE maybe_space { $$ = new Value(); $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue.CSS_UNICODE_RANGE }
1189  | hexcolor { $$ = new Value(); $$.id = 0; $$.string = $1; $$.unit = CSSPrimitiveValue.CSS_RGBCOLOR; }
1190  | '#' maybe_space { $$ = new Value(); $$.id = 0; $$.string = ""; $$.unit = CSSPrimitiveValue.CSS_RGBCOLOR; } /* Handle error case: "color: #;" */
1191  /* FIXME: according to the specs a function can have a unary_operator in front. I know no case where this makes sense */
1192  | function {
1193      $$ = $1;
1194  }
1195  | '%' maybe_space {} /* Handle width: %; */
1196  ;
1197
1198unary_term:
1199  INTEGER maybe_space { $$ = new Value(); $$.id = 0; $$.isInt = true; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_NUMBER; }
1200  | FLOATTOKEN maybe_space { $$ = new Value(); $$.id = 0; $$.isInt = false; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_NUMBER; }
1201  | PERCENTAGE maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_PERCENTAGE; }
1202  | PXS maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_PX; }
1203  | CMS maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_CM; }
1204  | MMS maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_MM; }
1205  | INS maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_IN; }
1206  | PTS maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_PT; }
1207  | PCS maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_PC; }
1208  | DEGS maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_DEG; }
1209  | RADS maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_RAD; }
1210  | GRADS maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_GRAD; }
1211  | MSECS maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_MS; }
1212  | SECS maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_S; }
1213  | HERZ maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_HZ; }
1214  | KHERZ maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_KHZ; }
1215  | EMS maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_EMS; }
1216  | QEMS maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = Value.Q_EMS; }
1217  | EXS maybe_space { $$ = new Value(); $$.id = 0; $$.fValue = $1; $$.unit = CSSPrimitiveValue.CSS_EXS; }
1218    ;
1219
1220
1221function:
1222    FUNCTION maybe_space expr ')' maybe_space {
1223        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
1224        var f:ParseFunction /* original: Function */ = p.createFloatingFunction();
1225        f.name = $1;
1226        f.args = p.sinkFloatingValueList($3);
1227        $$ = new Value();
1228        $$.id = 0;
1229        $$.unit = Value.Function;
1230        $$.function = f;
1231    } |
1232    FUNCTION maybe_space error {
1233        p /* original: CSSParser */ = (parser as ASCSSParser /* original: CSSParser */);
1234        f /* original: Function */ = p.createFloatingFunction();
1235        f.name = $1;
1236        f.args = null;
1237        $$ = new Value();
1238        $$.id = 0;
1239        $$.unit = Value.Function;
1240        $$.function = f;
1241  }
1242  ;
1243/*
1244 * There is a constraint on the color that it must
1245 * have either 3 or 6 hex-digits (i.e., [0-9a-fA-F])
1246 * after the "#"; e.g., "#000" is OK, but "#abcd" is not.
1247 */
1248hexcolor:
1249  HEX maybe_space { $$ = $1; }
1250  | IDSEL maybe_space { $$ = $1; }
1251  ;
1252
1253
1254/* error handling rules */
1255
1256invalid_at:
1257    '@' error invalid_block {
1258        $$ = null /* 0 */;
1259    }
1260  | '@' error ';' {
1261        $$ = null /* 0 */;
1262    }
1263    ;
1264
1265invalid_import:
1266    import {
1267        $$ = null /* 0 */;
1268    }
1269    ;
1270
1271invalid_rule:
1272    error invalid_block {
1273        $$ = null /* 0 */;
1274    }
1275/*
1276  Seems like the two rules below are trying too much and violating
1277  http://www.hixie.ch/tests/evil/mixed/csserrorhandling.html
1278
1279  | error ';' {
1280        $$ = 0;
1281    }
1282  | error '}' {
1283        $$ = 0;
1284    }
1285*/
1286    ;
1287
1288invalid_block:
1289    '{' error invalid_block_list error '}'
1290  | '{' error '}'
1291    ;
1292
1293invalid_block_list:
1294    invalid_block
1295  | invalid_block_list error invalid_block
1296;
1297
1298%%
1299import css.*;
1300
1301// units for parsed value
1302public static const U_FUnknown:uint   = 0x0000;
1303public static const U_FInteger:uint   = 0x0001;
1304public static const U_FNumber:uint    = 0x0002;  // Real Numbers
1305public static const U_FPercent:uint   = 0x0004;
1306public static const U_FLength:uint    = 0x0008;
1307public static const U_FAngle:uint     = 0x0010;
1308public static const U_FTime:uint      = 0x0020;
1309public static const U_FFrequency:uint = 0x0040;
1310public static const U_FRelative:uint  = 0x0100;
1311public static const U_FNonNeg:uint    = 0x0200;
1312
1313private var mDebugOut:Object = null;
1314
1315private var mLineNo:int;
1316private var mMarkedLineNo:int;
1317private var mListener:IParserListener;
1318
1319private var mPauseLimit:int = 3;
1320private var mPauseCount:int = 0;
1321private var mProgressiveMode:Boolean;
1322private var mLex:CSSLexer;
1323private var mPropertyExtension:IPropertyExtension;
1324
1325private var defaultNamespace:String = '*';
1326private var mInParseShorthand:int;
1327private var mCurrentShorthand:int;
1328private var mImplicitShorthand:Boolean;
1329public var maxParsedProperties:int;
1330private var mParsedProperties:Array = [];
1331public function get numParsedProperties():int
1332{
1333        return mParsedProperties.length;
1334}
1335
1336private var m_parsedRuleLists:Array;
1337private var mParsedStyleObjects:Array /* of StyleBase */ = [];
1338
1339public var styleElement:StyleList;
1340public var mediaQuery:MediaQuery;
1341public var important:Boolean;
1342
1343private var mStrict:Boolean;
1344public function get strict():Boolean
1345{
1346        return mStrict;
1347}
1348
1349public var id:int;
1350public var rule:CSSRule;
1351public var valueList:ValueList;
1352
1353private static const star:String /* original: UChar */ = '*';
1354
1355function ASCSSParser(aSheet:StyleList, dbgout:Object, aProgressive:Boolean = false, aListener:IParserListener = null)
1356{
1357        m_parsedRuleLists = [];
1358        mListener = aListener;
1359        mProgressiveMode = aProgressive;
1360        mDebugOut = dbgout;
1361        styleElement = aSheet;
1362        mMarkedLineNo = mLineNo = 0;
1363
1364}
1365
1366private function pauseIfProgressive():void
1367{
1368        if (mProgressiveMode)
1369        {
1370                if (++mPauseCount >= mPauseLimit)
1371                {
1372                        mPauseCount = 0;
1373                        mLex.pause();
1374                }
1375        }
1376}
1377
1378private function markLine():void
1379{
1380        mMarkedLineNo = mLineNo;
1381}
1382
1383private function yylex():int {
1384        var ret:int = mLex.next();
1385
1386        if (ret == -1 && mListener)
1387        {
1388                mListener.cssParserPaused();
1389                return 0;
1390        }
1391
1392        yylval = mLex.tokenBody;
1393
1394        countNewLine(mLex.tokenBody);
1395       
1396        return ret;
1397}
1398
1399private function yyerror(msg:String):void {
1400        puts(msg + " near line "+(mLineNo+1));
1401}
1402
1403private function puts(s:*):void
1404{
1405        if (mDebugOut != null)
1406                mDebugOut.puts(s);
1407}
1408
1409private function countNewLine(tok:String):void
1410{
1411        if (!tok) return;
1412
1413        for (var cur:int = 0;;cur++)
1414        {
1415                if ((cur = tok.indexOf("\n", cur)) < 0)
1416                        break;
1417                mLineNo++;
1418        }
1419}
1420
1421public function get parser():ASCSSParser
1422{
1423        return this;
1424}
1425
1426public function set lexer(lx:CSSLexer):void
1427{
1428        mLex = lx;
1429}
1430
1431public function get lexer():CSSLexer
1432{
1433        return mLex;
1434}
1435
1436public function set propertyExtension(x:IPropertyExtension):void
1437{
1438        mPropertyExtension = x;
1439}
1440
1441public function inShorthand():Boolean
1442{
1443        return mInParseShorthand != 0;
1444}
1445
1446private function cssValueKeywordID(name:String):int
1447{
1448        if (CSSValueKeywords.MAP[name] || CSSValueKeywords.MAP[name] == 0)
1449                return CSSValueKeywords.MAP[name];
1450       
1451        return 0;
1452}
1453
1454private function cssPropertyID(name:String):int
1455{
1456        if (CSSPropertyID.MAP[name] || CSSPropertyID.MAP[name] == 0)
1457                return CSSPropertyID.MAP[name];
1458
1459    return -1;
1460}
1461
1462
1463// constructors
1464
1465private function createCharsetRule(charset:String):CSSRule
1466{
1467        if (!styleElement)
1468                return null;
1469        if (!styleElement.isCSSStyleSheet())
1470                return null;
1471
1472        var rule:CSSCharsetRule = new CSSCharsetRule(styleElement, charset);
1473        appendStyleObject(rule);
1474
1475        rule.startLineNo = mLineNo;
1476        rule.endLineNo   = mLineNo + 1;
1477
1478        markLine();
1479        return rule;
1480}
1481
1482private function appendStyleObject(o:StyleBase):void
1483{
1484        mParsedStyleObjects.push(o);
1485}
1486
1487private function createRuleList():CSSRuleList
1488{
1489        var list:CSSRuleList = new CSSRuleList();
1490        m_parsedRuleLists.append(list);
1491        return list;
1492}
1493
1494private function createMediaList():MediaList
1495{
1496    var list:MediaList = new MediaList();
1497    appendStyleObject(list);
1498    return list;
1499}
1500
1501private function createFontFaceRule():CSSRule
1502{
1503        var rule:CSSFontFaceRule = new CSSFontFaceRule(styleElement);
1504        appendStyleObject(rule);
1505        rule.declaration = new CSSMutableStyleDeclaration(rule, mParsedProperties);
1506        clearProperties();
1507        return rule;
1508}
1509
1510private function createImportRule(url:String, media:MediaList):CSSRule
1511{
1512        if (!media)
1513                return null;
1514        if (!styleElement)
1515                return null;
1516        if (!styleElement.isCSSStyleSheet())
1517                return null;
1518
1519        var rule:CSSImportRule = new CSSImportRule(styleElement, url, media);
1520        appendStyleObject(rule);
1521
1522        rule.startLineNo = mLineNo;
1523        rule.endLineNo   = mLineNo+1;
1524
1525        markLine();
1526
1527        return rule;
1528}
1529
1530private function createMediaRule(media:MediaList, rules:CSSRuleList):CSSRule
1531{
1532        if (!media)
1533                return null;
1534        if (!rules)
1535                return null;
1536        if (!styleElement)
1537                return null;
1538        if (!styleElement.isCSSStyleSheet())
1539                return null;
1540
1541        var rule:CSSMediaRule = new CSSMediaRule(styleElement, media, rules);
1542        appendStyleObject(rule);
1543        return rule;
1544}
1545
1546private function createStyleRule(sel:CSSSelector):CSSRule
1547{
1548        var rule:CSSStyleRule = null;
1549        if (sel != null)
1550        {
1551                rule = new CSSStyleRule(styleElement);
1552
1553                rule.startLineNo = mMarkedLineNo;
1554                rule.endLineNo   = mLineNo;
1555
1556                appendStyleObject(rule);
1557                rule.selector = sel;
1558                rule.declaration = new CSSMutableStyleDeclaration(rule, mParsedProperties);
1559        }
1560
1561        clearProperties();
1562        markLine();
1563        return rule;
1564}
1565
1566// dummy implements for C++ memory management funcs
1567
1568private function createFloatingSelector():CSSSelector
1569{
1570        return new CSSSelector();
1571}
1572
1573private function sinkFloatingSelector(s:CSSSelector):CSSSelector
1574{
1575        return s;
1576}
1577
1578private function createFloatingValueList():ValueList
1579{
1580        return new ValueList();
1581}
1582
1583private function sinkFloatingValueList(v:ValueList):ValueList
1584{
1585        return v;
1586}
1587
1588private function sinkFloatingValue(v:Value):Value
1589{
1590        return v;
1591}
1592
1593private function createFloatingMediaQueryExp(mediaFeature:String, values:ValueList):MediaQueryExp
1594{
1595        return new MediaQueryExp(mediaFeature, values);
1596}
1597
1598private function sinkFloatingMediaQueryExp(e:MediaQueryExp):MediaQueryExp
1599{
1600    return e;
1601}
1602
1603private function createFloatingMediaQueryExpList():Array
1604{
1605        return [];
1606}
1607
1608private function sinkFloatingMediaQueryExpList(l:Array):Array
1609{
1610    return l;
1611}
1612
1613private function createFloatingMediaQuery(r:int, mediaType:String, exprs:Array):MediaQuery
1614{
1615        return new MediaQuery(r, mediaType, exprs);
1616}
1617
1618private function createFloatingMediaQueryWithExprs(exprs:Array):MediaQuery
1619{
1620    return createFloatingMediaQuery(MediaQuery.None, "all", exprs);
1621}
1622
1623private function sinkFloatingMediaQuery(mq:MediaQuery):MediaQuery
1624{
1625        return mq;
1626}
1627
1628private function createFloatingFunction():ParseFunction
1629{
1630        return new ParseFunction();
1631}
1632
1633private function rollbackLastProperties(num:int):void
1634{
1635        if (!(num >= 0)) throw "assertion failed: (num >= 0)";
1636        if (!(numParsedProperties >= num)) throw "assertion failed: (numParsedProperties >= num)";
1637
1638        for (var i:int = 0; i < num; ++i)
1639                mParsedProperties.pop();
1640}
1641
1642private function clearProperties():void
1643{
1644        for (;mParsedProperties.length > 0;)
1645                mParsedProperties.shift();
1646}
1647
1648public function document():Document
1649{
1650        return null;
1651}
1652
1653// parsing
1654
1655private function parseValue(propId:int, important:Boolean):Boolean
1656{
1657        if (valueList == null)
1658                return false;
1659
1660        var val:Value = valueList.currentValue;
1661        if (val == null)
1662                return false;
1663
1664        var id:int   = val.id;
1665        var num:uint = inShorthand() ? 1 : valueList.length;
1666
1667        if (id == CSSValueKeywords.CSSValueInitial) {
1668                if (num != 1)
1669                        return false;
1670                addProperty(propId, new CSSInitialValue(false), important);
1671                return true;
1672        }
1673
1674        var valid_primitive:Boolean = false;
1675        var parsedValue:CSSValue;
1676
1677        switch(propId) {
1678                case CSSPropertyID.CSSPropertySize:                              // <length>{1,2} | auto | portrait | landscape | inherit
1679                case CSSPropertyID.CSSPropertyQuotes:                      // [<string> <string>]+ | none | inherit
1680                        if (id != 0)
1681                                valid_primitive = true;
1682                        break;
1683                case CSSPropertyID.CSSPropertyUnicodeBidi:               // normal | embed | bidi-override | inherit
1684                        if (id == CSSValueKeywords.CSSValueNormal ||
1685                                 id == CSSValueKeywords.CSSValueEmbed ||
1686                                 id == CSSValueKeywords.CSSValueBidiOverride)
1687                                valid_primitive = true;
1688                        break;
1689       
1690                case CSSPropertyID.CSSPropertyPosition:                  // static | relative | absolute | fixed | inherit
1691                        if (id == CSSValueKeywords.CSSValueStatic ||
1692                                 id == CSSValueKeywords.CSSValueRelative ||
1693                                 id == CSSValueKeywords.CSSValueAbsolute ||
1694                                 id == CSSValueKeywords.CSSValueFixed)
1695                                valid_primitive = true;
1696                        break;
1697
1698
1699                case CSSPropertyID.CSSPropertyBottom:               // <length> | <percentage> | auto | inherit
1700                case CSSPropertyID.CSSPropertyLeft:                 // <length> | <percentage> | auto | inherit
1701                case CSSPropertyID.CSSPropertyRight:                // <length> | <percentage> | auto | inherit
1702                case CSSPropertyID.CSSPropertyTop:                  // <length> | <percentage> | auto | inherit
1703                case CSSPropertyID.CSSPropertyMarginTop:           //// <margin-width> | inherit
1704                case CSSPropertyID.CSSPropertyMarginRight:         //   Which is defined as
1705                case CSSPropertyID.CSSPropertyMarginBottom:        //   <length> | <percentage> | auto | inherit
1706                case CSSPropertyID.CSSPropertyMarginLeft:          ////
1707                case CSSPropertyID.CSSPropertyWebkitMarginStart:
1708                if (id == CSSValueKeywords.CSSValueAuto)
1709                        valid_primitive = true;
1710                else
1711                        valid_primitive = (id == 0 && validUnit(val, U_FLength|U_FPercent, mStrict));
1712                break;
1713
1714                case CSSPropertyID.CSSPropertyPageBreakAfter:    // auto | always | avoid | left | right | inherit
1715                case CSSPropertyID.CSSPropertyPageBreakBefore:
1716                case CSSPropertyID.CSSPropertyWebkitColumnBreakAfter:
1717                case CSSPropertyID.CSSPropertyWebkitColumnBreakBefore:
1718                        if (id == CSSValueKeywords.CSSValueAuto ||
1719                                 id == CSSValueKeywords.CSSValueAlways ||
1720                                 id == CSSValueKeywords.CSSValueAvoid ||
1721                                 id == CSSValueKeywords.CSSValueLeft ||
1722                                 id == CSSValueKeywords.CSSValueRight)
1723                                valid_primitive = true;
1724                        break;
1725       
1726                case CSSPropertyID.CSSPropertyPageBreakInside:  // avoid | auto | inherit
1727                case CSSPropertyID.CSSPropertyWebkitColumnBreakInside:
1728                        if (id == CSSValueKeywords.CSSValueAuto || id == CSSValueKeywords.CSSValueAvoid)
1729                                valid_primitive = true;
1730                        break;
1731       
1732                case CSSPropertyID.CSSPropertyEmptyCells:                 // show | hide | inherit
1733                        if (id == CSSValueKeywords.CSSValueShow ||
1734                                 id == CSSValueKeywords.CSSValueHide)
1735                                valid_primitive = true;
1736                        break;
1737/*     
1738                case CSSPropertyID.CSSPropertyContent:                    // [ <string> | <uri> | <counter> | attr(X) | open-quote |
1739                        // close-quote | no-open-quote | no-close-quote ]+ | inherit
1740                        return parseContent(propId, important);
1741                        break;
1742*/     
1743                case CSSPropertyID.CSSPropertyWhiteSpace:                 // normal | pre | nowrap | inherit
1744                        if (id == CSSValueKeywords.CSSValueNormal ||
1745                                id == CSSValueKeywords.CSSValuePre ||
1746                                id == CSSValueKeywords.CSSValuePreWrap ||
1747                                id == CSSValueKeywords.CSSValuePreLine ||
1748                                id == CSSValueKeywords.CSSValueNowrap)
1749                                valid_primitive = true;
1750                        break;
1751       
1752                case CSSPropertyID.CSSPropertyClip:                              // <shape> | auto | inherit
1753                        if (id == CSSValueKeywords.CSSValueAuto)
1754                                valid_primitive = true;
1755        //              else if (val.unit == Value.Function)
1756        //                      return parseShape(propId, important);
1757                        break;
1758
1759                /* Start of supported CSS properties with validation. This is needed for parseShorthand to work
1760                 * correctly and allows optimization in WebCore::applyRule(..)
1761                 */
1762                case CSSPropertyID.CSSPropertyCaptionSide:               // top | bottom | left | right | inherit
1763                        if (id == CSSValueKeywords.CSSValueLeft || id == CSSValueKeywords.CSSValueRight ||
1764                                id == CSSValueKeywords.CSSValueTop || id == CSSValueKeywords.CSSValueBottom)
1765                                valid_primitive = true;
1766                        break;
1767       
1768                case CSSPropertyID.CSSPropertyBorderCollapse:     // collapse | separate | inherit
1769                        if (id == CSSValueKeywords.CSSValueCollapse || id == CSSValueKeywords.CSSValueSeparate)
1770                                valid_primitive = true;
1771                        break;
1772       
1773                case CSSPropertyID.CSSPropertyVisibility:                  // visible | hidden | collapse | inherit
1774                        if (id == CSSValueKeywords.CSSValueVisible || id == CSSValueKeywords.CSSValueHidden || id == CSSValueKeywords.CSSValueCollapse)
1775                                valid_primitive = true;
1776                        break;
1777       
1778                case CSSPropertyID.CSSPropertyOverflow: {
1779                        enterShorthandScope(propId);
1780                        if (num != 1 || !parseValue(CSSPropertyID.CSSPropertyOverflowX, important))
1781                        {
1782                                leaveShorthandScope();
1783                                return false;
1784                        }
1785
1786                        var ofvalue:CSSValue = CSSProperty(mParsedProperties[mParsedProperties.length - 1]).value;
1787                        addProperty(CSSPropertyID.CSSPropertyOverflowY, ofvalue, important);
1788
1789                        leaveShorthandScope();
1790                        return true;
1791                }
1792       
1793                case CSSPropertyID.CSSPropertyOverflowX:
1794                case CSSPropertyID.CSSPropertyOverflowY:                   // visible | hidden | scroll | auto | marquee | overlay | inherit
1795                        if (id == CSSValueKeywords.CSSValueVisible || id == CSSValueKeywords.CSSValueHidden || id == CSSValueKeywords.CSSValueScroll || id == CSSValueKeywords.CSSValueAuto ||
1796                                id == CSSValueKeywords.CSSValueOverlay || id == CSSValueKeywords.CSSValueWebkitMarquee)
1797                                valid_primitive = true;
1798                        break;
1799       
1800                case CSSPropertyID.CSSPropertyListStylePosition:  // inside | outside | inherit
1801                        if (id == CSSValueKeywords.CSSValueInside || id == CSSValueKeywords.CSSValueOutside)
1802                                valid_primitive = true;
1803                        break;
1804       
1805                case CSSPropertyID.CSSPropertyListStyleType:
1806                        // disc | circle | square | decimal | decimal-leading-zero | lower-roman |
1807                        // upper-roman | lower-greek | lower-alpha | lower-latin | upper-alpha |
1808                        // upper-latin | hebrew | armenian | georgian | cjk-ideographic | hiragana |
1809                        // katakana | hiragana-iroha | katakana-iroha | none | inherit
1810                        if ((id >= CSSValueKeywords.CSSValueDisc && id <= CSSValueKeywords.CSSValueKatakanaIroha) || id == CSSValueKeywords.CSSValueNone)
1811                                valid_primitive = true;
1812                        break;
1813       
1814                case CSSPropertyID.CSSPropertyDisplay:
1815                        // inline | block | list-item | run-in | inline-block | table |
1816                        // inline-table | table-row-group | table-header-group | table-footer-group | table-row |
1817                        // table-column-group | table-column | table-cell | table-caption | box | inline-box | none | inherit
1818                        if ((id >= CSSValueKeywords.CSSValueInline && id <= CSSValueKeywords.CSSValueWebkitInlineBox) || id == CSSValueKeywords.CSSValueNone)
1819                                valid_primitive = true;
1820                        break;
1821       
1822                case CSSPropertyID.CSSPropertyDirection:                        // ltr | rtl | inherit
1823                        if (id == CSSValueKeywords.CSSValueLtr || id == CSSValueKeywords.CSSValueRtl)
1824                                valid_primitive = true;
1825                        break;
1826       
1827                case CSSPropertyID.CSSPropertyTextTransform:       // capitalize | uppercase | lowercase | none | inherit
1828                        if ((id >= CSSValueKeywords.CSSValueCapitalize && id <= CSSValueKeywords.CSSValueLowercase) || id == CSSValueKeywords.CSSValueNone)
1829                                valid_primitive = true;
1830                        break;
1831       
1832                case CSSPropertyID.CSSPropertyFloat:                            // left | right | none | inherit + center for buggy CSS
1833                        if (id == CSSValueKeywords.CSSValueLeft || id == CSSValueKeywords.CSSValueRight ||
1834                                 id == CSSValueKeywords.CSSValueNone || id == CSSValueKeywords.CSSValueCenter)
1835                                valid_primitive = true;
1836                        break;
1837       
1838                case CSSPropertyID.CSSPropertyClear:                            // none | left | right | both | inherit
1839                        if (id == CSSValueKeywords.CSSValueNone || id == CSSValueKeywords.CSSValueLeft ||
1840                                 id == CSSValueKeywords.CSSValueRight|| id == CSSValueKeywords.CSSValueBoth)
1841                                valid_primitive = true;
1842                        break;
1843       
1844                case CSSPropertyID.CSSPropertyTextAlign:
1845                        // left | right | center | justify | webkit_left | webkit_right | webkit_center | start | end | <string> | inherit
1846                        if ((id >= CSSValueKeywords.CSSValueWebkitAuto && id <= CSSValueKeywords.CSSValueWebkitCenter) || id == CSSValueKeywords.CSSValueStart || id == CSSValueKeywords.CSSValueEnd ||
1847                                 val.unit == CSSPrimitiveValue.CSS_STRING)
1848                                valid_primitive = true;
1849                        break;
1850       
1851                case CSSPropertyID.CSSPropertyOutlineStyle:             // <border-style> | auto | inherit
1852                        if (id == CSSValueKeywords.CSSValueAuto) {
1853                                valid_primitive = true;
1854                                break;
1855                        } // Fall through!
1856                case CSSPropertyID.CSSPropertyBorderTopStyle:    //// <border-style> | inherit
1857                case CSSPropertyID.CSSPropertyBorderRightStyle:   //   Defined as:      none | hidden | dotted | dashed |
1858                case CSSPropertyID.CSSPropertyBorderBottomStyle:  //   solid | double | groove | ridge | inset | outset
1859                case CSSPropertyID.CSSPropertyBorderLeftStyle:
1860                case CSSPropertyID.CSSPropertyWebkitColumnRuleStyle:
1861                        if (id >= CSSValueKeywords.CSSValueNone && id <= CSSValueKeywords.CSSValueDouble)
1862                                valid_primitive = true;
1863                        break;
1864       
1865                case CSSPropertyID.CSSPropertyFontWeight:  // normal | bold | bolder | lighter | 100 | 200 | 300 | 400 |
1866                        // 500 | 600 | 700 | 800 | 900 | inherit
1867                        if (id >= CSSValueKeywords.CSSValueNormal && id <= CSSValueKeywords.CSSValue900) {
1868                                // Allready correct id
1869                                valid_primitive = true;
1870                        } else if (validUnit(val, U_FInteger|U_FNonNeg, false)) {
1871                                var weight:int = int(val.fValue);
1872                                if ((weight % 100) != 0)
1873                                        break;
1874                                weight /= 100;
1875                                if (weight >= 1 && weight <= 9) {
1876                                        id = CSSValueKeywords.CSSValue100 + weight - 1;
1877                                        valid_primitive = true;
1878                                }
1879                        }
1880                        break;
1881
1882                case CSSPropertyID.CSSPropertyBorderSpacing: {
1883                        const BORDERSPACING_PROPERTIES:Array = [ CSSPropertyID.CSSPropertyWebkitBorderHorizontalSpacing,
1884                                                                                                        CSSPropertyID.CSSPropertyWebkitBorderVerticalSpacing ];
1885                        if (num == 1) {
1886                                enterShorthandScope(CSSPropertyID.CSSPropertyBorderSpacing);
1887                                if (!parseValue(BORDERSPACING_PROPERTIES[0], important))
1888                                {
1889                                        leaveShorthandScope();
1890                                        return false;
1891                                }
1892                                var bs1val:CSSValue = CSSProperty(mParsedProperties[mParsedProperties.length-1]).value;
1893                                addProperty(BORDERSPACING_PROPERTIES[1], bs1val, important);
1894
1895                                leaveShorthandScope();
1896                                return true;
1897                        }
1898                        else if (num == 2) {
1899                                enterShorthandScope(CSSPropertyID.CSSPropertyBorderSpacing);
1900
1901                                if (!parseValue(BORDERSPACING_PROPERTIES[0], important) || !parseValue(BORDERSPACING_PROPERTIES[1], important))
1902                                {
1903                                        leaveShorthandScope();
1904                                        return false;
1905                                }
1906                                leaveShorthandScope();
1907                                return true;
1908                        }
1909                        return false;
1910                }
1911                case CSSPropertyID.CSSPropertyWebkitBorderHorizontalSpacing:
1912                case CSSPropertyID.CSSPropertyWebkitBorderVerticalSpacing:
1913                        valid_primitive = validUnit(val, U_FLength|U_FNonNeg, mStrict);
1914                        break;
1915                case CSSPropertyID.CSSPropertyScrollbarFaceColor:                // IE5.5
1916                case CSSPropertyID.CSSPropertyScrollbarShadowColor:        // IE5.5
1917                case CSSPropertyID.CSSPropertyScrollbarHighlightColor:  // IE5.5
1918                case CSSPropertyID.CSSPropertyScrollbar3dlightColor:      // IE5.5
1919                case CSSPropertyID.CSSPropertyScrollbarDarkshadowColor:   // IE5.5
1920                case CSSPropertyID.CSSPropertyScrollbarTrackColor:              // IE5.5
1921                case CSSPropertyID.CSSPropertyScrollbarArrowColor:              // IE5.5
1922                        if (mStrict)
1923                                break;
1924                        /* nobreak */
1925                case CSSPropertyID.CSSPropertyOutlineColor:             // <color> | invert | inherit
1926                        // Outline color has "invert" as additional keyword.
1927                        // Also, we want to allow the special focus color even in strict parsing mode.
1928                        if (propId == CSSPropertyID.CSSPropertyOutlineColor && (id == CSSValueKeywords.CSSValueInvert || id == CSSValueKeywords.CSSValueWebkitFocusRingColor)) {
1929                                valid_primitive = true;
1930                                break;
1931                        }
1932                        /* nobreak */
1933
1934                case CSSPropertyID.CSSPropertyBackgroundColor:     // <color> | inherit
1935                case CSSPropertyID.CSSPropertyBorderTopColor:     // <color> | inherit
1936                case CSSPropertyID.CSSPropertyBorderRightColor:   // <color> | inherit
1937                case CSSPropertyID.CSSPropertyBorderBottomColor:  // <color> | inherit
1938                case CSSPropertyID.CSSPropertyBorderLeftColor:    // <color> | inherit
1939                case CSSPropertyID.CSSPropertyColor:                // <color> | inherit
1940                case CSSPropertyID.CSSPropertyTextLineThroughColor: // CSS3 text decoration colors
1941                case CSSPropertyID.CSSPropertyTextUnderlineColor:
1942                case CSSPropertyID.CSSPropertyTextOverlineColor:
1943                case CSSPropertyID.CSSPropertyWebkitColumnRuleColor:
1944                case CSSPropertyID.CSSPropertyWebkitTextFillColor:
1945                case CSSPropertyID.CSSPropertyWebkitTextStrokeColor:
1946                        if (id == CSSValueKeywords.CSSValueWebkitText)
1947                                valid_primitive = true; // Always allow this, even when strict parsing is on,
1948                                                        // since we use this in our UA sheets.
1949                else
1950                        if (id >= CSSValueKeywords.CSSValueAqua && id <= CSSValueKeywords.CSSValueWindowtext || id == CSSValueKeywords.CSSValueMenu ||
1951                                        (id >= CSSValueKeywords.CSSValueWebkitFocusRingColor && id < CSSValueKeywords.CSSValueWebkitText && !mStrict))
1952                        {
1953                                valid_primitive = true;
1954                }
1955                        else
1956                        {
1957                    parsedValue = parseColor();
1958                    if (parsedValue != null)
1959                        valueList.next();
1960                }
1961                break;
1962
1963/*
1964        case CSSPropertyCursor:
1965*/
1966
1967                case CSSPropertyID.CSSPropertyBackgroundAttachment:
1968                case CSSPropertyID.CSSPropertyWebkitBackgroundClip:
1969                case CSSPropertyID.CSSPropertyWebkitBackgroundComposite:
1970                case CSSPropertyID.CSSPropertyBackgroundImage:
1971                case CSSPropertyID.CSSPropertyWebkitBackgroundOrigin:
1972                case CSSPropertyID.CSSPropertyBackgroundPosition:
1973                case CSSPropertyID.CSSPropertyBackgroundPositionX:
1974                case CSSPropertyID.CSSPropertyBackgroundPositionY:
1975                case CSSPropertyID.CSSPropertyWebkitBackgroundSize:
1976                case CSSPropertyID.CSSPropertyBackgroundRepeat: {
1977                        var imgvals:Array = [null, null]
1978                        var propIds:Array = [0, 0];
1979                        if (parseBackgroundProperty(propId, propIds, imgvals)) {
1980                                addProperty(propIds[0], imgvals[0], important);
1981                                if (imgvals[1])
1982                                        addProperty(propIds[1], imgvals[1], important);
1983                                return true;
1984                        }
1985                        return false;
1986                }
1987
1988                case CSSPropertyID.CSSPropertyListStyleImage:    // <uri> | none | inherit
1989                        if (id == CSSValueKeywords.CSSValueNone) {
1990                                parsedValue = new CSSImageValue();
1991                                valueList.next();
1992                        }
1993                        else if (val.unit == CSSPrimitiveValue.CSS_URI) {
1994                                // ### allow string in non strict mode?
1995                                var uri:String = ASCSS.parseURL(val.stringVal);
1996                                if (uri.length > 0) {
1997                                        parsedValue = new CSSImageValue((new KURL(styleElement.baseURL, uri)).toString(), styleElement);
1998                                        valueList.next();
1999                                }
2000                        }
2001                        break;
2002
2003                case CSSPropertyID.CSSPropertyWebkitTextStrokeWidth:
2004                case CSSPropertyID.CSSPropertyOutlineWidth:             // <border-width> | inherit
2005                case CSSPropertyID.CSSPropertyBorderTopWidth:    //// <border-width> | inherit
2006                case CSSPropertyID.CSSPropertyBorderRightWidth:   //   Which is defined as
2007                case CSSPropertyID.CSSPropertyBorderBottomWidth:  //   thin | medium | thick | <length>
2008                case CSSPropertyID.CSSPropertyBorderLeftWidth:
2009                case CSSPropertyID.CSSPropertyWebkitColumnRuleWidth:
2010                        if (id == CSSValueKeywords.CSSValueThin || id == CSSValueKeywords.CSSValueMedium || id == CSSValueKeywords.CSSValueThick)
2011                                valid_primitive = true;
2012                        else
2013                                valid_primitive = validUnit(val, U_FLength, mStrict);
2014                        break;
2015       
2016                case CSSPropertyID.CSSPropertyLetterSpacing:       // normal | <length> | inherit
2017                case CSSPropertyID.CSSPropertyWordSpacing:               // normal | <length> | inherit
2018                        if (id == CSSValueKeywords.CSSValueNormal)
2019                                valid_primitive = true;
2020                        else
2021                                valid_primitive = validUnit(val, U_FLength, mStrict);
2022                        break;
2023       
2024                case CSSPropertyID.CSSPropertyWordBreak:                  // normal | break-all | break-word (this is a custom extension)
2025                        if (id == CSSValueKeywords.CSSValueNormal || id == CSSValueKeywords.CSSValueBreakAll || id == CSSValueKeywords.CSSValueBreakWord)
2026                                valid_primitive = true;
2027                        break;
2028       
2029                case CSSPropertyID.CSSPropertyWordWrap:            // normal | break-word
2030                        if (id == CSSValueKeywords.CSSValueNormal || id == CSSValueKeywords.CSSValueBreakWord)
2031                                valid_primitive = true;
2032                        break;
2033       
2034                case CSSPropertyID.CSSPropertyTextIndent:                 // <length> | <percentage> | inherit
2035                case CSSPropertyID.CSSPropertyPaddingTop:                 //// <padding-width> | inherit
2036                case CSSPropertyID.CSSPropertyPaddingRight:             //   Which is defined as
2037                case CSSPropertyID.CSSPropertyPaddingBottom:       //   <length> | <percentage>
2038                case CSSPropertyID.CSSPropertyPaddingLeft:               ////
2039                case CSSPropertyID.CSSPropertyWebkitPaddingStart:
2040                        valid_primitive = (0 == id && validUnit(val, U_FLength|U_FPercent, mStrict));
2041                        break;
2042
2043                case CSSPropertyID.CSSPropertyMaxHeight:                   // <length> | <percentage> | none | inherit
2044                case CSSPropertyID.CSSPropertyMaxWidth:                 // <length> | <percentage> | none | inherit
2045                        if (id == CSSValueKeywords.CSSValueNone || id == CSSValueKeywords.CSSValueIntrinsic || id == CSSValueKeywords.CSSValueMinIntrinsic) {
2046                                valid_primitive = true;
2047                                break;
2048                        }
2049                        /* nobreak */
2050                case CSSPropertyID.CSSPropertyMinHeight:                   // <length> | <percentage> | inherit
2051                case CSSPropertyID.CSSPropertyMinWidth:                 // <length> | <percentage> | inherit
2052                        if (id == CSSValueKeywords.CSSValueIntrinsic || id == CSSValueKeywords.CSSValueMinIntrinsic)
2053                                valid_primitive = true;
2054                        else
2055                                valid_primitive = (0 == id && validUnit(val, U_FLength|U_FPercent|U_FNonNeg, mStrict));
2056                        break;
2057       
2058                case CSSPropertyID.CSSPropertyFontSize:
2059                        // <absolute-size> | <relative-size> | <length> | <percentage> | inherit
2060                        if (id >= CSSValueKeywords.CSSValueXxSmall && id <= CSSValueKeywords.CSSValueLarger)
2061                                valid_primitive = true;
2062                        else
2063                                valid_primitive = (validUnit(val, U_FLength|U_FPercent, mStrict));
2064                        break;
2065       
2066                case CSSPropertyID.CSSPropertyFontStyle:                   // normal | italic | oblique | inherit
2067                        if (id == CSSValueKeywords.CSSValueNormal || id == CSSValueKeywords.CSSValueItalic || id == CSSValueKeywords.CSSValueOblique)
2068                                valid_primitive = true;
2069                        break;
2070       
2071                case CSSPropertyID.CSSPropertyFontVariant:               // normal | small-caps | inherit
2072                        if (id == CSSValueKeywords.CSSValueNormal || id == CSSValueKeywords.CSSValueSmallCaps)
2073                                valid_primitive = true;
2074                        break;
2075       
2076                case CSSPropertyID.CSSPropertyVerticalAlign:
2077                        // baseline | sub | super | top | text-top | middle | bottom | text-bottom |
2078                        // <percentage> | <length> | inherit
2079       
2080                        if (id >= CSSValueKeywords.CSSValueBaseline && id <= CSSValueKeywords.CSSValueWebkitBaselineMiddle)
2081                                valid_primitive = true;
2082                        else
2083                                valid_primitive = (0 == id && validUnit(val, U_FLength|U_FPercent, mStrict));
2084                        break;
2085       
2086                case CSSPropertyID.CSSPropertyHeight:                      // <length> | <percentage> | auto | inherit
2087                case CSSPropertyID.CSSPropertyWidth:                            // <length> | <percentage> | auto | inherit
2088                        if (id == CSSValueKeywords.CSSValueAuto || id == CSSValueKeywords.CSSValueIntrinsic || id == CSSValueKeywords.CSSValueMinIntrinsic)
2089                                valid_primitive = true;
2090                        else
2091                                // ### handle multilength case where we allow relative units
2092                                valid_primitive = (0 == id && validUnit(val, U_FLength|U_FPercent|U_FNonNeg, mStrict));
2093                        break;
2094
2095                case CSSPropertyID.CSSPropertyBottom:               // <length> | <percentage> | auto | inherit
2096                case CSSPropertyID.CSSPropertyLeft:                 // <length> | <percentage> | auto | inherit
2097                case CSSPropertyID.CSSPropertyRight:                // <length> | <percentage> | auto | inherit
2098                case CSSPropertyID.CSSPropertyTop:                  // <length> | <percentage> | auto | inherit
2099                case CSSPropertyID.CSSPropertyMarginTop:           //// <margin-width> | inherit
2100                case CSSPropertyID.CSSPropertyMarginRight:         //   Which is defined as
2101                case CSSPropertyID.CSSPropertyMarginBottom:        //   <length> | <percentage> | auto | inherit
2102                case CSSPropertyID.CSSPropertyMarginLeft:          ////
2103                case CSSPropertyID.CSSPropertyWebkitMarginStart:
2104                        if (id == CSSValueKeywords.CSSValueAuto)
2105                                valid_primitive = true;
2106                        else
2107                                valid_primitive = (0 == id && validUnit(val, U_FLength|U_FPercent, mStrict));
2108                        break;
2109
2110                case CSSPropertyID.CSSPropertyZIndex:                     // auto | <integer> | inherit
2111                        if (id == CSSValueKeywords.CSSValueAuto) {
2112                                valid_primitive = true;
2113                                break;
2114                        }
2115                        /* nobreak */
2116                case CSSPropertyID.CSSPropertyOrphans:                    // <integer> | inherit
2117                case CSSPropertyID.CSSPropertyWidows:                      // <integer> | inherit
2118                        // ### not supported later on
2119                        valid_primitive = (0 == id && validUnit(val, U_FInteger, false));
2120                        break;
2121
2122                case CSSPropertyID.CSSPropertyLineHeight:                 // normal | <number> | <length> | <percentage> | inherit
2123                        if (id == CSSValueKeywords.CSSValueNormal)
2124                                valid_primitive = true;
2125                        else
2126                                valid_primitive = (0 == id && validUnit(val, U_FNumber|U_FLength|U_FPercent, mStrict));
2127                        break;
2128        /*
2129                case CSSPropertyID.CSSPropertyCounterIncrement: // [ <identifier> <integer>? ]+ | none | inherit
2130                        if (id != CSSValueNone)
2131                                return parseCounter(propId, 1, important);
2132                        valid_primitive = true;
2133                        break;
2134        */
2135
2136                case CSSPropertyID.CSSPropertyFontFamily:
2137                // [[ <family-name> | <generic-family> ],]* [<family-name> | <generic-family>] | inherit
2138                {
2139                        parsedValue = parseFontFamily();
2140                        break;
2141                }
2142
2143                case CSSPropertyID.CSSPropertyTextDecoration:
2144                case CSSPropertyID.CSSPropertyWebkitTextDecorationsInEffect:
2145                        // none | [ underline || overline || line-through || blink ] | inherit
2146                        if (id == CSSValueKeywords.CSSValueNone) {
2147                                valid_primitive = true;
2148                        } else {
2149                                var decolist:CSSValueList = new CSSValueList();
2150                                var is_valid:Boolean = true;
2151                                while(is_valid && val != null) {
2152                                        switch (val.id) {
2153                                        case CSSValueKeywords.CSSValueBlink:
2154                                                break;
2155                                        case CSSValueKeywords.CSSValueUnderline:
2156                                        case CSSValueKeywords.CSSValueOverline:
2157                                        case CSSValueKeywords.CSSValueLineThrough:
2158                                                decolist.append(CSSPrimitiveValue.newId(val.id));
2159                                                break;
2160                                        default:
2161                                                is_valid = false;
2162                                        }
2163                                        val = valueList.next();
2164                                }
2165                                if (decolist.length != 0 && is_valid) {
2166                                        parsedValue = decolist;
2167                                        valueList.next();
2168                                }
2169                        }
2170                        break;
2171
2172                case CSSPropertyID.CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3
2173                case CSSPropertyID.CSSPropertyWebkitBoxShadow:
2174                if (id == CSSValueKeywords.CSSValueNone)
2175                        valid_primitive = true;
2176                else
2177                        return parseShadow(propId, important);
2178                break;
2179
2180        // -- shorthands
2181                case CSSPropertyID.CSSPropertyBackground:
2182                        // ['background-color' || 'background-image' || 'background-size' || 'background-repeat' ||
2183                        // 'background-attachment' || 'background-position'] | inherit
2184                        return parseBackgroundShorthand(important);             
2185
2186
2187                case CSSPropertyID.CSSPropertyBorder:
2188                        const BORDER_PROPERTIES:Array = [CSSPropertyID.CSSPropertyBorderWidth, CSSPropertyID.CSSPropertyBorderStyle, CSSPropertyID.CSSPropertyBorderColor];
2189                        return parseShorthand(propId, BORDER_PROPERTIES, important);
2190                        break;
2191
2192                case CSSPropertyID.CSSPropertyBorderTop:
2193                        // [ 'border-top-width' || 'border-style' || <color> ] | inherit
2194                {
2195                        const BORDER_TOP_PROPERTIES:Array = [ CSSPropertyID.CSSPropertyBorderTopWidth, CSSPropertyID.CSSPropertyBorderTopStyle,
2196                                                                                CSSPropertyID.CSSPropertyBorderTopColor ];
2197                        return parseShorthand(propId, BORDER_TOP_PROPERTIES, important);
2198                }
2199                case CSSPropertyID.CSSPropertyBorderRight:
2200                        // [ 'border-right-width' || 'border-style' || <color> ] | inherit
2201                {
2202                        const BORDER_RIGHT_PROPERTIES:Array = [ CSSPropertyID.CSSPropertyBorderRightWidth, CSSPropertyID.CSSPropertyBorderRightStyle,
2203                                                                                CSSPropertyID.CSSPropertyBorderRightColor ];
2204                        return parseShorthand(propId, BORDER_RIGHT_PROPERTIES, important);
2205                }
2206                case CSSPropertyID.CSSPropertyBorderBottom:
2207                        // [ 'border-bottom-width' || 'border-style' || <color> ] | inherit
2208                {
2209                        const BORDER_BOTTOM_PROPERTIES:Array = [ CSSPropertyID.CSSPropertyBorderBottomWidth, CSSPropertyID.CSSPropertyBorderBottomStyle,
2210                                                                                CSSPropertyID.CSSPropertyBorderBottomColor ];
2211                        return parseShorthand(propId, BORDER_BOTTOM_PROPERTIES, important);
2212                }
2213                case CSSPropertyID.CSSPropertyBorderLeft:
2214                        // [ 'border-left-width' || 'border-style' || <color> ] | inherit
2215                {
2216                        const BORDER_LEFT_PROPERTIES:Array = [ CSSPropertyID.CSSPropertyBorderLeftWidth, CSSPropertyID.CSSPropertyBorderLeftStyle,
2217                                                                                CSSPropertyID.CSSPropertyBorderLeftColor ];
2218                        return parseShorthand(propId, BORDER_LEFT_PROPERTIES, important);
2219                }
2220
2221
2222                case CSSPropertyID.CSSPropertyBorderColor:
2223                // <color>{1,4} | inherit
2224                {
2225                        const BORDERCOLOR_PROPERTIES:Array = [ CSSPropertyID.CSSPropertyBorderTopColor, CSSPropertyID.CSSPropertyBorderRightColor,
2226                                                               CSSPropertyID.CSSPropertyBorderBottomColor, CSSPropertyID.CSSPropertyBorderLeftColor ];
2227                        return parse4Values(propId, BORDERCOLOR_PROPERTIES, important);
2228                }
2229
2230                case CSSPropertyID.CSSPropertyBorderWidth:
2231                // <border-width>{1,4} | inherit
2232                {
2233                        const BORDERWIDTH_PROPERTIES:Array = [ CSSPropertyID.CSSPropertyBorderTopWidth, CSSPropertyID.CSSPropertyBorderRightWidth,
2234                                                               CSSPropertyID.CSSPropertyBorderBottomWidth, CSSPropertyID.CSSPropertyBorderLeftWidth];
2235                        return parse4Values(propId, BORDERWIDTH_PROPERTIES, important);
2236                }
2237                case CSSPropertyID.CSSPropertyBorderStyle:
2238                // <border-style>{1,4} | inherit
2239                {
2240                        const BORDERSTYLE_PROPERTIES:Array = [ CSSPropertyID.CSSPropertyBorderTopStyle, CSSPropertyID.CSSPropertyBorderRightStyle,
2241                                                               CSSPropertyID.CSSPropertyBorderBottomStyle, CSSPropertyID.CSSPropertyBorderLeftStyle ];
2242                        return parse4Values(propId, BORDERSTYLE_PROPERTIES, important);
2243                }
2244                case CSSPropertyID.CSSPropertyMargin:
2245                // <margin-width>{1,4} | inherit
2246                {
2247                        const MARGIN_PROPERTIES:Array = [ CSSPropertyID.CSSPropertyMarginTop, CSSPropertyID.CSSPropertyMarginRight,
2248                                                          CSSPropertyID.CSSPropertyMarginBottom, CSSPropertyID.CSSPropertyMarginLeft ];
2249                        return parse4Values(propId, MARGIN_PROPERTIES, important);
2250                }
2251                case CSSPropertyID.CSSPropertyPadding:
2252                // <padding-width>{1,4} | inherit
2253                {
2254                        const PADDING_PROPERTIES:Array = [ CSSPropertyID.CSSPropertyPaddingTop, CSSPropertyID.CSSPropertyPaddingRight,
2255                                                           CSSPropertyID.CSSPropertyPaddingBottom, CSSPropertyID.CSSPropertyPaddingLeft ];
2256                        return parse4Values(propId, PADDING_PROPERTIES, important);
2257                }
2258
2259                default:
2260                        if (mPropertyExtension)
2261                        {
2262                                if (mPropertyExtension.isValidPrimitiveValue(propId, id))
2263                                        valid_primitive = true;
2264                        }
2265                        break;
2266        }
2267
2268        if (valid_primitive) {
2269                if (id != 0)
2270                        parsedValue = CSSPrimitiveValue.newId(id);
2271                else if (val.unit >= CSSPrimitiveValue.CSS_NUMBER && val.unit <= CSSPrimitiveValue.CSS_KHZ)
2272                        parsedValue = CSSPrimitiveValue.newUnitNumber(val.fValue, val.unit);
2273        else if (val.unit == CSSPrimitiveValue.CSS_STRING)
2274            parsedValue = CSSPrimitiveValue.newUnitString(val.stringVal, val.unit);
2275/*
2276        else if (value->unit >= Value::Q_EMS)
2277            parsedValue = new CSSQuirkPrimitiveValue(value->fValue, CSSPrimitiveValue::CSS_EMS);
2278*/
2279        valueList.next();
2280    }
2281
2282        if (parsedValue != null) {
2283                if (valueList.currentValue == null || inShorthand()) {
2284                        addProperty(propId, parsedValue, important);
2285                        return true;
2286                }
2287        }
2288
2289        return false;
2290}
2291
2292
2293private function validUnit(aValue:Value, aUnitFlags:uint, aStrict:Boolean):Boolean
2294{
2295        if ((aUnitFlags & U_FNonNeg) != 0 && aValue.fValue < 0)
2296                return false;
2297
2298    var b:Boolean = false;
2299    switch(aValue.unit) {
2300    case CSSPrimitiveValue.CSS_NUMBER:
2301                b = (aUnitFlags & U_FNumber) != 0;
2302                if (!b && ((aUnitFlags & (U_FLength | U_FAngle)) != 0 && (aValue.fValue == 0 || !aStrict))) {
2303                        aValue.unit = ((aUnitFlags & U_FLength) !=0 ) ? CSSPrimitiveValue.CSS_PX : CSSPrimitiveValue.CSS_DEG;
2304                        b = true;
2305                }
2306                if (!b && (aUnitFlags & U_FInteger) != 0 && aValue.isInt)
2307                        b = true;
2308
2309                break;
2310        case CSSPrimitiveValue.CSS_PERCENTAGE:
2311                b = (aUnitFlags & U_FPercent) != 0;
2312                break;
2313        case Value.Q_EMS:
2314        case CSSPrimitiveValue.CSS_EMS:
2315        case CSSPrimitiveValue.CSS_EXS:
2316        case CSSPrimitiveValue.CSS_PX:
2317        case CSSPrimitiveValue.CSS_CM:
2318        case CSSPrimitiveValue.CSS_MM:
2319        case CSSPrimitiveValue.CSS_IN:
2320        case CSSPrimitiveValue.CSS_PT:
2321        case CSSPrimitiveValue.CSS_PC:
2322                b = (aUnitFlags & U_FLength) != 0;
2323                break;
2324        case CSSPrimitiveValue.CSS_MS:
2325        case CSSPrimitiveValue.CSS_S:
2326                b = (aUnitFlags & U_FTime) != 0;
2327                break;
2328        case CSSPrimitiveValue.CSS_DEG:
2329        case CSSPrimitiveValue.CSS_RAD:
2330        case CSSPrimitiveValue.CSS_GRAD:
2331                b = (aUnitFlags & U_FAngle) != 0;
2332                break;
2333        case CSSPrimitiveValue.CSS_HZ:
2334        case CSSPrimitiveValue.CSS_KHZ:
2335        case CSSPrimitiveValue.CSS_DIMENSION:
2336    default:
2337        break;
2338        }
2339
2340        return b;
2341}
2342
2343private function addProperty(propId:int, value:CSSValue, important:Boolean):void
2344{
2345        var p:CSSProperty = new CSSProperty(propId, value, important, mCurrentShorthand, mImplicitShorthand);
2346        mParsedProperties.push(p);
2347}
2348
2349// shorthand parsing
2350
2351private function enterShorthandScope(propId:int):void
2352{
2353        if (0 == (mInParseShorthand++))
2354                mCurrentShorthand = propId;
2355}
2356
2357private function leaveShorthandScope():void
2358{
2359        if (0 == (--mInParseShorthand))
2360                mCurrentShorthand = 0;
2361}
2362
2363private function parseShorthand(propId:int, properties:Array, important:Boolean):Boolean
2364{
2365        enterShorthandScope(propId);
2366        var rval:Boolean = parseShorthandInternal(propId, properties, important);
2367        leaveShorthandScope();
2368        return rval;
2369}
2370
2371private function parseShorthandInternal(propId:int, properties:Array, important:Boolean):Boolean
2372{
2373        // We try to match as many properties as possible
2374        // We set up an array of booleans to mark which property has been found,
2375        // and we try to search for properties until it makes no longer any sense.
2376        var numProperties:int = properties.length;
2377
2378        var i:int;
2379        var found:Boolean = false;
2380        var fnd:Array = new Array(6); // Trust me ;)
2381        for (i = 0; i < numProperties; i++)
2382                fnd[i] = false;
2383
2384        while (valueList.currentValue != null) {
2385                found = false;
2386                for (var propIndex:int = 0; !found && propIndex < numProperties; ++propIndex) {
2387                        if (!fnd[propIndex]) {
2388                                if (parseValue(properties[propIndex], important))
2389                                        fnd[propIndex] = found = true;
2390                        }
2391                }
2392       
2393                // if we didn't find at least one match, this is an
2394                // invalid shorthand and we have to ignore it
2395                if (!found)
2396                        return false;
2397        }
2398
2399    // Fill in any remaining properties with the initial value.
2400    mImplicitShorthand = true;
2401    for (i = 0; i < numProperties; ++i) {
2402        if (!fnd[i])
2403            addProperty(properties[i], new CSSInitialValue(true), important);
2404    }
2405    mImplicitShorthand = false;
2406
2407        return true;
2408}
2409
2410private function parseBackgroundShorthand(important:Boolean):Boolean
2411{
2412        enterShorthandScope(CSSPropertyID.CSSPropertyBackground);
2413        var rval:Boolean = parseBackgroundShorthandInternal(important);
2414        leaveShorthandScope();
2415
2416        return rval;
2417}
2418
2419private function parseBackgroundShorthandInternal(important:Boolean):Boolean
2420{
2421        // Position must come before color in this array because a plain old "0" is a legal color
2422        // in quirks mode but it's usually the X coordinate of a position.
2423        // FIXME: Add CSSPropertyKhtmlBackgroundSize to the shorthand.
2424        const properties:Array = [
2425                CSSPropertyID.CSSPropertyBackgroundImage, CSSPropertyID.CSSPropertyBackgroundRepeat,
2426                CSSPropertyID.CSSPropertyBackgroundAttachment, CSSPropertyID.CSSPropertyBackgroundPosition, CSSPropertyID.CSSPropertyWebkitBackgroundClip,
2427                CSSPropertyID.CSSPropertyWebkitBackgroundOrigin, CSSPropertyID.CSSPropertyBackgroundColor ];
2428
2429        var numProperties:int = properties.length;
2430
2431        var parsedProperty:Array /* of Boolean */ = new Array(numProperties); // use undefined as false
2432        var values:Array /* of CSSValue */ = new Array(numProperties);
2433        var positionYValue:CSSValue = null;
2434        var i:int;
2435
2436    while (valueList.currentValue != null) {
2437                var val:Value = valueList.currentValue;
2438        if (val.unit == Value.Operator && val.iValue == Value.OP_COMMA) {
2439            // We hit the end.  Fill in all remaining values with the initial value.
2440            valueList.next();
2441            for (i = 0; i < numProperties; ++i) {
2442                                if (properties[i] == CSSPropertyID.CSSPropertyBackgroundColor && parsedProperty[i])
2443                                        // Color is not allowed except as the last item in a list.  Reject the entire
2444                                        // property.
2445                                        return false;
2446                                if (!parsedProperty[i] && properties[i] != CSSPropertyID.CSSPropertyBackgroundColor) {
2447                                        values[i] = addBackgroundValue(values[i], new CSSInitialValue(true));
2448                                        if (properties[i] == CSSPropertyID.CSSPropertyBackgroundPosition)
2449                                                positionYValue = addBackgroundValue(positionYValue, new CSSInitialValue(true));
2450                                }
2451                                parsedProperty[i] = false;
2452                        }
2453                        if (valueList.currentValue == null)
2454                                break;
2455                }
2456
2457                var found:Boolean = false;
2458                for (i = 0; !found && i < numProperties; ++i) {
2459                        if (!parsedProperty[i]) {
2460                                var vals:Array = [null, null];
2461                                // var propId1:int, propId2:int;
2462                                if (parseBackgroundProperty(properties[i], null, vals)) {
2463                                        parsedProperty[i] = found = true;
2464                                        values[i] = addBackgroundValue(values[i], vals[0]);
2465                                        if (properties[i] == CSSPropertyID.CSSPropertyBackgroundPosition)
2466                                                positionYValue = addBackgroundValue(positionYValue, vals[1]);
2467                                }
2468                        }
2469                }
2470               
2471                // if we didn't find at least one match, this is an
2472                // invalid shorthand and we have to ignore it
2473                if (!found)
2474                        return false;
2475        }
2476
2477        // Fill in any remaining properties with the initial value.
2478        for (i = 0; i < numProperties; ++i) {
2479                if (!parsedProperty[i]) {
2480                        values[i] = addBackgroundValue(values[i], new CSSInitialValue(true));
2481                if (properties[i] == CSSPropertyID.CSSPropertyBackgroundPosition)
2482                        positionYValue = addBackgroundValue(positionYValue, new CSSInitialValue(true));
2483                }
2484        }
2485
2486        // Now add all of the properties we found.
2487        for (i = 0; i < numProperties; i++) {
2488                if (properties[i] == CSSPropertyID.CSSPropertyBackgroundPosition) {
2489                        addProperty(CSSPropertyID.CSSPropertyBackgroundPositionX, values[i], important);
2490                        // it's OK to call positionYValue.release() since we only see CSSPropertyID.CSSPropertyBackgroundPosition once
2491                        addProperty(CSSPropertyID.CSSPropertyBackgroundPositionY, positionYValue, important);
2492                } else
2493                        addProperty(properties[i], values[i], important);
2494        }
2495
2496        return true;
2497}
2498
2499private function addBackgroundValue(lval:CSSValue, rval:CSSValue):CSSValue /* returns new lval ref */
2500{
2501        if (lval != null) {
2502                if (lval is CSSValueList) {
2503                        CSSValueList(lval).append(rval);
2504                        return lval;
2505                }
2506        else {
2507                        var oldlVal:CSSValue = lval;
2508                        var list:CSSValueList = new CSSValueList();
2509                        list.append(oldlVal);
2510                        list.append(rval);
2511                        return list;
2512                }
2513        }
2514        else
2515                return rval
2516}
2517
2518private function parse4Values(propId:int, properties:Array, important:Boolean):Boolean
2519{
2520        var num:int = inShorthand() ? 1 : valueList.length;
2521        enterShorthandScope(propId);
2522        var rval:Boolean = parse4ValuesInternal(propId, properties, important, num);
2523        leaveShorthandScope();
2524        return rval;
2525}
2526
2527private function parse4ValuesInternal(propId:int, properties:Array, important:Boolean, num:int):Boolean
2528{
2529        /* From the CSS 2 specs, 8.3
2530         * If there is only one value, it applies to all sides. If there are two values, the top and
2531         * bottom margins are set to the first value and the right and left margins are set to the second.
2532         * If there are three values, the top is set to the first value, the left and right are set to the
2533         * second, and the bottom is set to the third. If there are four values, they apply to the top,
2534         * right, bottom, and left, respectively.
2535         */
2536
2537        // the order is top, right, bottom, left
2538        var value:CSSValue;
2539        switch (num) {
2540                case 1: {
2541                        if (!parseValue(properties[0], important))
2542                                return false;
2543                        value = CSSProperty(mParsedProperties[mParsedProperties.length-1]).value;
2544                        mImplicitShorthand = true;
2545                        addProperty(properties[1], value, important);
2546                        addProperty(properties[2], value, important);
2547                        addProperty(properties[3], value, important);
2548                        mImplicitShorthand = false;
2549                        break;
2550                }
2551                case 2: {
2552                        if (!parseValue(properties[0], important) || !parseValue(properties[1], important))
2553                                return false;
2554
2555                        value = CSSProperty(mParsedProperties[mParsedProperties.length-2]).value;
2556                        mImplicitShorthand = true;
2557                        addProperty(properties[2], value, important);
2558                        value = CSSProperty(mParsedProperties[mParsedProperties.length-2]).value;
2559                        addProperty(properties[3], value, important);
2560                        mImplicitShorthand = false;
2561                        break;
2562                }
2563                case 3: {
2564                        if (!parseValue(properties[0], important) || !parseValue(properties[1], important) || !parseValue(properties[2], important))
2565                                return false;
2566                        value = CSSProperty(mParsedProperties[mParsedProperties.length-2]).value;
2567                        mImplicitShorthand = true;
2568                        addProperty(properties[3], value, important);
2569                        mImplicitShorthand = false;
2570                        break;
2571                }
2572                case 4: {
2573                        if (!parseValue(properties[0], important) || !parseValue(properties[1], important) ||
2574                                !parseValue(properties[2], important) || !parseValue(properties[3], important))
2575                                return false;
2576                        break;
2577                }
2578                default: {
2579                        return false;
2580                }
2581        }
2582       
2583        return true;
2584}
2585
2586private function parseShadow(propId:int, important:Boolean):Boolean
2587{
2588        var context:ShadowParseContext = new ShadowParseContext();
2589        var val:Value;
2590        while ((val = valueList.currentValue)) {
2591                // Check for a comma break first.
2592                if (val.unit == Value.Operator) {
2593                        if (val.iValue != Value.OP_COMMA || !context.allowBreak)
2594                                // Other operators aren't legal or we aren't done with the current shadow
2595                                // value.  Treat as invalid.
2596                                return false;
2597                       
2598                        // The value is good.  Commit it.
2599                        context.commitValue();
2600                }
2601                // Check to see if we're a length.
2602                else if (validUnit(val, U_FLength, true)) {
2603                        // We required a length and didn't get one. Invalid.
2604                        if (!context.allowLength())
2605                                return false;
2606
2607                        // A length is allowed here.  Construct the value and add it.
2608                        context.commitLength(val);
2609                }
2610                else {
2611                        // The only other type of value that's ok is a color value.
2612                        var parsedColor:CSSPrimitiveValue;
2613                        var isColor:Boolean = (val.id >= CSSValueKeywords.CSSValueAqua && val.id <= CSSValueKeywords.CSSValueWindowtext || val.id == CSSValueKeywords.CSSValueMenu ||
2614                                                        (val.id >= CSSValueKeywords.CSSValueWebkitFocusRingColor && val.id <= CSSValueKeywords.CSSValueWebkitText && !mStrict));
2615                        if (isColor) {
2616                                if (!context.allowColor)
2617                                        return false;
2618                                parsedColor = CSSPrimitiveValue.newId(val.id);
2619                        }
2620
2621                        if (!parsedColor)
2622                                // It's not built-in. Try to parse it as a color.
2623                                parsedColor = parseColor(val);
2624
2625                        if (!parsedColor || !context.allowColor)
2626                                return false; // This value is not a color or length and is invalid or
2627                                                          // it is a color, but a color isn't allowed at this point.
2628                       
2629                        context.commitColor(parsedColor);
2630                }
2631
2632                valueList.next();
2633        }
2634
2635        if (context.allowBreak) {
2636                context.commitValue();
2637                if (context.values.length) {
2638                        addProperty(propId, context.values, important);
2639                        valueList.next();
2640                        return true;
2641                }
2642        }
2643       
2644        return false;
2645}
2646
2647private function parseFontFamily():CSSValueList
2648{
2649        var list:CSSValueList = new CSSValueList();
2650        var value:Value = valueList.currentValue;
2651        var currFamily:FontFamilyValue = null;
2652        while (value) {
2653                var nextValue:Value = valueList.next();
2654                var nextValBreaksFont:Boolean = !nextValue ||
2655                                                                 (nextValue.unit == Value.Operator && nextValue.iValue == Value.OP_COMMA);
2656                var nextValIsFontName:Boolean = nextValue &&
2657                        ((nextValue.id >= CSSValueKeywords.CSSValueSerif && nextValue.id <= CSSValueKeywords.CSSValueWebkitBody) ||
2658                        (nextValue.unit == CSSPrimitiveValue.CSS_STRING || nextValue.unit == CSSPrimitiveValue.CSS_IDENT));
2659
2660                if (value.id >= CSSValueKeywords.CSSValueSerif && value.id <= CSSValueKeywords.CSSValueWebkitBody) {
2661                        if (currFamily)
2662                                currFamily.appendSpaceSeparated(value.stringVal);
2663                        else if (nextValBreaksFont || !nextValIsFontName)
2664                                list.append(CSSPrimitiveValue.newId(value.id));
2665                        else
2666                                list.append(currFamily = new FontFamilyValue(value.stringVal));
2667                }
2668                else if (value.unit == CSSPrimitiveValue.CSS_STRING) {
2669                        // Strings never share in a family name.
2670                        currFamily = null;
2671                        list.append(new FontFamilyValue(value.stringVal));
2672                }
2673                else if (value.unit == CSSPrimitiveValue.CSS_IDENT) {
2674                        if (currFamily)
2675                                currFamily.appendSpaceSeparated(value.stringVal);
2676                        else if (nextValBreaksFont || !nextValIsFontName)
2677                                list.append(new FontFamilyValue(value.stringVal));
2678                        else
2679                                list.append(currFamily = new FontFamilyValue(value.stringVal));
2680                }
2681                else {
2682                        break;
2683                }
2684               
2685                if (!nextValue)
2686                        break;
2687
2688                if (nextValBreaksFont) {
2689                        value = valueList.next();
2690                        currFamily = null;
2691                }
2692                else if (nextValIsFontName)
2693                        value = nextValue;
2694                else
2695                        break;
2696        }
2697        if (list.length == 0) {
2698                list = null;
2699        }
2700        return list;
2701}
2702
2703private function parseColor(aValue:Value = null):CSSPrimitiveValue
2704{
2705        var c:uint = WKColor.transparent;
2706
2707        var res:Object;
2708        if (null == (res = parseColorFromValue((aValue != null) ? aValue : valueList.currentValue)))
2709                return null;
2710        else
2711                c = uint(res);
2712
2713        return CSSPrimitiveValue.newColor(c);
2714}
2715
2716private function parseColorFromValue(value:Value, svg:Boolean = false):Object
2717{
2718        var res:Object = null;
2719        if (value.unit == CSSPrimitiveValue.CSS_RGBCOLOR) {
2720                if (null == (res = parseColorString(value.stringVal, mStrict && value.unit == CSSPrimitiveValue.CSS_IDENT)))
2721                        return null;
2722    }
2723
2724        return res;
2725}
2726
2727private function parseColorString(name:String, strict:Boolean):Object
2728{
2729        var res:Object = null;
2730    if (!strict && (res = WKColor.parseHexColor(name)) != null)
2731        return res;
2732
2733    return null;
2734}
2735
2736
2737private function parseBackgroundProperty(propId:int, outPropIds:Array, retValue:Array):Boolean
2738{
2739        var values:CSSValueList;
2740        var values2:CSSValueList;
2741        var val:Value;
2742
2743        var value:CSSValue;
2744        var value2:CSSValue;
2745       
2746        var allowComma:Boolean = false;
2747       
2748        retValue[0] = retValue[1] = null;
2749
2750        if (outPropIds != null)
2751        {
2752                outPropIds[0] = propId;
2753                outPropIds[1] = propId;
2754                if (propId == CSSPropertyID.CSSPropertyBackgroundPosition) {
2755                        outPropIds[0] = CSSPropertyID.CSSPropertyBackgroundPositionX;
2756                        outPropIds[1] = CSSPropertyID.CSSPropertyBackgroundPositionY;
2757                }
2758        }
2759
2760        while (null != (val = valueList.currentValue)) {
2761                var currValue:CSSValue;
2762                var currValue2:CSSValue;
2763               
2764                if (allowComma) {
2765                        if (val.unit != Value.Operator || val.iValue != Value.OP_COMMA)
2766                                return false;
2767                        valueList.next();
2768                        allowComma = false;
2769                } else {
2770                        var curvalret:Array;
2771                        switch (propId) {
2772                                case CSSPropertyID.CSSPropertyBackgroundAttachment:
2773                                        if (val.id == CSSValueKeywords.CSSValueScroll || val.id == CSSValueKeywords.CSSValueFixed) {
2774                                                currValue = CSSPrimitiveValue.newId(val.id);
2775                                                valueList.next();
2776                                        }
2777                                        break;
2778                                case CSSPropertyID.CSSPropertyBackgroundColor:
2779                                        currValue = parseBackgroundColor();
2780                                        if (currValue)
2781                                                valueList.next();
2782                                        break;
2783                                case CSSPropertyID.CSSPropertyBackgroundImage:
2784                                        if (null != (currValue = parseBackgroundImage(currValue)))
2785                                                valueList.next();
2786                                        break;
2787                                case CSSPropertyID.CSSPropertyWebkitBackgroundClip:
2788                                case CSSPropertyID.CSSPropertyWebkitBackgroundOrigin:
2789                                        if (val.id == CSSValueKeywords.CSSValueBorder || val.id == CSSValueKeywords.CSSValuePadding || val.id == CSSValueKeywords.CSSValueContent || val.id == CSSValueKeywords.CSSValueText) {
2790                                                currValue = CSSPrimitiveValue.newId(val.id);
2791                                                valueList.next();
2792                                        }
2793                                        break;
2794
2795                                case CSSPropertyID.CSSPropertyBackgroundPosition:
2796                                        curvalret = [currValue, currValue2];
2797                                        parseBackgroundPosition(curvalret);
2798                                        currValue = curvalret[0]; currValue2 = curvalret[1];
2799                                        // unlike the other functions, parseBackgroundPosition advances the valueList pointer
2800                                        break;
2801                                case CSSPropertyID.CSSPropertyBackgroundPositionX: {
2802                                        currValue = parseBackgroundPositionXY([false, false]);
2803                                        if (currValue)
2804                                                valueList.next();
2805                                        break;
2806                                }
2807                                case CSSPropertyID.CSSPropertyBackgroundPositionY: {
2808                                        currValue = parseBackgroundPositionXY([false, false]);
2809                                        if (currValue)
2810                                                valueList.next();
2811                                        break;
2812                                }
2813
2814                                case CSSPropertyID.CSSPropertyWebkitBackgroundComposite:
2815                                        if ((val.id >= CSSValueKeywords.CSSValueClear && val.id <= CSSValueKeywords.CSSValuePlusLighter) || val.id == CSSValueKeywords.CSSValueHighlight) {
2816                                                currValue = CSSPrimitiveValue.newId(val.id);
2817                                                valueList.next();
2818                                        }
2819                                        break;
2820                                case CSSPropertyID.CSSPropertyBackgroundRepeat:
2821                                        if (val.id >= CSSValueKeywords.CSSValueRepeat && val.id <= CSSValueKeywords.CSSValueNoRepeat) {
2822                                                currValue =CSSPrimitiveValue.newId(val.id);
2823                                                valueList.next();
2824                                        }
2825                                        break;
2826                                case CSSPropertyID.CSSPropertyWebkitBackgroundSize:
2827                                        currValue = parseBackgroundSize();
2828                                        if (currValue)
2829                                                valueList.next();
2830                                        break;
2831
2832                        }
2833                        if (!currValue)
2834                                return false;
2835                       
2836                        if (value && !values) {
2837                                values = new CSSValueList();
2838                                values.append(value);
2839                        }
2840                       
2841                        if (value2 && !values2) {
2842                                values2 = new CSSValueList();
2843                                values2.append(value2);
2844                        }
2845                       
2846                        if (values)
2847                                values.append(currValue);
2848                        else
2849                                value = currValue;
2850                        if (currValue2) {
2851                                if (values2)
2852                                        values2.append(currValue2);
2853                                else
2854                                        value2 = currValue2;
2855                        }
2856
2857                        allowComma = true;
2858                }
2859
2860                // When parsing the 'background' shorthand property, we let it handle building up the lists for all
2861                // properties.
2862                if (inShorthand())
2863                        break;
2864
2865        }
2866
2867        if (values && values.length) {
2868                retValue[0] = values;
2869                if (values2 && values2.length)
2870                        retValue[1] = values2;
2871                return true;
2872        }
2873
2874        if (value) {
2875                retValue[0] = value;
2876                retValue[1] = value2;
2877                return true;
2878        }
2879
2880        return false;
2881}
2882
2883private function parseBackgroundSize():CSSValue
2884{
2885        var value:Value = valueList.currentValue;
2886        var parsedValue1:CSSPrimitiveValue;
2887       
2888        if (value.id == CSSValueKeywords.CSSValueAuto)
2889                parsedValue1 = CSSPrimitiveValue.newUnitNumber(0, CSSPrimitiveValue.CSS_UNKNOWN);
2890        else {
2891                if (!validUnit(value, U_FLength|U_FPercent, mStrict))
2892                        return null;
2893                parsedValue1 = CSSPrimitiveValue.newUnitNumber(value.fValue, value.unit);
2894        }
2895       
2896        var parsedValue2:CSSPrimitiveValue = parsedValue1;
2897        if ((value = valueList.next())) {
2898                if (value.id == CSSValueKeywords.CSSValueAuto)
2899                        parsedValue2 = CSSPrimitiveValue.newUnitNumber(0, CSSPrimitiveValue.CSS_UNKNOWN);
2900                else {
2901                        if (!validUnit(value, U_FLength|U_FPercent, mStrict)) {
2902                                return null;
2903                        }
2904                        parsedValue2 = CSSPrimitiveValue.newUnitNumber(value.fValue, value.unit);
2905                }
2906        }
2907       
2908        var pair:Pair = new Pair(parsedValue1, parsedValue2);
2909        return CSSPrimitiveValue.newPair(pair);
2910}
2911
2912private function parseBackgroundPositionXY(founds:Array /* [x, y] */):CSSValue
2913{
2914        var id:int = valueList.currentValue.id;
2915        if (id == CSSValueKeywords.CSSValueLeft || id == CSSValueKeywords.CSSValueTop || id == CSSValueKeywords.CSSValueRight || id == CSSValueKeywords.CSSValueBottom || id == CSSValueKeywords.CSSValueCenter) {
2916                var percent:int = 0;
2917                if (id == CSSValueKeywords.CSSValueLeft || id == CSSValueKeywords.CSSValueRight) {
2918                        if (founds[0])
2919                                return null;
2920                        founds[0] = true;
2921                        if (id == CSSValueKeywords.CSSValueRight)
2922                                percent = 100;
2923                }
2924                else if (id == CSSValueKeywords.CSSValueTop || id == CSSValueKeywords.CSSValueBottom) {
2925                        if (founds[1])
2926                                return null;
2927                        founds[1] = true;
2928                        if (id == CSSValueKeywords.CSSValueBottom)
2929                                percent = 100;
2930                }
2931                else if (id == CSSValueKeywords.CSSValueCenter)
2932                        // Center is ambiguous, so we're not sure which position we've found yet, an x or a y.
2933                        percent = 50;
2934                return CSSPrimitiveValue.newUnitNumber(percent, CSSPrimitiveValue.CSS_PERCENTAGE);
2935        }
2936        if (validUnit(valueList.currentValue, U_FPercent|U_FLength, mStrict))
2937                return CSSPrimitiveValue.newUnitNumber(valueList.currentValue.fValue, valueList.currentValue.unit);
2938                               
2939        return null;
2940}
2941
2942private function parseBackgroundPosition(values:Array):void
2943{
2944        var value:Value = valueList.currentValue;
2945       
2946
2947        // Parse the first value.  We're just making sure that it is one of the valid keywords or a percentage/length.
2948        // bool value1IsX = false, value1IsY = false;
2949        var value1Is:Array = [false, false];
2950        values[0] = parseBackgroundPositionXY(value1Is);
2951        if (!values[0])
2952                return;
2953       
2954        // It only takes one value for background-position to be correctly parsed if it was specified in a shorthand (since we
2955        // can assume that any other values belong to the rest of the shorthand).  If we're not parsing a shorthand, though, the
2956        // value was explicitly specified for our property.
2957        value = valueList.next();
2958       
2959        // First check for the comma.  If so, we are finished parsing this value or value pair.
2960        if (value && value.unit == Value.Operator && value.iValue == Value.OP_COMMA)
2961                value = null;
2962
2963        // bool value2IsX = false, value2IsY = false;
2964        var value2Is:Array = [false, false];
2965        if (value) {
2966                values[1] = parseBackgroundPositionXY(value2Is);
2967                if (values[1])
2968                        valueList.next();
2969                else {
2970                        if (!inShorthand()) {
2971                                values[0] = null;
2972                                return;
2973                        }
2974                }
2975        }
2976       
2977        if (!values[1])
2978                // Only one value was specified.  If that value was not a keyword, then it sets the x position, and the y position
2979                // is simply 50%.  This is our default.
2980                // For keywords, the keyword was either an x-keyword (left/right), a y-keyword (top/bottom), or an ambiguous keyword (center).
2981                // For left/right/center, the default of 50% in the y is still correct.
2982                values[1] = CSSPrimitiveValue.newUnitNumber(50, CSSPrimitiveValue.CSS_PERCENTAGE);
2983
2984        //if (value1IsY || value2IsX)
2985        if (value1Is[1] || value2Is[0])
2986        {
2987                var t:Object = values[0];
2988                values[0] = values[1];
2989                values[1] = t;
2990        }
2991}
2992
2993private function parseBackgroundColor():CSSValue
2994{
2995    var id:int = valueList.currentValue.id;
2996    if (id == CSSValueKeywords.CSSValueWebkitText || (id >= CSSValueKeywords.CSSValueAqua && id <= CSSValueKeywords.CSSValueWindowtext) || id == CSSValueKeywords.CSSValueMenu ||
2997        (id >= CSSValueKeywords.CSSValueGrey && id < CSSValueKeywords.CSSValueWebkitText && !mStrict))
2998       return CSSPrimitiveValue.newId(id);
2999    return parseColor();
3000}
3001
3002private function parseBackgroundImage(initvalue:CSSValue):CSSValue
3003{
3004    if (valueList.currentValue.id == CSSValueKeywords.CSSValueNone) {
3005        return new CSSImageValue();
3006    }
3007
3008    if (valueList.currentValue.unit == CSSPrimitiveValue.CSS_URI) {
3009        var uri:String = ASCSS.parseURL(valueList.currentValue.stringVal);
3010        if (uri.length > 0)
3011                return new CSSImageValue((new KURL(styleElement.baseURL, uri)).toString(), styleElement);
3012                return initvalue;
3013    }
3014    return null;
3015}
Note: See TracBrowser for help on using the browser.