Skip to content

Commit ef6b562

Browse files
committed
support hwb color declaration
1 parent 24010e6 commit ef6b562

9 files changed

Lines changed: 485 additions & 5 deletions

File tree

src/main/java/org/htmlunit/cssparser/dom/CSSValueImpl.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,10 @@ else if (value.getLexicalUnitType() == LexicalUnitType.HSLCOLOR) {
199199
// HSLColor
200200
value_ = new HSLColorImpl(value.getFunctionName(), value.getParameters());
201201
}
202+
else if (value.getLexicalUnitType() == LexicalUnitType.HWBCOLOR) {
203+
// HWBColor
204+
value_ = new HWBColorImpl(value.getFunctionName(), value.getParameters());
205+
}
202206
else if (value.getLexicalUnitType() == LexicalUnitType.COUNTER_FUNCTION) {
203207
// Counter
204208
value_ = new CounterImpl(false, value.getParameters());

src/main/java/org/htmlunit/cssparser/dom/HSLColorImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public HSLColorImpl(final String function, final LexicalUnit lu) throws DOMExcep
9797

9898
next = next.getNextLexicalUnit();
9999
if (next == null) {
100-
throw new DOMException(DOMException.SYNTAX_ERR, function_ + "b requires at least three values.");
100+
throw new DOMException(DOMException.SYNTAX_ERR, function_ + " requires at least three values.");
101101
}
102102

103103
if (LexicalUnitType.NONE == next.getLexicalUnitType()) {
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/*
2+
* Copyright (c) 2019-2024 Ronald Brill.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
package org.htmlunit.cssparser.dom;
16+
17+
import java.io.Serializable;
18+
import java.util.Locale;
19+
20+
import org.htmlunit.cssparser.parser.LexicalUnit;
21+
import org.htmlunit.cssparser.parser.LexicalUnit.LexicalUnitType;
22+
import org.w3c.dom.DOMException;
23+
24+
/**
25+
* Implementation of HWBColor.
26+
*
27+
* @author Ronald Brill
28+
*/
29+
public class HWBColorImpl implements Serializable {
30+
private CSSValueImpl hue_;
31+
private CSSValueImpl whiteness_;
32+
private CSSValueImpl blackness_;
33+
private CSSValueImpl alpha_;
34+
35+
/**
36+
* Constructor that reads the values from the given
37+
* chain of LexicalUnits.
38+
* @param function the name of the function; hwb
39+
* @param lu the values
40+
* @throws DOMException in case of error
41+
*/
42+
public HWBColorImpl(final String function, final LexicalUnit lu) throws DOMException {
43+
if (function == null) {
44+
throw new DOMException(DOMException.SYNTAX_ERR, "Color space hwb is required.");
45+
}
46+
final String functionLC = function.toLowerCase(Locale.ROOT);
47+
if (!"hwb".equals(functionLC)) {
48+
throw new DOMException(DOMException.SYNTAX_ERR, "Color space '" + functionLC + "' not supported.");
49+
}
50+
51+
LexicalUnit next = lu;
52+
if (next == null) {
53+
throw new DOMException(DOMException.SYNTAX_ERR, "hwb requires at least three values.");
54+
}
55+
hue_ = new CSSValueImpl(next, true);
56+
57+
next = next.getNextLexicalUnit();
58+
if (next == null) {
59+
throw new DOMException(DOMException.SYNTAX_ERR, "hwb requires at least three values.");
60+
}
61+
62+
if (LexicalUnitType.NONE != next.getLexicalUnitType()
63+
&& LexicalUnitType.PERCENTAGE != next.getLexicalUnitType()) {
64+
throw new DOMException(DOMException.SYNTAX_ERR, "Whiteness part has to be percentage.");
65+
}
66+
whiteness_ = new CSSValueImpl(next, true);
67+
68+
next = next.getNextLexicalUnit();
69+
if (next == null) {
70+
throw new DOMException(DOMException.SYNTAX_ERR, "hwb requires at least three values.");
71+
}
72+
if (next.getLexicalUnitType() == LexicalUnitType.OPERATOR_COMMA) {
73+
throw new DOMException(DOMException.SYNTAX_ERR,
74+
"hwb requires consitent separators (blank or comma).");
75+
}
76+
77+
if (LexicalUnitType.NONE != next.getLexicalUnitType()
78+
&& LexicalUnitType.PERCENTAGE != next.getLexicalUnitType()) {
79+
throw new DOMException(DOMException.SYNTAX_ERR, "Blackness part has to be percentage.");
80+
}
81+
blackness_ = new CSSValueImpl(next, true);
82+
next = next.getNextLexicalUnit();
83+
if (next == null) {
84+
return;
85+
}
86+
87+
if (next.getLexicalUnitType() != LexicalUnitType.OPERATOR_SLASH) {
88+
throw new DOMException(DOMException.SYNTAX_ERR, "hwb alpha value must be separated by '/'.");
89+
}
90+
next = next.getNextLexicalUnit();
91+
if (next == null) {
92+
throw new DOMException(DOMException.SYNTAX_ERR, "Missing alpha value.");
93+
}
94+
95+
if (LexicalUnitType.INTEGER != next.getLexicalUnitType()
96+
&& LexicalUnitType.REAL != next.getLexicalUnitType()
97+
&& LexicalUnitType.PERCENTAGE != next.getLexicalUnitType()) {
98+
throw new DOMException(DOMException.SYNTAX_ERR, "Alpha part has to be numeric or percentage.");
99+
}
100+
alpha_ = new CSSValueImpl(next, true);
101+
102+
next = next.getNextLexicalUnit();
103+
if (next != null) {
104+
throw new DOMException(DOMException.SYNTAX_ERR, "Too many parameters for hwb function.");
105+
}
106+
}
107+
108+
/**
109+
* @return the hue part.
110+
*/
111+
public CSSValueImpl getHue() {
112+
return hue_;
113+
}
114+
115+
/**
116+
* Sets the hue part to a new value.
117+
* @param hue the new CSSValueImpl
118+
*/
119+
public void setHue(final CSSValueImpl hue) {
120+
hue_ = hue;
121+
}
122+
123+
/**
124+
* @return the whiteness part.
125+
*/
126+
public CSSValueImpl getWhiteness() {
127+
return whiteness_;
128+
}
129+
130+
/**
131+
* Sets the whiteness part to a new value.
132+
* @param whiteness the new CSSValueImpl
133+
*/
134+
public void setWhiteness(final CSSValueImpl whiteness) {
135+
whiteness_ = whiteness;
136+
}
137+
138+
/**
139+
* @return the blackness part.
140+
*/
141+
public CSSValueImpl getBlackness() {
142+
return blackness_;
143+
}
144+
145+
/**
146+
* Sets the blackness part to a new value.
147+
* @param blackness the new CSSValueImpl
148+
*/
149+
public void setBlackness(final CSSValueImpl blackness) {
150+
blackness_ = blackness;
151+
}
152+
153+
/**
154+
* @return the alpha part.
155+
*/
156+
public CSSValueImpl getAlpha() {
157+
return alpha_;
158+
}
159+
160+
/**
161+
* Sets the alpha part to a new value.
162+
* @param alpha the new CSSValueImpl
163+
*/
164+
public void setAlpha(final CSSValueImpl alpha) {
165+
alpha_ = alpha;
166+
}
167+
168+
/**
169+
* {@inheritDoc}
170+
*/
171+
@Override
172+
public String toString() {
173+
final StringBuilder sb = new StringBuilder();
174+
175+
sb
176+
.append("hwb(")
177+
.append(hue_)
178+
.append(" ")
179+
.append(whiteness_)
180+
.append(" ")
181+
.append(blackness_);
182+
183+
if (null != alpha_) {
184+
sb.append(" / ").append(alpha_);
185+
}
186+
187+
sb.append(")");
188+
189+
return sb.toString();
190+
}
191+
}

src/main/java/org/htmlunit/cssparser/parser/AbstractCSSParser.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -799,6 +799,11 @@ protected LexicalUnit hslColorInternal(final LexicalUnit prev, final String func
799799
return LexicalUnitImpl.createHslColor(prev, funct, param);
800800
}
801801

802+
protected LexicalUnit hwbColorInternal(final LexicalUnit prev, final String funct,
803+
final LexicalUnit param) {
804+
return LexicalUnitImpl.createHwbColor(prev, funct, param);
805+
}
806+
802807
/**
803808
* Processes a hexadecimal color definition.
804809
*

src/main/java/org/htmlunit/cssparser/parser/LexicalUnit.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ enum LexicalUnitType {
9898
RGBCOLOR,
9999
/** HSLCOLOR. */
100100
HSLCOLOR,
101+
/** HWBCOLOR. */
102+
HWBCOLOR,
101103
/** NONE. */
102104
NONE,
103105

src/main/java/org/htmlunit/cssparser/parser/LexicalUnitImpl.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1071,14 +1071,24 @@ public static LexicalUnit createRgbColor(final LexicalUnit prev, final String fu
10711071

10721072
/**
10731073
* @param prev the previous LexicalUnit
1074-
* @param funct the name rgb or rgba
1074+
* @param funct the name hsl or hsla
10751075
* @param params the params
10761076
* @return lexical unit with type rgb color
10771077
*/
10781078
public static LexicalUnit createHslColor(final LexicalUnit prev, final String funct, final LexicalUnit params) {
10791079
return new LexicalUnitImpl(prev, LexicalUnitType.HSLCOLOR, funct, params);
10801080
}
10811081

1082+
/**
1083+
* @param prev the previous LexicalUnit
1084+
* @param funct the name hwb
1085+
* @param params the params
1086+
* @return lexical unit with type rgb color
1087+
*/
1088+
public static LexicalUnit createHwbColor(final LexicalUnit prev, final String funct, final LexicalUnit params) {
1089+
return new LexicalUnitImpl(prev, LexicalUnitType.HWBCOLOR, funct, params);
1090+
}
1091+
10821092
/**
10831093
* @param prev the previous LexicalUnit
10841094
* @return lexical unit with type rgb color

src/main/javacc/CSS3Parser.jj

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,7 @@ TOKEN_MGR_DECLS :
420420

421421
| < FUNCTION_RGB: "rgb" ("a")? <LROUND> >
422422
| < FUNCTION_HSL: "hsl" ("a")? <LROUND> >
423+
| < FUNCTION_HWB: "hwb" <LROUND> >
423424

424425
| < CUSTOM_PROPERTY_NAME: < MINUS > <MINUS > <NMSTART> ( <NMCHAR> )* >
425426

@@ -1596,6 +1597,7 @@ LexicalUnit term(LexicalUnit prev) :
15961597
| value = function(prev)
15971598
| value = rgbColor(prev)
15981599
| value = hslColor(prev)
1600+
| value = hwbColor(prev)
15991601
| value = calc(prev)
16001602
| value = var(prev)
16011603
)
@@ -2094,6 +2096,80 @@ LexicalUnit hslColor(LexicalUnit prev) :
20942096
}
20952097
}
20962098

2099+
2100+
// hwb()
2101+
//
2102+
LexicalUnit hwbColor(LexicalUnit prev) :
2103+
{
2104+
Token t;
2105+
char op = ' ';
2106+
LexicalUnit param = null;
2107+
LexicalUnit next = null;
2108+
String funct;
2109+
}
2110+
{
2111+
t = <FUNCTION_HWB> { funct = unescape(t.image.substring(0, t.image.length() - 1), false); }
2112+
( <S> )*
2113+
2114+
(
2115+
(op = unaryOperator() )?
2116+
(
2117+
<NONE> { param = LexicalUnitImpl.createNone(null); }
2118+
| param = number(null, op)
2119+
| t = <ANGLE_DEG> { param = LexicalUnitImpl.createDegree(null, doubleValue(op, t.image)); }
2120+
| t = <ANGLE_RAD> { param = LexicalUnitImpl.createRadian(null, doubleValue(op, t.image)); }
2121+
| t = <ANGLE_GRAD> { param = LexicalUnitImpl.createGradian(null, doubleValue(op, t.image)); }
2122+
| t = <ANGLE_TURN> { param = LexicalUnitImpl.createTurn(null, doubleValue(op, t.image)); }
2123+
)
2124+
)
2125+
{ op = ' '; next = param; }
2126+
2127+
( <S> )*
2128+
2129+
(
2130+
(op = unaryOperator() )?
2131+
(
2132+
<NONE> { next = LexicalUnitImpl.createNone(next); }
2133+
| next = percentage(next, op)
2134+
)
2135+
)
2136+
{ op = ' '; }
2137+
2138+
( <S> )*
2139+
2140+
(
2141+
(op = unaryOperator() )?
2142+
(
2143+
<NONE> { next = LexicalUnitImpl.createNone(next); }
2144+
| next = percentage(next, op)
2145+
)
2146+
)
2147+
{ op = ' '; }
2148+
2149+
( <S> )*
2150+
(
2151+
(
2152+
<SLASH> { next = LexicalUnitImpl.createSlash(next); }
2153+
( <S> )*
2154+
)?
2155+
2156+
(op = unaryOperator() )?
2157+
(
2158+
<NONE> { next = LexicalUnitImpl.createNone(next); }
2159+
| next = number(next, op)
2160+
| next = percentage(next, op)
2161+
)
2162+
2163+
( <S> )*
2164+
)?
2165+
2166+
<RROUND>
2167+
{
2168+
return hwbColorInternal(prev, funct, param);
2169+
}
2170+
}
2171+
2172+
20972173
//
20982174
// number()
20992175
//

0 commit comments

Comments
 (0)