Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / Source / core / dom / shadow / ElementShadow.cpp
blob7dd2fc7da5661c7d45a1b0bf0ca56287746e3772
1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
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.
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.
27 #include "config.h"
28 #include "core/dom/shadow/ElementShadow.h"
30 #include "core/css/StyleSheetList.h"
31 #include "core/dom/ElementTraversal.h"
32 #include "core/dom/NodeTraversal.h"
33 #include "core/dom/shadow/DistributedNodes.h"
34 #include "core/frame/UseCounter.h"
35 #include "core/html/HTMLContentElement.h"
36 #include "core/html/HTMLShadowElement.h"
37 #include "core/inspector/InspectorInstrumentation.h"
38 #include "platform/EventDispatchForbiddenScope.h"
39 #include "platform/ScriptForbiddenScope.h"
41 namespace blink {
43 class DistributionPool final {
44 STACK_ALLOCATED();
45 public:
46 explicit DistributionPool(const ContainerNode&);
47 void clear();
48 ~DistributionPool();
49 void distributeTo(InsertionPoint*, ElementShadow*);
50 void populateChildren(const ContainerNode&);
52 private:
53 void detachNonDistributedNodes();
54 WillBeHeapVector<RawPtrWillBeMember<Node>, 32> m_nodes;
55 Vector<bool, 32> m_distributed;
58 inline DistributionPool::DistributionPool(const ContainerNode& parent)
60 populateChildren(parent);
63 inline void DistributionPool::clear()
65 detachNonDistributedNodes();
66 m_nodes.clear();
67 m_distributed.clear();
70 inline void DistributionPool::populateChildren(const ContainerNode& parent)
72 clear();
73 for (Node* child = parent.firstChild(); child; child = child->nextSibling()) {
74 if (isActiveInsertionPoint(*child)) {
75 InsertionPoint* insertionPoint = toInsertionPoint(child);
76 for (size_t i = 0; i < insertionPoint->distributedNodesSize(); ++i)
77 m_nodes.append(insertionPoint->distributedNodeAt(i));
78 } else {
79 m_nodes.append(child);
82 m_distributed.resize(m_nodes.size());
83 m_distributed.fill(false);
86 void DistributionPool::distributeTo(InsertionPoint* insertionPoint, ElementShadow* elementShadow)
88 DistributedNodes distributedNodes;
90 for (size_t i = 0; i < m_nodes.size(); ++i) {
91 if (m_distributed[i])
92 continue;
94 if (isHTMLContentElement(*insertionPoint) && !toHTMLContentElement(insertionPoint)->canSelectNode(m_nodes, i))
95 continue;
97 Node* node = m_nodes[i];
98 distributedNodes.append(node);
99 elementShadow->didDistributeNode(node, insertionPoint);
100 m_distributed[i] = true;
103 // Distributes fallback elements
104 if (insertionPoint->isContentInsertionPoint() && distributedNodes.isEmpty()) {
105 for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fallbackNode = fallbackNode->nextSibling()) {
106 distributedNodes.append(fallbackNode);
107 elementShadow->didDistributeNode(fallbackNode, insertionPoint);
110 insertionPoint->setDistributedNodes(distributedNodes);
113 inline DistributionPool::~DistributionPool()
115 detachNonDistributedNodes();
118 inline void DistributionPool::detachNonDistributedNodes()
120 for (size_t i = 0; i < m_nodes.size(); ++i) {
121 if (m_distributed[i])
122 continue;
123 if (m_nodes[i]->layoutObject())
124 m_nodes[i]->lazyReattachIfAttached();
128 PassOwnPtrWillBeRawPtr<ElementShadow> ElementShadow::create()
130 return adoptPtrWillBeNoop(new ElementShadow());
133 ElementShadow::ElementShadow()
134 : m_needsDistributionRecalc(false)
135 , m_needsSelectFeatureSet(false)
139 ElementShadow::~ElementShadow()
141 #if !ENABLE(OILPAN)
142 removeDetachedShadowRoots();
143 #endif
146 ShadowRoot& ElementShadow::addShadowRoot(Element& shadowHost, ShadowRootType type)
148 EventDispatchForbiddenScope assertNoEventDispatch;
149 ScriptForbiddenScope forbidScript;
151 if (type == ShadowRootType::OpenByDefault) {
152 if (!youngestShadowRoot()) {
153 shadowHost.willAddFirstAuthorShadowRoot();
154 } else if (youngestShadowRoot()->type() == ShadowRootType::UserAgent) {
155 shadowHost.willAddFirstAuthorShadowRoot();
156 UseCounter::countDeprecation(shadowHost.document(), UseCounter::ElementCreateShadowRootMultipleWithUserAgentShadowRoot);
157 } else {
158 UseCounter::countDeprecation(shadowHost.document(), UseCounter::ElementCreateShadowRootMultiple);
160 } else if (type == ShadowRootType::Open || type == ShadowRootType::Closed) {
161 shadowHost.willAddFirstAuthorShadowRoot();
164 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot())
165 root->lazyReattachIfAttached();
167 RefPtrWillBeRawPtr<ShadowRoot> shadowRoot = ShadowRoot::create(shadowHost.document(), type);
168 shadowRoot->setParentOrShadowHostNode(&shadowHost);
169 shadowRoot->setParentTreeScope(shadowHost.treeScope());
170 m_shadowRoots.push(shadowRoot.get());
171 setNeedsDistributionRecalc();
173 shadowRoot->insertedInto(&shadowHost);
174 shadowHost.setChildNeedsStyleRecalc();
175 shadowHost.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::Shadow));
177 InspectorInstrumentation::didPushShadowRoot(&shadowHost, shadowRoot.get());
179 return *shadowRoot;
182 #if !ENABLE(OILPAN)
183 void ElementShadow::removeDetachedShadowRoots()
185 // Dont protect this ref count.
186 Element* shadowHost = host();
187 ASSERT(shadowHost);
189 while (RefPtrWillBeRawPtr<ShadowRoot> oldRoot = m_shadowRoots.head()) {
190 InspectorInstrumentation::willPopShadowRoot(shadowHost, oldRoot.get());
191 shadowHost->document().removeFocusedElementOfSubtree(oldRoot.get());
192 m_shadowRoots.removeHead();
193 oldRoot->setParentOrShadowHostNode(0);
194 oldRoot->setParentTreeScope(shadowHost->document());
195 oldRoot->setPrev(0);
196 oldRoot->setNext(0);
199 #endif
201 void ElementShadow::attach(const Node::AttachContext& context)
203 Node::AttachContext childrenContext(context);
204 childrenContext.resolvedStyle = 0;
206 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
207 if (root->needsAttach())
208 root->attach(childrenContext);
212 void ElementShadow::detach(const Node::AttachContext& context)
214 Node::AttachContext childrenContext(context);
215 childrenContext.resolvedStyle = 0;
217 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot())
218 root->detach(childrenContext);
221 void ElementShadow::setNeedsDistributionRecalc()
223 if (m_needsDistributionRecalc)
224 return;
225 m_needsDistributionRecalc = true;
226 host()->markAncestorsWithChildNeedsDistributionRecalc();
227 clearDistribution();
230 bool ElementShadow::hasSameStyles(const ElementShadow* other) const
232 ShadowRoot* root = youngestShadowRoot();
233 ShadowRoot* otherRoot = other->youngestShadowRoot();
234 while (root || otherRoot) {
235 if (!root || !otherRoot)
236 return false;
238 StyleSheetList* list = root->styleSheets();
239 StyleSheetList* otherList = otherRoot->styleSheets();
241 if (list->length() != otherList->length())
242 return false;
244 for (size_t i = 0; i < list->length(); i++) {
245 if (toCSSStyleSheet(list->item(i))->contents() != toCSSStyleSheet(otherList->item(i))->contents())
246 return false;
248 root = root->olderShadowRoot();
249 otherRoot = otherRoot->olderShadowRoot();
252 return true;
255 const InsertionPoint* ElementShadow::finalDestinationInsertionPointFor(const Node* key) const
257 ASSERT(key && !key->needsDistributionRecalc());
258 NodeToDestinationInsertionPoints::const_iterator it = m_nodeToInsertionPoints.find(key);
259 #if ENABLE(OILPAN)
260 return it == m_nodeToInsertionPoints.end() ? nullptr : it->value->last().get();
261 #else
262 return it == m_nodeToInsertionPoints.end() ? nullptr : it->value.last().get();
263 #endif
266 const DestinationInsertionPoints* ElementShadow::destinationInsertionPointsFor(const Node* key) const
268 ASSERT(key && !key->needsDistributionRecalc());
269 NodeToDestinationInsertionPoints::const_iterator it = m_nodeToInsertionPoints.find(key);
270 #if ENABLE(OILPAN)
271 return it == m_nodeToInsertionPoints.end() ? nullptr : it->value.get();
272 #else
273 return it == m_nodeToInsertionPoints.end() ? nullptr : &it->value;
274 #endif
277 void ElementShadow::distribute()
279 host()->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::Shadow));
280 WillBeHeapVector<RawPtrWillBeMember<HTMLShadowElement>, 32> shadowInsertionPoints;
281 DistributionPool pool(*host());
283 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
284 HTMLShadowElement* shadowInsertionPoint = 0;
285 const WillBeHeapVector<RefPtrWillBeMember<InsertionPoint>>& insertionPoints = root->descendantInsertionPoints();
286 for (size_t i = 0; i < insertionPoints.size(); ++i) {
287 InsertionPoint* point = insertionPoints[i].get();
288 if (!point->isActive())
289 continue;
290 if (isHTMLShadowElement(*point)) {
291 ASSERT(!shadowInsertionPoint);
292 shadowInsertionPoint = toHTMLShadowElement(point);
293 shadowInsertionPoints.append(shadowInsertionPoint);
294 } else {
295 pool.distributeTo(point, this);
296 if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*point))
297 shadow->setNeedsDistributionRecalc();
302 for (size_t i = shadowInsertionPoints.size(); i > 0; --i) {
303 HTMLShadowElement* shadowInsertionPoint = shadowInsertionPoints[i - 1];
304 ShadowRoot* root = shadowInsertionPoint->containingShadowRoot();
305 ASSERT(root);
306 if (root->isOldest()) {
307 pool.distributeTo(shadowInsertionPoint, this);
308 } else if (root->olderShadowRoot()->type() == root->type()) {
309 // Only allow reprojecting older shadow roots between the same type to
310 // disallow reprojecting UA elements into author shadows.
311 DistributionPool olderShadowRootPool(*root->olderShadowRoot());
312 olderShadowRootPool.distributeTo(shadowInsertionPoint, this);
313 root->olderShadowRoot()->setShadowInsertionPointOfYoungerShadowRoot(shadowInsertionPoint);
315 if (ElementShadow* shadow = shadowWhereNodeCanBeDistributed(*shadowInsertionPoint))
316 shadow->setNeedsDistributionRecalc();
318 InspectorInstrumentation::didPerformElementShadowDistribution(host());
321 void ElementShadow::didDistributeNode(const Node* node, InsertionPoint* insertionPoint)
323 #if ENABLE(OILPAN)
324 NodeToDestinationInsertionPoints::AddResult result = m_nodeToInsertionPoints.add(node, nullptr);
325 if (result.isNewEntry)
326 result.storedValue->value = adoptPtrWillBeNoop(new DestinationInsertionPoints());
327 result.storedValue->value->append(insertionPoint);
328 #else
329 NodeToDestinationInsertionPoints::AddResult result = m_nodeToInsertionPoints.add(node, DestinationInsertionPoints());
330 result.storedValue->value.append(insertionPoint);
331 #endif
334 const SelectRuleFeatureSet& ElementShadow::ensureSelectFeatureSet()
336 if (!m_needsSelectFeatureSet)
337 return m_selectFeatures;
339 m_selectFeatures.clear();
340 for (ShadowRoot* root = oldestShadowRoot(); root; root = root->youngerShadowRoot())
341 collectSelectFeatureSetFrom(*root);
342 m_needsSelectFeatureSet = false;
343 return m_selectFeatures;
346 void ElementShadow::collectSelectFeatureSetFrom(ShadowRoot& root)
348 if (!root.containsShadowRoots() && !root.containsContentElements())
349 return;
351 for (Element& element : ElementTraversal::descendantsOf(root)) {
352 if (ElementShadow* shadow = element.shadow())
353 m_selectFeatures.add(shadow->ensureSelectFeatureSet());
354 if (!isHTMLContentElement(element))
355 continue;
356 const CSSSelectorList& list = toHTMLContentElement(element).selectorList();
357 m_selectFeatures.collectFeaturesFromSelectorList(list);
361 void ElementShadow::willAffectSelector()
363 for (ElementShadow* shadow = this; shadow; shadow = shadow->containingShadow()) {
364 if (shadow->needsSelectFeatureSet())
365 break;
366 shadow->setNeedsSelectFeatureSet();
368 setNeedsDistributionRecalc();
371 void ElementShadow::clearDistribution()
373 m_nodeToInsertionPoints.clear();
375 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot())
376 root->setShadowInsertionPointOfYoungerShadowRoot(nullptr);
379 DEFINE_TRACE(ElementShadow)
381 #if ENABLE(OILPAN)
382 visitor->trace(m_nodeToInsertionPoints);
383 visitor->trace(m_selectFeatures);
384 // Shadow roots are linked with previous and next pointers which are traced.
385 // It is therefore enough to trace one of the shadow roots here and the
386 // rest will be traced from there.
387 visitor->trace(m_shadowRoots.head());
388 #endif
391 } // namespace