~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/html/shadow/ContentDistributor.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "ContentDistributor.h"
 
29
 
 
30
#include "ContentSelectorQuery.h"
 
31
#include "ElementShadow.h"
 
32
#include "HTMLContentElement.h"
 
33
#include "HTMLShadowElement.h"
 
34
#include "ShadowRoot.h"
 
35
 
 
36
 
 
37
namespace WebCore {
 
38
 
 
39
void ContentDistribution::swap(ContentDistribution& other)
 
40
{
 
41
    m_nodes.swap(other.m_nodes);
 
42
    m_indices.swap(other.m_indices);
 
43
}
 
44
 
 
45
void ContentDistribution::append(PassRefPtr<Node> node)
 
46
{
 
47
    size_t size = m_nodes.size();
 
48
    m_indices.set(node.get(), size);
 
49
    m_nodes.append(node);
 
50
}
 
51
 
 
52
size_t ContentDistribution::find(const Node* node) const
 
53
{
 
54
    HashMap<const Node*, size_t>::const_iterator it = m_indices.find(node);
 
55
    if (it == m_indices.end())
 
56
        return notFound;
 
57
 
 
58
    return it.get()->value;
 
59
}
 
60
 
 
61
ShadowRootContentDistributionData::ShadowRootContentDistributionData()
 
62
    : m_insertionPointAssignedTo(0)
 
63
    , m_numberOfShadowElementChildren(0)
 
64
    , m_numberOfContentElementChildren(0)
 
65
    , m_numberOfElementShadowChildren(0)
 
66
    , m_insertionPointListIsValid(false)
 
67
{
 
68
}
 
69
 
 
70
void ShadowRootContentDistributionData::invalidateInsertionPointList()
 
71
{
 
72
    m_insertionPointListIsValid = false;
 
73
    m_insertionPointList.clear();
 
74
}
 
75
 
 
76
const Vector<InsertionPoint*>& ShadowRootContentDistributionData::ensureInsertionPointList(ShadowRoot* shadowRoot)
 
77
{
 
78
    if (m_insertionPointListIsValid)
 
79
        return m_insertionPointList;
 
80
 
 
81
    m_insertionPointListIsValid = true;
 
82
    ASSERT(m_insertionPointList.isEmpty());
 
83
 
 
84
    if (!shadowRoot->hasInsertionPoint())
 
85
        return m_insertionPointList;
 
86
 
 
87
    for (Node* node = shadowRoot; node; node = node->traverseNextNode(shadowRoot)) {
 
88
        if (node->isInsertionPoint())
 
89
            m_insertionPointList.append(toInsertionPoint(node));
 
90
    }
 
91
 
 
92
    return m_insertionPointList;
 
93
}
 
94
 
 
95
ContentDistributor::ContentDistributor()
 
96
    : m_validity(Undetermined)
 
97
{
 
98
}
 
99
 
 
100
ContentDistributor::~ContentDistributor()
 
101
{
 
102
}
 
103
 
 
104
InsertionPoint* ContentDistributor::findInsertionPointFor(const Node* key) const
 
105
{
 
106
    return m_nodeToInsertionPoint.get(key);
 
107
}
 
108
 
 
109
void ContentDistributor::populate(Node* node, ContentDistribution& pool)
 
110
{
 
111
    if (!isActiveInsertionPoint(node)) {
 
112
        pool.append(node);
 
113
        return;
 
114
    }
 
115
 
 
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);
 
120
    } else {
 
121
        for (Node* fallbackNode = insertionPoint->firstChild(); fallbackNode; fallbackNode = fallbackNode->nextSibling())
 
122
            pool.append(fallbackNode);
 
123
    }
 
124
}
 
125
 
 
126
void ContentDistributor::distribute(Element* host)
 
127
{
 
128
    ASSERT(needsDistribution());
 
129
    ASSERT(m_nodeToInsertionPoint.isEmpty());
 
130
 
 
131
    m_validity = Valid;
 
132
 
 
133
    ContentDistribution pool;
 
134
    for (Node* node = host->firstChild(); node; node = node->nextSibling())
 
135
        populate(node, pool);
 
136
 
 
137
    Vector<bool> distributed(pool.size());
 
138
    distributed.fill(false);
 
139
 
 
140
    Vector<HTMLShadowElement*, 8> activeShadowInsertionPoints;
 
141
    for (ShadowRoot* root = host->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
 
142
        HTMLShadowElement* firstActiveShadowInsertionPoint = 0;
 
143
 
 
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())
 
148
                continue;
 
149
 
 
150
            if (isHTMLShadowElement(point)) {
 
151
                if (!firstActiveShadowInsertionPoint)
 
152
                    firstActiveShadowInsertionPoint = toHTMLShadowElement(point);
 
153
            } else {
 
154
                distributeSelectionsTo(point, pool, distributed);
 
155
                if (ElementShadow* shadow = point->parentNode()->isElementNode() ? toElement(point->parentNode())->shadow() : 0)
 
156
                    shadow->invalidateDistribution();
 
157
            }
 
158
        }
 
