Refactored To Remove CSS3 define

Accessing the extended string names no longer requires editing a library
header file.
This commit is contained in:
Michael Miller
2016-07-04 13:19:25 -07:00
parent 05e3d13934
commit 7743a76242
9 changed files with 793 additions and 485 deletions
+184 -15
View File
@@ -28,9 +28,45 @@ License along with NeoPixel. If not, see
#include <Arduino.h>
#include "RgbColor.h"
// Due to Arduino's lack of Project settings for symbols, library code (c,cpp)
// files can't react to defines in sketch, so this must be defined here
// #define USE_CSS3_COLORS 1
#define MAX_HTML_COLOR_NAME_LEN 21
#ifndef pgm_read_ptr
// ESP8266 doesn't define this macro
#define pgm_read_ptr(addr) (*reinterpret_cast<const void* const *>(addr))
#endif
#ifndef countof
#define countof(array) (sizeof(array)/sizeof(array[0]))
#endif
// ------------------------------------------------------------------------
// HtmlColorPair represents an association between a name and a HTML color code
// ------------------------------------------------------------------------
struct HtmlColorPair
{
PGM_P Name;
uint32_t Color;
};
// ------------------------------------------------------------------------
// HtmlShortColorNames is a template class used for Parse and ToString
// ------------------------------------------------------------------------
class HtmlShortColorNames
{
public:
static const HtmlColorPair* Pair(uint8_t index);
static uint8_t Count();
};
// ------------------------------------------------------------------------
// HtmlColorNames is a template class used for Parse and ToString
// ------------------------------------------------------------------------
class HtmlColorNames
{
public:
static const HtmlColorPair* Pair(uint8_t index);
static uint8_t Count();
};
// ------------------------------------------------------------------------
// HtmlColor represents a color object that is represented by a single uint32
@@ -80,7 +116,7 @@ struct HtmlColor
// ------------------------------------------------------------------------
// Parse a HTML4/CSS3 color name
//
// T_HTMLCOLORNAMES - template class that defines the collection of names
// name - the color name
// nameSize - the max size of name to check
//
@@ -90,9 +126,6 @@ struct HtmlColor
// nameSize is reached, no match is found in the name/color pair table, or
// a non-alphanumeric is read like seperators or whitespace.
//
// It accepts all standard HTML4 names and, if USE_CSS3_COLORS macro is
// defined, the extended color names defined in CSS3 standard also.
//
// It also accepts 3 or 6 digit hexadecimal notation (#rgb or #rrggbb),
// but it doesn't accept RGB, RGBA nor HSL values.
//
@@ -102,22 +135,135 @@ struct HtmlColor
// parsing will stop at the first non-alpha numeric
//
// Name MUST NOT be a PROGMEM pointer
//
// examples:
// Parse<HtmlShortColorNames>(buff, buffSize);
// Parse<HtmlColorNames>(buff, buffSize);
// ------------------------------------------------------------------------
size_t Parse(const char* name, size_t nameSize);
size_t Parse(const char* name)
{
return Parse(name, strlen(name) + 1);
template <typename T_HTMLCOLORNAMES> size_t Parse(const char* name, size_t nameSize)
{
if (nameSize > 0)
{
if (name[0] == '#')
{
// Parse an hexadecimal notation "#rrbbgg" or "#rgb"
//
uint8_t temp[6]; // stores preconverted chars to hex values
uint8_t tempSize = 0;
for (uint8_t indexChar = 1; indexChar < nameSize && indexChar < 8; ++indexChar)
{
char c = name[indexChar];
if (c >= '0' && c <= '9')
{
c -= '0';
}
else
{
// Convert a letter to lower case (only for ASCII letters)
// It's faster & smaller than tolower()
c |= 32;
if (c >= 'a' && c <= 'f')
{
c = c - 'a' + 10;
}
else
{
// we found an non hexidecimal char
// which could be null, deliminator, or other spacing
break;
}
}
temp[tempSize] = c;
tempSize++;
}
if (tempSize != 3 && tempSize != 6)
{
// invalid count of numerical chars
return 0;
}
else
{
uint32_t color = 0;
for (uint8_t indexChar = 0; indexChar < tempSize; ++indexChar)
{
color = color * 16 + temp[indexChar];
if (tempSize == 3)
{
// 3 digit hexadecimal notation can be supported easily
// duplicating digits.
color = color * 16 + temp[indexChar];
}
}
Color = color;
return tempSize;
}
}
else
{
// parse a standard name for the color
//
// the normal list is small enough a binary search isn't interesting,
for (uint8_t indexName = 0; indexName < T_HTMLCOLORNAMES::Count(); ++indexName)
{
const HtmlColorPair* colorPair = T_HTMLCOLORNAMES::Pair(indexName);
PGM_P searchName = (PGM_P)pgm_read_ptr(&colorPair->Name);
size_t str1Size = nameSize;
const char* str1 = name;
const char* str2P = searchName;
uint16_t result;
while (str1Size > 0)
{
char ch1 = tolower(*str1++);
char ch2 = tolower(pgm_read_byte(str2P++));
result = ch1 - ch2;
if (result != 0 || ch2 == '\0')
{
if (ch2 == '\0' && !isalnum(ch1))
{
// the string continues but is not part of a
// valid color name,
// ends in white space, deliminator, etc
result = 0;
}
break;
}
result = -1; // have not reached the end of searchName;
str1Size--;
}
if (result == 0)
{
Color = pgm_read_dword(&colorPair->Color);
return nameSize - str1Size;
}
}
}
}
return 0;
}
size_t Parse(String const &name)
template <typename T_HTMLCOLORNAMES> size_t Parse(const char* name)
{
return Parse(name.c_str(), name.length() + 1);
return Parse<T_HTMLCOLORNAMES>(name, MAX_HTML_COLOR_NAME_LEN + 1);
}
template <typename T_HTMLCOLORNAMES> size_t Parse(String const &name)
{
return Parse<T_HTMLCOLORNAMES>(name.c_str(), name.length() + 1);
}
// ------------------------------------------------------------------------
// Converts this color code to its HTML4/CSS3 name
//
// T_HTMLCOLORNAMES - template class that defines the collection of names
// buf - buffer to write the string
// bufSize - actual size of buf array
//
@@ -125,8 +271,29 @@ struct HtmlColor
//
// If there is not enough space in the buffer, it will write as many
// characters as allowed and will always finish the buffer with a NUL char
//
// examples:
// ToString<HtmlShortColorNames>(buf, bufSize);
// ToString<htmlColorNames>(buf, bufSize);
// ------------------------------------------------------------------------
size_t ToString(char *buf, size_t bufSize) const;
template <typename T_HTMLCOLORNAMES> size_t ToString(char* buf, size_t bufSize) const
{
// search for a color value/name pairs first
for (uint8_t indexName = 0; indexName < T_HTMLCOLORNAMES::Count(); ++indexName)
{
const HtmlColorPair* colorPair = T_HTMLCOLORNAMES::Pair(indexName);
if (pgm_read_dword(&colorPair->Color) == Color)
{
PGM_P name = (PGM_P)pgm_read_ptr(&colorPair->Name);
strncpy_P(buf, name, bufSize);
return strlen_P(name);
}
}
// no color name pair match, convert using numerical format
return ToNumericalString(buf, bufSize);
}
// ------------------------------------------------------------------------
// Converts this color code to its HTML4/CSS3 numerical name
@@ -139,6 +306,7 @@ struct HtmlColor
// If there is not enough space in the buffer, it will write as many
// characters as allowed and will always finish the buffer with a NUL char
// ------------------------------------------------------------------------
size_t ToNumericalString(char* buf, size_t bufSize) const;
// ------------------------------------------------------------------------
@@ -150,6 +318,7 @@ struct HtmlColor
// x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space
// y - unit value (0.0 - 1.0) that defines the blend progress in vertical space
// ------------------------------------------------------------------------
static HtmlColor BilinearBlend(const HtmlColor& c00,
const HtmlColor& c01,
const HtmlColor& c10,