Skip to content

Commit

Permalink
Implement media query merging when bubbling
Browse files Browse the repository at this point in the history
  • Loading branch information
xzyfer committed Jan 5, 2015
1 parent bf98127 commit ca88350
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 5 deletions.
3 changes: 3 additions & 0 deletions ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ namespace Sass {
// needed for rearranging nested rulesets during CSS emission
virtual bool is_hoistable() { return false; }
virtual bool is_invisible() { return false; }
virtual bool bubbles() { return false; }
virtual Block* block() { return 0; }
};
inline Statement::~Statement() { }
Expand Down Expand Up @@ -361,6 +362,7 @@ namespace Sass {
Bubble(string path, Position position, Statement* n, Statement* g = 0, size_t t = 0)
: Statement(path, position), node_(n), group_end_(g), tabs_(t)
{ statement_type(BUBBLE); }
bool bubbles() { return true; }
ATTACH_OPERATIONS();
};

Expand All @@ -378,6 +380,7 @@ namespace Sass {
Media_Block(string path, Position position, List* mqs, Block* b, Selector* s)
: Has_Block(path, position, b), media_queries_(mqs), selector_(s)
{ statement_type(MEDIA); }
bool bubbles() { return true; }
bool is_hoistable() { return true; }
bool is_invisible() {
bool is_invisible = true;
Expand Down
109 changes: 106 additions & 3 deletions cssize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ namespace Sass {
return bb;
}

Statement* Cssize::operator()(Ruleset* r)
{
p_stack.push_back(r);
Ruleset* rr = new (ctx.mem) Ruleset(r->path(),
r->position(),
r->selector(),
r->block()->perform(this)->block());
p_stack.pop_back();

return rr;
}

Statement* Cssize::operator()(Media_Block* m)
{
if (parent()->statement_type() == Statement::MEDIA)
Expand All @@ -51,6 +63,11 @@ namespace Sass {
return debubble(mm->block(), mm)->block();
}

bool Cssize::bubblable(Statement* s)
{
return s->statement_type() == Statement::RULESET || s->bubbles();
}

Statement* Cssize::flatten(Statement* s)
{
Block* bb = s->block();
Expand Down Expand Up @@ -103,7 +120,10 @@ namespace Sass {
Block* slice = baz[i].second;

if (!is_bubble) {
if (!previous_parent) {
if (!parent) {
*result << slice;
}
else if (!previous_parent) {
previous_parent = static_cast<Has_Block*>(parent);

Has_Block* new_parent = static_cast<Has_Block*>(parent);
Expand All @@ -122,8 +142,20 @@ namespace Sass {
for (size_t j = 0, K = slice->length(); j < K; ++j)
{
Statement* ss = 0;
if ((*slice)[j]->statement_type() == Statement::BUBBLE) {
ss = static_cast<Bubble*>((*slice)[j])->node();
Bubble* b = static_cast<Bubble*>((*slice)[j]);

if (!parent ||
b->node()->statement_type() != Statement::MEDIA ||
static_cast<Media_Block*>(b->node())->media_queries() == static_cast<Media_Block*>(parent)->media_queries())
{
ss = b->node();
}
else
{
List* mq = merge_media_queries(static_cast<Media_Block*>(b->node()), static_cast<Media_Block*>(parent));
if (!mq->length()) continue;
static_cast<Media_Block*>(b->node())->media_queries(mq);
ss = b->node();
}

if (!ss) continue;
Expand Down Expand Up @@ -162,4 +194,75 @@ namespace Sass {
}
}
}

List* Cssize::merge_media_queries(Media_Block* m1, Media_Block* m2)
{
List* qq = new (ctx.mem) List(m1->media_queries()->path(),
m1->media_queries()->position(),
m1->media_queries()->length());

for (size_t i = 0, L = m1->media_queries()->length(); i < L; i++) {
for (size_t j = 0, K = m2->media_queries()->length(); j < K; j++) {
Media_Query* mq1 = static_cast<Media_Query*>((*m1->media_queries())[i]);
Media_Query* mq2 = static_cast<Media_Query*>((*m2->media_queries())[j]);
Media_Query* mq = merge_media_query(mq1, mq2);

if (mq) *qq << mq;
}
}

return qq;
}


Media_Query* Cssize::merge_media_query(Media_Query* mq1, Media_Query* mq2)
{
To_String to_string;

string type;
string mod;

string m1 = string(mq1->is_restricted() ? "only" : mq1->is_negated() ? "not" : "");
string t1 = mq1->media_type() ? mq1->media_type()->perform(&to_string) : "";
string m2 = string(mq2->is_restricted() ? "only" : mq1->is_negated() ? "not" : "");
string t2 = mq2->media_type() ? mq2->media_type()->perform(&to_string) : "";


if (t1.empty()) t1 = t2;
if (t2.empty()) t2 = t1;

if ((m1 == "not") ^ (m2 == "not")) {
if (t1 == t2) {
return 0;
}
type = m1 == "not" ? t2 : t1;
mod = m1 == "not" ? m2 : m1;
}
else if (m1 == "not" && m2 == "not") {
if (t1 != t2) {
return 0;
}
type = t1;
mod = "not";
}
else if (t1 != t2) {
return 0;
} else {
type = t1;
mod = m1.empty() ? m2 : m1;
}

Media_Query* mm = new (ctx.mem) Media_Query(
mq1->path(), mq1->position(), 0,
mq1->length() + mq2->length(), mod == "not", mod == "only"
);

if (!type.empty()) {
mm->media_type(new (ctx.mem) String_Constant(mq1->path(), mq1->position(), type));
}

*mm += mq2;
*mm += mq1;
return mm;
}
}
8 changes: 6 additions & 2 deletions cssize.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ namespace Sass {
using Operation<Statement*>::operator();

Statement* operator()(Block*);
// Statement* operator()(Ruleset*);
Statement* operator()(Ruleset*);
// Statement* operator()(Propset*);
// Statement* operator()(Bubble*);
Statement* operator()(Media_Block*);
Expand All @@ -63,8 +63,12 @@ namespace Sass {

Statement* parent();
vector<pair<bool, Block*>> slice_by_bubble(Statement*);
Statement* debubble(Block*, Statement*);
Statement* debubble(Block* children, Statement* parent = 0);
Statement* flatten(Statement*);
bool bubblable(Statement*);

List* merge_media_queries(Media_Block*, Media_Block*);
Media_Query* merge_media_query(Media_Query*, Media_Query*);

template <typename U>
Statement* fallback(U x) { return fallback_impl(x); }
Expand Down

0 comments on commit ca88350

Please sign in to comment.