159
 
 
160
        if (firstActiveShadowInsertionPoint)
 
161
            activeShadowInsertionPoints.append(firstActiveShadowInsertionPoint);
 
162
    }
 
163
 
 
164
    for (size_t i = activeShadowInsertionPoints.size(); i > 0; --i) {
 
165
        HTMLShadowElement* shadowElement = activeShadowInsertionPoints[i - 1];
 
166
        ShadowRoot* root = shadowElement->shadowRoot();
 
167
        ASSERT(root);
 
168
        if (root->olderShadowRoot()) {
 
169
            distributeNodeChildrenTo(shadowElement, root->olderShadowRoot());
 
170
            root->olderShadowRoot()->setAssignedTo(shadowElement);
 
171
        } else {
 
172
            distributeSelectionsTo(shadowElement, pool, distributed);
 
173
            if (ElementShadow* shadow = shadowElement->parentNode()->isElementNode() ? toElement(shadowElement->parentNode())->shadow() : 0)
 
174
                shadow->invalidateDistribution();
 
175
        }
 
176
    }
 
177
}
 
178
 
 
179
bool ContentDistributor::invalidate(Element* host)
 
180
{
 
181
    ASSERT(needsInvalidation());
 
182
    bool needsReattach = (m_validity == Undetermined) || !m_nodeToInsertionPoint.isEmpty();
 
183
 
 
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();
 
190
        }
 
191
    }
 
192
 
 
193
    m_validity = Invalidating;
 
194
    m_nodeToInsertionPoint.clear();
 
195
    return needsReattach;
 
196
}
 
197
 
 
198
void ContentDistributor::finishInivalidation()
 
199
{
 
200
    ASSERT(m_validity == Invalidating);
 
201
    m_validity = Invalidated;
 
202
}
 
203
 
 
204
void ContentDistributor::distributeSelectionsTo(InsertionPoint* insertionPoint, const ContentDistribution& pool, Vector<bool>& distributed)
 
205
{
 
206
    ContentDistribution distribution;
 
207
    ContentSelectorQuery query(insertionPoint);
 
208
 
 
209
    for (size_t i = 0; i < pool.size(); ++i) {
 
210
        if (distributed[i])
 
211
            continue;
 
212
 
 
213
        if (!query.matches(pool.nodes(), i))
 
214
            continue;
 
215
 
 
216
        Node* child = pool.at(i).get();
 
217
        distribution.append(child);
 
218
        m_nodeToInsertionPoint.add(child, insertionPoint);
 
219
        distributed[i] = true;
 
220
    }
 
221
 
 
222
    insertionPoint->setDistribution(distribution);
 
223
}
 
224
 
 
225
void ContentDistributor::distributeNodeChildrenTo(InsertionPoint* insertionPoint, ContainerNode* containerNode)
 
226
{
 
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);
 
236
                }
 
237
            } else {
 
238
                for (Node* child = innerInsertionPoint->firstChild(); child; child = child->nextSibling()) {
 
239
                    distribution.append(child);
 
240
                    m_nodeToInsertionPoint.add(child, insertionPoint);
 
241
                }
 
242
            }
 
243
        } else {
 
244
            distribution.append(node);
 
245
            if (!m_nodeToInsertionPoint.contains(node))
 
246
                m_nodeToInsertionPoint.add(node, insertionPoint);
 
247
        }
 
248
    }
 
249
 
 
250
    insertionPoint->setDistribution(distribution);
 
251
}
 
252
 
 
253
void ContentDistributor::invalidateDistributionIn(ContentDistribution* list)
 
254
{
 
255
    for (size_t i = 0; i < list->size(); ++i)
 
256
        m_nodeToInsertionPoint.remove(list->at(i).get());
 
257
    list->clear();
 
258
}
 
259
 
 
260
}