Skip to content

Commit 649beb7

Browse files
committed
Added implementation of new color functions #131
1 parent 4ceb46c commit 649beb7

File tree

3 files changed

+392
-19
lines changed

3 files changed

+392
-19
lines changed

src/AngleSharp.Css.Tests/Functions/CssColorFunction.cs

+132
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,138 @@ public void ParseRgbWithSpacesAndNoneL4_Issue131()
5252
var color = s.GetColor();
5353
Assert.AreEqual("rgba(255, 0, 128, 0.35)", color);
5454
}
55+
56+
[Test]
57+
public void ParseOklabToRgb_First()
58+
{
59+
var html = @"<p style='color: oklab(40.1% 0.1143 0.045)'>Text</p>";
60+
var dom = ParseDocument(html);
61+
var p = dom.QuerySelector("p");
62+
var s = p.GetStyle();
63+
var color = s.GetColor();
64+
Assert.AreEqual("rgba(125, 35, 40, 1)", color);
65+
}
66+
67+
[Test]
68+
public void ParseOklabToRgb_Second()
69+
{
70+
var html = @"<p style='color: oklab(59.69% 0.1007 0.1191);'>Text</p>";
71+
var dom = ParseDocument(html);
72+
var p = dom.QuerySelector("p");
73+
var s = p.GetStyle();
74+
var color = s.GetColor();
75+
Assert.AreEqual("rgba(198, 93, 7, 1)", color);
76+
}
77+
78+
[Test]
79+
public void ParseOklabToRgb_Alpha()
80+
{
81+
var html = @"<p style='color: oklab(59.69% 0.1007 0.1191 / 0.5);'>Text</p>";
82+
var dom = ParseDocument(html);
83+
var p = dom.QuerySelector("p");
84+
var s = p.GetStyle();
85+
var color = s.GetColor();
86+
Assert.AreEqual("rgba(198, 93, 7, 0.5)", color);
87+
}
88+
89+
[Test]
90+
public void ParseOklchToRgb_First()
91+
{
92+
var html = @"<p style='color: oklch(40.1% 0.123 21.57)'>Text</p>";
93+
var dom = ParseDocument(html);
94+
var p = dom.QuerySelector("p");
95+
var s = p.GetStyle();
96+
var color = s.GetColor();
97+
Assert.AreEqual("rgba(125, 35, 40, 1)", color);
98+
}
99+
100+
[Test]
101+
public void ParseOklchToRgb_Second()
102+
{
103+
var html = @"<p style='color: oklch(59.69% 0.156 49.77)'>Text</p>";
104+
var dom = ParseDocument(html);
105+
var p = dom.QuerySelector("p");
106+
var s = p.GetStyle();
107+
var color = s.GetColor();
108+
Assert.AreEqual("rgba(198, 93, 7, 1)", color);
109+
}
110+
111+
[Test]
112+
public void ParseOklchToRgb_Alpha()
113+
{
114+
var html = @"<p style='color: oklch(59.69% 0.156 49.77 / .5)'>Text</p>";
115+
var dom = ParseDocument(html);
116+
var p = dom.QuerySelector("p");
117+
var s = p.GetStyle();
118+
var color = s.GetColor();
119+
Assert.AreEqual("rgba(198, 93, 7, 0.5)", color);
120+
}
121+
122+
[Test]
123+
public void ParseLabToRgb_First()
124+
{
125+
var html = @"<p style='color: lab(29.2345% 39.3825 20.0664);'>Text</p>";
126+
var dom = ParseDocument(html);
127+
var p = dom.QuerySelector("p");
128+
var s = p.GetStyle();
129+
var color = s.GetColor();
130+
Assert.AreEqual("rgba(125, 35, 40, 1)", color);
131+
}
132+
133+
[Test]
134+
public void ParseLabToRgb_Second()
135+
{
136+
var html = @"<p style='color: lab(52.2345% 40.1645 59.9971);'>Text</p>";
137+
var dom = ParseDocument(html);
138+
var p = dom.QuerySelector("p");
139+
var s = p.GetStyle();
140+
var color = s.GetColor();
141+
Assert.AreEqual("rgba(198, 93, 6, 1)", color);
142+
}
143+
144+
[Test]
145+
public void ParseLabToRgb_Alpha()
146+
{
147+
var html = @"<p style='color: lab(52.2345% 40.1645 59.9971 / .5);'>Text</p>";
148+
var dom = ParseDocument(html);
149+
var p = dom.QuerySelector("p");
150+
var s = p.GetStyle();
151+
var color = s.GetColor();
152+
Assert.AreEqual("rgba(198, 93, 6, 0.5)", color);
153+
}
154+
155+
[Test]
156+
public void ParseLchToRgb_First()
157+
{
158+
var html = @"<p style='color: lch(29.2345% 44.2 27);'>Text</p>";
159+
var dom = ParseDocument(html);
160+
var p = dom.QuerySelector("p");
161+
var s = p.GetStyle();
162+
var color = s.GetColor();
163+
Assert.AreEqual("rgba(125, 35, 40, 1)", color);
164+
}
165+
166+
[Test]
167+
public void ParseLchToRgb_Second()
168+
{
169+
var html = @"<p style='color: lch(52.2345% 72.2 56.2)'>Text</p>";
170+
var dom = ParseDocument(html);
171+
var p = dom.QuerySelector("p");
172+
var s = p.GetStyle();
173+
var color = s.GetColor();
174+
Assert.AreEqual("rgba(198, 93, 6, 1)", color);
175+
}
176+
177+
[Test]
178+
public void ParseLchToRgb_Alpha()
179+
{
180+
var html = @"<p style='color: lch(52.2345% 72.2 56.2 / .5)'>Text</p>";
181+
var dom = ParseDocument(html);
182+
var p = dom.QuerySelector("p");
183+
var s = p.GetStyle();
184+
var color = s.GetColor();
185+
Assert.AreEqual("rgba(198, 93, 6, 0.5)", color);
186+
}
55187
}
56188
}
57189

