1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 2004-2005 Allan Sandfeld Jensen (kde@carewolf.com)
4  * Copyright (C) 2006, 2007 Nicholas Shanks (webkit@nickshanks.com)
5  * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc.
6  * All rights reserved.
7  * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
8  * Copyright (C) 2007, 2008 Eric Seidel <eric@webkit.org>
9  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
10  * (http://www.torchmobile.com/)
11  * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
12  * Copyright (C) Research In Motion Limited 2011. All rights reserved.
13  * Copyright (C) 2012 Google Inc. All rights reserved.
14  *
15  * This library is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU Library General Public
17  * License as published by the Free Software Foundation; either
18  * version 2 of the License, or (at your option) any later version.
19  *
20  * This library is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * Library General Public License for more details.
24  *
25  * You should have received a copy of the GNU Library General Public License
26  * along with this library; see the file COPYING.LIB.  If not, write to
27  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
28  * Boston, MA 02110-1301, USA.
29  */
30 
31 #include "third_party/blink/renderer/core/css/page_rule_collector.h"
32 
33 #include <algorithm>
34 #include "third_party/blink/renderer/core/css/css_property_value_set.h"
35 #include "third_party/blink/renderer/core/css/style_rule.h"
36 #include "third_party/blink/renderer/core/style/computed_style.h"
37 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
38 
39 namespace blink {
40 
ComparePageRules(const StyleRulePage * r1,const StyleRulePage * r2)41 static inline bool ComparePageRules(const StyleRulePage* r1,
42                                     const StyleRulePage* r2) {
43   return r1->Selector()->Specificity() < r2->Selector()->Specificity();
44 }
45 
IsLeftPage(const ComputedStyle * root_element_style,uint32_t page_index) const46 bool PageRuleCollector::IsLeftPage(const ComputedStyle* root_element_style,
47                                    uint32_t page_index) const {
48   bool is_first_page_left = false;
49   DCHECK(root_element_style);
50   if (!root_element_style->IsLeftToRightDirection())
51     is_first_page_left = true;
52 
53   return (page_index + (is_first_page_left ? 1 : 0)) % 2;
54 }
55 
IsFirstPage(uint32_t page_index) const56 bool PageRuleCollector::IsFirstPage(uint32_t page_index) const {
57   // FIXME: In case of forced left/right page, page at index 1 (not 0) can be
58   // the first page.
59   return (!page_index);
60 }
61 
PageRuleCollector(const ComputedStyle * root_element_style,uint32_t page_index,const AtomicString & page_name,MatchResult & match_result)62 PageRuleCollector::PageRuleCollector(const ComputedStyle* root_element_style,
63                                      uint32_t page_index,
64                                      const AtomicString& page_name,
65                                      MatchResult& match_result)
66     : is_left_page_(IsLeftPage(root_element_style, page_index)),
67       is_first_page_(IsFirstPage(page_index)),
68       page_name_(page_name),
69       result_(match_result) {}
70 
MatchPageRules(RuleSet * rules)71 void PageRuleCollector::MatchPageRules(RuleSet* rules) {
72   if (!rules)
73     return;
74 
75   rules->CompactRulesIfNeeded();
76   HeapVector<Member<StyleRulePage>> matched_page_rules;
77   MatchPageRulesForList(matched_page_rules, rules->PageRules());
78   if (matched_page_rules.IsEmpty())
79     return;
80 
81   std::stable_sort(matched_page_rules.begin(), matched_page_rules.end(),
82                    ComparePageRules);
83 
84   for (unsigned i = 0; i < matched_page_rules.size(); i++)
85     result_.AddMatchedProperties(&matched_page_rules[i]->Properties());
86 }
87 
CheckPageSelectorComponents(const CSSSelector * selector,bool is_left_page,bool is_first_page,const AtomicString & page_name)88 static bool CheckPageSelectorComponents(const CSSSelector* selector,
89                                         bool is_left_page,
90                                         bool is_first_page,
91                                         const AtomicString& page_name) {
92   for (const CSSSelector* component = selector; component;
93        component = component->TagHistory()) {
94     if (component->Match() == CSSSelector::kTag) {
95       const AtomicString& local_name = component->TagQName().LocalName();
96       DCHECK_NE(local_name, CSSSelector::UniversalSelectorAtom());
97       if (local_name != page_name)
98         return false;
99     }
100 
101     CSSSelector::PseudoType pseudo_type = component->GetPseudoType();
102     if ((pseudo_type == CSSSelector::kPseudoLeftPage && !is_left_page) ||
103         (pseudo_type == CSSSelector::kPseudoRightPage && is_left_page) ||
104         (pseudo_type == CSSSelector::kPseudoFirstPage && !is_first_page)) {
105       return false;
106     }
107   }
108   return true;
109 }
110 
MatchPageRulesForList(HeapVector<Member<StyleRulePage>> & matched_rules,const HeapVector<Member<StyleRulePage>> & rules)111 void PageRuleCollector::MatchPageRulesForList(
112     HeapVector<Member<StyleRulePage>>& matched_rules,
113     const HeapVector<Member<StyleRulePage>>& rules) {
114   for (unsigned i = 0; i < rules.size(); ++i) {
115     StyleRulePage* rule = rules[i];
116 
117     if (!CheckPageSelectorComponents(rule->Selector(), is_left_page_,
118                                      is_first_page_, page_name_))
119       continue;
120 
121     // If the rule has no properties to apply, then ignore it.
122     const CSSPropertyValueSet& properties = rule->Properties();
123     if (properties.IsEmpty())
124       continue;
125 
126     // Add this rule to our list of matched rules.
127     matched_rules.push_back(rule);
128   }
129 }
130 
131 }  // namespace blink
132