Skip to content

Commit 1ee853c

Browse files
committed
split up parse()
1 parent caaa955 commit 1ee853c

File tree

1 file changed

+167
-137
lines changed

1 file changed

+167
-137
lines changed

csscolorparser.cpp

Lines changed: 167 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -273,173 +273,172 @@ Color CSSColorParser::parse(const std::string& css_str) {
273273
return parse(css_str, valid);
274274
}
275275

276-
Color CSSColorParser::parse(const std::string& css_str, bool& valid) {
277-
valid = false;
276+
void parseHexRGB(const std::string& css_str, size_t pos, size_t end, bool& matched, bool& valid, Color& color) {
277+
if (!match('#', css_str, pos, end)) {
278+
return;
279+
}
278280

279-
size_t pos = 0;
280-
size_t end = css_str.length();
281+
matched = true;
282+
int read = 0;
281283

282-
skip_whitespace(css_str, pos, end);
283-
if (pos == end) {
284-
return {};
285-
}
284+
//const char* str = css_str.c_str() + pos;
285+
int64_t iv = parse_int(css_str, pos, read, 16);
286+
if (iv < 0) {
287+
// Invalid: out of range.
288+
return;
289+
}
286290

287-
// #abc and #abc123 syntax.
288-
if (match('#', css_str, pos, end)) {
289-
int read = 0;
291+
pos += read;
292+
skip_whitespace(css_str, pos, end);
293+
if (pos != end) {
294+
// Invalid: contains trailing chars.
295+
return;
296+
}
290297

291-
//const char* str = css_str.c_str() + pos;
292-
int64_t iv = parse_int(css_str, pos, read, 16);
293-
if (iv < 0) {
294-
// Invalid: out of range.
295-
return {};
298+
if (read == 3) { // rgb
299+
if (iv <= 0xfff) {
300+
valid = true;
301+
color = {
302+
static_cast<uint8_t>(((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8)),
303+
static_cast<uint8_t>((iv & 0xf0) | ((iv & 0xf0) >> 4)),
304+
static_cast<uint8_t>((iv & 0xf) | ((iv & 0xf) << 4)),
305+
1
306+
};
296307
}
297-
298-
pos += read;
299-
skip_whitespace(css_str, pos, end);
300-
if (pos != end) {
301-
// Invalid: contains trailing chars.
302-
return {};
308+
} else if (read == 6) { // rrggbb
309+
if (iv <= 0xffffff) {
310+
valid = true;
311+
color = {
312+
static_cast<uint8_t>((iv & 0xff0000) >> 16),
313+
static_cast<uint8_t>((iv & 0xff00) >> 8),
314+
static_cast<uint8_t>(iv & 0xff),
315+
1
316+
};
303317
}
304-
305-
if (read == 3) { // rgb
306-
if (iv <= 0xfff) {
307-
valid = true;
308-
return {
309-
static_cast<uint8_t>(((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8)),
310-
static_cast<uint8_t>((iv & 0xf0) | ((iv & 0xf0) >> 4)),
311-
static_cast<uint8_t>((iv & 0xf) | ((iv & 0xf) << 4)),
312-
1
313-
};
314-
}
315-
} else if (read == 6) { // rrggbb
316-
if (iv <= 0xffffff) {
317-
valid = true;
318-
return {
319-
static_cast<uint8_t>((iv & 0xff0000) >> 16),
320-
static_cast<uint8_t>((iv & 0xff00) >> 8),
321-
static_cast<uint8_t>(iv & 0xff),
322-
1
323-
};
324-
}
325-
} else if (read == 4) { // argb
326-
if (iv <= 0xffff) {
327-
valid = true;
328-
return {
329-
static_cast<uint8_t>(((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8)),
330-
static_cast<uint8_t>((iv & 0xf0) | ((iv & 0xf0) >> 4)),
331-
static_cast<uint8_t>((iv & 0xf) | ((iv & 0xf) << 4)),
332-
static_cast<uint8_t>((iv & 0xf000) >> 12) / 255.0f,
333-
};
334-
}
335-
} else if (read == 8) { // aarrggbb
336-
if (iv <= 0xffffffff) {
337-
valid = true;
338-
return {
339-
static_cast<uint8_t>((iv & 0xff0000) >> 16),
340-
static_cast<uint8_t>((iv & 0xff00) >> 8),
341-
static_cast<uint8_t>(iv & 0xff),
342-
static_cast<uint8_t>((iv & 0xff000000) >> 24) / 255.0f,
343-
};
344-
}
318+
} else if (read == 4) { // argb
319+
if (iv <= 0xffff) {
320+
valid = true;
321+
color = {
322+
static_cast<uint8_t>(((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8)),
323+
static_cast<uint8_t>((iv & 0xf0) | ((iv & 0xf0) >> 4)),
324+
static_cast<uint8_t>((iv & 0xf) | ((iv & 0xf) << 4)),
325+
static_cast<uint8_t>((iv & 0xf000) >> 12) / 255.0f,
326+
};
327+
}
328+
} else if (read == 8) { // aarrggbb
329+
if (iv <= 0xffffffff) {
330+
valid = true;
331+
color = {
332+
static_cast<uint8_t>((iv & 0xff0000) >> 16),
333+
static_cast<uint8_t>((iv & 0xff00) >> 8),
334+
static_cast<uint8_t>(iv & 0xff),
335+
static_cast<uint8_t>((iv & 0xff000000) >> 24) / 255.0f,
336+
};
345337
}
346-
347-
return {};
348338
}
339+
}
349340

350-
bool rgb, hsl = false, hasAlpha = false;
351-
rgb = match_prefix("rgb", css_str, pos, end);
352-
if (!rgb) {
353-
hsl = match_prefix("hsl", css_str, pos, end);
354-
}
355-
if (rgb || hsl) {
356-
hasAlpha = match('a', css_str, pos, end);
341+
void parseRGB(const std::string& css_str, size_t pos, size_t end, bool& matched, bool& valid, Color& color) {
357342

358-
if (!match('(', css_str, pos, end)) { return {}; }
359-
}
343+
if (!match_prefix("rgb", css_str, pos, end))
344+
return;
360345

361-
if (rgb) {
362-
float values[4] = { 0, 0, 0, 1 };
346+
matched = true;
363347

364-
for (int i = 0; i < (hasAlpha ? 4 : 3); i++) {
365-
if (i > 0 && !match(',', css_str, pos, end)) { return {}; }
348+
bool hasAlpha = match('a', css_str, pos, end);
366349

367-
int read = 0;
368-
values[i] = parse_float(css_str, pos, read);
350+
if (!match('(', css_str, pos, end)) { return; }
369351

370-
if (read == 0) { return {}; }
371-
pos += read;
352+
float values[4] = { 0, 0, 0, 1 };
372353

373-
if (match('%', css_str, pos, end)) {
374-
if (i < 3) {
375-
values[i] = (values[i] / 100.0f * 255.0f);
376-
} else {
377-
values[i] = clamp_css_float(values[i] / 100.0f);
378-
}
379-
}
380-
skip_whitespace(css_str, pos, end);
381-
}
382-
if (!match(')', css_str, pos, end)) { return {}; }
354+
for (int i = 0; i < (hasAlpha ? 4 : 3); i++) {
355+
if (i > 0 && !match(',', css_str, pos, end)) { return; }
383356

384-
valid = true;
385-
return {
386-
clamp_css_byte(values[0]),
387-
clamp_css_byte(values[1]),
388-
clamp_css_byte(values[2]),
389-
values[3]
390-
};
357+
int read = 0;
358+
values[i] = parse_float(css_str, pos, read);
391359

392-
} else if (hsl) {
360+
if (read == 0) { return; }
361+
pos += read;
362+
363+
if (match('%', css_str, pos, end)) {
364+
if (i < 3) {
365+
values[i] = (values[i] / 100.0f * 255.0f);
366+
} else {
367+
values[i] = clamp_css_float(values[i] / 100.0f);
368+
}
369+
}
370+
skip_whitespace(css_str, pos, end);
371+
}
372+
if (!match(')', css_str, pos, end)) { return; }
373+
374+
valid = true;
375+
color = {
376+
clamp_css_byte(values[0]),
377+
clamp_css_byte(values[1]),
378+
clamp_css_byte(values[2]),
379+
values[3]
380+
};
381+
}
393382

394-
float values[4] = { 0, 0, 0, 1 };
383+
void parseHSL(const std::string& css_str, size_t pos, size_t end, bool& matched, bool& valid, Color& color) {
384+
if (!match_prefix("hsl", css_str, pos, end))
385+
return;
395386

396-
for (int i = 0; i < (hasAlpha ? 4 : 3); i++) {
397-
if (i > 0 && !match(',', css_str, pos, end)) { return {}; }
387+
matched = true;
398388

399-
int read = 0;
400-
values[i] = parse_float(css_str, pos, read);
389+
bool hasAlpha = match('a', css_str, pos, end);
401390

402-
if (read == 0) { return {}; }
403-
pos += read;
391+
if (!match('(', css_str, pos, end)) { return; }
404392

405-
if (match('%', css_str, pos, end)) {
406-
// NB: previously the % was ignored in this case - make it an error?
407-
if (i > 0) {
408-
values[i] = clamp_css_float(values[i] / 100.0f);
409-
}
410-
}
411-
skip_whitespace(css_str, pos, end);
412-
}
413-
if (!match(')', css_str, pos, end)) { return {}; }
393+
float values[4] = { 0, 0, 0, 1 };
414394

415-
float h = values[0] / 360.0f;
416-
while (h < 0.0f) h++;
417-
while (h > 1.0f) h--;
395+
for (int i = 0; i < (hasAlpha ? 4 : 3); i++) {
396+
if (i > 0 && !match(',', css_str, pos, end)) { return; }
418397

419-
// NOTE(deanm): According to the CSS spec s/l should only be
420-
// percentages, but we don't bother and let float or percentage.
421-
float s = values[1];
422-
float l = values[2];
398+
int read = 0;
399+
values[i] = parse_float(css_str, pos, read);
423400

424-
float m2 = l <= 0.5f ? l * (s + 1.0f) : l + s - l * s;
425-
float m1 = l * 2.0f - m2;
401+
if (read == 0) { return; }
402+
pos += read;
426403

427-
valid = true;
428-
return {
429-
clamp_css_byte(css_hue_to_rgb(m1, m2, h + 1.0f / 3.0f) * 255.0f),
430-
clamp_css_byte(css_hue_to_rgb(m1, m2, h) * 255.0f),
431-
clamp_css_byte(css_hue_to_rgb(m1, m2, h - 1.0f / 3.0f) * 255.0f),
432-
values[3]
433-
};
404+
if (match('%', css_str, pos, end)) {
405+
// NB: previously the % was ignored in this case - make it an error?
406+
if (i > 0) {
407+
values[i] = clamp_css_float(values[i] / 100.0f);
408+
}
409+
}
410+
skip_whitespace(css_str, pos, end);
434411
}
412+
if (!match(')', css_str, pos, end)) { return; }
413+
414+
float h = values[0] / 360.0f;
415+
while (h < 0.0f) h++;
416+
while (h > 1.0f) h--;
417+
418+
// NOTE(deanm): According to the CSS spec s/l should only be
419+
// percentages, but we don't bother and let float or percentage.
420+
float s = values[1];
421+
float l = values[2];
422+
423+
float m2 = l <= 0.5f ? l * (s + 1.0f) : l + s - l * s;
424+
float m1 = l * 2.0f - m2;
425+
426+
valid = true;
427+
color = {
428+
clamp_css_byte(css_hue_to_rgb(m1, m2, h + 1.0f / 3.0f) * 255.0f),
429+
clamp_css_byte(css_hue_to_rgb(m1, m2, h) * 255.0f),
430+
clamp_css_byte(css_hue_to_rgb(m1, m2, h - 1.0f / 3.0f) * 255.0f),
431+
values[3]
432+
};
433+
}
435434

435+
void parseNamedColor(const std::string& css_str, size_t pos, size_t end, bool& valid, Color& color){
436436
// TODO: ignore trailing whitespace?
437-
438437
size_t length = end - pos;
439438

440439
// Skip if longer than longest named color
441440
if (length > 20)
442-
return {};
441+
return;
443442

444443
// Convert to lowercase.
445444
char cstr[32];
@@ -457,9 +456,40 @@ Color CSSColorParser::parse(const std::string& css_str, bool& valid) {
457456

458457
if (it != itEnd && std::strcmp(it->name, cstr) == 0) {
459458
valid = true;
460-
return it->color;
459+
color = it->color;
460+
}
461+
}
462+
463+
464+
Color CSSColorParser::parse(const std::string& css_str, bool& valid) {
465+
valid = false;
466+
467+
size_t pos = 0;
468+
size_t end = css_str.length();
469+
bool matched = false;
470+
Color color;
471+
472+
skip_whitespace(css_str, pos, end);
473+
if (pos == end) {
474+
return {};
475+
}
476+
477+
parseHexRGB(css_str, pos, end, matched, valid, color);
478+
if (matched) {
479+
return color;
480+
}
481+
482+
parseRGB(css_str, pos, end, matched, valid, color);
483+
if (matched) {
484+
return color;
485+
}
486+
487+
parseHSL(css_str, pos, end, matched, valid, color);
488+
if (matched) {
489+
return color;
461490
}
462491

463-
// No named color found
464-
return {};
492+
parseNamedColor(css_str, pos, end, valid, color);
493+
494+
return color;
465495
}

0 commit comments

Comments
 (0)