src/AngleSharp.Css/Parser/Micro/ColorParser.cs

+145-19
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
namespace AngleSharp.Css.Parser
22
{
33
using AngleSharp.Css.Values;
4-
using AngleSharp.Io;
54
using AngleSharp.Text;
65
using System;
76
using System.Collections.Generic;
@@ -227,30 +226,130 @@ static class ColorParser
227226

228227
private static Color? ParseLab(StringSource source)
229228
{
230-
// lab(50% 40 59.5)
231-
// lab(50 % 40 59.5 / 0.5)
229+
var l = ParseLabComponent(source);
230+
source.SkipSpacesAndComments();
231+
var a = ParseLabComponent(source);
232+
source.SkipSpacesAndComments();
233+
var b = ParseLabComponent(source);
234+
source.SkipSpacesAndComments();
235+
var c = source.Current;
236+
var alpha = new Nullable<Double>(1.0);
237+
238+
if (l != null && a != null && b != null)
239+
{
240+
source.SkipCurrentAndSpaces();
241+
242+
if (c == Symbols.Solidus)
243+
{
244+
alpha = ParseAlpha(source);
245+
source.SkipSpacesAndComments();
246+
c = source.Current;
247+
source.SkipCurrentAndSpaces();
248+
}
249+
250+
if (c == Symbols.RoundBracketClose)
251+
{
252+
return Color.FromLab(l.Value, a.Value, b.Value, alpha.Value);
253+
}
254+
}
255+
232256
return null;
233257
}
234258

235259
private static Color? ParseLch(StringSource source)
236260
{
237-
// lch(52.2% 72.2 50)
238-
// lch(52.2 % 72.2 50 / 0.5)
261+
var l = ParseLabComponent(source);
262+
source.SkipSpacesAndComments();
263+
var c = ParseLabComponent(source);
264+
source.SkipSpacesAndComments();
265+
var h = ParseAngle(source);
266+
source.SkipSpacesAndComments();
267+
var chr = source.Current;
268+
var a = new Nullable<Double>(1.0);
269+
270+
if (l != null && c != null && h != null)
271+
{
272+
source.SkipCurrentAndSpaces();
273+
274+
if (chr == Symbols.Solidus)
275+
{
276+
a = ParseAlpha(source);
277+
source.SkipSpacesAndComments();
278+
chr = source.Current;
279+
source.SkipCurrentAndSpaces();
280+
}
281+
282+
if (chr == Symbols.RoundBracketClose)
283+
{
284+
return Color.FromLch(l.Value, c.Value, h.Value, a.Value);
285+
}
286+
}
287+
239288
return null;
240289
}
241290

242291

243292
private static Color? ParseOklab(StringSource source)
244293
{
245-
// oklab(59% 0.1 0.1)
246-
// oklab(59 % 0.1 0.1 / 0.5)
294+
var l = ParseLabComponent(source);
295+
source.SkipSpacesAndComments();
296+
var a = ParseLabComponent(source);
297+
source.SkipSpacesAndComments();
298+
var b = ParseLabComponent(source);
299+
source.SkipSpacesAndComments();
300+
var c = source.Current;
301+
var alpha = new Nullable<Double>(1.0);
302+
303+
if (l != null && a != null && b != null)
304+
{
305+
source.SkipCurrentAndSpaces();
306+
307+
if (c == Symbols.Solidus)
308+
{
309+
alpha = ParseAlpha(source);
310+
source.SkipSpacesAndComments();
311+
c = source.Current;
312+
source.SkipCurrentAndSpaces();
313+
}
314+
315+
if (c == Symbols.RoundBracketClose)
316+
{
317+
return Color.FromOklab(l.Value, a.Value, b.Value, alpha.Value);
318+
}
319+
}
320+
247321
return null;
248322
}
249323

250324
private static Color? ParseOklch(StringSource source)
251325
{
252-
// oklch(60% 0.15 50)
253-
// oklch(60 % 0.15 50 / 0.5)
326+
var l = ParseLabComponent(source);
327+
source.SkipSpacesAndComments();
328+
var c = ParseLabComponent(source);
329+
source.SkipSpacesAndComments();
330+
var h = ParseAngle(source);
331+
source.SkipSpacesAndComments();
332+
var chr = source.Current;
333+
var a = new Nullable<Double>(1.0);
334+
335+
if (l != null && c != null && h != null)
336+
{
337+
source.SkipCurrentAndSpaces();
338+
339+
if (chr == Symbols.Solidus)
340+
{
341+
a = ParseAlpha(source);
342+
source.SkipSpacesAndComments();
343+
chr = source.Current;
344+
source.SkipCurrentAndSpaces();
345+
}
346+
347+
if (chr == Symbols.RoundBracketClose)
348+
{
349+
return Color.FromOklch(l.Value, c.Value, h.Value, a.Value);
350+
}
351+
}
352+
254353
return null;
255354
}
256355

@@ -285,6 +384,31 @@ static class ColorParser
285384
return null;
286385
}
287386

