Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ project adheres to [Semantic Versioning](http://semver.org/).
* Fix error message HTTP response status code in image src setter
* `roundRect()` shape incorrect when radii were large relative to rectangle size (#2400)
* Reject loadImage when src is null or invalid (#2304)
* Add support for percentage in rgb and rgba parsing. Fix bug with parsing for alpha and percentages.

3.2.0
==================
Expand Down
65 changes: 42 additions & 23 deletions src/color.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#include <limits>
#include <map>
#include <string>

// Compatibility with Visual Studio versions prior to VS2015
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
Expand Down Expand Up @@ -153,14 +152,45 @@ wrap_float(T value, T limit) {
// return (value % limit + limit) % limit;
// }

/*
* Parse and clip a percentage value. Returns a float in the range [0, 1].
*/


static bool
check_percentage(const char* str) {
while (*str && *str != '%' && *str != ',' && *str != ' ' && *str != '/') ++str;
return *str == '%';
}

static bool
parse_clipped_percentage(const char** pStr, float *pFraction) {
float percentage;
bool result = parse_css_number(pStr,&percentage);
const char*& str = *pStr;
if (result) {
if (*str == '%') {
++str;
*pFraction = clip(percentage, 0.0f, 100.0f) / 100.0f;
return result;
}
}
return false;
}

/*
* Parse color channel value
*/

static bool
parse_rgb_channel(const char** pStr, uint8_t *pChannel) {
float f_channel;
if (parse_css_number(pStr, &f_channel)) {
bool percentage = check_percentage(*pStr);
if(percentage && parse_clipped_percentage(pStr, &f_channel)) {
int channel = (int) ceil(255 * f_channel);
*pChannel = channel;
return true;
} else if (parse_css_number(pStr, &f_channel)) {
int channel = (int) ceil(f_channel);
*pChannel = clip(channel, 0, 255);
return true;
Expand All @@ -182,24 +212,6 @@ parse_degrees(const char** pStr, float *pDegrees) {
return false;
}

/*
* Parse and clip a percentage value. Returns a float in the range [0, 1].
*/

static bool
parse_clipped_percentage(const char** pStr, float *pFraction) {
float percentage;
bool result = parse_css_number(pStr,&percentage);
const char*& str = *pStr;
if (result) {
if (*str == '%') {
++str;
*pFraction = clip(percentage, 0.0f, 100.0f) / 100.0f;
return result;
}
}
return false;
}

/*
* Macros to help with parsing inside rgba_from_*_string
Expand Down Expand Up @@ -231,13 +243,15 @@ parse_clipped_percentage(const char** pStr, float *pFraction) {
#define ALPHA(NAME) \
if (*str >= '1' && *str <= '9') { \
NAME = 0; \
float n = .1f; \
while(*str >='0' && *str <= '9') { \
NAME += (*str - '0') * n; \
NAME = NAME * 10 + (*str - '0'); \
str++; \
} \
while(*str == ' ')str++; \
if(*str != '%') { \
if(*str == '%') { \
NAME *= 0.01f; \
++str; \
} else { \
NAME = 1; \
} \
} else { \
Expand All @@ -253,6 +267,11 @@ parse_clipped_percentage(const char** pStr, float *pFraction) {
NAME += (*str++ - '0') * n; \
n *= .1f; \
} \
while(*str == ' ')str++; \
if(*str == '%') { \
NAME *= 0.01f; \
++str; \
} \
} \
} \
do {} while (0) // require trailing semicolon
Expand Down
21 changes: 21 additions & 0 deletions test/canvas.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,27 @@ describe('Canvas', function () {

ctx.fillStyle = 'rgb( 255, 300.09, 90, 40%)'
assert.equal('rgba(255, 255, 90, 0.40)', ctx.fillStyle)

ctx.fillStyle = 'rgb( 255, 100%, 50%, 60%)'
assert.equal('rgba(255, 255, 128, 0.60)', ctx.fillStyle)

ctx.fillStyle = 'rgb( 255, 20%, 90, 70%)'
assert.equal('rgba(255, 51, 90, 0.70)', ctx.fillStyle)

ctx.fillStyle = 'rgb( 100%, 300%, 90, 50%)'
assert.equal('rgba(255, 255, 90, 0.50)', ctx.fillStyle)

ctx.fillStyle = 'rgb( 100%, 300.09, 90%, 0)'
assert.equal('rgba(255, 255, 230, 0.00)', ctx.fillStyle)

ctx.fillStyle = 'rgb( 100%, 99%, 80% 50%)'
assert.equal('rgba(255, 253, 204, 0.50)', ctx.fillStyle)

ctx.fillStyle = 'rgb( 100%, 99.99%, 40% / 50%)'
assert.equal('rgba(255, 255, 102, 0.50)', ctx.fillStyle)

ctx.fillStyle = 'rgb( 100%, 33.33%, 66.66%, 2%)'
assert.equal('rgba(255, 85, 170, 0.02)', ctx.fillStyle)
// hsl / hsla tests

ctx.fillStyle = 'hsl(0, 0%, 0%)'
Expand Down
Loading