Skip to content

Commit aa9852b

Browse files
committed
Implement internal HSLA color representation
1 parent aabb867 commit aa9852b

28 files changed

+860
-760
lines changed

src/ast.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,25 @@ namespace Sass {
511511
/////////////////////////////////////////////////////////////////////////
512512
/////////////////////////////////////////////////////////////////////////
513513

514+
Expression::Expression(ParserState pstate, bool d, bool e, bool i, Type ct)
515+
: AST_Node(pstate),
516+
is_delayed_(d),
517+
is_expanded_(e),
518+
is_interpolant_(i),
519+
concrete_type_(ct)
520+
{ }
521+
522+
Expression::Expression(const Expression* ptr)
523+
: AST_Node(ptr),
524+
is_delayed_(ptr->is_delayed_),
525+
is_expanded_(ptr->is_expanded_),
526+
is_interpolant_(ptr->is_interpolant_),
527+
concrete_type_(ptr->concrete_type_)
528+
{ }
529+
530+
/////////////////////////////////////////////////////////////////////////
531+
/////////////////////////////////////////////////////////////////////////
532+
514533
Unary_Expression::Unary_Expression(ParserState pstate, Type t, Expression_Obj o)
515534
: Expression(pstate), optype_(t), operand_(o), hash_(0)
516535
{ }

src/ast.hpp

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ namespace Sass {
8080
case LT: return "lt";
8181
case LTE: return "lte";
8282
case ADD: return "plus";
83-
case SUB: return "sub";
83+
case SUB: return "minus";
8484
case MUL: return "times";
8585
case DIV: return "div";
8686
case MOD: return "mod";
@@ -198,21 +198,7 @@ namespace Sass {
198198
ADD_PROPERTY(bool, is_interpolant)
199199
ADD_PROPERTY(Type, concrete_type)
200200
public:
201-
Expression(ParserState pstate,
202-
bool d = false, bool e = false, bool i = false, Type ct = NONE)
203-
: AST_Node(pstate),
204-
is_delayed_(d),
205-
is_expanded_(e),
206-
is_interpolant_(i),
207-
concrete_type_(ct)
208-
{ }
209-
Expression(const Expression* ptr)
210-
: AST_Node(ptr),
211-
is_delayed_(ptr->is_delayed_),
212-
is_expanded_(ptr->is_expanded_),
213-
is_interpolant_(ptr->is_interpolant_),
214-
concrete_type_(ptr->concrete_type_)
215-
{ }
201+
Expression(ParserState pstate, bool d = false, bool e = false, bool i = false, Type ct = NONE);
216202
virtual operator bool() { return true; }
217203
virtual ~Expression() { }
218204
virtual bool is_invisible() const { return false; }
@@ -441,7 +427,6 @@ namespace Sass {
441427
ADD_PROPERTY(bool, group_end)
442428
public:
443429
Statement(ParserState pstate, Type st = NONE, size_t t = 0);
444-
Statement(const Statement* ptr); // copy constructor
445430
virtual ~Statement() = 0; // virtual destructor
446431
// needed for rearranging nested rulesets during CSS emission
447432
virtual bool bubbles();

src/ast2c.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ namespace Sass {
1616
union Sass_Value* AST2C::operator()(Custom_Error_Ptr e)
1717
{ return sass_make_error(e->message().c_str()); }
1818

19-
union Sass_Value* AST2C::operator()(Color_Ptr c)
19+
union Sass_Value* AST2C::operator()(Color_RGBA_Ptr c)
2020
{ return sass_make_color(c->r(), c->g(), c->b(), c->a()); }
2121

22+
union Sass_Value* AST2C::operator()(Color_HSLA_Ptr c)
23+
{ return operator()(c->toRGBA()); }
24+
2225
union Sass_Value* AST2C::operator()(String_Constant_Ptr s)
2326
{
2427
if (s->quote_mark()) {

src/ast2c.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ namespace Sass {
1616

1717
union Sass_Value* operator()(Boolean_Ptr);
1818
union Sass_Value* operator()(Number_Ptr);
19-
union Sass_Value* operator()(Color_Ptr);
19+
union Sass_Value* operator()(Color_RGBA_Ptr);
20+
union Sass_Value* operator()(Color_HSLA_Ptr);
2021
union Sass_Value* operator()(String_Constant_Ptr);
2122
union Sass_Value* operator()(String_Quoted_Ptr);
2223
union Sass_Value* operator()(Custom_Warning_Ptr);

src/ast_def_macros.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ public: \
7474
virtual klass##_Ptr clone(std::string, size_t) const = 0; \
7575

7676
#define ATTACH_VIRTUAL_AST_OPERATIONS(klass) \
77+
klass(const klass* ptr); \
7778
virtual klass##_Ptr copy(std::string, size_t) const override = 0; \
7879
virtual klass##_Ptr clone(std::string, size_t) const override = 0; \
7980

@@ -89,6 +90,7 @@ public: \
8990
virtual klass##_Ptr clone() const = 0; \
9091

9192
#define ATTACH_VIRTUAL_AST_OPERATIONS(klass) \
93+
klass(const klass* ptr); \
9294
virtual klass##_Ptr copy() const override = 0; \
9395
virtual klass##_Ptr clone() const override = 0; \
9496

src/ast_fwd_decl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ namespace Sass {
1919
IMPLEMENT_BASE_CAST(Has_Block)
2020
IMPLEMENT_BASE_CAST(PreValue)
2121
IMPLEMENT_BASE_CAST(Value)
22+
IMPLEMENT_BASE_CAST(Color)
2223
IMPLEMENT_BASE_CAST(List)
2324
IMPLEMENT_BASE_CAST(String)
2425
IMPLEMENT_BASE_CAST(String_Constant)

src/ast_fwd_decl.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,12 @@ namespace Sass {
166166
class Color;
167167
typedef Color* Color_Ptr;
168168
typedef Color const* Color_Ptr_Const;
169+
class Color_RGBA;
170+
typedef Color_RGBA* Color_RGBA_Ptr;
171+
typedef Color_RGBA const* Color_RGBA_Ptr_Const;
172+
class Color_HSLA;
173+
typedef Color_HSLA* Color_HSLA_Ptr;
174+
typedef Color_HSLA const* Color_HSLA_Ptr_Const;
169175
class Boolean;
170176
typedef Boolean* Boolean_Ptr;
171177
typedef Boolean const* Boolean_Ptr_Const;
@@ -321,6 +327,8 @@ namespace Sass {
321327
IMPL_MEM_OBJ(Variable);
322328
IMPL_MEM_OBJ(Number);
323329
IMPL_MEM_OBJ(Color);
330+
IMPL_MEM_OBJ(Color_RGBA);
331+
IMPL_MEM_OBJ(Color_HSLA);
324332
IMPL_MEM_OBJ(Boolean);
325333
IMPL_MEM_OBJ(String_Schema);
326334
IMPL_MEM_OBJ(String);
@@ -477,6 +485,7 @@ namespace Sass {
477485
DECLARE_BASE_CAST(PreValue)
478486
DECLARE_BASE_CAST(Value)
479487
DECLARE_BASE_CAST(List)
488+
DECLARE_BASE_CAST(Color)
480489
DECLARE_BASE_CAST(String)
481490
DECLARE_BASE_CAST(String_Constant)
482491
DECLARE_BASE_CAST(Supports_Condition)

src/ast_selectors.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ namespace Sass {
5050
mutable size_t hash_;
5151
public:
5252
Selector(ParserState pstate);
53-
Selector(const Selector* ptr);
5453
virtual ~Selector() = 0;
5554
size_t hash() const override = 0;
5655
virtual unsigned long specificity() const = 0;
@@ -115,7 +114,6 @@ namespace Sass {
115114
HASH_PROPERTY(bool, has_ns)
116115
public:
117116
Simple_Selector(ParserState pstate, std::string n = "");
118-
Simple_Selector(const Simple_Selector* ptr);
119117
virtual std::string ns_name() const;
120118
size_t hash() const override;
121119
bool empty() const;

src/ast_values.cpp

Lines changed: 165 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ namespace Sass {
210210
{
211211
return sass_op_to_name(optype());
212212
}
213-
213+
214214
const std::string Binary_Expression::separator()
215215
{
216216
return sass_op_separator(optype());
@@ -221,7 +221,7 @@ namespace Sass {
221221
return is_left_interpolant() ||
222222
is_right_interpolant();
223223
}
224-
224+
225225
void Binary_Expression::set_delayed(bool delayed)
226226
{
227227
right()->set_delayed(delayed);
@@ -485,24 +485,52 @@ namespace Sass {
485485
/////////////////////////////////////////////////////////////////////////
486486
/////////////////////////////////////////////////////////////////////////
487487

488-
Color::Color(ParserState pstate, double r, double g, double b, double a, const std::string disp)
489-
: Value(pstate), r_(r), g_(g), b_(b), a_(a), disp_(disp),
488+
Color::Color(ParserState pstate, double a, const std::string disp)
489+
: Value(pstate),
490+
disp_(disp), a_(a),
490491
hash_(0)
491492
{ concrete_type(COLOR); }
492493

493494
Color::Color(const Color* ptr)
494-
: Value(ptr),
495-
r_(ptr->r_),
496-
g_(ptr->g_),
497-
b_(ptr->b_),
495+
: Value(ptr->pstate()),
496+
// reset on copy
497+
disp_(""),
498498
a_(ptr->a_),
499-
disp_(ptr->disp_),
500499
hash_(ptr->hash_)
501500
{ concrete_type(COLOR); }
502501

503502
bool Color::operator== (const Expression& rhs) const
504503
{
505-
if (auto r = Cast<Color>(&rhs)) {
504+
if (auto r = Cast<Color_RGBA>(&rhs)) {
505+
return *this == *r;
506+
}
507+
else if (auto r = Cast<Color_HSLA>(&rhs)) {
508+
return *this == *r;
509+
}
510+
else if (auto r = Cast<Color>(&rhs)) {
511+
return a_ == r->a();
512+
}
513+
return false;
514+
}
515+
516+
/////////////////////////////////////////////////////////////////////////
517+
/////////////////////////////////////////////////////////////////////////
518+
519+
Color_RGBA::Color_RGBA(ParserState pstate, double r, double g, double b, double a, const std::string disp)
520+
: Color(pstate, a, disp),
521+
r_(r), g_(g), b_(b)
522+
{ concrete_type(COLOR); }
523+
524+
Color_RGBA::Color_RGBA(const Color_RGBA* ptr)
525+
: Color(ptr),
526+
r_(ptr->r_),
527+
g_(ptr->g_),
528+
b_(ptr->b_)
529+
{ concrete_type(COLOR); }
530+
531+
bool Color_RGBA::operator== (const Expression& rhs) const
532+
{
533+
if (auto r = Cast<Color_RGBA>(&rhs)) {
506534
return r_ == r->r() &&
507535
g_ == r->g() &&
508536
b_ == r->b() &&
@@ -511,17 +539,140 @@ namespace Sass {
511539
return false;
512540
}
513541

514-
size_t Color::hash() const
542+
size_t Color_RGBA::hash() const
515543
{
516544
if (hash_ == 0) {
517-
hash_ = std::hash<double>()(a_);
545+
hash_ = std::hash<std::string>()("RGBA");
546+
hash_combine(hash_, std::hash<double>()(a_));
518547
hash_combine(hash_, std::hash<double>()(r_));
519548
hash_combine(hash_, std::hash<double>()(g_));
520549
hash_combine(hash_, std::hash<double>()(b_));
521550
}
522551
return hash_;
523552
}
524553

554+
Color_HSLA_Ptr Color_RGBA::toHSLA(bool copy)
555+
{
556+
557+
// Algorithm from http://en.wikipedia.org/wiki/wHSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
558+
double r = r_ / 255.0;
559+
double g = g_ / 255.0;
560+
double b = b_ / 255.0;
561+
562+
double max = std::max(r, std::max(g, b));
563+
double min = std::min(r, std::min(g, b));
564+
double delta = max - min;
565+
566+
double h = 0;
567+
double s;
568+
double l = (max + min) / 2.0;
569+
570+
if (NEAR_EQUAL(max, min)) {
571+
h = s = 0; // achromatic
572+
}
573+
else {
574+
if (l < 0.5) s = delta / (max + min);
575+
else s = delta / (2.0 - max - min);
576+
577+
if (r == max) h = (g - b) / delta + (g < b ? 6 : 0);
578+
else if (g == max) h = (b - r) / delta + 2;
579+
else if (b == max) h = (r - g) / delta + 4;
580+
}
581+
582+
// HSL hsl_struct;
583+
h = h * 60;
584+
s = s * 100;
585+
l = l * 100;
586+
587+
return SASS_MEMORY_NEW(Color_HSLA,
588+
pstate(), h, s, l, a(), ""
589+
);
590+
}
591+
592+
Color_RGBA_Ptr Color_RGBA::toRGBA(bool copy)
593+
{
594+
return copy ? SASS_MEMORY_COPY(this) : this;
595+
}
596+
597+
/////////////////////////////////////////////////////////////////////////
598+
/////////////////////////////////////////////////////////////////////////
599+
600+
Color_HSLA::Color_HSLA(ParserState pstate, double h, double s, double l, double a, const std::string disp)
601+
: Color(pstate, a, disp),
602+
h_(absmod(h, 360.0)),
603+
s_(clip(s, 0.0, 100.0)),
604+
l_(clip(l, 0.0, 100.0))
605+
// hash_(0)
606+
{ concrete_type(COLOR); }
607+
608+
Color_HSLA::Color_HSLA(const Color_HSLA* ptr)
609+
: Color(ptr),
610+
h_(ptr->h_),
611+
s_(ptr->s_),
612+
l_(ptr->l_)
613+
// hash_(ptr->hash_)
614+
{ concrete_type(COLOR); }
615+
616+
bool Color_HSLA::operator== (const Expression& rhs) const
617+
{
618+
if (auto r = Cast<Color_HSLA>(&rhs)) {
619+
return h_ == r->h() &&
620+
s_ == r->s() &&
621+
l_ == r->l() &&
622+
a_ == r->a();
623+
}
624+
return false;
625+
}
626+
627+
size_t Color_HSLA::hash() const
628+
{
629+
if (hash_ == 0) {
630+
hash_ = std::hash<std::string>()("HSLA");
631+
hash_combine(hash_, std::hash<double>()(a_));
632+
hash_combine(hash_, std::hash<double>()(h_));
633+
hash_combine(hash_, std::hash<double>()(s_));
634+
hash_combine(hash_, std::hash<double>()(l_));
635+
}
636+
return hash_;
637+
}
638+
639+
// hue to RGB helper function
640+
double h_to_rgb(double m1, double m2, double h)
641+
{
642+
h = absmod(h, 1.0);
643+
if (h*6.0 < 1) return m1 + (m2 - m1)*h*6;
644+
if (h*2.0 < 1) return m2;
645+
if (h*3.0 < 2) return m1 + (m2 - m1) * (2.0/3.0 - h)*6;
646+
return m1;
647+
}
648+
649+
Color_RGBA_Ptr Color_HSLA::toRGBA(bool copy)
650+
{
651+
652+
double h = absmod(h_ / 360.0, 1.0);
653+
double s = clip(s_ / 100.0, 0.0, 1.0);
654+
double l = clip(l_ / 100.0, 0.0, 1.0);
655+
656+
// Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
657+
double m2;
658+
if (l <= 0.5) m2 = l*(s+1.0);
659+
else m2 = (l+s)-(l*s);
660+
double m1 = (l*2.0)-m2;
661+
// round the results -- consider moving this into the Color constructor
662+
double r = (h_to_rgb(m1, m2, h + 1.0/3.0) * 255.0);
663+
double g = (h_to_rgb(m1, m2, h) * 255.0);
664+
double b = (h_to_rgb(m1, m2, h - 1.0/3.0) * 255.0);
665+
666+
return SASS_MEMORY_NEW(Color_RGBA,
667+
pstate(), r, g, b, a(), ""
668+
);
669+
}
670+
671+
Color_HSLA_Ptr Color_HSLA::toHSLA(bool copy)
672+
{
673+
return copy ? SASS_MEMORY_COPY(this) : this;
674+
}
675+
525676
/////////////////////////////////////////////////////////////////////////
526677
/////////////////////////////////////////////////////////////////////////
527678

@@ -796,7 +947,8 @@ namespace Sass {
796947
IMPLEMENT_AST_OPERATORS(Function_Call);
797948
IMPLEMENT_AST_OPERATORS(Variable);
798949
IMPLEMENT_AST_OPERATORS(Number);
799-
IMPLEMENT_AST_OPERATORS(Color);
950+
IMPLEMENT_AST_OPERATORS(Color_RGBA);
951+
IMPLEMENT_AST_OPERATORS(Color_HSLA);
800952
IMPLEMENT_AST_OPERATORS(Custom_Error);
801953
IMPLEMENT_AST_OPERATORS(Custom_Warning);
802954
IMPLEMENT_AST_OPERATORS(Boolean);

0 commit comments

Comments
 (0)