Skip to content

Commit

Permalink
RCSS: support hsl and hsla colors
Browse files Browse the repository at this point in the history
  • Loading branch information
AmaiKinono committed Sep 21, 2024
1 parent 9d36a83 commit e610bfc
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 23 deletions.
108 changes: 85 additions & 23 deletions Source/Core/PropertyParserColour.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,34 @@
*/

#include "PropertyParserColour.h"
#include <algorithm>
#include <array>
#include <cmath>
#include <string.h>

namespace Rml {

// Helper function for hsl->rgb conversion.
static float HSL_f(float h, float s, float l, float n) {
float k = std::fmod((n + h * (1.0f / 30.0f)), 12.0f);
float a = s * std::min(l, 1.0f - l);
return l - a * std::max(-1.0f, std::min({k - 3.0f, 9.0f - k, 1.0f}));
}

// Ref: https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB_alternative
static void HSLAToRGBA(std::array<float, 4>& vals) {
if (vals[1] == 0.0f) {
vals[0] = vals[1] = vals[2];
}
else
{
auto [h, s, l, _] = vals;
vals[0] = HSL_f(h, s, l, 0.0f);
vals[1] = HSL_f(h, s, l, 8.0f);
vals[2] = HSL_f(h, s, l, 4.0f);
}
}

const PropertyParserColour::ColourMap PropertyParserColour::html_colours = {
{"black", Colourb(0, 0, 0)},
{"silver", Colourb(192, 192, 192)},
Expand Down Expand Up @@ -116,7 +140,8 @@ bool PropertyParserColour::ParseColour(Colourb& colour, const String& value)
colour[i] = (byte)(tens * 16 + ones);
}
}
else if (value.substr(0, 3) == "rgb")
else if (auto prefix = value.substr(0, 3);
prefix == "rgb" || prefix == "hsl")
{
StringList values;
values.reserve(4);
Expand All @@ -129,33 +154,70 @@ bool PropertyParserColour::ParseColour(Colourb& colour, const String& value)

StringUtilities::ExpandString(values, value.substr(begin_values, value.rfind(')') - begin_values), ',');

// Check if we're parsing an 'rgba' or 'rgb' colour declaration.
if (value.size() > 3 && value[3] == 'a')
if (prefix == "rgb")
{
if (values.size() != 4)
return false;
// Check if we're parsing an 'rgba' or 'rgb' colour declaration.
if (value.size() > 3 && value[3] == 'a')
{
if (values.size() != 4)
return false;
}
else
{
if (values.size() != 3)
return false;

values.push_back("255");
}

// Parse the RGBA values.
for (int i = 0; i < 4; ++i)
{
int component;

// We're parsing a percentage value.
if (values[i].size() > 0 && values[i][values[i].size() - 1] == '%')
component = int((float)atof(values[i].substr(0, values[i].size() - 1).c_str()) * (255.0f / 100.0f));
// We're parsing a 0 -> 255 integer value.
else
component = atoi(values[i].c_str());

colour[i] = (byte)(Math::Clamp(component, 0, 255));
}
}
else
{
if (values.size() != 3)
return false;

values.push_back("255");
}

// Parse the three RGB values.
for (int i = 0; i < 4; ++i)
{
int component;

// We're parsing a percentage value.
if (values[i].size() > 0 && values[i][values[i].size() - 1] == '%')
component = int((float)atof(values[i].substr(0, values[i].size() - 1).c_str()) * (255.0f / 100.0f));
// We're parsing a 0 -> 255 integer value.
// Check if we're parsing an 'hsla' or 'hsl' colour declaration.
if (value.size() > 3 && value[3] == 'a')
{
if (values.size() != 4)
return false;
}
else
component = atoi(values[i].c_str());

colour[i] = (byte)(Math::Clamp(component, 0, 255));
{
if (values.size() != 3)
return false;

values.push_back("1.0");
}

// Parse the HSLA values.
std::array<float, 4> vals;
// H is a number in degrees, A is a number between 0.0 and 1.0.
for (int i : {0, 3})
vals[i] = (float)atof(values[i].c_str());
// S and L are percentage values.
for (int i: {1, 2})
if (values[i].size() > 0 && values[i][values[i].size() - 1] == '%')
vals[i] = (float)atof(values[i].substr(0, values[i].size() - 1).c_str()) * (1.0f / 100.0f);
else
return false;

HSLAToRGBA(vals);
for (int i = 0; i < 4; ++i)
{
colour[i] = (byte)(Math::Clamp((int)(vals[i] * 255.0f), 0, 255));
}
}
}
else
Expand Down
9 changes: 9 additions & 0 deletions Tests/Source/UnitTests/Properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ TEST_CASE("Properties")
ColorStop{ColourbPremultiplied(0, 150, 0, 150), NumericValue{10.f, Unit::DP}},
},
},
{
"hsl(233, 0%, 50%), hsl(240, 100%, 50%) 50%, hsla(120, 100%, 50%, 0.5) 10dp",
"#7f7f7f, #0000ff 50%, #00ff007f 10dp",
{
ColorStop{ColourbPremultiplied(127, 127, 127), NumericValue{}},
ColorStop{ColourbPremultiplied(0, 0, 255), NumericValue{50.f, Unit::PERCENT}},
ColorStop{ColourbPremultiplied(0, 127, 0, 127), NumericValue{10.f, Unit::DP}},
},
},
{
"red 50px 20%, blue 10in",
"#ff0000 50px, #ff0000 20%, #0000ff 10in",
Expand Down

0 comments on commit e610bfc

Please sign in to comment.