forked from mozilla/gecko-dev
-
Notifications
You must be signed in to change notification settings - Fork 2
/
nsCSSParser.cpp
8857 lines (8016 loc) · 277 KB
/
nsCSSParser.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* emk <VYV03354@nifty.ne.jp>
* Daniel Glazman <glazman@netscape.com>
* L. David Baron <dbaron@dbaron.org>
* Boris Zbarsky <bzbarsky@mit.edu>
* Mats Palmgren <mats.palmgren@bredband.net>
* Christian Biesinger <cbiesinger@web.de>
* Jeff Walden <jwalden+code@mit.edu>
* Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>, Collabora Ltd.
* Siraj Razick <siraj.razick@collabora.co.uk>, Collabora Ltd.
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* parsing of CSS stylesheets, based on a token stream from the CSS scanner */
#include "nsCSSParser.h"
#include "nsCSSProps.h"
#include "nsCSSKeywords.h"
#include "nsCSSScanner.h"
#include "mozilla/css/Loader.h"
#include "mozilla/css/StyleRule.h"
#include "mozilla/css/ImportRule.h"
#include "nsCSSRules.h"
#include "mozilla/css/NameSpaceRule.h"
#include "nsIUnicharInputStream.h"
#include "nsCSSStyleSheet.h"
#include "mozilla/css/Declaration.h"
#include "nsStyleConsts.h"
#include "nsIURL.h"
#include "nsNetUtil.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsReadableUtils.h"
#include "nsUnicharUtils.h"
#include "nsIAtom.h"
#include "nsCOMArray.h"
#include "nsColor.h"
#include "nsCSSPseudoClasses.h"
#include "nsCSSPseudoElements.h"
#include "nsCSSAnonBoxes.h"
#include "nsINameSpaceManager.h"
#include "nsXMLNameSpaceMap.h"
#include "nsThemeConstants.h"
#include "nsContentErrors.h"
#include "nsPrintfCString.h"
#include "nsIMediaList.h"
#include "nsILookAndFeel.h"
#include "nsStyleUtil.h"
#include "nsIPrincipal.h"
#include "prprf.h"
#include "math.h"
#include "nsContentUtils.h"
#include "nsDOMError.h"
#include "nsAutoPtr.h"
#include "nsTArray.h"
#include "prlog.h"
#include "CSSCalc.h"
#include "nsMediaFeatures.h"
namespace css = mozilla::css;
// Flags for ParseVariant method
#define VARIANT_KEYWORD 0x000001 // K
#define VARIANT_LENGTH 0x000002 // L
#define VARIANT_PERCENT 0x000004 // P
#define VARIANT_COLOR 0x000008 // C eCSSUnit_Color, eCSSUnit_Ident (e.g. "red")
#define VARIANT_URL 0x000010 // U
#define VARIANT_NUMBER 0x000020 // N
#define VARIANT_INTEGER 0x000040 // I
#define VARIANT_ANGLE 0x000080 // G
#define VARIANT_FREQUENCY 0x000100 // F
#define VARIANT_TIME 0x000200 // T
#define VARIANT_STRING 0x000400 // S
#define VARIANT_COUNTER 0x000800 //
#define VARIANT_ATTR 0x001000 //
#define VARIANT_IDENTIFIER 0x002000 // D
#define VARIANT_IDENTIFIER_NO_INHERIT 0x004000 // like above, but excluding
// 'inherit' and 'initial'
#define VARIANT_AUTO 0x010000 // A
#define VARIANT_INHERIT 0x020000 // H eCSSUnit_Initial, eCSSUnit_Inherit
#define VARIANT_NONE 0x040000 // O
#define VARIANT_NORMAL 0x080000 // M
#define VARIANT_SYSFONT 0x100000 // eCSSUnit_System_Font
#define VARIANT_GRADIENT 0x200000 // eCSSUnit_Gradient
#define VARIANT_TIMING_FUNCTION 0x400000 // cubic-bezier() and steps()
#define VARIANT_ALL 0x800000 //
#define VARIANT_IMAGE_RECT 0x01000000 // eCSSUnit_Function
// This is an extra bit that says that a VARIANT_ANGLE allows unitless zero:
#define VARIANT_ZERO_ANGLE 0x02000000 // unitless zero for angles
#define VARIANT_CALC 0x04000000 // eCSSUnit_Calc
#define VARIANT_ELEMENT 0x08000000 // eCSSUnit_Element
// Common combinations of variants
#define VARIANT_AL (VARIANT_AUTO | VARIANT_LENGTH)
#define VARIANT_LP (VARIANT_LENGTH | VARIANT_PERCENT)
#define VARIANT_AH (VARIANT_AUTO | VARIANT_INHERIT)
#define VARIANT_AHLP (VARIANT_AH | VARIANT_LP)
#define VARIANT_AHI (VARIANT_AH | VARIANT_INTEGER)
#define VARIANT_AHK (VARIANT_AH | VARIANT_KEYWORD)
#define VARIANT_AHKLP (VARIANT_AHLP | VARIANT_KEYWORD)
#define VARIANT_AHL (VARIANT_AH | VARIANT_LENGTH)
#define VARIANT_AHKL (VARIANT_AHK | VARIANT_LENGTH)
#define VARIANT_HK (VARIANT_INHERIT | VARIANT_KEYWORD)
#define VARIANT_HKF (VARIANT_HK | VARIANT_FREQUENCY)
#define VARIANT_HKI (VARIANT_HK | VARIANT_INTEGER)
#define VARIANT_HKL (VARIANT_HK | VARIANT_LENGTH)
#define VARIANT_HKLP (VARIANT_HK | VARIANT_LP)
#define VARIANT_HKLPO (VARIANT_HKLP | VARIANT_NONE)
#define VARIANT_HL (VARIANT_INHERIT | VARIANT_LENGTH)
#define VARIANT_HI (VARIANT_INHERIT | VARIANT_INTEGER)
#define VARIANT_HLP (VARIANT_HL | VARIANT_PERCENT)
#define VARIANT_HLPN (VARIANT_HLP | VARIANT_NUMBER)
#define VARIANT_HLPO (VARIANT_HLP | VARIANT_NONE)
#define VARIANT_HTP (VARIANT_INHERIT | VARIANT_TIME | VARIANT_PERCENT)
#define VARIANT_HMK (VARIANT_HK | VARIANT_NORMAL)
#define VARIANT_HC (VARIANT_INHERIT | VARIANT_COLOR)
#define VARIANT_HCK (VARIANT_HK | VARIANT_COLOR)
#define VARIANT_HUK (VARIANT_HK | VARIANT_URL)
#define VARIANT_HUO (VARIANT_INHERIT | VARIANT_URL | VARIANT_NONE)
#define VARIANT_AHUO (VARIANT_AUTO | VARIANT_HUO)
#define VARIANT_HPN (VARIANT_INHERIT | VARIANT_PERCENT | VARIANT_NUMBER)
#define VARIANT_HN (VARIANT_INHERIT | VARIANT_NUMBER)
#define VARIANT_HON (VARIANT_HN | VARIANT_NONE)
#define VARIANT_HOS (VARIANT_INHERIT | VARIANT_NONE | VARIANT_STRING)
#define VARIANT_LPN (VARIANT_LP | VARIANT_NUMBER)
#define VARIANT_UK (VARIANT_URL | VARIANT_KEYWORD)
#define VARIANT_UO (VARIANT_URL | VARIANT_NONE)
#define VARIANT_ANGLE_OR_ZERO (VARIANT_ANGLE | VARIANT_ZERO_ANGLE)
#define VARIANT_TRANSFORM_LPCALC (VARIANT_LP | VARIANT_CALC)
#define VARIANT_IMAGE (VARIANT_URL | VARIANT_NONE | VARIANT_GRADIENT | \
VARIANT_IMAGE_RECT | VARIANT_ELEMENT)
// This lives here because it depends on the above macros.
const PRUint32
nsCSSProps::kParserVariantTable[eCSSProperty_COUNT_no_shorthands] = {
#define CSS_PROP(name_, id_, method_, flags_, parsevariant_, kwtable_, \
stylestruct_, stylestructoffset_, animtype_) \
parsevariant_,
#include "nsCSSPropList.h"
#undef CSS_PROP
};
//----------------------------------------------------------------------
namespace {
// Rule processing function
typedef void (* RuleAppendFunc) (nsICSSRule* aRule, void* aData);
static void AppendRuleToArray(nsICSSRule* aRule, void* aArray);
static void AppendRuleToSheet(nsICSSRule* aRule, void* aParser);
// Your basic top-down recursive descent style parser
// The exposed methods and members of this class are precisely those
// needed by nsCSSParser, far below.
class CSSParserImpl {
public:
CSSParserImpl();
~CSSParserImpl();
nsresult SetStyleSheet(nsCSSStyleSheet* aSheet);
nsresult SetQuirkMode(PRBool aQuirkMode);
#ifdef MOZ_SVG
nsresult SetSVGMode(PRBool aSVGMode);
#endif
nsresult SetChildLoader(mozilla::css::Loader* aChildLoader);
// Clears everything set by the above Set*() functions.
void Reset();
nsresult Parse(nsIUnicharInputStream* aInput,
nsIURI* aSheetURI,
nsIURI* aBaseURI,
nsIPrincipal* aSheetPrincipal,
PRUint32 aLineNumber,
PRBool aAllowUnsafeRules);
nsresult ParseStyleAttribute(const nsAString& aAttributeValue,
nsIURI* aDocURL,
nsIURI* aBaseURL,
nsIPrincipal* aNodePrincipal,
css::StyleRule** aResult);
nsresult ParseDeclarations(const nsAString& aBuffer,
nsIURI* aSheetURL,
nsIURI* aBaseURL,
nsIPrincipal* aSheetPrincipal,
css::Declaration* aDeclaration,
PRBool* aChanged);
nsresult ParseRule(const nsAString& aRule,
nsIURI* aSheetURL,
nsIURI* aBaseURL,
nsIPrincipal* aSheetPrincipal,
nsCOMArray<nsICSSRule>& aResult);
nsresult ParseProperty(const nsCSSProperty aPropID,
const nsAString& aPropValue,
nsIURI* aSheetURL,
nsIURI* aBaseURL,
nsIPrincipal* aSheetPrincipal,
css::Declaration* aDeclaration,
PRBool* aChanged,
PRBool aIsImportant);
nsresult ParseMediaList(const nsSubstring& aBuffer,
nsIURI* aURL, // for error reporting
PRUint32 aLineNumber, // for error reporting
nsMediaList* aMediaList,
PRBool aHTMLMode);
nsresult ParseColorString(const nsSubstring& aBuffer,
nsIURI* aURL, // for error reporting
PRUint32 aLineNumber, // for error reporting
nscolor* aColor);
nsresult ParseSelectorString(const nsSubstring& aSelectorString,
nsIURI* aURL, // for error reporting
PRUint32 aLineNumber, // for error reporting
nsCSSSelectorList **aSelectorList);
#ifdef MOZ_CSS_ANIMATIONS
already_AddRefed<nsCSSKeyframeRule>
ParseKeyframeRule(const nsSubstring& aBuffer,
nsIURI* aURL,
PRUint32 aLineNumber);
bool ParseKeyframeSelectorString(const nsSubstring& aSelectorString,
nsIURI* aURL, // for error reporting
PRUint32 aLineNumber, // for error reporting
nsTArray<float>& aSelectorList);
#endif
protected:
class nsAutoParseCompoundProperty;
friend class nsAutoParseCompoundProperty;
void AppendRule(nsICSSRule* aRule);
friend void AppendRuleToSheet(nsICSSRule*, void*); // calls AppendRule
/**
* This helper class automatically calls SetParsingCompoundProperty in its
* constructor and takes care of resetting it to false in its destructor.
*/
class nsAutoParseCompoundProperty {
public:
nsAutoParseCompoundProperty(CSSParserImpl* aParser) : mParser(aParser)
{
NS_ASSERTION(!aParser->IsParsingCompoundProperty(),
"already parsing compound property");
NS_ASSERTION(aParser, "Null parser?");
aParser->SetParsingCompoundProperty(PR_TRUE);
}
~nsAutoParseCompoundProperty()
{
mParser->SetParsingCompoundProperty(PR_FALSE);
}
private:
CSSParserImpl* mParser;
};
void InitScanner(nsIUnicharInputStream* aInput, nsIURI* aSheetURI,
PRUint32 aLineNumber, nsIURI* aBaseURI,
nsIPrincipal* aSheetPrincipal);
// the caller must hold on to aBuffer until parsing is done
void InitScanner(const nsSubstring& aString, nsIURI* aSheetURI,
PRUint32 aLineNumber, nsIURI* aBaseURI,
nsIPrincipal* aSheetPrincipal);
void ReleaseScanner(void);
#ifdef MOZ_SVG
PRBool IsSVGMode() const {
return mScanner.IsSVGMode();
}
#endif
PRBool GetToken(PRBool aSkipWS);
void UngetToken();
// get the part in paretheses of the url() function, which is really a
// part of a token in the CSS grammar, but we're using a combination
// of the parser and the scanner to do it to handle the backtracking
// required by the error handling of the tokenization (since if we
// fail to scan the full token, we should fall back to tokenizing as
// FUNCTION ... ')').
// Note that this function WILL WRITE TO aURL IN SOME FAILURE CASES.
PRBool GetURLInParens(nsString& aURL);
void AssertInitialState() {
NS_PRECONDITION(!mHTMLMediaMode, "Bad initial state");
NS_PRECONDITION(!mParsingCompoundProperty, "Bad initial state");
}
PRBool ExpectSymbol(PRUnichar aSymbol, PRBool aSkipWS);
PRBool ExpectEndProperty();
PRBool CheckEndProperty();
nsSubstring* NextIdent();
void SkipUntil(PRUnichar aStopSymbol);
void SkipUntilOneOf(const PRUnichar* aStopSymbolChars);
void SkipRuleSet(PRBool aInsideBraces);
PRBool SkipAtRule(PRBool aInsideBlock);
PRBool SkipDeclaration(PRBool aCheckForBraces);
PRBool PushGroup(css::GroupRule* aRule);
void PopGroup();
PRBool ParseRuleSet(RuleAppendFunc aAppendFunc, void* aProcessData,
PRBool aInsideBraces = PR_FALSE);
PRBool ParseAtRule(RuleAppendFunc aAppendFunc, void* aProcessData);
PRBool ParseCharsetRule(RuleAppendFunc aAppendFunc, void* aProcessData);
PRBool ParseImportRule(RuleAppendFunc aAppendFunc, void* aProcessData);
PRBool ParseURLOrString(nsString& aURL);
PRBool GatherMedia(nsMediaList* aMedia,
PRBool aInAtRule);
PRBool ParseMediaQuery(PRBool aInAtRule, nsMediaQuery **aQuery,
PRBool *aParsedSomething, PRBool *aHitStop);
PRBool ParseMediaQueryExpression(nsMediaQuery* aQuery);
void ProcessImport(const nsString& aURLSpec,
nsMediaList* aMedia,
RuleAppendFunc aAppendFunc,
void* aProcessData);
PRBool ParseGroupRule(css::GroupRule* aRule, RuleAppendFunc aAppendFunc,
void* aProcessData);
PRBool ParseMediaRule(RuleAppendFunc aAppendFunc, void* aProcessData);
PRBool ParseMozDocumentRule(RuleAppendFunc aAppendFunc, void* aProcessData);
PRBool ParseNameSpaceRule(RuleAppendFunc aAppendFunc, void* aProcessData);
void ProcessNameSpace(const nsString& aPrefix,
const nsString& aURLSpec, RuleAppendFunc aAppendFunc,
void* aProcessData);
PRBool ParseFontFaceRule(RuleAppendFunc aAppendFunc, void* aProcessData);
PRBool ParseFontDescriptor(nsCSSFontFaceRule* aRule);
PRBool ParseFontDescriptorValue(nsCSSFontDesc aDescID,
nsCSSValue& aValue);
PRBool ParsePageRule(RuleAppendFunc aAppendFunc, void* aProcessData);
#ifdef MOZ_CSS_ANIMATIONS
PRBool ParseKeyframesRule(RuleAppendFunc aAppendFunc, void* aProcessData);
already_AddRefed<nsCSSKeyframeRule> ParseKeyframeRule();
PRBool ParseKeyframeSelectorList(nsTArray<float>& aSelectorList);
#endif
enum nsSelectorParsingStatus {
// we have parsed a selector and we saw a token that cannot be
// part of a selector:
eSelectorParsingStatus_Done,
// we should continue parsing the selector:
eSelectorParsingStatus_Continue,
// we saw an unexpected token or token value,
// or we saw end-of-file with an unfinished selector:
eSelectorParsingStatus_Error
};
nsSelectorParsingStatus ParseIDSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector);
nsSelectorParsingStatus ParseClassSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector);
// aPseudoElement and aPseudoElementArgs are the location where
// pseudo-elements (as opposed to pseudo-classes) are stored;
// pseudo-classes are stored on aSelector. aPseudoElement and
// aPseudoElementArgs must be non-null iff !aIsNegated.
nsSelectorParsingStatus ParsePseudoSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector,
PRBool aIsNegated,
nsIAtom** aPseudoElement,
nsAtomList** aPseudoElementArgs,
nsCSSPseudoElements::Type* aPseudoElementType);
nsSelectorParsingStatus ParseAttributeSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector);
nsSelectorParsingStatus ParseTypeOrUniversalSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector,
PRBool aIsNegated);
nsSelectorParsingStatus ParsePseudoClassWithIdentArg(nsCSSSelector& aSelector,
nsCSSPseudoClasses::Type aType);
nsSelectorParsingStatus ParsePseudoClassWithNthPairArg(nsCSSSelector& aSelector,
nsCSSPseudoClasses::Type aType);
nsSelectorParsingStatus ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector,
nsCSSPseudoClasses::Type aType);
nsSelectorParsingStatus ParseNegatedSimpleSelector(PRInt32& aDataMask,
nsCSSSelector& aSelector);
// If aStopChar is non-zero, the selector list is done when we hit
// aStopChar. Otherwise, it's done when we hit EOF.
PRBool ParseSelectorList(nsCSSSelectorList*& aListHead,
PRUnichar aStopChar);
PRBool ParseSelectorGroup(nsCSSSelectorList*& aListHead);
PRBool ParseSelector(nsCSSSelectorList* aList, PRUnichar aPrevCombinator);
css::Declaration* ParseDeclarationBlock(PRBool aCheckForBraces);
PRBool ParseDeclaration(css::Declaration* aDeclaration,
PRBool aCheckForBraces,
PRBool aMustCallValueAppended,
PRBool* aChanged);
PRBool ParseProperty(nsCSSProperty aPropID);
PRBool ParsePropertyByFunction(nsCSSProperty aPropID);
PRBool ParseSingleValueProperty(nsCSSValue& aValue,
nsCSSProperty aPropID);
enum PriorityParsingStatus {
ePriority_None,
ePriority_Important,
ePriority_Error
};
PriorityParsingStatus ParsePriority();
#ifdef MOZ_XUL
PRBool ParseTreePseudoElement(nsAtomList **aPseudoElementArgs);
#endif
void InitBoxPropsAsPhysical(const nsCSSProperty *aSourceProperties);
// Property specific parsing routines
PRBool ParseAzimuth(nsCSSValue& aValue);
PRBool ParseBackground();
struct BackgroundParseState {
nsCSSValue& mColor;
nsCSSValueList* mImage;
nsCSSValueList* mRepeat;
nsCSSValueList* mAttachment;
nsCSSValueList* mClip;
nsCSSValueList* mOrigin;
nsCSSValuePairList* mPosition;
nsCSSValuePairList* mSize;
BackgroundParseState(
nsCSSValue& aColor, nsCSSValueList* aImage, nsCSSValueList* aRepeat,
nsCSSValueList* aAttachment, nsCSSValueList* aClip,
nsCSSValueList* aOrigin, nsCSSValuePairList* aPosition,
nsCSSValuePairList* aSize) :
mColor(aColor), mImage(aImage), mRepeat(aRepeat),
mAttachment(aAttachment), mClip(aClip), mOrigin(aOrigin),
mPosition(aPosition), mSize(aSize) {};
};
PRBool ParseBackgroundItem(BackgroundParseState& aState);
PRBool ParseValueList(nsCSSProperty aPropID); // a single value prop-id
PRBool ParseBackgroundPosition();
PRBool ParseBoxPositionValues(nsCSSValuePair& aOut, PRBool aAcceptsInherit);
PRBool ParseBackgroundSize();
PRBool ParseBackgroundSizeValues(nsCSSValuePair& aOut);
PRBool ParseBorderColor();
PRBool ParseBorderColors(nsCSSProperty aProperty);
PRBool ParseBorderImage();
PRBool ParseBorderSpacing();
PRBool ParseBorderSide(const nsCSSProperty aPropIDs[],
PRBool aSetAllSides);
PRBool ParseDirectionalBorderSide(const nsCSSProperty aPropIDs[],
PRInt32 aSourceType);
PRBool ParseBorderStyle();
PRBool ParseBorderWidth();
PRBool ParseCalc(nsCSSValue &aValue, PRInt32 aVariantMask);
PRBool ParseCalcAdditiveExpression(nsCSSValue& aValue,
PRInt32& aVariantMask);
PRBool ParseCalcMultiplicativeExpression(nsCSSValue& aValue,
PRInt32& aVariantMask,
PRBool *aHadFinalWS);
PRBool ParseCalcTerm(nsCSSValue& aValue, PRInt32& aVariantMask);
PRBool RequireWhitespace();
// for 'clip' and '-moz-image-region'
PRBool ParseRect(nsCSSProperty aPropID);
PRBool ParseContent();
PRBool ParseCounterData(nsCSSProperty aPropID);
PRBool ParseCue();
PRBool ParseCursor();
PRBool ParseFont();
PRBool ParseFontWeight(nsCSSValue& aValue);
PRBool ParseOneFamily(nsAString& aValue);
PRBool ParseFamily(nsCSSValue& aValue);
PRBool ParseFontSrc(nsCSSValue& aValue);
PRBool ParseFontSrcFormat(nsTArray<nsCSSValue>& values);
PRBool ParseFontRanges(nsCSSValue& aValue);
PRBool ParseListStyle();
PRBool ParseMargin();
PRBool ParseMarks(nsCSSValue& aValue);
PRBool ParseMozTransform();
PRBool ParseOutline();
PRBool ParseOverflow();
PRBool ParsePadding();
PRBool ParsePause();
PRBool ParseQuotes();
PRBool ParseSize();
PRBool ParseTextDecoration(nsCSSValue& aValue);
PRBool ParseShadowItem(nsCSSValue& aValue, PRBool aIsBoxShadow);
PRBool ParseShadowList(nsCSSProperty aProperty);
PRBool ParseTransitionProperty();
PRBool ParseTransitionTimingFunctionValues(nsCSSValue& aValue);
PRBool ParseTransitionTimingFunctionValueComponent(float& aComponent,
char aStop,
PRBool aCheckRange);
PRBool ParseTransitionStepTimingFunctionValues(nsCSSValue& aValue);
enum ParseAnimationOrTransitionShorthandResult {
eParseAnimationOrTransitionShorthand_Values,
eParseAnimationOrTransitionShorthand_Inherit,
eParseAnimationOrTransitionShorthand_Error
};
ParseAnimationOrTransitionShorthandResult
ParseAnimationOrTransitionShorthand(const nsCSSProperty* aProperties,
const nsCSSValue* aInitialValues,
nsCSSValue* aValues,
size_t aNumProperties);
PRBool ParseTransition();
#ifdef MOZ_CSS_ANIMATIONS
PRBool ParseAnimation();
#endif
#ifdef MOZ_SVG
PRBool ParsePaint(nsCSSProperty aPropID);
PRBool ParseDasharray();
PRBool ParseMarker();
#endif
// Reused utility parsing routines
void AppendValue(nsCSSProperty aPropID, const nsCSSValue& aValue);
PRBool ParseBoxProperties(const nsCSSProperty aPropIDs[]);
PRBool ParseDirectionalBoxProperty(nsCSSProperty aProperty,
PRInt32 aSourceType);
PRBool ParseBoxCornerRadius(const nsCSSProperty aPropID);
PRBool ParseBoxCornerRadii(const nsCSSProperty aPropIDs[]);
PRInt32 ParseChoice(nsCSSValue aValues[],
const nsCSSProperty aPropIDs[], PRInt32 aNumIDs);
PRBool ParseColor(nsCSSValue& aValue);
PRBool ParseColorComponent(PRUint8& aComponent,
PRInt32& aType, char aStop);
// ParseHSLColor parses everything starting with the opening '('
// up through and including the aStop char.
PRBool ParseHSLColor(nscolor& aColor, char aStop);
// ParseColorOpacity will enforce that the color ends with a ')'
// after the opacity
PRBool ParseColorOpacity(PRUint8& aOpacity);
PRBool ParseEnum(nsCSSValue& aValue, const PRInt32 aKeywordTable[]);
PRBool ParseVariant(nsCSSValue& aValue,
PRInt32 aVariantMask,
const PRInt32 aKeywordTable[]);
PRBool ParseNonNegativeVariant(nsCSSValue& aValue,
PRInt32 aVariantMask,
const PRInt32 aKeywordTable[]);
PRBool ParsePositiveNonZeroVariant(nsCSSValue& aValue,
PRInt32 aVariantMask,
const PRInt32 aKeywordTable[]);
PRBool ParseCounter(nsCSSValue& aValue);
PRBool ParseAttr(nsCSSValue& aValue);
PRBool SetValueToURL(nsCSSValue& aValue, const nsString& aURL);
PRBool TranslateDimension(nsCSSValue& aValue, PRInt32 aVariantMask,
float aNumber, const nsString& aUnit);
PRBool ParseImageRect(nsCSSValue& aImage);
PRBool ParseElement(nsCSSValue& aValue);
PRBool ParseColorStop(nsCSSValueGradient* aGradient);
PRBool ParseGradient(nsCSSValue& aValue, PRBool aIsRadial,
PRBool aIsRepeating);
void SetParsingCompoundProperty(PRBool aBool) {
NS_ASSERTION(aBool == PR_TRUE || aBool == PR_FALSE, "bad PRBool value");
mParsingCompoundProperty = aBool;
}
PRBool IsParsingCompoundProperty(void) const {
return mParsingCompoundProperty;
}
/* Functions for -moz-transform Parsing */
PRBool ParseSingleTransform(nsCSSValue& aValue);
PRBool ParseFunction(const nsString &aFunction, const PRInt32 aAllowedTypes[],
PRUint16 aMinElems, PRUint16 aMaxElems,
nsCSSValue &aValue);
PRBool ParseFunctionInternals(const PRInt32 aVariantMask[],
PRUint16 aMinElems,
PRUint16 aMaxElems,
nsTArray<nsCSSValue>& aOutput);
/* Functions for -moz-transform-origin Parsing */
PRBool ParseMozTransformOrigin();
/* Find and return the namespace ID associated with aPrefix.
If aPrefix has not been declared in an @namespace rule, returns
kNameSpaceID_Unknown and sets mFoundUnresolvablePrefix to true. */
PRInt32 GetNamespaceIdForPrefix(const nsString& aPrefix);
/* Find the correct default namespace, and set it on aSelector. */
void SetDefaultNamespaceOnSelector(nsCSSSelector& aSelector);
// Current token. The value is valid after calling GetToken and invalidated
// by UngetToken.
nsCSSToken mToken;
// Our scanner.
nsCSSScanner mScanner;
// The URI to be used as a base for relative URIs.
nsCOMPtr<nsIURI> mBaseURI;
// The URI to be used as an HTTP "Referer" and for error reporting.
nsCOMPtr<nsIURI> mSheetURI;
// The principal of the sheet involved
nsCOMPtr<nsIPrincipal> mSheetPrincipal;
// The sheet we're parsing into
nsRefPtr<nsCSSStyleSheet> mSheet;
// Used for @import rules
mozilla::css::Loader* mChildLoader; // not ref counted, it owns us
// Sheet section we're in. This is used to enforce correct ordering of the
// various rule types (eg the fact that a @charset rule must come before
// anything else). Note that there are checks of similar things in various
// places in nsCSSStyleSheet.cpp (e.g in insertRule, RebuildChildList).
enum nsCSSSection {
eCSSSection_Charset,
eCSSSection_Import,
eCSSSection_NameSpace,
eCSSSection_General
};
nsCSSSection mSection;
nsXMLNameSpaceMap *mNameSpaceMap; // weak, mSheet owns it
// After an UngetToken is done this flag is true. The next call to
// GetToken clears the flag.
PRPackedBool mHavePushBack : 1;
// True if we are in quirks mode; false in standards or almost standards mode
PRPackedBool mNavQuirkMode : 1;
// True if unsafe rules should be allowed
PRPackedBool mUnsafeRulesEnabled : 1;
// True for parsing media lists for HTML attributes, where we have to
// ignore CSS comments.
PRPackedBool mHTMLMediaMode : 1;
// This flag is set when parsing a non-box shorthand; it's used to not apply
// some quirks during shorthand parsing
PRPackedBool mParsingCompoundProperty : 1;
// GetNamespaceIdForPrefix will set mFoundUnresolvablePrefix to true
// when it encounters a prefix that is not mapped to a namespace.
PRPackedBool mFoundUnresolvablePrefix : 1;
#ifdef DEBUG
PRPackedBool mScannerInited : 1;
#endif
// Stack of rule groups; used for @media and such.
nsTArray<nsRefPtr<css::GroupRule> > mGroupStack;
// During the parsing of a property (which may be a shorthand), the data
// are stored in |mTempData|. (It is needed to ensure that parser
// errors cause the data to be ignored, and to ensure that a
// non-'!important' declaration does not override an '!important'
// one.)
nsCSSExpandedDataBlock mTempData;
// All data from successfully parsed properties are placed into |mData|.
nsCSSExpandedDataBlock mData;
public:
// Used from nsCSSParser constructors and destructors
CSSParserImpl* mNextFree;
};
static void AppendRuleToArray(nsICSSRule* aRule, void* aArray)
{
static_cast<nsCOMArray<nsICSSRule>*>(aArray)->AppendObject(aRule);
}
static void AppendRuleToSheet(nsICSSRule* aRule, void* aParser)
{
CSSParserImpl* parser = (CSSParserImpl*) aParser;
parser->AppendRule(aRule);
}
#ifdef CSS_REPORT_PARSE_ERRORS
#define REPORT_UNEXPECTED(msg_) \
mScanner.ReportUnexpected(#msg_)
#define REPORT_UNEXPECTED_P(msg_, params_) \
mScanner.ReportUnexpectedParams(#msg_, params_, NS_ARRAY_LENGTH(params_))
#define REPORT_UNEXPECTED_EOF(lf_) \
mScanner.ReportUnexpectedEOF(#lf_)
#define REPORT_UNEXPECTED_EOF_CHAR(ch_) \
mScanner.ReportUnexpectedEOF(ch_)
#define REPORT_UNEXPECTED_TOKEN(msg_) \
mScanner.ReportUnexpectedToken(mToken, #msg_)
#define REPORT_UNEXPECTED_TOKEN_P(msg_, params_) \
mScanner.ReportUnexpectedTokenParams(mToken, #msg_, \
params_, NS_ARRAY_LENGTH(params_))
#define OUTPUT_ERROR() \
mScanner.OutputError()
#define CLEAR_ERROR() \
mScanner.ClearError()
#else
#define REPORT_UNEXPECTED(msg_)
#define REPORT_UNEXPECTED_P(msg_, params_)
#define REPORT_UNEXPECTED_EOF(lf_)
#define REPORT_UNEXPECTED_EOF_CHAR(ch_)
#define REPORT_UNEXPECTED_TOKEN(msg_)
#define REPORT_UNEXPECTED_TOKEN_P(msg_, params_)
#define OUTPUT_ERROR()
#define CLEAR_ERROR()
#endif
CSSParserImpl::CSSParserImpl()
: mToken(),
mScanner(),
mChildLoader(nsnull),
mSection(eCSSSection_Charset),
mNameSpaceMap(nsnull),
mHavePushBack(PR_FALSE),
mNavQuirkMode(PR_FALSE),
mUnsafeRulesEnabled(PR_FALSE),
mHTMLMediaMode(PR_FALSE),
mParsingCompoundProperty(PR_FALSE),
mFoundUnresolvablePrefix(PR_FALSE)
#ifdef DEBUG
, mScannerInited(PR_FALSE)
#endif
, mNextFree(nsnull)
{
}
CSSParserImpl::~CSSParserImpl()
{
mData.AssertInitialState();
mTempData.AssertInitialState();
}
nsresult
CSSParserImpl::SetStyleSheet(nsCSSStyleSheet* aSheet)
{
if (aSheet != mSheet) {
// Switch to using the new sheet, if any
mGroupStack.Clear();
mSheet = aSheet;
if (mSheet) {
mNameSpaceMap = mSheet->GetNameSpaceMap();
} else {
mNameSpaceMap = nsnull;
}
}
return NS_OK;
}
nsresult
CSSParserImpl::SetQuirkMode(PRBool aQuirkMode)
{
NS_ASSERTION(aQuirkMode == PR_TRUE || aQuirkMode == PR_FALSE, "bad PRBool value");
mNavQuirkMode = aQuirkMode;
return NS_OK;
}
#ifdef MOZ_SVG
nsresult
CSSParserImpl::SetSVGMode(PRBool aSVGMode)
{
NS_ASSERTION(aSVGMode == PR_TRUE || aSVGMode == PR_FALSE,
"bad PRBool value");
mScanner.SetSVGMode(aSVGMode);
return NS_OK;
}
#endif
nsresult
CSSParserImpl::SetChildLoader(mozilla::css::Loader* aChildLoader)
{
mChildLoader = aChildLoader; // not ref counted, it owns us
return NS_OK;
}
void
CSSParserImpl::Reset()
{
NS_ASSERTION(! mScannerInited, "resetting with scanner active");
SetStyleSheet(nsnull);
SetQuirkMode(PR_FALSE);
#ifdef MOZ_SVG
SetSVGMode(PR_FALSE);
#endif // MOZ_SVG
SetChildLoader(nsnull);
}
void
CSSParserImpl::InitScanner(nsIUnicharInputStream* aInput, nsIURI* aSheetURI,
PRUint32 aLineNumber, nsIURI* aBaseURI,
nsIPrincipal* aSheetPrincipal)
{
NS_ASSERTION(! mScannerInited, "already have scanner");
mScanner.Init(aInput, nsnull, 0, aSheetURI, aLineNumber, mSheet,
mChildLoader);
#ifdef DEBUG
mScannerInited = PR_TRUE;
#endif
mBaseURI = aBaseURI;
mSheetURI = aSheetURI;
mSheetPrincipal = aSheetPrincipal;
mHavePushBack = PR_FALSE;
}
void
CSSParserImpl::InitScanner(const nsSubstring& aString, nsIURI* aSheetURI,
PRUint32 aLineNumber, nsIURI* aBaseURI,
nsIPrincipal* aSheetPrincipal)
{
// Having it not own the string is OK since the caller will hold on to
// the stream until we're done parsing.
NS_ASSERTION(! mScannerInited, "already have scanner");
mScanner.Init(nsnull, aString.BeginReading(), aString.Length(), aSheetURI,
aLineNumber, mSheet, mChildLoader);
#ifdef DEBUG
mScannerInited = PR_TRUE;
#endif
mBaseURI = aBaseURI;
mSheetURI = aSheetURI;
mSheetPrincipal = aSheetPrincipal;
mHavePushBack = PR_FALSE;
}
void
CSSParserImpl::ReleaseScanner(void)
{
mScanner.Close();
#ifdef DEBUG
mScannerInited = PR_FALSE;
#endif
mBaseURI = nsnull;
mSheetURI = nsnull;
mSheetPrincipal = nsnull;
}
nsresult
CSSParserImpl::Parse(nsIUnicharInputStream* aInput,
nsIURI* aSheetURI,
nsIURI* aBaseURI,
nsIPrincipal* aSheetPrincipal,
PRUint32 aLineNumber,
PRBool aAllowUnsafeRules)
{
NS_PRECONDITION(aSheetPrincipal, "Must have principal here!");
NS_ASSERTION(nsnull != aBaseURI, "need base URI");
NS_ASSERTION(nsnull != aSheetURI, "need sheet URI");
AssertInitialState();
NS_PRECONDITION(mSheet, "Must have sheet to parse into");
NS_ENSURE_STATE(mSheet);
#ifdef DEBUG
nsIURI* uri = mSheet->GetSheetURI();
PRBool equal;
NS_ASSERTION(NS_SUCCEEDED(aSheetURI->Equals(uri, &equal)) && equal,
"Sheet URI does not match passed URI");
NS_ASSERTION(NS_SUCCEEDED(mSheet->Principal()->Equals(aSheetPrincipal,
&equal)) &&
equal,
"Sheet principal does not match passed principal");
#endif
InitScanner(aInput, aSheetURI, aLineNumber, aBaseURI, aSheetPrincipal);
PRInt32 ruleCount = mSheet->StyleRuleCount();
if (0 < ruleCount) {
nsICSSRule* lastRule = nsnull;
mSheet->GetStyleRuleAt(ruleCount - 1, lastRule);
if (lastRule) {
switch (lastRule->GetType()) {
case nsICSSRule::CHARSET_RULE:
case nsICSSRule::IMPORT_RULE:
mSection = eCSSSection_Import;
break;
case nsICSSRule::NAMESPACE_RULE:
mSection = eCSSSection_NameSpace;
break;
default:
mSection = eCSSSection_General;
break;
}
NS_RELEASE(lastRule);
}
}
else {
mSection = eCSSSection_Charset; // sheet is empty, any rules are fair
}
mUnsafeRulesEnabled = aAllowUnsafeRules;
nsCSSToken* tk = &mToken;
for (;;) {
// Get next non-whitespace token
if (!GetToken(PR_TRUE)) {
OUTPUT_ERROR();
break;
}
if (eCSSToken_HTMLComment == tk->mType) {
continue; // legal here only
}
if (eCSSToken_AtKeyword == tk->mType) {
ParseAtRule(AppendRuleToSheet, this);
continue;
}
UngetToken();
if (ParseRuleSet(AppendRuleToSheet, this)) {
mSection = eCSSSection_General;
}
}
ReleaseScanner();
mUnsafeRulesEnabled = PR_FALSE;
// XXX check for low level errors
return NS_OK;
}
/**
* Determines whether the identifier contained in the given string is a
* vendor-specific identifier, as described in CSS 2.1 section 4.1.2.1.
*/
static PRBool
NonMozillaVendorIdentifier(const nsAString& ident)
{
return (ident.First() == PRUnichar('-') &&
!StringBeginsWith(ident, NS_LITERAL_STRING("-moz-"))) ||
ident.First() == PRUnichar('_');
}
nsresult
CSSParserImpl::ParseStyleAttribute(const nsAString& aAttributeValue,
nsIURI* aDocURI,
nsIURI* aBaseURI,
nsIPrincipal* aNodePrincipal,
css::StyleRule** aResult)
{
NS_PRECONDITION(aNodePrincipal, "Must have principal here!");
AssertInitialState();
NS_ASSERTION(nsnull != aBaseURI, "need base URI");