1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 2004-2005 Allan Sandfeld Jensen (kde (at) carewolf.com) 4 * Copyright (C) 2006, 2007 Nicholas Shanks (webkit (at) nickshanks.com) 5 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. 6 * Copyright (C) 2007 Alexey Proskuryakov <ap (at) webkit.org> 7 * Copyright (C) 2007, 2008 Eric Seidel <eric (at) webkit.org> 8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 9 * Copyright (c) 2011, Code Aurora Forum. All rights reserved. 10 * Copyright (C) Research In Motion Limited 2011. All rights reserved. 11 * Copyright (C) 2013 Google Inc. All rights reserved. 12 * 13 * This library is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU Library General Public 15 * License as published by the Free Software Foundation; either 16 * version 2 of the License, or (at your option) any later version. 17 * 18 * This library is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 * Library General Public License for more details. 22 * 23 * You should have received a copy of the GNU Library General Public License 24 * along with this library; see the file COPYING.LIB. If not, write to 25 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 26 * Boston, MA 02110-1301, USA. 27 */ 28 29 #include "config.h" 30 #include "core/css/TreeBoundaryCrossingRules.h" 31 32 #include "core/css/ElementRuleCollector.h" 33 #include "core/css/RuleFeature.h" 34 #include "core/dom/StyleEngine.h" 35 #include "core/dom/shadow/ShadowRoot.h" 36 37 namespace blink { 38 39 static void addRules(RuleSet* ruleSet, const WillBeHeapVector<MinimalRuleData>& rules) 40 { 41 for (unsigned i = 0; i < rules.size(); ++i) { 42 const MinimalRuleData& info = rules[i]; 43 ruleSet->addRule(info.m_rule, info.m_selectorIndex, info.m_flags); 44 } 45 } 46 47 void TreeBoundaryCrossingRules::addTreeBoundaryCrossingRules(const RuleSet& authorRules, CSSStyleSheet* parentStyleSheet, unsigned parentIndex, ContainerNode& scopingNode) 48 { 49 if (authorRules.treeBoundaryCrossingRules().isEmpty() && (scopingNode.isDocumentNode() || authorRules.shadowDistributedRules().isEmpty())) 50 return; 51 OwnPtrWillBeRawPtr<RuleSet> ruleSetForScope = RuleSet::create(); 52 addRules(ruleSetForScope.get(), authorRules.treeBoundaryCrossingRules()); 53 if (!scopingNode.isDocumentNode()) 54 addRules(ruleSetForScope.get(), authorRules.shadowDistributedRules()); 55 56 if (!m_treeBoundaryCrossingRuleSetMap.contains(&scopingNode)) { 57 m_treeBoundaryCrossingRuleSetMap.add(&scopingNode, adoptPtrWillBeNoop(new CSSStyleSheetRuleSubSet())); 58 m_scopingNodes.add(&scopingNode); 59 } 60 CSSStyleSheetRuleSubSet* ruleSubSet = m_treeBoundaryCrossingRuleSetMap.get(&scopingNode); 61 ruleSubSet->append(RuleSubSet::create(parentStyleSheet, parentIndex, ruleSetForScope.release())); 62 } 63 64 void TreeBoundaryCrossingRules::collectTreeBoundaryCrossingRules(Element* element, ElementRuleCollector& collector, bool includeEmptyRules) 65 { 66 if (m_treeBoundaryCrossingRuleSetMap.isEmpty()) 67 return; 68 69 RuleRange ruleRange = collector.matchedResult().ranges.authorRuleRange(); 70 71 // When comparing rules declared in outer treescopes, outer's rules win. 72 CascadeOrder outerCascadeOrder = size() + size(); 73 // When comparing rules declared in inner treescopes, inner's rules win. 74 CascadeOrder innerCascadeOrder = size(); 75 76 for (DocumentOrderedList::iterator it = m_scopingNodes.begin(); it != m_scopingNodes.end(); ++it) { 77 const ContainerNode* scopingNode = toContainerNode(*it); 78 CSSStyleSheetRuleSubSet* ruleSubSet = m_treeBoundaryCrossingRuleSetMap.get(scopingNode); 79 bool isInnerTreeScope = element->treeScope().isInclusiveAncestorOf(scopingNode->treeScope()); 80 81 CascadeOrder cascadeOrder = isInnerTreeScope ? innerCascadeOrder : outerCascadeOrder; 82 for (CSSStyleSheetRuleSubSet::iterator it = ruleSubSet->begin(); it != ruleSubSet->end(); ++it) { 83 MatchRequest request((*it)->ruleSet.get(), includeEmptyRules, scopingNode, (*it)->parentStyleSheet, (*it)->parentIndex); 84 collector.collectMatchingRules(request, ruleRange, SelectorChecker::ScopeContainsLastMatchedElement, ignoreCascadeScope, cascadeOrder, true); 85 } 86 ++innerCascadeOrder; 87 --outerCascadeOrder; 88 } 89 } 90 91 void TreeBoundaryCrossingRules::reset(const ContainerNode* scopingNode) 92 { 93 m_treeBoundaryCrossingRuleSetMap.remove(scopingNode); 94 m_scopingNodes.remove(scopingNode); 95 } 96 97 void TreeBoundaryCrossingRules::collectFeaturesFromRuleSubSet(CSSStyleSheetRuleSubSet* ruleSubSet, RuleFeatureSet& features) 98 { 99 for (CSSStyleSheetRuleSubSet::iterator it = ruleSubSet->begin(); it != ruleSubSet->end(); ++it) 100 features.add((*it)->ruleSet->features()); 101 } 102 103 void TreeBoundaryCrossingRules::collectFeaturesTo(RuleFeatureSet& features) 104 { 105 for (TreeBoundaryCrossingRuleSetMap::iterator::Values it = m_treeBoundaryCrossingRuleSetMap.values().begin(); it != m_treeBoundaryCrossingRuleSetMap.values().end(); ++it) 106 collectFeaturesFromRuleSubSet(it->get(), features); 107 } 108 109 void TreeBoundaryCrossingRules::trace(Visitor* visitor) 110 { 111 #if ENABLE(OILPAN) 112 visitor->trace(m_treeBoundaryCrossingRuleSetMap); 113 visitor->trace(m_scopingNodes); 114 #endif 115 } 116 117 void TreeBoundaryCrossingRules::RuleSubSet::trace(Visitor* visitor) 118 { 119 visitor->trace(ruleSet); 120 } 121 122 } // namespace blink 123