2
* Copyright (C) 2011 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
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.
28
#include "ContentDistributor.h"
30
#include "ContentSelectorQuery.h"
31
#include "ElementShadow.h"
32
#include "HTMLContentElement.h"
33
#include "HTMLShadowElement.h"
34
#include "ShadowRoot.h"
39
void ContentDistribution::swap(ContentDistribution& other)
41
m_nodes.swap(other.m_nodes);
42
m_indices.swap(other.m_indices);
45
void ContentDistribution::append(PassRefPtr<Node> node)
47
size_t size = m_nodes.size();
48
m_indices.set(node.get(), size);
52
size_t ContentDistribution::find(const Node* node) const
54
HashMap<const Node*, size_t>::const_iterator it = m_indices.find(node);
55
if (it == m_indices.end())
58
return it.get()->value;
61
ShadowRootContentDistributionData::ShadowRootContentDistributionData()
62
: m_insertionPointAssignedTo(0)
63
, m_numberOfShadowElementChildren(0)
64
, m_numberOfContentElementChildren(0)
65
, m_numberOfElementShadowChildren(0)
66
, m_insertionPointListIsValid(false)
70
void ShadowRootContentDistributionData::invalidateInsertionPointList()
72
m_insertionPointListIsValid = false;
73
m_insertionPointList.clear();
76
const Vector<InsertionPoint*>& ShadowRootContentDistributionData::ensureInsertionPointList(ShadowRoot* shadowRoot)
78
if (m_insertionPointListIsValid)
79
return m_insertionPointList;
81
m_insertionPointListIsValid = true;
82
ASSERT(m_insertionPointList.isEmpty());
84
if (!shadowRoot->hasInsertionPoint())
85
return m_insertionPointList;
87
for (Node* node = shadowRoot; node; node = node->traverseNextNode(shadowRoot)) {
88
if (node->isInsertionPoint())
89
m_insertionPointList.append(toInsertionPoint(node));
92
return m_insertionPointList;
95
ContentDistributor::ContentDistributor()
96
: m_validity(Undetermined)
100
ContentDistributor::~ContentDistributor()
104
InsertionPoint* ContentDistributor::findInsertionPointFor(const Node* key) const
106
return m_nodeToInsertionPoint.get(key);
109
void ContentDistributor::populate(Node* node, ContentDistribution& pool)
111
if (!isActiveInsertionPoint(node)) {
116
InsertionPoint* insertionPoint = toInsertionPoint(node);
117
if (insertionPoint->hasDistribution()) {
118
for (size_t i = 0; i < insertionPoint->size(); ++i)
119
populate(insertionPoint->at(i), pool);
121
for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fallbackNode = fallbackNode->nextSibling())
122
pool.append(fallbackNode);
126
void ContentDistributor::distribute(Element* host)
128
ASSERT(needsDistribution());
129
ASSERT(m_nodeToInsertionPoint.isEmpty());
133
ContentDistribution pool;
134
for (Node* node = host->firstChild(); node; node = node->nextSibling())
135
populate(node, pool);
137
Vector<bool> distributed(pool.size());
138
distributed.fill(false);
140
Vector<HTMLShadowElement*, 8> activeShadowInsertionPoints;
141
for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
142
HTMLShadowElement* firstActiveShadowInsertionPoint = 0;
144
const Vector<InsertionPoint*>& insertionPoints = root->insertionPointList();
145
for (size_t i = 0; i < insertionPoints.size(); ++i) {
146
InsertionPoint* point = insertionPoints[i];
147
if (!point->isActive())
150
if (isHTMLShadowElement(point)) {
151
if (!firstActiveShadowInsertionPoint)
152
firstActiveShadowInsertionPoint = toHTMLShadowElement(point);
154
distributeSelectionsTo(point, pool, distributed);
155
if (ElementShadow* shadow = point->parentNode()->isElementNode() ? toElement(point->parentNode())->shadow() : 0)
156
shadow->invalidateDistribution();
160
if (firstActiveShadowInsertionPoint)
161
activeShadowInsertionPoints.append(firstActiveShadowInsertionPoint);
164
for (size_t i = activeShadowInsertionPoints.size(); i > 0; --i) {
165
HTMLShadowElement* shadowElement = activeShadowInsertionPoints[i - 1];
166
ShadowRoot* root = shadowElement->shadowRoot();
168
if (root->olderShadowRoot()) {
169
distributeNodeChildrenTo(shadowElement, root->olderShadowRoot());
170
root->olderShadowRoot()->setAssignedTo(shadowElement);
172
distributeSelectionsTo(shadowElement, pool, distributed);
173
if (ElementShadow* shadow = shadowElement->parentNode()->isElementNode() ? toElement(shadowElement->parentNode())->shadow() : 0)
174
shadow->invalidateDistribution();
179
bool ContentDistributor::invalidate(Element* host)
181
ASSERT(needsInvalidation());
182
bool needsReattach = (m_validity == Undetermined) || !m_nodeToInsertionPoint.isEmpty();
184
for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
185
root->setAssignedTo(0);
186
const Vector<InsertionPoint*>& insertionPoints = root->insertionPointList();
187
for (size_t i = 0; i < insertionPoints.size(); ++i) {
188
needsReattach = needsReattach || true;
189
insertionPoints[i]->clearDistribution();
193
m_validity = Invalidating;
194
m_nodeToInsertionPoint.clear();
195
return needsReattach;
198
void ContentDistributor::finishInivalidation()
200
ASSERT(m_validity == Invalidating);
201
m_validity = Invalidated;
204
void ContentDistributor::distributeSelectionsTo(InsertionPoint* insertionPoint, const ContentDistribution& pool, Vector<bool>& distributed)
206
ContentDistribution distribution;
207
ContentSelectorQuery query(insertionPoint);
209
for (size_t i = 0; i < pool.size(); ++i) {
213
if (!query.matches(pool.nodes(), i))
216
Node* child = pool.at(i).get();
217
distribution.append(child);
218
m_nodeToInsertionPoint.add(child, insertionPoint);
219
distributed[i] = true;
222
insertionPoint->setDistribution(distribution);
225
void ContentDistributor::distributeNodeChildrenTo(InsertionPoint* insertionPoint, ContainerNode* containerNode)
227
ContentDistribution distribution;
228
for (Node* node = containerNode->firstChild(); node; node = node->nextSibling()) {
229
if (isActiveInsertionPoint(node)) {
230
InsertionPoint* innerInsertionPoint = toInsertionPoint(node);
231
if (innerInsertionPoint->hasDistribution()) {
232
for (size_t i = 0; i < innerInsertionPoint->size(); ++i) {
233
distribution.append(innerInsertionPoint->at(i));
234
if (!m_nodeToInsertionPoint.contains(innerInsertionPoint->at(i)))
235
m_nodeToInsertionPoint.add(innerInsertionPoint->at(i), insertionPoint);
238
for (Node* child = innerInsertionPoint->firstChild(); child; child = child->nextSibling()) {
239
distribution.append(child);
240
m_nodeToInsertionPoint.add(child, insertionPoint);
244
distribution.append(node);
245
if (!m_nodeToInsertionPoint.contains(node))
246
m_nodeToInsertionPoint.add(node, insertionPoint);
250
insertionPoint->setDistribution(distribution);
253
void ContentDistributor::invalidateDistributionIn(ContentDistribution* list)
255
for (size_t i = 0; i < list->size(); ++i)
256
m_nodeToInsertionPoint.remove(list->at(i).get());