1/*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Neither the name of Google Inc. nor the names of its
11 * contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "ShadowRoot.h"
29
30#include "ContentDistributor.h"
31#include "ElementShadow.h"
32#include "HistogramSupport.h"
33#include "InsertionPoint.h"
34#include "RuntimeEnabledFeatures.h"
35#include "StyleResolver.h"
36#include "Text.h"
37#include "markup.h"
38
39namespace WebCore {
40
41struct SameSizeAsShadowRoot : public DocumentFragment, public TreeScope {
42    unsigned countersAndFlags[1];
43};
44
45COMPILE_ASSERT(sizeof(ShadowRoot) == sizeof(SameSizeAsShadowRoot), shadowroot_should_stay_small);
46
47enum ShadowRootUsageOriginType {
48    ShadowRootUsageOriginWeb = 0,
49    ShadowRootUsageOriginNotWeb,
50    ShadowRootUsageOriginMax
51};
52
53ShadowRoot::ShadowRoot(Document* document, ShadowRootType type)
54    : DocumentFragment(0, CreateShadowRoot)
55    , TreeScope(this, document)
56    , m_numberOfStyles(0)
57    , m_applyAuthorStyles(false)
58    , m_resetStyleInheritance(false)
59    , m_type(type)
60{
61    ASSERT(document);
62}
63
64ShadowRoot::~ShadowRoot()
65{
66    // We cannot let ContainerNode destructor call willBeDeletedFrom()
67    // for this ShadowRoot instance because TreeScope destructor
68    // clears Node::m_treeScope thus ContainerNode is no longer able
69    // to access it Document reference after that.
70    willBeDeletedFrom(documentInternal());
71
72    // We must remove all of our children first before the TreeScope destructor
73    // runs so we don't go through TreeScopeAdopter for each child with a
74    // destructed tree scope in each descendant.
75    removeDetachedChildren();
76
77    // We must call clearRareData() here since a ShadowRoot class inherits TreeScope
78    // as well as Node. See a comment on TreeScope.h for the reason.
79    if (hasRareData())
80        clearRareData();
81}
82
83void ShadowRoot::dispose()
84{
85    removeDetachedChildren();
86}
87
88PassRefPtr<Node> ShadowRoot::cloneNode(bool, ExceptionCode& ec)
89{
90    ec = DATA_CLONE_ERR;
91    return 0;
92}
93
94String ShadowRoot::innerHTML() const
95{
96    return createMarkup(this, ChildrenOnly);
97}
98
99void ShadowRoot::setInnerHTML(const String& markup, ExceptionCode& ec)
100{
101    if (isOrphan()) {
102        ec = INVALID_ACCESS_ERR;
103        return;
104    }
105
106    if (RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(markup, host(), AllowScriptingContent, ec))
107        replaceChildrenWithFragment(this, fragment.release(), ec);
108}
109
110bool ShadowRoot::childTypeAllowed(NodeType type) const
111{
112    switch (type) {
113    case ELEMENT_NODE:
114    case PROCESSING_INSTRUCTION_NODE:
115    case COMMENT_NODE:
116    case TEXT_NODE:
117    case CDATA_SECTION_NODE:
118    case ENTITY_REFERENCE_NODE:
119        return true;
120    default:
121        return false;
122    }
123}
124
125void ShadowRoot::recalcStyle(StyleChange change)
126{
127    // ShadowRoot doesn't support custom callbacks.
128    ASSERT(!hasCustomStyleCallbacks());
129
130    StyleResolver* styleResolver = document()->ensureStyleResolver();
131    styleResolver->pushParentShadowRoot(this);
132
133    for (Node* child = firstChild(); child; child = child->nextSibling()) {
134        if (child->isElementNode())
135            toElement(child)->recalcStyle(change);
136        else if (child->isTextNode())
137            toText(child)->recalcTextStyle(change);
138    }
139
140    styleResolver->popParentShadowRoot(this);
141    clearNeedsStyleRecalc();
142    clearChildNeedsStyleRecalc();
143}
144
145void ShadowRoot::setApplyAuthorStyles(bool value)
146{
147    if (isOrphan())
148        return;
149
150    if (m_applyAuthorStyles != value) {
151        m_applyAuthorStyles = value;
152        host()->setNeedsStyleRecalc();
153    }
154}
155
156void ShadowRoot::setResetStyleInheritance(bool value)
157{
158    if (isOrphan())
159        return;
160
161    if (value != m_resetStyleInheritance) {
162        m_resetStyleInheritance = value;
163        if (attached() && owner())
164            owner()->recalcStyle(Force);
165    }
166}
167
168void ShadowRoot::attach(const AttachContext& context)
169{
170    StyleResolver* styleResolver = document()->ensureStyleResolver();
171    styleResolver->pushParentShadowRoot(this);
172    DocumentFragment::attach(context);
173    styleResolver->popParentShadowRoot(this);
174}
175
176void ShadowRoot::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
177{
178    if (isOrphan())
179        return;
180
181    ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
182    owner()->invalidateDistribution();
183}
184
185void ShadowRoot::registerScopedHTMLStyleChild()
186{
187    ++m_numberOfStyles;
188    setHasScopedHTMLStyleChild(true);
189}
190
191void ShadowRoot::unregisterScopedHTMLStyleChild()
192{
193    ASSERT(hasScopedHTMLStyleChild() && m_numberOfStyles > 0);
194    --m_numberOfStyles;
195    setHasScopedHTMLStyleChild(m_numberOfStyles > 0);
196}
197
198}
199