| // Copyright 2015 The Cobalt Authors. 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/compound_selector.h" | |
| #include <algorithm> | |
| #include <memory> | |
| #include <utility> | |
| #include "cobalt/cssom/pseudo_element.h" | |
| #include "cobalt/cssom/selector_visitor.h" | |
| namespace cobalt { | |
| namespace cssom { | |
| namespace { | |
| bool SimpleSelectorsLessThan(const std::unique_ptr<SimpleSelector>& lhs, | |
| const std::unique_ptr<SimpleSelector>& rhs) { | |
| if (lhs->type() < rhs->type()) { | |
| return true; | |
| } | |
| if (rhs->type() < lhs->type()) { | |
| return false; | |
| } | |
| if (lhs->text() < rhs->text()) { | |
| return true; | |
| } | |
| if (rhs->text() < lhs->text()) { | |
| return false; | |
| } | |
| if (lhs->value() < rhs->value()) { | |
| return true; | |
| } | |
| if (rhs->value() < lhs->value()) { | |
| return false; | |
| } | |
| // Pseudo class selectors may contain compound selectors, which also need to | |
| // be compared. | |
| if (lhs->type() == kPseudoClass) { | |
| CompoundSelector* lhs_compound_selector = | |
| lhs->GetContainedCompoundSelector(); | |
| CompoundSelector* rhs_compound_selector = | |
| rhs->GetContainedCompoundSelector(); | |
| if (lhs_compound_selector && rhs_compound_selector) { | |
| if (*lhs_compound_selector < *rhs_compound_selector) { | |
| return true; | |
| } | |
| if (*rhs_compound_selector < *lhs_compound_selector) { | |
| return false; | |
| } | |
| } else if (rhs_compound_selector) { | |
| return true; | |
| } else if (lhs_compound_selector) { | |
| return false; | |
| } | |
| } | |
| return false; | |
| } | |
| } // namespace | |
| CompoundSelector::CompoundSelector() | |
| : left_combinator_(NULL), | |
| has_pseudo_element_(false), | |
| requires_rule_matching_verification_visit_(false) {} | |
| CompoundSelector::~CompoundSelector() {} | |
| bool CompoundSelector::operator<(const CompoundSelector& that) const { | |
| if (simple_selectors_.size() < that.simple_selectors_.size()) { | |
| return true; | |
| } | |
| if (that.simple_selectors_.size() < simple_selectors_.size()) { | |
| return false; | |
| } | |
| for (size_t i = 0; i < simple_selectors_.size(); ++i) { | |
| if (SimpleSelectorsLessThan(simple_selectors_[i], | |
| that.simple_selectors_[i])) { | |
| return true; | |
| } | |
| if (SimpleSelectorsLessThan(that.simple_selectors_[i], | |
| simple_selectors_[i])) { | |
| return false; | |
| } | |
| } | |
| return false; | |
| } | |
| void CompoundSelector::Accept(SelectorVisitor* visitor) { | |
| visitor->VisitCompoundSelector(this); | |
| } | |
| void CompoundSelector::AppendSelector( | |
| std::unique_ptr<SimpleSelector> simple_selector) { | |
| specificity_.AddFrom(simple_selector->GetSpecificity()); | |
| has_pseudo_element_ = | |
| has_pseudo_element_ || simple_selector->AsPseudoElement() != NULL; | |
| // There are two cases where the selectors require a visit: | |
| // 1. There are multiple selectors. Gathering only tests against the first | |
| // selector and the later selectors must also be verified to match. | |
| // 2. The single selector's AlwaysRequiresRuleMatchingVerificationVisit() call | |
| // returns true. This indicates that being gathered as a candidate is not | |
| // sufficient to prove a match and that additional verification checks are | |
| // required. | |
| requires_rule_matching_verification_visit_ = | |
| requires_rule_matching_verification_visit_ || | |
| !simple_selectors_.empty() || | |
| simple_selector->AlwaysRequiresRuleMatchingVerificationVisit(); | |
| // Insert the new selector in sorted order. | |
| auto pos = | |
| std::lower_bound(simple_selectors_.begin(), simple_selectors_.end(), | |
| simple_selector, SimpleSelectorsLessThan); | |
| simple_selectors_.insert(pos, std::move(simple_selector)); | |
| } | |
| void CompoundSelector::set_right_combinator( | |
| std::unique_ptr<Combinator> combinator) { | |
| right_combinator_ = std::move(combinator); | |
| } | |
| } // namespace cssom | |
| } // namespace cobalt |