387+
private static Double? ParseLabComponent(StringSource source)
388+
{
389+
var pos = source.Index;
390+
var unit = source.ParseUnit();
391+
392+
if (unit == null)
393+
{
394+
source.BackTo(pos);
395+
396+
if (source.IsIdentifier(CssKeywords.None))
397+
{
398+
return 0;
399+
}
400+
401+
return null;
402+
}
403+
404+
if ((unit.Dimension == String.Empty || unit.Dimension == "%") && Double.TryParse(unit.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var value))
405+
{
406+
return value;
407+
}
408+
409+
return null;
410+
}
411+
288412
private static Byte? ParseRgbOrNoneComponent(StringSource source)
289413
{
290414
var pos = source.Index;
@@ -309,17 +433,19 @@ static class ColorParser
309433
{
310434
var unit = source.ParseUnit();
311435

312-
if (unit != null &&
313-
Int32.TryParse(unit.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value))
436+
if (unit == null)
314437
{
315-
if (unit.Dimension == "%")
316-
{
317-
return (Byte)Math.Round((255.0 * value) / 100.0);
318-
}
319-
else if (unit.Dimension == String.Empty)
320-
{
321-
return (Byte)Math.Max(Math.Min(value, 255f), 0f);
322-
}
438+
return null;
439+
}
440+
441+
if (unit.Dimension == String.Empty && Int32.TryParse(unit.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var num))
442+
{
443+
return (Byte)Math.Max(Math.Min(num, 255f), 0f);
444+
}
445+
446+
if (unit.Dimension == "%" && Double.TryParse(unit.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var val))
447+
{
448+
return (Byte)Math.Round((255.0 * val) / 100.0);
323449
}
324450

325451
return null;

0 commit comments

Comments
 (0)