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
33#include "CSSGroupingRule.h"
34
35#include "CSSParser.h"
36#include "CSSRuleList.h"
37#include "CSSStyleSheet.h"
38#include "ExceptionCode.h"
39#include "StyleRule.h"
40#include <wtf/text/StringBuilder.h>
41
42namespace WebCore {
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    ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size());
54    for (unsigned i = 0; i < m_childRuleCSSOMWrappers.size(); ++i) {
55        if (m_childRuleCSSOMWrappers[i])
56            m_childRuleCSSOMWrappers[i]->setParentRule(0);
57    }
58}
59
60unsigned CSSGroupingRule::insertRule(const String& ruleString, unsigned index, ExceptionCode& ec)
61{
62    ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size());
63
64    if (index > m_groupRule->childRules().size()) {
65        // INDEX_SIZE_ERR: Raised if the specified index is not a valid insertion point.
66        ec = INDEX_SIZE_ERR;
67        return 0;
68    }
69
70    CSSParser parser(parserContext());
71    CSSStyleSheet* styleSheet = parentStyleSheet();
72    RefPtr<StyleRuleBase> newRule = parser.parseRule(styleSheet ? styleSheet->contents() : 0, ruleString);
73    if (!newRule) {
74        // SYNTAX_ERR: Raised if the specified rule has a syntax error and is unparsable.
75        ec = SYNTAX_ERR;
76        return 0;
77    }
78
79    if (newRule->isImportRule()) {
80        // FIXME: an HIERARCHY_REQUEST_ERR should also be thrown for a @charset or a nested
81        // @media rule. They are currently not getting parsed, resulting in a SYNTAX_ERR
82        // to get raised above.
83
84        // HIERARCHY_REQUEST_ERR: Raised if the rule cannot be inserted at the specified
85        // index, e.g., if an @import rule is inserted after a standard rule set or other
86        // at-rule.
87        ec = HIERARCHY_REQUEST_ERR;
88        return 0;
89    }
90    CSSStyleSheet::RuleMutationScope mutationScope(this);
91
92    m_groupRule->wrapperInsertRule(index, newRule);
93
94    m_childRuleCSSOMWrappers.insert(index, RefPtr<CSSRule>());
95    return index;
96}
97
98void CSSGroupingRule::deleteRule(unsigned index, ExceptionCode& ec)
99{
100    ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size());
101
102    if (index >= m_groupRule->childRules().size()) {
103        // INDEX_SIZE_ERR: Raised if the specified index does not correspond to a
104        // rule in the media rule list.
105        ec = INDEX_SIZE_ERR;
106        return;
107    }
108
109    CSSStyleSheet::RuleMutationScope mutationScope(this);
110
111    m_groupRule->wrapperRemoveRule(index);
112
113    if (m_childRuleCSSOMWrappers[index])
114        m_childRuleCSSOMWrappers[index]->setParentRule(0);
115    m_childRuleCSSOMWrappers.remove(index);
116}
117
118void CSSGroupingRule::appendCssTextForItems(StringBuilder& result) const
119{
120    unsigned size = length();
121    for (unsigned i = 0; i < size; ++i) {
122        result.appendLiteral("  ");
123        result.append(item(i)->cssText());
124        result.append('\n');
125    }
126}
127
128unsigned CSSGroupingRule::length() const
129{
130    return m_groupRule->childRules().size();
131}
132
133CSSRule* CSSGroupingRule::item(unsigned index) const
134{
135    if (index >= length())
136        return 0;
137    ASSERT(m_childRuleCSSOMWrappers.size() == m_groupRule->childRules().size());
138    RefPtr<CSSRule>& rule = m_childRuleCSSOMWrappers[index];
139    if (!rule)
140        rule = m_groupRule->childRules()[index]->createCSSOMWrapper(const_cast<CSSGroupingRule*>(this));
141    return rule.get();
142}
143
144CSSRuleList* CSSGroupingRule::cssRules() const
145{
146    if (!m_ruleListCSSOMWrapper)
147        m_ruleListCSSOMWrapper = adoptPtr(new LiveCSSRuleList<CSSGroupingRule>(const_cast<CSSGroupingRule*>(this)));
148    return m_ruleListCSSOMWrapper.get();
149}
150
151void CSSGroupingRule::reattach(StyleRuleBase* rule)
152{
153    ASSERT(rule);
154    m_groupRule = static_cast<StyleRuleGroup*>(rule);
155    for (unsigned i = 0; i < m_childRuleCSSOMWrappers.size(); ++i) {
156        if (m_childRuleCSSOMWrappers[i])
157            m_childRuleCSSOMWrappers[i]->reattach(m_groupRule->childRules()[i].get());
158    }
159}
160
161} // namespace WebCore
162