From e67717cae61c3eecd27364828a0e99667fd3d118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 12 Mar 2014 12:35:37 +0100 Subject: [PATCH 01/12] c++ port --- .gitignore | 2 + Makefile | 19 +++ csscolorparser.cpp | 286 +++++++++++++++++++++++++++++++++++++++++++++ csscolorparser.hpp | 44 +++++++ main.cpp | 22 ++++ 5 files changed, 373 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 csscolorparser.cpp create mode 100644 csscolorparser.hpp create mode 100644 main.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fa2caeb --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.o +/color \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2aef76e --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +CXXFLAGS = -std=c++11 -Wall -Wextra -Wno-unused-parameter + +BIN = color +SRCS = main.cpp +SRCS += csscolorparser.cpp +OBJS = $(patsubst %.cpp,%.o,$(SRCS)) + +build: $(BIN) + +$(BIN): $(OBJS) + $(CXX) $(CXXFLAGS) -o $@ $^ + +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $^ + +clean: + rm -rf *.o $(BIN) + +.PHONY: clean diff --git a/csscolorparser.cpp b/csscolorparser.cpp new file mode 100644 index 0000000..10eac09 --- /dev/null +++ b/csscolorparser.cpp @@ -0,0 +1,286 @@ +// (c) Dean McNamee , 2012. +// C++ port by Konstantin Käfer , 2014. +// +// https://github.com/deanm/css-color-parser-js +// https://github.com/kkaefer/css-color-parser-cpp +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#include "csscolorparser.hpp" + +#include +#include +#include +#include +#include + +using namespace CSSColorParser; + +// http://www.w3.org/TR/css3-color/ +const std::map kCSSColorTable = { + { "transparent", { 0, 0, 0, 0 } }, { "aliceblue", { 240, 248, 255, 1 } }, + { "antiquewhite", { 250, 235, 215, 1 } }, { "aqua", { 0, 255, 255, 1 } }, + { "aquamarine", { 127, 255, 212, 1 } }, { "azure", { 240, 255, 255, 1 } }, + { "beige", { 245, 245, 220, 1 } }, { "bisque", { 255, 228, 196, 1 } }, + { "black", { 0, 0, 0, 1 } }, { "blanchedalmond", { 255, 235, 205, 1 } }, + { "blue", { 0, 0, 255, 1 } }, { "blueviolet", { 138, 43, 226, 1 } }, + { "brown", { 165, 42, 42, 1 } }, { "burlywood", { 222, 184, 135, 1 } }, + { "cadetblue", { 95, 158, 160, 1 } }, { "chartreuse", { 127, 255, 0, 1 } }, + { "chocolate", { 210, 105, 30, 1 } }, { "coral", { 255, 127, 80, 1 } }, + { "cornflowerblue", { 100, 149, 237, 1 } }, { "cornsilk", { 255, 248, 220, 1 } }, + { "crimson", { 220, 20, 60, 1 } }, { "cyan", { 0, 255, 255, 1 } }, + { "darkblue", { 0, 0, 139, 1 } }, { "darkcyan", { 0, 139, 139, 1 } }, + { "darkgoldenrod", { 184, 134, 11, 1 } }, { "darkgray", { 169, 169, 169, 1 } }, + { "darkgreen", { 0, 100, 0, 1 } }, { "darkgrey", { 169, 169, 169, 1 } }, + { "darkkhaki", { 189, 183, 107, 1 } }, { "darkmagenta", { 139, 0, 139, 1 } }, + { "darkolivegreen", { 85, 107, 47, 1 } }, { "darkorange", { 255, 140, 0, 1 } }, + { "darkorchid", { 153, 50, 204, 1 } }, { "darkred", { 139, 0, 0, 1 } }, + { "darksalmon", { 233, 150, 122, 1 } }, { "darkseagreen", { 143, 188, 143, 1 } }, + { "darkslateblue", { 72, 61, 139, 1 } }, { "darkslategray", { 47, 79, 79, 1 } }, + { "darkslategrey", { 47, 79, 79, 1 } }, { "darkturquoise", { 0, 206, 209, 1 } }, + { "darkviolet", { 148, 0, 211, 1 } }, { "deeppink", { 255, 20, 147, 1 } }, + { "deepskyblue", { 0, 191, 255, 1 } }, { "dimgray", { 105, 105, 105, 1 } }, + { "dimgrey", { 105, 105, 105, 1 } }, { "dodgerblue", { 30, 144, 255, 1 } }, + { "firebrick", { 178, 34, 34, 1 } }, { "floralwhite", { 255, 250, 240, 1 } }, + { "forestgreen", { 34, 139, 34, 1 } }, { "fuchsia", { 255, 0, 255, 1 } }, + { "gainsboro", { 220, 220, 220, 1 } }, { "ghostwhite", { 248, 248, 255, 1 } }, + { "gold", { 255, 215, 0, 1 } }, { "goldenrod", { 218, 165, 32, 1 } }, + { "gray", { 128, 128, 128, 1 } }, { "green", { 0, 128, 0, 1 } }, + { "greenyellow", { 173, 255, 47, 1 } }, { "grey", { 128, 128, 128, 1 } }, + { "honeydew", { 240, 255, 240, 1 } }, { "hotpink", { 255, 105, 180, 1 } }, + { "indianred", { 205, 92, 92, 1 } }, { "indigo", { 75, 0, 130, 1 } }, + { "ivory", { 255, 255, 240, 1 } }, { "khaki", { 240, 230, 140, 1 } }, + { "lavender", { 230, 230, 250, 1 } }, { "lavenderblush", { 255, 240, 245, 1 } }, + { "lawngreen", { 124, 252, 0, 1 } }, { "lemonchiffon", { 255, 250, 205, 1 } }, + { "lightblue", { 173, 216, 230, 1 } }, { "lightcoral", { 240, 128, 128, 1 } }, + { "lightcyan", { 224, 255, 255, 1 } }, { "lightgoldenrodyellow", { 250, 250, 210, 1 } }, + { "lightgray", { 211, 211, 211, 1 } }, { "lightgreen", { 144, 238, 144, 1 } }, + { "lightgrey", { 211, 211, 211, 1 } }, { "lightpink", { 255, 182, 193, 1 } }, + { "lightsalmon", { 255, 160, 122, 1 } }, { "lightseagreen", { 32, 178, 170, 1 } }, + { "lightskyblue", { 135, 206, 250, 1 } }, { "lightslategray", { 119, 136, 153, 1 } }, + { "lightslategrey", { 119, 136, 153, 1 } }, { "lightsteelblue", { 176, 196, 222, 1 } }, + { "lightyellow", { 255, 255, 224, 1 } }, { "lime", { 0, 255, 0, 1 } }, + { "limegreen", { 50, 205, 50, 1 } }, { "linen", { 250, 240, 230, 1 } }, + { "magenta", { 255, 0, 255, 1 } }, { "maroon", { 128, 0, 0, 1 } }, + { "mediumaquamarine", { 102, 205, 170, 1 } }, { "mediumblue", { 0, 0, 205, 1 } }, + { "mediumorchid", { 186, 85, 211, 1 } }, { "mediumpurple", { 147, 112, 219, 1 } }, + { "mediumseagreen", { 60, 179, 113, 1 } }, { "mediumslateblue", { 123, 104, 238, 1 } }, + { "mediumspringgreen", { 0, 250, 154, 1 } }, { "mediumturquoise", { 72, 209, 204, 1 } }, + { "mediumvioletred", { 199, 21, 133, 1 } }, { "midnightblue", { 25, 25, 112, 1 } }, + { "mintcream", { 245, 255, 250, 1 } }, { "mistyrose", { 255, 228, 225, 1 } }, + { "moccasin", { 255, 228, 181, 1 } }, { "navajowhite", { 255, 222, 173, 1 } }, + { "navy", { 0, 0, 128, 1 } }, { "oldlace", { 253, 245, 230, 1 } }, + { "olive", { 128, 128, 0, 1 } }, { "olivedrab", { 107, 142, 35, 1 } }, + { "orange", { 255, 165, 0, 1 } }, { "orangered", { 255, 69, 0, 1 } }, + { "orchid", { 218, 112, 214, 1 } }, { "palegoldenrod", { 238, 232, 170, 1 } }, + { "palegreen", { 152, 251, 152, 1 } }, { "paleturquoise", { 175, 238, 238, 1 } }, + { "palevioletred", { 219, 112, 147, 1 } }, { "papayawhip", { 255, 239, 213, 1 } }, + { "peachpuff", { 255, 218, 185, 1 } }, { "peru", { 205, 133, 63, 1 } }, + { "pink", { 255, 192, 203, 1 } }, { "plum", { 221, 160, 221, 1 } }, + { "powderblue", { 176, 224, 230, 1 } }, { "purple", { 128, 0, 128, 1 } }, + { "red", { 255, 0, 0, 1 } }, { "rosybrown", { 188, 143, 143, 1 } }, + { "royalblue", { 65, 105, 225, 1 } }, { "saddlebrown", { 139, 69, 19, 1 } }, + { "salmon", { 250, 128, 114, 1 } }, { "sandybrown", { 244, 164, 96, 1 } }, + { "seagreen", { 46, 139, 87, 1 } }, { "seashell", { 255, 245, 238, 1 } }, + { "sienna", { 160, 82, 45, 1 } }, { "silver", { 192, 192, 192, 1 } }, + { "skyblue", { 135, 206, 235, 1 } }, { "slateblue", { 106, 90, 205, 1 } }, + { "slategray", { 112, 128, 144, 1 } }, { "slategrey", { 112, 128, 144, 1 } }, + { "snow", { 255, 250, 250, 1 } }, { "springgreen", { 0, 255, 127, 1 } }, + { "steelblue", { 70, 130, 180, 1 } }, { "tan", { 210, 180, 140, 1 } }, + { "teal", { 0, 128, 128, 1 } }, { "thistle", { 216, 191, 216, 1 } }, + { "tomato", { 255, 99, 71, 1 } }, { "turquoise", { 64, 224, 208, 1 } }, + { "violet", { 238, 130, 238, 1 } }, { "wheat", { 245, 222, 179, 1 } }, + { "white", { 255, 255, 255, 1 } }, { "whitesmoke", { 245, 245, 245, 1 } }, + { "yellow", { 255, 255, 0, 1 } }, { "yellowgreen", { 154, 205, 50, 1 } } +}; + + +template +uint8_t clamp_css_byte(T i) { // Clamp to integer 0 .. 255. + i = round(i); // Seems to be what Chrome does (vs truncation). + return i < 0 ? 0 : i > 255 ? 255 : i; +} + +template +float clamp_css_float(T f) { // Clamp to float 0.0 .. 1.0. + return f < 0 ? 0 : f > 1 ? 1 : f; +} + +float parseFloat(const std::string& str) { + return strtof(str.c_str(), nullptr); +} + +int64_t parseInt(const std::string& str, uint8_t base = 10) { + return strtoll(str.c_str(), nullptr, base); +} + +uint8_t parse_css_int(const std::string& str) { // int or percentage. + if (str.length() && str.back() == '%') { + return clamp_css_byte(parseFloat(str) / 100.0f * 255.0f); + } else { + return clamp_css_byte(parseInt(str)); + } +} + +float parse_css_float(const std::string& str) { // float or percentage. + if (str.length() && str.back() == '%') { + return clamp_css_float(parseFloat(str) / 100.0f); + } else { + return clamp_css_float(parseFloat(str)); + } +} + +float css_hue_to_rgb(float m1, float m2, float h) { + if (h < 0.0f) { + h += 1.0f; + } else if (h > 1.0f) { + h -= 1.0f; + } + + if (h * 6.0f < 1.0f) { + return m1 + (m2 - m1) * h * 6.0f; + } + if (h * 2.0f < 1.0f) { + return m2; + } + if (h * 3.0f < 2.0f) { + return m1 + (m2 - m1) * (2.0 / 3.0 - h) * 6.0f; + } + return m1; +} + + + +std::vector split(const std::string& s, char delim) { + std::vector elems; + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) { + elems.push_back(item); + } + return elems; +} + +Color CSSColorParser::parse(const std::string& css_str) { + std::string str = css_str; + + // Remove all whitespace, not compliant, but should just be more accepting. + str.erase(std::remove(str.begin(), str.end(), ' '), str.end()); + + // Convert to lowercase. + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + + // Color keywords (and transparent) lookup. + auto it = kCSSColorTable.find(str); + if (it != kCSSColorTable.end()) { + return it->second; + } + + // #abc and #abc123 syntax. + if (str.length() && str.front() == '#') { + if (str.length() == 4) { + int64_t iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. + if (!(iv >= 0 && iv <= 0xfff)) { + return {}; + } else { + return { + static_cast(((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8)), + static_cast((iv & 0xf0) | ((iv & 0xf0) >> 4)), + static_cast((iv & 0xf) | ((iv & 0xf) << 4)), + 1 + }; + } + } else if (str.length() == 7) { + int64_t iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. + if (!(iv >= 0 && iv <= 0xffffff)) { + return {}; // Covers NaN. + } else { + return { + static_cast((iv & 0xff0000) >> 16), + static_cast((iv & 0xff00) >> 8), + static_cast(iv & 0xff), + 1 + }; + } + } + + return {}; + } + + size_t op = str.find_first_of('('), ep = str.find_first_of(')'); + if (op != std::string::npos && ep + 1 == str.length()) { + const std::string fname = str.substr(0, op); + const std::vector params = split(str.substr(op + 1, ep - (op + 1)), ','); + + float alpha = 1.0f; + + if (fname == "rgba" || fname == "rgb") { + if (fname == "rgba") { + if (params.size() != 4) { + return {}; + } + alpha = parse_css_float(params.back()); + } else { + if (params.size() != 3) { + return {}; + } + } + + return { + parse_css_int(params[0]), + parse_css_int(params[1]), + parse_css_int(params[2]), + alpha + }; + + } else if (fname == "hsla" || fname == "hsl") { + if (fname == "hsla") { + if (params.size() != 4) { + return {}; + } + alpha = parse_css_float(params.back()); + } else { + if (params.size() != 3) { + return {}; + } + } + + float h = parseFloat(params[0]) / 360.0f; + while (h < 0.0f) h++; + while (h > 1.0f) h--; + + // NOTE(deanm): According to the CSS spec s/l should only be + // percentages, but we don't bother and let float or percentage. + float s = parse_css_float(params[1]); + float l = parse_css_float(params[2]); + + float m2 = l <= 0.5f ? l * (s + 1.0f) : l + s - l * s; + float m1 = l * 2.0f - m2; + + return { + clamp_css_byte(css_hue_to_rgb(m1, m2, h + 1.0f / 3.0f) * 255.0f), + clamp_css_byte(css_hue_to_rgb(m1, m2, h) * 255.0f), + clamp_css_byte(css_hue_to_rgb(m1, m2, h - 1.0f / 3.0f) * 255.0f), + alpha + }; + } + } + + return {}; +} diff --git a/csscolorparser.hpp b/csscolorparser.hpp new file mode 100644 index 0000000..1d07462 --- /dev/null +++ b/csscolorparser.hpp @@ -0,0 +1,44 @@ +// (c) Dean McNamee , 2012. +// C++ port by Konstantin Käfer , 2014. +// +// https://github.com/deanm/css-color-parser-js +// https://github.com/kkaefer/css-color-parser-cpp +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#ifndef CSS_COLOR_PARSER_CPP +#define CSS_COLOR_PARSER_CPP + +#include + +namespace CSSColorParser { + +struct Color { + inline Color() {} + inline Color(unsigned char r, unsigned char g, unsigned char b, float a) + : r(r), g(g), b(b), a(a) {} + unsigned char r = 0, g = 0, b = 0; + float a = 1.0f; +}; + +Color parse(const std::string& css_str); + +} + +#endif diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..bb475e4 --- /dev/null +++ b/main.cpp @@ -0,0 +1,22 @@ +#include "csscolorparser.hpp" + +#include + +std::ostream& operator<<(std::ostream& os, const CSSColorParser::Color& color) { + return os << "rgba(" << (int)color.r << ", " << (int)color.g << ", " << (int)color.b << ", " << color.a << ")"; +} + +int main() { + using namespace CSSColorParser; + + std::cout << "rgba(255, 128, 12, 0.5) == " << parse(" rgba (255, 128, 12, 0.5)") << std::endl; + std::cout << "rgba(255, 255, 255, 1) == " << parse("#fff") << std::endl; + std::cout << "rgba(255, 0, 17, 1) == " << parse("#ff0011") << std::endl; + std::cout << "rgba(106, 90, 205, 1) == " << parse("slateblue") << std::endl; + std::cout << "rgba(0, 0, 0, 1) == " << parse("blah") << std::endl; + std::cout << "rgba(0, 0, 0, 1) == " << parse("ffffff") << std::endl; + std::cout << "rgba(226, 233, 233, 0.5) == " << parse("hsla(900, 15%, 90%, 0.5)") << std::endl; + std::cout << "rgba(0, 0, 0, 1) == " << parse("hsla(900, 15%, 90%)") << std::endl; + std::cout << "rgba(226, 233, 233, 1) == " << parse("hsl(900, 15%, 90%)") << std::endl; + std::cout << "rgba(226, 233, 233, 1) == " << parse("hsl(900, 0.15, 90%)") << std::endl; // NOTE: not spec compliant. +} From 5e2780060872a258279b7332d7d0134cae039e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 12 Mar 2014 12:37:51 +0100 Subject: [PATCH 02/12] add readme --- README | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 README diff --git a/README b/README new file mode 100644 index 0000000..290ff3e --- /dev/null +++ b/README @@ -0,0 +1,46 @@ +https://github.com/kkaefer/css-color-parser-cpp + +JavaScript parser for CSS color strings. + +> CSSColorParser::parse(" rgba (255, 128, 12, 0.5)"); + Color [ 255, 128, 12, 0.5 ] +> CSSColorParser::parse("#fff"); + Color [ 255, 255, 255, 1 ] +> CSSColorParser::parse("#ff0011"); + Color [ 255, 0, 17, 1 ] +> CSSColorParser::parse("slateblue"); + Color [ 106, 90, 205, 1 ] +> CSSColorParser::parse("blah"); + Color [ 0, 0, 0, 1 ] +> CSSColorParser::parse("ffffff"); + Color [ 0, 0, 0, 1 ] +> CSSColorParser::parse("hsla(900, 15%, 90%, 0.5)") + Color [ 226, 233, 233, 0.5 ] +> CSSColorParser::parse("hsla(900, 15%, 90%)") + Color [ 0, 0, 0, 1 ] +> CSSColorParser::parse("hsl(900, 15%, 90%)") + Color [ 226, 233, 233, 1 ] +> CSSColorParser::parse("hsl(900, 0.15, 90%)") // NOTE: not spec compliant. + Color [ 226, 233, 233, 1 ] + + +(c) Dean McNamee , 2012. +(c) Konstantin Käfer , 2014. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. \ No newline at end of file From 575145ddf0f6acea02d2f34ffa05dcbcb7f4f423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Wed, 12 Mar 2014 12:38:56 +0100 Subject: [PATCH 03/12] it's c++ --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 290ff3e..ba3dc9d 100644 --- a/README +++ b/README @@ -1,6 +1,6 @@ https://github.com/kkaefer/css-color-parser-cpp -JavaScript parser for CSS color strings. +C++ parser for CSS color strings. > CSSColorParser::parse(" rgba (255, 128, 12, 0.5)"); Color [ 255, 128, 12, 0.5 ] From 6035ad85e5e5ec5ee8448deb2a8555e5ec9cd279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 30 Oct 2014 16:25:23 -0400 Subject: [PATCH 04/12] add include header and use std::round --- csscolorparser.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csscolorparser.cpp b/csscolorparser.cpp index 10eac09..d9461a2 100644 --- a/csscolorparser.cpp +++ b/csscolorparser.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include using namespace CSSColorParser; @@ -113,7 +114,7 @@ const std::map kCSSColorTable = { template uint8_t clamp_css_byte(T i) { // Clamp to integer 0 .. 255. - i = round(i); // Seems to be what Chrome does (vs truncation). + i = std::round(i); // Seems to be what Chrome does (vs truncation). return i < 0 ? 0 : i > 255 ? 255 : i; } From 7bdb3ebc457874c2e6f59c982bafa44ae0cae4f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Thu, 30 Oct 2014 16:32:07 -0400 Subject: [PATCH 05/12] use plain array instead of std::map --- csscolorparser.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/csscolorparser.cpp b/csscolorparser.cpp index d9461a2..7ba989f 100644 --- a/csscolorparser.cpp +++ b/csscolorparser.cpp @@ -29,12 +29,12 @@ #include #include #include -#include using namespace CSSColorParser; // http://www.w3.org/TR/css3-color/ -const std::map kCSSColorTable = { +struct NamedColor { const char *const name; const Color color; }; +const NamedColor namedColors[] = { { "transparent", { 0, 0, 0, 0 } }, { "aliceblue", { 240, 248, 255, 1 } }, { "antiquewhite", { 250, 235, 215, 1 } }, { "aqua", { 0, 255, 255, 1 } }, { "aquamarine", { 127, 255, 212, 1 } }, { "azure", { 240, 255, 255, 1 } }, @@ -111,6 +111,8 @@ const std::map kCSSColorTable = { { "yellow", { 255, 255, 0, 1 } }, { "yellowgreen", { 154, 205, 50, 1 } } }; +const size_t namedColorCount = sizeof (namedColors) / sizeof (NamedColor); + template uint8_t clamp_css_byte(T i) { // Clamp to integer 0 .. 255. @@ -187,10 +189,11 @@ Color CSSColorParser::parse(const std::string& css_str) { // Convert to lowercase. std::transform(str.begin(), str.end(), str.begin(), ::tolower); - // Color keywords (and transparent) lookup. - auto it = kCSSColorTable.find(str); - if (it != kCSSColorTable.end()) { - return it->second; + + for (size_t i = 0; i < namedColorCount; i++) { + if (str == namedColors[i].name) { + return namedColors[i].color; + } } // #abc and #abc123 syntax. From 5e877248746c64640a64d6ff0c1e3de2a482b400 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 13 Jan 2017 13:45:53 +0100 Subject: [PATCH 06/12] changes from https://github.com/mapbox/mapbox-gl-native/tree/master/src/csscolorparser --- csscolorparser.cpp | 8 +++++--- csscolorparser.hpp | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/csscolorparser.cpp b/csscolorparser.cpp index 7ba989f..592f10f 100644 --- a/csscolorparser.cpp +++ b/csscolorparser.cpp @@ -30,7 +30,7 @@ #include #include -using namespace CSSColorParser; +namespace CSSColorParser { // http://www.w3.org/TR/css3-color/ struct NamedColor { const char *const name; const Color color; }; @@ -116,7 +116,7 @@ const size_t namedColorCount = sizeof (namedColors) / sizeof (NamedColor); template uint8_t clamp_css_byte(T i) { // Clamp to integer 0 .. 255. - i = std::round(i); // Seems to be what Chrome does (vs truncation). + i = ::round(i); // Seems to be what Chrome does (vs truncation). return i < 0 ? 0 : i > 255 ? 255 : i; } @@ -180,7 +180,7 @@ std::vector split(const std::string& s, char delim) { return elems; } -Color CSSColorParser::parse(const std::string& css_str) { +Color parse(const std::string& css_str) { std::string str = css_str; // Remove all whitespace, not compliant, but should just be more accepting. @@ -288,3 +288,5 @@ Color CSSColorParser::parse(const std::string& css_str) { return {}; } + +} // namespace CSSColorParser diff --git a/csscolorparser.hpp b/csscolorparser.hpp index 1d07462..6caf796 100644 --- a/csscolorparser.hpp +++ b/csscolorparser.hpp @@ -31,8 +31,8 @@ namespace CSSColorParser { struct Color { inline Color() {} - inline Color(unsigned char r, unsigned char g, unsigned char b, float a) - : r(r), g(g), b(b), a(a) {} + inline Color(unsigned char r_, unsigned char g_, unsigned char b_, float a_) + : r(r_), g(g_), b(b_), a(a_) {} unsigned char r = 0, g = 0, b = 0; float a = 1.0f; }; From 1cc165dd12232235dfa4daa12d9824da4fa76670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 13 Jan 2017 14:19:38 +0100 Subject: [PATCH 07/12] cleanups --- .clang-format | 18 ++++++++++++++ Makefile | 13 ++++------- csscolorparser.cpp | 9 ++++--- csscolorparser.hpp | 19 +++++++++++---- main.cpp | 22 ------------------ test.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 99 insertions(+), 40 deletions(-) create mode 100644 .clang-format delete mode 100644 main.cpp create mode 100644 test.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..ff0f39e --- /dev/null +++ b/.clang-format @@ -0,0 +1,18 @@ +Standard: Cpp11 +IndentWidth: 4 +AccessModifierOffset: -4 +UseTab: Never +BinPackParameters: false +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortBlocksOnASingleLine: false +AllowShortFunctionsOnASingleLine: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +AlwaysBreakTemplateDeclarations: true +NamespaceIndentation: None +PointerBindsToType: true +SpacesInParentheses: false +BreakBeforeBraces: Attach +ColumnLimit: 100 +Cpp11BracedListStyle: false +SpacesBeforeTrailingComments: 1 diff --git a/Makefile b/Makefile index 2aef76e..c557e92 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,14 @@ -CXXFLAGS = -std=c++11 -Wall -Wextra -Wno-unused-parameter +CXXFLAGS = -std=c++11 -Wall -Wextra -Wpedantic -Weverything -Wno-c++98-compat -Wno-missing-prototypes -Wno-padded -Wno-unused-parameter -BIN = color -SRCS = main.cpp -SRCS += csscolorparser.cpp -OBJS = $(patsubst %.cpp,%.o,$(SRCS)) +build: test -build: $(BIN) - -$(BIN): $(OBJS) +test: csscolorparser.o test.o $(CXX) $(CXXFLAGS) -o $@ $^ %.o: %.cpp $(CXX) $(CXXFLAGS) -c -o $@ $^ clean: - rm -rf *.o $(BIN) + rm -rf *.o test .PHONY: clean diff --git a/csscolorparser.cpp b/csscolorparser.cpp index 592f10f..eb75523 100644 --- a/csscolorparser.cpp +++ b/csscolorparser.cpp @@ -1,5 +1,5 @@ // (c) Dean McNamee , 2012. -// C++ port by Konstantin Käfer , 2014. +// C++ port by Mapbox, Konstantin Käfer , 2014-2017. // // https://github.com/deanm/css-color-parser-js // https://github.com/kkaefer/css-color-parser-cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include namespace CSSColorParser { @@ -117,12 +116,12 @@ const size_t namedColorCount = sizeof (namedColors) / sizeof (NamedColor); template uint8_t clamp_css_byte(T i) { // Clamp to integer 0 .. 255. i = ::round(i); // Seems to be what Chrome does (vs truncation). - return i < 0 ? 0 : i > 255 ? 255 : i; + return i < 0 ? 0 : i > 255 ? 255 : uint8_t(i); } template float clamp_css_float(T f) { // Clamp to float 0.0 .. 1.0. - return f < 0 ? 0 : f > 1 ? 1 : f; + return f < 0 ? 0 : f > 1 ? 1 : float(f); } float parseFloat(const std::string& str) { @@ -163,7 +162,7 @@ float css_hue_to_rgb(float m1, float m2, float h) { return m2; } if (h * 3.0f < 2.0f) { - return m1 + (m2 - m1) * (2.0 / 3.0 - h) * 6.0f; + return m1 + (m2 - m1) * (2.0f / 3.0f - h) * 6.0f; } return m1; } diff --git a/csscolorparser.hpp b/csscolorparser.hpp index 6caf796..c0ef767 100644 --- a/csscolorparser.hpp +++ b/csscolorparser.hpp @@ -1,5 +1,5 @@ // (c) Dean McNamee , 2012. -// C++ port by Konstantin Käfer , 2014. +// C++ port by Mapbox, Konstantin Käfer , 2014-2017. // // https://github.com/deanm/css-color-parser-js // https://github.com/kkaefer/css-color-parser-cpp @@ -26,19 +26,30 @@ #define CSS_COLOR_PARSER_CPP #include +#include namespace CSSColorParser { struct Color { - inline Color() {} + inline Color() { + } inline Color(unsigned char r_, unsigned char g_, unsigned char b_, float a_) - : r(r_), g(g_), b(b_), a(a_) {} + : r(r_), g(g_), b(b_), a(a_ > 1 ? 1 : a_ < 0 ? 0 : a_) { + } unsigned char r = 0, g = 0, b = 0; float a = 1.0f; }; -Color parse(const std::string& css_str); +inline bool operator==(const Color& lhs, const Color& rhs) { + return lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b && ::fabs(lhs.a - lhs.b) < 0.0001f; +} +inline bool operator!=(const Color& lhs, const Color& rhs) { + return !(lhs == rhs); } +Color parse(const std::string& css_str); + +} // namespace CSSColorParser + #endif diff --git a/main.cpp b/main.cpp deleted file mode 100644 index bb475e4..0000000 --- a/main.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "csscolorparser.hpp" - -#include - -std::ostream& operator<<(std::ostream& os, const CSSColorParser::Color& color) { - return os << "rgba(" << (int)color.r << ", " << (int)color.g << ", " << (int)color.b << ", " << color.a << ")"; -} - -int main() { - using namespace CSSColorParser; - - std::cout << "rgba(255, 128, 12, 0.5) == " << parse(" rgba (255, 128, 12, 0.5)") << std::endl; - std::cout << "rgba(255, 255, 255, 1) == " << parse("#fff") << std::endl; - std::cout << "rgba(255, 0, 17, 1) == " << parse("#ff0011") << std::endl; - std::cout << "rgba(106, 90, 205, 1) == " << parse("slateblue") << std::endl; - std::cout << "rgba(0, 0, 0, 1) == " << parse("blah") << std::endl; - std::cout << "rgba(0, 0, 0, 1) == " << parse("ffffff") << std::endl; - std::cout << "rgba(226, 233, 233, 0.5) == " << parse("hsla(900, 15%, 90%, 0.5)") << std::endl; - std::cout << "rgba(0, 0, 0, 1) == " << parse("hsla(900, 15%, 90%)") << std::endl; - std::cout << "rgba(226, 233, 233, 1) == " << parse("hsl(900, 15%, 90%)") << std::endl; - std::cout << "rgba(226, 233, 233, 1) == " << parse("hsl(900, 0.15, 90%)") << std::endl; // NOTE: not spec compliant. -} diff --git a/test.cpp b/test.cpp new file mode 100644 index 0000000..1f17304 --- /dev/null +++ b/test.cpp @@ -0,0 +1,58 @@ +#include "csscolorparser.hpp" + +#include + +using namespace CSSColorParser; + +std::ostream& operator<<(std::ostream& os, const Color& color) { + return os << "rgba(" << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " + << color.a << ")"; +} + +static bool errored = false; + +void ASSERT_EQUAL(const Color& expected, const std::string& input) { + const auto actual = parse(input); + if (expected != actual) { + errored = true; + std::cerr << "\033[1mERROR!: expected " << expected << " != parsed " << actual + << " when parsing \"" << input << "\"\033[0m" << std::endl; + } else { + std::cerr << "Passed: " << actual << std::endl; + } +} + +void ASSERT_EQUAL(const Color& expected, const Color& actual) { + if (expected != actual) { + errored = true; + std::cerr << "\033[1mERROR!: expected " << expected << " != actual " << actual << "\"\033[0m" << std::endl; + } else { + std::cerr << "Passed: " << actual << std::endl; + } +} + +int main() { + try { + ASSERT_EQUAL(Color{ 255, 128, 12, 0.5 }, " rgba (255, 128, 12, 0.5)"); + ASSERT_EQUAL(Color{ 255, 255, 255, 1 }, "#fff"); + ASSERT_EQUAL(Color{ 255, 0, 17, 1 }, "#ff0011"); + ASSERT_EQUAL(Color{ 106, 90, 205, 1 }, "slateblue"); + ASSERT_EQUAL(Color{ 0, 0, 0, 1 }, "blah"); + ASSERT_EQUAL(Color{ 0, 0, 0, 1 }, "ffffff"); + ASSERT_EQUAL(Color{ 226, 233, 233, 0.5 }, "hsla(900, 15%, 90%, 0.5)"); + ASSERT_EQUAL(Color{ 0, 0, 0, 1 }, "hsla(900, 15%, 90%)"); + ASSERT_EQUAL(Color{ 226, 233, 233, 1 }, "hsl(900, 15%, 90%)"); + ASSERT_EQUAL(Color{ 226, 233, 233, 1 }, "hsl(900, 0.15, 90%)"); // NOTE: not spec compliamt. + + // Out of range: + ASSERT_EQUAL(Color{ 0, 0, 0, 1 }, "xxx"); + ASSERT_EQUAL(Color{ 255, 128, 12, 1 }, " rgba (255, 128, 12, 2)"); + ASSERT_EQUAL(Color{ 255, 128, 12, 1 }, " rgba (400, 128, 12, 2)"); + ASSERT_EQUAL(Color{ 255, 128, 12, 1 }, Color{ 255, 128, 12, 3 }); + } catch(std::exception& ex) { + std::cerr << "EXCEPTION!: " << ex.what() << std::endl; + return 2; + } + + return errored ? 1 : 0; +} From 4feb2b90967f2b4cd2b313c28a3af43f972af9ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 13 Jan 2017 14:40:57 +0100 Subject: [PATCH 08/12] add fuzzing --- .gitignore | 4 +++- Makefile | 10 ++++++++-- fuzz.cpp | 13 +++++++++++++ fuzz.sh | 4 ++++ input/a | 1 + input/b | 1 + input/c | 1 + input/d | 1 + input/e | 1 + input/f | 1 + 10 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 fuzz.cpp create mode 100644 fuzz.sh create mode 100644 input/a create mode 100644 input/b create mode 100644 input/c create mode 100644 input/d create mode 100644 input/e create mode 100644 input/f diff --git a/.gitignore b/.gitignore index fa2caeb..71bbbe6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ *.o -/color \ No newline at end of file +/test +/fuzz +/output \ No newline at end of file diff --git a/Makefile b/Makefile index c557e92..759d1b0 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,20 @@ -CXXFLAGS = -std=c++11 -Wall -Wextra -Wpedantic -Weverything -Wno-c++98-compat -Wno-missing-prototypes -Wno-padded -Wno-unused-parameter +CXXFLAGS = -std=c++11 -Wall -Wextra -Wpedantic -Wno-unused-parameter build: test test: csscolorparser.o test.o $(CXX) $(CXXFLAGS) -o $@ $^ +fuzz: csscolorparser.o fuzz.o + afl-clang-fast++ $(CXXFLAGS) -o $@ $^ + +fuzz.o: fuzz.cpp + afl-clang-fast++ $(CXXFLAGS) -c -o $@ $^ + %.o: %.cpp $(CXX) $(CXXFLAGS) -c -o $@ $^ clean: - rm -rf *.o test + rm -rf *.o test fuzz .PHONY: clean diff --git a/fuzz.cpp b/fuzz.cpp new file mode 100644 index 0000000..1e6f749 --- /dev/null +++ b/fuzz.cpp @@ -0,0 +1,13 @@ +#include "csscolorparser.hpp" + +#include +#include + +int main(int argc, char* argv[]) { + while (__AFL_LOOP(1000)) { + // Pass stdin to the function. + std::cin >> std::noskipws; + CSSColorParser::parse({ std::istream_iterator(std::cin), std::istream_iterator() }); + } + return 0; +} \ No newline at end of file diff --git a/fuzz.sh b/fuzz.sh new file mode 100644 index 0000000..323ee0e --- /dev/null +++ b/fuzz.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env sh + +make fuzz +afl-fuzz -i input -o output -- ./fuzz diff --git a/input/a b/input/a new file mode 100644 index 0000000..b099b6c --- /dev/null +++ b/input/a @@ -0,0 +1 @@ +rgba(255, 128, 12, 0.5) \ No newline at end of file diff --git a/input/b b/input/b new file mode 100644 index 0000000..0f4692b --- /dev/null +++ b/input/b @@ -0,0 +1 @@ +#fff \ No newline at end of file diff --git a/input/c b/input/c new file mode 100644 index 0000000..795054f --- /dev/null +++ b/input/c @@ -0,0 +1 @@ +#ff0011 \ No newline at end of file diff --git a/input/d b/input/d new file mode 100644 index 0000000..74f4c62 --- /dev/null +++ b/input/d @@ -0,0 +1 @@ +slateblue \ No newline at end of file diff --git a/input/e b/input/e new file mode 100644 index 0000000..de53aff --- /dev/null +++ b/input/e @@ -0,0 +1 @@ +ffffff \ No newline at end of file diff --git a/input/f b/input/f new file mode 100644 index 0000000..e83404c --- /dev/null +++ b/input/f @@ -0,0 +1 @@ +hsla(900, 15%, 90%, 0.5) \ No newline at end of file From 4262ac80ae0919f81b5a2504bb6596114a5db618 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Fri, 31 Mar 2017 18:07:45 +0300 Subject: [PATCH 09/12] return empty optional when color could not be parsed --- Makefile | 2 +- csscolorparser.cpp | 20 ++++++++++---------- csscolorparser.hpp | 8 ++++++-- test.cpp | 26 +++++++++++++++----------- 4 files changed, 32 insertions(+), 24 deletions(-) diff --git a/Makefile b/Makefile index 759d1b0..82d4fb9 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CXXFLAGS = -std=c++11 -Wall -Wextra -Wpedantic -Wno-unused-parameter +CXXFLAGS = -std=c++14 -Wall -Wextra -Wpedantic -Wno-unused-parameter build: test diff --git a/csscolorparser.cpp b/csscolorparser.cpp index eb75523..e4db8c7 100644 --- a/csscolorparser.cpp +++ b/csscolorparser.cpp @@ -179,7 +179,7 @@ std::vector split(const std::string& s, char delim) { return elems; } -Color parse(const std::string& css_str) { +optional parse(const std::string& css_str) { std::string str = css_str; // Remove all whitespace, not compliant, but should just be more accepting. @@ -191,7 +191,7 @@ Color parse(const std::string& css_str) { for (size_t i = 0; i < namedColorCount; i++) { if (str == namedColors[i].name) { - return namedColors[i].color; + return { namedColors[i].color }; } } @@ -202,24 +202,24 @@ Color parse(const std::string& css_str) { if (!(iv >= 0 && iv <= 0xfff)) { return {}; } else { - return { + return {{ static_cast(((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8)), static_cast((iv & 0xf0) | ((iv & 0xf0) >> 4)), static_cast((iv & 0xf) | ((iv & 0xf) << 4)), 1 - }; + }}; } } else if (str.length() == 7) { int64_t iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. if (!(iv >= 0 && iv <= 0xffffff)) { return {}; // Covers NaN. } else { - return { + return {{ static_cast((iv & 0xff0000) >> 16), static_cast((iv & 0xff00) >> 8), static_cast(iv & 0xff), 1 - }; + }}; } } @@ -245,12 +245,12 @@ Color parse(const std::string& css_str) { } } - return { + return {{ parse_css_int(params[0]), parse_css_int(params[1]), parse_css_int(params[2]), alpha - }; + }}; } else if (fname == "hsla" || fname == "hsl") { if (fname == "hsla") { @@ -276,12 +276,12 @@ Color parse(const std::string& css_str) { float m2 = l <= 0.5f ? l * (s + 1.0f) : l + s - l * s; float m1 = l * 2.0f - m2; - return { + return {{ clamp_css_byte(css_hue_to_rgb(m1, m2, h + 1.0f / 3.0f) * 255.0f), clamp_css_byte(css_hue_to_rgb(m1, m2, h) * 255.0f), clamp_css_byte(css_hue_to_rgb(m1, m2, h - 1.0f / 3.0f) * 255.0f), alpha - }; + }}; } } diff --git a/csscolorparser.hpp b/csscolorparser.hpp index c0ef767..0e16ec4 100644 --- a/csscolorparser.hpp +++ b/csscolorparser.hpp @@ -27,9 +27,13 @@ #include #include +#include namespace CSSColorParser { +template +using optional = std::experimental::optional; + struct Color { inline Color() { } @@ -41,14 +45,14 @@ struct Color { }; inline bool operator==(const Color& lhs, const Color& rhs) { - return lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b && ::fabs(lhs.a - lhs.b) < 0.0001f; + return lhs.r == rhs.r && lhs.g == rhs.g && lhs.b == rhs.b && ::fabs(lhs.a - rhs.a) < 0.0001f; } inline bool operator!=(const Color& lhs, const Color& rhs) { return !(lhs == rhs); } -Color parse(const std::string& css_str); +optional parse(const std::string& css_str); } // namespace CSSColorParser diff --git a/test.cpp b/test.cpp index 1f17304..fc93644 100644 --- a/test.cpp +++ b/test.cpp @@ -4,30 +4,34 @@ using namespace CSSColorParser; -std::ostream& operator<<(std::ostream& os, const Color& color) { - return os << "rgba(" << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " - << color.a << ")"; +std::ostream& operator<<(std::ostream& os, const optional& color) { + if (color) { + return os << "rgba(" << int(color->r) << ", " << int(color->g) << ", " << int(color->b) + << ", " << color->a << ")"; + } else { + return os << ""; + } } static bool errored = false; -void ASSERT_EQUAL(const Color& expected, const std::string& input) { +void ASSERT_EQUAL(const optional& expected, const std::string& input) { const auto actual = parse(input); if (expected != actual) { errored = true; std::cerr << "\033[1mERROR!: expected " << expected << " != parsed " << actual << " when parsing \"" << input << "\"\033[0m" << std::endl; } else { - std::cerr << "Passed: " << actual << std::endl; + std::cerr << "Passed: " << actual << " expected when parsing \"" << input << "\"" << std::endl; } } -void ASSERT_EQUAL(const Color& expected, const Color& actual) { +void ASSERT_EQUAL(const optional& expected, const optional& actual) { if (expected != actual) { errored = true; std::cerr << "\033[1mERROR!: expected " << expected << " != actual " << actual << "\"\033[0m" << std::endl; } else { - std::cerr << "Passed: " << actual << std::endl; + std::cerr << "Passed: " << actual << " expected" << std::endl; } } @@ -37,15 +41,15 @@ int main() { ASSERT_EQUAL(Color{ 255, 255, 255, 1 }, "#fff"); ASSERT_EQUAL(Color{ 255, 0, 17, 1 }, "#ff0011"); ASSERT_EQUAL(Color{ 106, 90, 205, 1 }, "slateblue"); - ASSERT_EQUAL(Color{ 0, 0, 0, 1 }, "blah"); - ASSERT_EQUAL(Color{ 0, 0, 0, 1 }, "ffffff"); + ASSERT_EQUAL({}, "blah"); + ASSERT_EQUAL({}, "ffffff"); ASSERT_EQUAL(Color{ 226, 233, 233, 0.5 }, "hsla(900, 15%, 90%, 0.5)"); - ASSERT_EQUAL(Color{ 0, 0, 0, 1 }, "hsla(900, 15%, 90%)"); + ASSERT_EQUAL({}, "hsla(900, 15%, 90%)"); ASSERT_EQUAL(Color{ 226, 233, 233, 1 }, "hsl(900, 15%, 90%)"); ASSERT_EQUAL(Color{ 226, 233, 233, 1 }, "hsl(900, 0.15, 90%)"); // NOTE: not spec compliamt. // Out of range: - ASSERT_EQUAL(Color{ 0, 0, 0, 1 }, "xxx"); + ASSERT_EQUAL({}, "xxx"); ASSERT_EQUAL(Color{ 255, 128, 12, 1 }, " rgba (255, 128, 12, 2)"); ASSERT_EQUAL(Color{ 255, 128, 12, 1 }, " rgba (400, 128, 12, 2)"); ASSERT_EQUAL(Color{ 255, 128, 12, 1 }, Color{ 255, 128, 12, 3 }); From 4f51c64fbce0eae1b24ca9ddb252eeba04f548f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 12 May 2017 16:10:17 +0200 Subject: [PATCH 10/12] Removed unused variable namedColorCount --- csscolorparser.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/csscolorparser.cpp b/csscolorparser.cpp index e4db8c7..5658f2b 100644 --- a/csscolorparser.cpp +++ b/csscolorparser.cpp @@ -110,9 +110,6 @@ const NamedColor namedColors[] = { { "yellow", { 255, 255, 0, 1 } }, { "yellowgreen", { 154, 205, 50, 1 } } }; -const size_t namedColorCount = sizeof (namedColors) / sizeof (NamedColor); - - template uint8_t clamp_css_byte(T i) { // Clamp to integer 0 .. 255. i = ::round(i); // Seems to be what Chrome does (vs truncation). From 325ad381167163a14c1480b3fe3b4384e9f08b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 22 May 2018 11:17:52 +0200 Subject: [PATCH 11/12] fix hang when using very large angles for hue in hsl colors --- csscolorparser.cpp | 5 +++-- test.cpp | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/csscolorparser.cpp b/csscolorparser.cpp index 5658f2b..e7a4e50 100644 --- a/csscolorparser.cpp +++ b/csscolorparser.cpp @@ -262,8 +262,9 @@ optional parse(const std::string& css_str) { } float h = parseFloat(params[0]) / 360.0f; - while (h < 0.0f) h++; - while (h > 1.0f) h--; + float i; + // Normalize the hue to [0..1[ + h = std::modf(h, &i); // NOTE(deanm): According to the CSS spec s/l should only be // percentages, but we don't bother and let float or percentage. diff --git a/test.cpp b/test.cpp index fc93644..25fa852 100644 --- a/test.cpp +++ b/test.cpp @@ -47,6 +47,10 @@ int main() { ASSERT_EQUAL({}, "hsla(900, 15%, 90%)"); ASSERT_EQUAL(Color{ 226, 233, 233, 1 }, "hsl(900, 15%, 90%)"); ASSERT_EQUAL(Color{ 226, 233, 233, 1 }, "hsl(900, 0.15, 90%)"); // NOTE: not spec compliamt. + ASSERT_EQUAL(Color{ 0, 0, 0, 1 }, "hsl(9999999999999999999, 0, 0)"); // NOTE: float precision loss + ASSERT_EQUAL(Color{ 255, 191, 0, 1 }, "hsl(45, 100%, 50%)"); + ASSERT_EQUAL(Color{ 255, 191, 0, 1 }, "hsl(-315, 100%, 50%)"); + ASSERT_EQUAL(Color{ 255, 191, 0, 1 }, "hsl(-675, 100%, 50%)"); // Out of range: ASSERT_EQUAL({}, "xxx"); From 33d0c489c0fb5e16ab7b3bc133af5a9d14bd4565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 22 May 2018 11:22:09 +0200 Subject: [PATCH 12/12] correctly iterate over named colors fixup to 4f51c64fbce0eae1b24ca9ddb252eeba04f548f3 --- csscolorparser.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/csscolorparser.cpp b/csscolorparser.cpp index e7a4e50..106dae6 100644 --- a/csscolorparser.cpp +++ b/csscolorparser.cpp @@ -185,10 +185,9 @@ optional parse(const std::string& css_str) { // Convert to lowercase. std::transform(str.begin(), str.end(), str.begin(), ::tolower); - - for (size_t i = 0; i < namedColorCount; i++) { - if (str == namedColors[i].name) { - return { namedColors[i].color }; + for (const auto& namedColor : namedColors) { + if (str == namedColor.name) { + return { namedColor.color }; } }