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 42namespace blink { 43 44CSSGroupingRule::CSSGroupingRule(StyleRuleGroup* groupRule, CSSStyleSheet* parent) 45 : CSSRule(parent) 46 , m_groupRule(groupRule) 47 , m_childRuleCSSOMWrappers(groupRule->childRules().size()) 48{ 49} 50 51CSSGroupingRule::~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 62unsigned 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 94void 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 112void 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 122unsigned CSSGroupingRule::length() const 123{ 124 return m_groupRule->childRules().size(); 125} 126 127CSSRule* 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 138CSSRuleList* 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 145void 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 155void 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