@@ -273,173 +273,172 @@ Color CSSColorParser::parse(const std::string& css_str) {
273
273
return parse (css_str, valid);
274
274
}
275
275
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
+ }
278
280
279
- size_t pos = 0 ;
280
- size_t end = css_str. length () ;
281
+ matched = true ;
282
+ int read = 0 ;
281
283
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
+ }
286
290
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
+ }
290
297
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
+ };
296
307
}
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
+ };
303
317
}
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
+ };
345
337
}
346
-
347
- return {};
348
338
}
339
+ }
349
340
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) {
357
342
358
- if (!match ( ' ( ' , css_str, pos, end)) { return {}; }
359
- }
343
+ if (!match_prefix ( " rgb " , css_str, pos, end))
344
+ return ;
360
345
361
- if (rgb) {
362
- float values[4 ] = { 0 , 0 , 0 , 1 };
346
+ matched = true ;
363
347
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);
366
349
367
- int read = 0 ;
368
- values[i] = parse_float (css_str, pos, read);
350
+ if (!match (' (' , css_str, pos, end)) { return ; }
369
351
370
- if (read == 0 ) { return {}; }
371
- pos += read;
352
+ float values[4 ] = { 0 , 0 , 0 , 1 };
372
353
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 ; }
383
356
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);
391
359
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
+ }
393
382
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 ;
395
386
396
- for (int i = 0 ; i < (hasAlpha ? 4 : 3 ); i++) {
397
- if (i > 0 && !match (' ,' , css_str, pos, end)) { return {}; }
387
+ matched = true ;
398
388
399
- int read = 0 ;
400
- values[i] = parse_float (css_str, pos, read);
389
+ bool hasAlpha = match (' a' , css_str, pos, end);
401
390
402
- if (read == 0 ) { return {}; }
403
- pos += read;
391
+ if (!match (' (' , css_str, pos, end)) { return ; }
404
392
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 };
414
394
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 ; }
418
397
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);
423
400
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 ;
426
403
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) ;
434
411
}
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
+ }
435
434
435
+ void parseNamedColor (const std::string& css_str, size_t pos, size_t end, bool & valid, Color& color){
436
436
// TODO: ignore trailing whitespace?
437
-
438
437
size_t length = end - pos;
439
438
440
439
// Skip if longer than longest named color
441
440
if (length > 20 )
442
- return {} ;
441
+ return ;
443
442
444
443
// Convert to lowercase.
445
444
char cstr[32 ];
@@ -457,9 +456,40 @@ Color CSSColorParser::parse(const std::string& css_str, bool& valid) {
457
456
458
457
if (it != itEnd && std::strcmp (it->name , cstr) == 0 ) {
459
458
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;
461
490
}
462
491
463
- // No named color found
464
- return {};
492
+ parseNamedColor (css_str, pos, end, valid, color);
493
+
494
+ return color;
465
495
}
0 commit comments