1 /* 2 * Copyright (C) 2011 Adobe Systems Incorporated. All rights reserved. 3 * Copyright (C) 2012 Apple Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above 10 * copyright notice, this list of conditions and the following 11 * disclaimer. 12 * 2. Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer in the documentation and/or other materials 15 * provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 26 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "core/css/CSSGroupingRule.h" 33 34 #include "bindings/core/v8/ExceptionState.h" 35 #include "core/css/CSSRuleList.h" 36 #include "core/css/CSSStyleSheet.h" 37 #include "core/css/parser/CSSParser.h" 38 #include "core/dom/ExceptionCode.h" 39 #include "core/frame/UseCounter.h" 40 #include "wtf/text/StringBuilder.h" 41 42 namespace blink { 43 44 CSSGroupingRule::CSSGroupingRule(StyleRuleGroup* groupRule, CSSStyleSheet* parent) 45 : CSSRule(parent) 46 , m_groupRule(groupRule) 47 , m_childRuleCSSOMWrappers(groupRule->childRules().size()) 48 { 49 } 50 51 CSSGroupingRule::~CSSGroupingRule() 52 { 53 #if !ENABLE(OILPAN) 54 ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size()); 55 for (unsigned i = 0; i < m_childRuleCSSOMWrappers.size(); ++i) { 56 if (m_childRuleCSSOMWrappers[i]) 57 m_childRuleCSSOMWrappers[i]->setParentRule(0); 58 } 59 #endif 60 } 61 62 unsigned CSSGroupingRule::insertRule(const String& ruleString, unsigned index, ExceptionState& exceptionState) 63 { 64 ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size()); 65 66 if (index > m_groupRule->childRules().size()) { 67 exceptionState.throwDOMException(IndexSizeError, "the index " + String::number(index) + " must be less than or equal to the length of the rule list."); 68 return 0; 69 } 70 71 CSSStyleSheet* styleSheet = parentStyleSheet(); 72 CSSParserContext context(parserContext(), UseCounter::getFrom(styleSheet)); 73 RefPtrWillBeRawPtr<StyleRuleBase> newRule = CSSParser::parseRule(context, styleSheet ? styleSheet->contents() : 0, ruleString); 74 if (!newRule) { 75 exceptionState.throwDOMException(SyntaxError, "the rule '" + ruleString + "' is invalid and cannot be parsed."); 76 return 0; 77 } 78 79 if (newRule->isImportRule()) { 80 // FIXME: an HierarchyRequestError should also be thrown for a @charset or a nested 81 // @media rule. They are currently not getting parsed, resulting in a SyntaxError 82 // to get raised above. 83 exceptionState.throwDOMException(HierarchyRequestError, "'@import' rules cannot be inserted inside a group rule."); 84 return 0; 85 } 86 CSSStyleSheet::RuleMutationScope mutationScope(this); 87 88 m_groupRule->wrapperInsertRule(index, newRule); 89 90 m_childRuleCSSOMWrappers.insert(index, RefPtrWillBeMember<CSSRule>(nullptr)); 91 return index; 92 } 93 94 void CSSGroupingRule::deleteRule(unsigned index, ExceptionState& exceptionState) 95 { 96 ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size()); 97 98 if (index >= m_groupRule->childRules().size()) { 99 exceptionState.throwDOMException(IndexSizeError, "the index " + String::number(index) + " is greated than the length of the rule list."); 100 return; 101 } 102 103 CSSStyleSheet::RuleMutationScope mutationScope(this); 104 105 m_groupRule->wrapperRemoveRule(index); 106 107 if (m_childRuleCSSOMWrappers[index]) 108 m_childRuleCSSOMWrappers[index]->setParentRule(0); 109 m_childRuleCSSOMWrappers.remove(index); 110 } 111 112 void CSSGroupingRule::appendCSSTextForItems(StringBuilder& result) const 113 { 114 unsigned size = length(); 115 for (unsigned i = 0; i < size; ++i) { 116 result.appendLiteral(" "); 117 result.append(item(i)->cssText()); 118 result.append('\n'); 119 } 120 } 121 122 unsigned CSSGroupingRule::length() const 123 { 124 return m_groupRule->childRules().size(); 125 } 126 127 CSSRule* CSSGroupingRule::item(unsigned index) const 128 { 129 if (index >= length()) 130 return 0; 131 ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size()); 132 RefPtrWillBeMember<CSSRule>& rule = m_childRuleCSSOMWrappers[index]; 133 if (!rule) 134 rule = m_groupRule->childRules()[index]->createCSSOMWrapper(const_cast<CSSGroupingRule*>(this)); 135 return rule.get(); 136 } 137 138 CSSRuleList* CSSGroupingRule::cssRules() const 139 { 140 if (!m_ruleListCSSOMWrapper) 141 m_ruleListCSSOMWrapper = LiveCSSRuleList<CSSGroupingRule>::create(const_cast<CSSGroupingRule*>(this)); 142 return m_ruleListCSSOMWrapper.get(); 143 } 144 145 void CSSGroupingRule::reattach(StyleRuleBase* rule) 146 { 147 ASSERT(rule); 148 m_groupRule = static_cast<StyleRuleGroup*>(rule); 149 for (unsigned i = 0; i < m_childRuleCSSOMWrappers.size(); ++i) { 150 if (m_childRuleCSSOMWrappers[i]) 151 m_childRuleCSSOMWrappers[i]->reattach(m_groupRule->childRules()[i].get()); 152 } 153 } 154 155 void CSSGroupingRule::trace(Visitor* visitor) 156 { 157 CSSRule::trace(visitor); 158 #if ENABLE(OILPAN) 159 visitor->trace(m_childRuleCSSOMWrappers); 160 #endif 161 visitor->trace(m_groupRule); 162 visitor->trace(m_ruleListCSSOMWrapper); 163 } 164 165 } // namespace blink 166