blob: edf397a379100bde16c4ce7cbff05b3dcdd13342 [file] [log] [blame]
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cobalt/cssom/selector_tree.h"
#include "cobalt/cssom/complex_selector.h"
#include "cobalt/cssom/compound_selector.h"
#include "cobalt/cssom/css_style_rule.h"
namespace cobalt {
namespace cssom {
bool SelectorTree::CompoundNodeLessThan::operator()(
const CompoundSelector* lhs, const CompoundSelector* rhs) const {
return *lhs < *rhs;
}
SelectorTree::Node::Node()
: combinator_mask_(0),
compound_selector_(NULL),
selector_mask_(0),
pseudo_class_mask_(0) {}
SelectorTree::Node::Node(CompoundSelector* compound_selector,
Specificity parent_specificity)
: combinator_mask_(0),
compound_selector_(compound_selector),
cumulative_specificity_(parent_specificity),
selector_mask_(0),
pseudo_class_mask_(0) {
cumulative_specificity_.AddFrom(compound_selector_->GetSpecificity());
}
void SelectorTree::AppendRule(CSSStyleRule* rule) {
for (Selectors::const_iterator it = rule->selectors().begin();
it != rule->selectors().end(); ++it) {
DCHECK((*it)->AsComplexSelector());
Node* node = GetOrCreateNodeForComplexSelector((*it)->AsComplexSelector());
node->rules().push_back(base::AsWeakPtr(rule));
}
}
void SelectorTree::RemoveRule(CSSStyleRule* rule) {
for (Selectors::const_iterator it = rule->selectors().begin();
it != rule->selectors().end(); ++it) {
DCHECK((*it)->AsComplexSelector());
Node* node = GetOrCreateNodeForComplexSelector((*it)->AsComplexSelector());
for (Rules::iterator remove_it = node->rules().begin();
remove_it != node->rules().end(); ++remove_it) {
if (*remove_it == rule) {
node->rules().erase(remove_it);
break;
}
}
}
}
const SelectorTree::OwnedNodes& SelectorTree::children(
const Node* node, CombinatorType combinator) {
return owned_nodes_map_[std::make_pair(node, combinator)];
}
SelectorTree::Node* SelectorTree::GetOrCreateNodeForComplexSelector(
ComplexSelector* complex_selector) {
CompoundSelector* selector = complex_selector->first_selector();
Node* node = GetOrCreateNodeForCompoundSelector(selector, &root_,
kDescendantCombinator);
while (selector->right_combinator()) {
Combinator* combinator = selector->right_combinator();
selector = combinator->right_selector();
node = GetOrCreateNodeForCompoundSelector(selector, node,
combinator->GetCombinatorType());
}
return node;
}
SelectorTree::Node* SelectorTree::GetOrCreateNodeForCompoundSelector(
CompoundSelector* compound_selector, Node* parent_node,
CombinatorType combinator) {
if (combinator == kNextSiblingCombinator ||
combinator == kFollowingSiblingCombinator) {
has_sibling_combinators_ = true;
}
OwnedNodes& owned_nodes =
owned_nodes_map_[std::make_pair(parent_node, combinator)];
OwnedNodes::iterator child_node_it = owned_nodes.find(compound_selector);
if (child_node_it != owned_nodes.end()) {
return child_node_it->second;
}
Node* child_node =
new Node(compound_selector, parent_node->cumulative_specificity());
parent_node->combinator_mask_ |= (1 << combinator);
owned_nodes[compound_selector] = child_node;
(*compound_selector->simple_selectors().begin())
->IndexSelectorTreeNode(parent_node, child_node, combinator);
return child_node;
}
} // namespace cssom
} // namespace cobalt