@@ -203,35 +203,20 @@ float clamp_css_float(T f) { // Clamp to float 0.0 .. 1.0.
203
203
return f < 0 ? 0 : f > 1 ? 1 : f;
204
204
}
205
205
206
- float parse_float (const std::string& str) {
207
- return strtof (str.c_str (), nullptr );
208
- }
209
-
210
- int64_t parse_int (const char * str, int & read, uint8_t base) {
211
- char *pos = nullptr ;
212
- int64_t val = strtoll (str, &pos, base);
213
- read = pos - str;
206
+ int64_t parse_int (const std::string& str, int pos, int & read, uint8_t base) {
207
+ const char *s = str.c_str () + pos;
208
+ char *end = nullptr ;
209
+ int64_t val = strtoll (s, &end, base);
210
+ read = end - s;
214
211
return val;
215
212
}
216
213
217
- int64_t parse_int (const std::string& str) {
218
- return strtoll (str.c_str (), nullptr , 10 );
219
- }
220
-
221
- uint8_t parse_css_int (const std::string& str) { // int or percentage.
222
- if (str.length () && str.back () == ' %' ) {
223
- return clamp_css_byte (parse_float (str) / 100 .0f * 255 .0f );
224
- } else {
225
- return clamp_css_byte (parse_int (str));
226
- }
227
- }
228
-
229
- float parse_css_float (const std::string& str) { // float or percentage.
230
- if (str.length () && str.back () == ' %' ) {
231
- return clamp_css_float (parse_float (str) / 100 .0f );
232
- } else {
233
- return clamp_css_float (parse_float (str));
234
- }
214
+ float parse_float (const std::string& str, int pos, int & read) {
215
+ const char *s = str.c_str () + pos;
216
+ char *end = nullptr ;
217
+ float val = strtof (s, &end);
218
+ read = end - s;
219
+ return val;
235
220
}
236
221
237
222
float css_hue_to_rgb (float m1, float m2, float h) {
@@ -254,7 +239,7 @@ float css_hue_to_rgb(float m1, float m2, float h) {
254
239
}
255
240
256
241
bool match (char c, const std::string& text, size_t & pos, size_t end) {
257
- if (end < pos + 1 )
242
+ if (pos >= end )
258
243
return false ;
259
244
260
245
if (c != tolower (text[pos]))
@@ -266,7 +251,7 @@ bool match(char c, const std::string& text, size_t& pos, size_t end) {
266
251
267
252
bool match_prefix (const std::string& prefix, const std::string& text, size_t & pos, size_t end) {
268
253
size_t length = prefix.size ();
269
- if (end < length + pos)
254
+ if (length + pos > end )
270
255
return false ;
271
256
272
257
for (size_t i = 0 ; i < length; ++i)
@@ -283,18 +268,6 @@ void skip_whitespace(const std::string& text, size_t& pos, size_t end){
283
268
}
284
269
}
285
270
286
- std::vector<std::string> split (const std::string& s, char delim, size_t position) {
287
- std::vector<std::string> elems;
288
- std::stringstream ss (s);
289
- ss.seekg (position);
290
-
291
- std::string item;
292
- while (std::getline (ss, item, delim)) {
293
- elems.push_back (item);
294
- }
295
- return elems;
296
- }
297
-
298
271
Color CSSColorParser::parse (const std::string& css_str) {
299
272
bool valid;
300
273
return parse (css_str, valid);
@@ -315,8 +288,8 @@ Color CSSColorParser::parse(const std::string& css_str, bool& valid) {
315
288
if (match (' #' , css_str, pos, end)) {
316
289
int read = 0 ;
317
290
318
- const char * str = css_str.c_str () + pos;
319
- int64_t iv = parse_int (str , read, 16 );
291
+ // const char* str = css_str.c_str() + pos;
292
+ int64_t iv = parse_int (css_str, pos , read, 16 );
320
293
if (iv < 0 ) {
321
294
// Invalid: out of range.
322
295
return {};
@@ -374,78 +347,94 @@ Color CSSColorParser::parse(const std::string& css_str, bool& valid) {
374
347
return {};
375
348
}
376
349
377
- bool rgb, hsl = false ;
350
+ bool rgb, hsl = false , hasAlpha = false ;
378
351
rgb = match_prefix (" rgb" , css_str, pos, end);
379
352
if (!rgb) {
380
353
hsl = match_prefix (" hsl" , css_str, pos, end);
381
354
}
382
355
if (rgb || hsl) {
356
+ hasAlpha = match (' a' , css_str, pos, end);
383
357
384
- bool hasAlpha = match (' a' , css_str, pos, end);
358
+ if (!match (' (' , css_str, pos, end)) { return {}; }
359
+ }
385
360
386
- if (!match (' (' , css_str, pos, end)) {
387
- return {};
388
- }
361
+ if (rgb) {
362
+ float values[4 ] = { 0 , 0 , 0 , 1 };
389
363
390
- // TODO: validation
391
- const std::vector<std::string> params = split (css_str, ' ,' , pos);
364
+ for ( int i = 0 ; i < (hasAlpha ? 4 : 3 ); i++) {
365
+ if (i > 0 && ! match ( ' ,' , css_str, pos, end)) { return {}; }
392
366
393
- float alpha = 1 .0f ;
367
+ int read = 0 ;
368
+ values[i] = parse_float (css_str, pos, read);
394
369
395
- if (rgb) {
396
- if (hasAlpha) {
397
- if (params.size () != 4 ) {
398
- return {};
399
- }
400
- alpha = parse_css_float (params.back ());
401
- } else {
402
- if (params.size () != 3 ) {
403
- return {};
370
+ if (read == 0 ) { return {}; }
371
+ pos += read;
372
+
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 );
404
378
}
405
379
}
380
+ skip_whitespace (css_str, pos, end);
381
+ }
382
+ if (!match (' )' , css_str, pos, end)) { return {}; }
406
383
407
- valid = true ;
408
- return {
409
- parse_css_int (params[0 ]),
410
- parse_css_int (params[1 ]),
411
- parse_css_int (params[2 ]),
412
- alpha
413
- };
414
-
415
- } else if (hsl) {
416
- if (hasAlpha) {
417
- if (params.size () != 4 ) {
418
- return {};
419
- }
420
- alpha = parse_css_float (params.back ());
421
- } else {
422
- if (params.size () != 3 ) {
423
- return {};
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
+ };
391
+
392
+ } else if (hsl) {
393
+
394
+ float values[4 ] = { 0 , 0 , 0 , 1 };
395
+
396
+ for (int i = 0 ; i < (hasAlpha ? 4 : 3 ); i++) {
397
+ if (i > 0 && !match (' ,' , css_str, pos, end)) { return {}; }
398
+
399
+ int read = 0 ;
400
+ values[i] = parse_float (css_str, pos, read);
401
+
402
+ if (read == 0 ) { return {}; }
403
+ pos += read;
404
+
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 );
424
409
}
425
410
}
426
-
427
- float h = parse_float (params[0 ].c_str ()) / 360 .0f ;
428
- while (h < 0 .0f ) h++;
429
- while (h > 1 .0f ) h--;
430
-
431
- // NOTE(deanm): According to the CSS spec s/l should only be
432
- // percentages, but we don't bother and let float or percentage.
433
- float s = parse_css_float (params[1 ]);
434
- float l = parse_css_float (params[2 ]);
435
-
436
- float m2 = l <= 0 .5f ? l * (s + 1 .0f ) : l + s - l * s;
437
- float m1 = l * 2 .0f - m2;
438
-
439
- valid = true ;
440
- return {
441
- clamp_css_byte (css_hue_to_rgb (m1, m2, h + 1 .0f / 3 .0f ) * 255 .0f ),
442
- clamp_css_byte (css_hue_to_rgb (m1, m2, h) * 255 .0f ),
443
- clamp_css_byte (css_hue_to_rgb (m1, m2, h - 1 .0f / 3 .0f ) * 255 .0f ),
444
- alpha
445
- };
411
+ skip_whitespace (css_str, pos, end);
446
412
}
413
+ if (!match (' )' , css_str, pos, end)) { return {}; }
414
+
415
+ float h = values[0 ] / 360 .0f ;
416
+ while (h < 0 .0f ) h++;
417
+ while (h > 1 .0f ) h--;
418
+
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 ];
423
+
424
+ float m2 = l <= 0 .5f ? l * (s + 1 .0f ) : l + s - l * s;
425
+ float m1 = l * 2 .0f - m2;
426
+
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
+ };
447
434
}
448
435
436
+ // TODO: ignore trailing whitespace?
437
+
449
438
size_t length = end - pos;
450
439
451
440
// Skip if longer than longest named color
0 commit comments