@@ -30,104 +30,124 @@ public function __construct(array $aColor, $iLineNo = 0)
3030 */
3131 public static function parse (ParserState $ oParserState , bool $ bIgnoreCase = false ): CSSFunction
3232 {
33- $ aColor = [];
34- if ($ oParserState ->comes ('# ' )) {
35- $ oParserState ->consume ('# ' );
36- $ sValue = $ oParserState ->parseIdentifier (false );
37- if ($ oParserState ->strlen ($ sValue ) === 3 ) {
38- $ sValue = $ sValue [0 ] . $ sValue [0 ] . $ sValue [1 ] . $ sValue [1 ] . $ sValue [2 ] . $ sValue [2 ];
39- } elseif ($ oParserState ->strlen ($ sValue ) === 4 ) {
40- $ sValue = $ sValue [0 ] . $ sValue [0 ] . $ sValue [1 ] . $ sValue [1 ] . $ sValue [2 ] . $ sValue [2 ] . $ sValue [3 ]
41- . $ sValue [3 ];
42- }
33+ return
34+ $ oParserState ->comes ('# ' )
35+ ? self ::parseHexColor ($ oParserState )
36+ : self ::parseColorFunction ($ oParserState );
37+ }
4338
44- if ($ oParserState ->strlen ($ sValue ) === 8 ) {
45- $ aColor = [
46- 'r ' => new Size (\intval ($ sValue [0 ] . $ sValue [1 ], 16 ), null , true , $ oParserState ->currentLine ()),
47- 'g ' => new Size (\intval ($ sValue [2 ] . $ sValue [3 ], 16 ), null , true , $ oParserState ->currentLine ()),
48- 'b ' => new Size (\intval ($ sValue [4 ] . $ sValue [5 ], 16 ), null , true , $ oParserState ->currentLine ()),
49- 'a ' => new Size (
50- \round (self ::mapRange (\intval ($ sValue [6 ] . $ sValue [7 ], 16 ), 0 , 255 , 0 , 1 ), 2 ),
51- null ,
52- true ,
53- $ oParserState ->currentLine ()
54- ),
55- ];
56- } elseif ($ oParserState ->strlen ($ sValue ) === 6 ) {
57- $ aColor = [
58- 'r ' => new Size (\intval ($ sValue [0 ] . $ sValue [1 ], 16 ), null , true , $ oParserState ->currentLine ()),
59- 'g ' => new Size (\intval ($ sValue [2 ] . $ sValue [3 ], 16 ), null , true , $ oParserState ->currentLine ()),
60- 'b ' => new Size (\intval ($ sValue [4 ] . $ sValue [5 ], 16 ), null , true , $ oParserState ->currentLine ()),
61- ];
62- } else {
63- throw new UnexpectedTokenException (
64- 'Invalid hex color value ' ,
65- $ sValue ,
66- 'custom ' ,
39+ /**
40+ * @throws UnexpectedEOFException
41+ * @throws UnexpectedTokenException
42+ */
43+ private static function parseHexColor (ParserState $ oParserState ): CSSFunction
44+ {
45+ $ oParserState ->consume ('# ' );
46+ $ sValue = $ oParserState ->parseIdentifier (false );
47+ if ($ oParserState ->strlen ($ sValue ) === 3 ) {
48+ $ sValue = $ sValue [0 ] . $ sValue [0 ] . $ sValue [1 ] . $ sValue [1 ] . $ sValue [2 ] . $ sValue [2 ];
49+ } elseif ($ oParserState ->strlen ($ sValue ) === 4 ) {
50+ $ sValue = $ sValue [0 ] . $ sValue [0 ] . $ sValue [1 ] . $ sValue [1 ] . $ sValue [2 ] . $ sValue [2 ] . $ sValue [3 ]
51+ . $ sValue [3 ];
52+ }
53+
54+ if ($ oParserState ->strlen ($ sValue ) === 8 ) {
55+ $ aColor = [
56+ 'r ' => new Size (\intval ($ sValue [0 ] . $ sValue [1 ], 16 ), null , true , $ oParserState ->currentLine ()),
57+ 'g ' => new Size (\intval ($ sValue [2 ] . $ sValue [3 ], 16 ), null , true , $ oParserState ->currentLine ()),
58+ 'b ' => new Size (\intval ($ sValue [4 ] . $ sValue [5 ], 16 ), null , true , $ oParserState ->currentLine ()),
59+ 'a ' => new Size (
60+ \round (self ::mapRange (\intval ($ sValue [6 ] . $ sValue [7 ], 16 ), 0 , 255 , 0 , 1 ), 2 ),
61+ null ,
62+ true ,
6763 $ oParserState ->currentLine ()
68- );
69- }
64+ ),
65+ ];
66+ } elseif ($ oParserState ->strlen ($ sValue ) === 6 ) {
67+ $ aColor = [
68+ 'r ' => new Size (\intval ($ sValue [0 ] . $ sValue [1 ], 16 ), null , true , $ oParserState ->currentLine ()),
69+ 'g ' => new Size (\intval ($ sValue [2 ] . $ sValue [3 ], 16 ), null , true , $ oParserState ->currentLine ()),
70+ 'b ' => new Size (\intval ($ sValue [4 ] . $ sValue [5 ], 16 ), null , true , $ oParserState ->currentLine ()),
71+ ];
7072 } else {
71- $ sColorMode = $ oParserState ->parseIdentifier (true );
73+ throw new UnexpectedTokenException (
74+ 'Invalid hex color value ' ,
75+ $ sValue ,
76+ 'custom ' ,
77+ $ oParserState ->currentLine ()
78+ );
79+ }
80+
81+ return new Color ($ aColor , $ oParserState ->currentLine ());
82+ }
83+
84+ /**
85+ * @throws UnexpectedEOFException
86+ * @throws UnexpectedTokenException
87+ */
88+ private static function parseColorFunction (ParserState $ oParserState ): CSSFunction
89+ {
90+ $ aColor = [];
91+
92+ $ sColorMode = $ oParserState ->parseIdentifier (true );
93+ $ oParserState ->consumeWhiteSpace ();
94+ $ oParserState ->consume ('( ' );
95+
96+ // CSS Color Module Level 4 says that `rgb` and `rgba` are now aliases; likewise `hsl` and `hsla`.
97+ // So, attempt to parse with the `a`, and allow for it not being there.
98+ switch ($ sColorMode ) {
99+ case 'rgb ' :
100+ $ colorModeForParsing = 'rgba ' ;
101+ $ mayHaveOptionalAlpha = true ;
102+ break ;
103+ case 'hsl ' :
104+ $ colorModeForParsing = 'hsla ' ;
105+ $ mayHaveOptionalAlpha = true ;
106+ break ;
107+ case 'rgba ' :
108+ // This is handled identically to the following case.
109+ case 'hsla ' :
110+ $ colorModeForParsing = $ sColorMode ;
111+ $ mayHaveOptionalAlpha = true ;
112+ break ;
113+ default :
114+ $ colorModeForParsing = $ sColorMode ;
115+ $ mayHaveOptionalAlpha = false ;
116+ }
117+
118+ $ bContainsVar = false ;
119+ $ iLength = $ oParserState ->strlen ($ colorModeForParsing );
120+ for ($ i = 0 ; $ i < $ iLength ; ++$ i ) {
72121 $ oParserState ->consumeWhiteSpace ();
73- $ oParserState ->consume ('( ' );
74-
75- // CSS Color Module Level 4 says that `rgb` and `rgba` are now aliases; likewise `hsl` and `hsla`.
76- // So, attempt to parse with the `a`, and allow for it not being there.
77- switch ($ sColorMode ) {
78- case 'rgb ' :
79- $ colorModeForParsing = 'rgba ' ;
80- $ mayHaveOptionalAlpha = true ;
81- break ;
82- case 'hsl ' :
83- $ colorModeForParsing = 'hsla ' ;
84- $ mayHaveOptionalAlpha = true ;
85- break ;
86- case 'rgba ' :
87- // This is handled identically to the following case.
88- case 'hsla ' :
89- $ colorModeForParsing = $ sColorMode ;
90- $ mayHaveOptionalAlpha = true ;
91- break ;
92- default :
93- $ colorModeForParsing = $ sColorMode ;
94- $ mayHaveOptionalAlpha = false ;
122+ if ($ oParserState ->comes ('var ' )) {
123+ $ aColor [$ colorModeForParsing [$ i ]] = CSSFunction::parseIdentifierOrFunction ($ oParserState );
124+ $ bContainsVar = true ;
125+ } else {
126+ $ aColor [$ colorModeForParsing [$ i ]] = Size::parse ($ oParserState , true );
95127 }
96128
97- $ bContainsVar = false ;
98- $ iLength = $ oParserState ->strlen ($ colorModeForParsing );
99- for ($ i = 0 ; $ i < $ iLength ; ++$ i ) {
100- $ oParserState ->consumeWhiteSpace ();
101- if ($ oParserState ->comes ('var ' )) {
102- $ aColor [$ colorModeForParsing [$ i ]] = CSSFunction::parseIdentifierOrFunction ($ oParserState );
103- $ bContainsVar = true ;
104- } else {
105- $ aColor [$ colorModeForParsing [$ i ]] = Size::parse ($ oParserState , true );
106- }
107-
108- // This must be done first, to consume comments as well, so that the `comes` test will work.
109- $ oParserState ->consumeWhiteSpace ();
110-
111- // With a `var` argument, the function can have fewer arguments.
112- // And as of CSS Color Module Level 4, the alpha argument is optional.
113- $ canCloseNow =
114- $ bContainsVar ||
115- ($ mayHaveOptionalAlpha && $ i >= $ iLength - 2 );
116- if ($ canCloseNow && $ oParserState ->comes (') ' )) {
117- break ;
118- }
119-
120- if ($ i < ($ iLength - 1 )) {
121- $ oParserState ->consume (', ' );
122- }
129+ // This must be done first, to consume comments as well, so that the `comes` test will work.
130+ $ oParserState ->consumeWhiteSpace ();
131+
132+ // With a `var` argument, the function can have fewer arguments.
133+ // And as of CSS Color Module Level 4, the alpha argument is optional.
134+ $ canCloseNow =
135+ $ bContainsVar ||
136+ ($ mayHaveOptionalAlpha && $ i >= $ iLength - 2 );
137+ if ($ canCloseNow && $ oParserState ->comes (') ' )) {
138+ break ;
123139 }
124- $ oParserState ->consume (') ' );
125140
126- if ($ bContainsVar ) {
127- return new CSSFunction ( $ sColorMode , \array_values ( $ aColor ), ' , ' , $ oParserState ->currentLine () );
141+ if ($ i < ( $ iLength - 1 ) ) {
142+ $ oParserState ->consume ( ' , ' );
128143 }
129144 }
130- return new Color ($ aColor , $ oParserState ->currentLine ());
145+ $ oParserState ->consume (') ' );
146+
147+ return
148+ $ bContainsVar
149+ ? new CSSFunction ($ sColorMode , \array_values ($ aColor ), ', ' , $ oParserState ->currentLine ())
150+ : new Color ($ aColor , $ oParserState ->currentLine ());
131151 }
132152
133153 private static function mapRange (float $ fVal , float $ fFromMin , float $ fFromMax , float $ fToMin , float $ fToMax ): float
0 commit comments