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