155a366a4ab5c4fdedeccae275c5ae0079e0e548
[WebKit-https.git] / Source / WebCore / dom / NodeRenderingContext.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2001 Dirk Mueller (mueller@kde.org)
5  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6  * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
7  * Copyright (C) 2011 Google Inc. All rights reserved.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  *
24  */
25
26 #include "config.h"
27 #include "NodeRenderingContext.h"
28
29 #include "ContainerNode.h"
30 #include "Node.h"
31 #include "RenderFullScreen.h"
32 #include "RenderObject.h"
33 #include "ShadowContentElement.h"
34 #include "ShadowRoot.h"
35
36 namespace WebCore {
37
38 NodeRenderingContext::NodeRenderingContext(Node* node)
39     : m_location(LocationNotInTree)
40     , m_phase(AttachStraight)
41     , m_node(node)
42     , m_parentNodeForRenderingAndStyle(0)
43     , m_visualParentShadowRoot(0)
44     , m_contentElement(0)
45     , m_style(0)
46 {
47     ContainerNode* parent = m_node->parentOrHostNode();
48     if (!parent)
49         return;
50
51     if (parent->isShadowRoot()) {
52         m_location = LocationShadowChild;
53         m_parentNodeForRenderingAndStyle = parent->shadowHost();
54         return;
55     }
56
57     m_location = LocationLightChild;
58
59     if (parent->isElementNode()) {
60         m_visualParentShadowRoot = toElement(parent)->shadowRoot();
61
62         if (m_visualParentShadowRoot) {
63             if ((m_contentElement = m_visualParentShadowRoot->activeContentElement())) {
64                 m_phase = AttachContentForwarded;
65                 m_parentNodeForRenderingAndStyle = NodeRenderingContext(m_contentElement).parentNodeForRenderingAndStyle();
66                 return;
67             } 
68                 
69             m_phase = AttachContentLight;
70             m_parentNodeForRenderingAndStyle = parent;
71             return;
72         }
73     }
74
75     m_parentNodeForRenderingAndStyle = parent;
76 }
77
78 NodeRenderingContext::NodeRenderingContext(Node* node, RenderStyle* style)
79     : m_location(LocationUndetermined)
80     , m_phase(AttachStraight)
81     , m_node(node)
82     , m_parentNodeForRenderingAndStyle(0)
83     , m_visualParentShadowRoot(0)
84     , m_contentElement(0)
85     , m_style(style)
86 {
87 }
88
89 NodeRenderingContext::~NodeRenderingContext()
90 {
91 }
92
93 void NodeRenderingContext::setStyle(PassRefPtr<RenderStyle> style)
94 {
95     m_style = style;
96 }
97
98 PassRefPtr<RenderStyle> NodeRenderingContext::releaseStyle()
99 {
100     return m_style.release();
101 }
102
103 static RenderObject* nextRendererOf(ShadowContentElement* parent, Node* current)
104 {
105     size_t currentIndex = parent->inclusionIndexOf(current);
106     if (currentIndex == notFound)
107         return 0;
108
109     for (size_t i = currentIndex + 1; i < parent->inclusionCount(); ++i) {
110         Node* candidate = parent->inclusionAt(i);
111         if (RenderObject* renderer = candidate->renderer())
112             return renderer;
113     }
114
115     return 0;
116 }
117
118 static RenderObject* previousRendererOf(ShadowContentElement* parent, Node* current)
119 {
120     RenderObject* lastRenderer = 0;
121
122     for (size_t i = 0; i < parent->inclusionCount(); ++i) {
123         Node* candidate = parent->inclusionAt(i);
124         if (current == candidate)
125             break;
126         if (RenderObject* renderer = candidate->renderer())
127             lastRenderer = renderer;
128     }
129
130     return lastRenderer;
131 }
132
133 static RenderObject* firstRendererOf(ShadowContentElement* parent)
134 {
135     size_t inclusionCount = parent->inclusionCount();
136     for (size_t i = 0; i < inclusionCount; ++i) {
137         Node* candidate = parent->inclusionAt(i);
138         if (RenderObject* renderer = candidate->renderer())
139             return renderer;
140     }
141
142     return 0;
143 }
144
145 static RenderObject* lastRendererOf(ShadowContentElement* parent)
146 {
147     size_t inclusionCount = parent->inclusionCount();
148     for (size_t i = 0; i < inclusionCount; ++i) {
149         Node* candidate = parent->inclusionAt(inclusionCount - i - 1);
150         if (RenderObject* renderer = candidate->renderer())
151             return renderer;
152     }
153
154     return 0;
155 }
156
157 RenderObject* NodeRenderingContext::nextRenderer() const
158 {
159     ASSERT(m_node->renderer() || m_location != LocationUndetermined);
160     if (RenderObject* renderer = m_node->renderer())
161         return renderer->nextSibling();
162
163     if (m_phase == AttachContentForwarded) {
164         if (RenderObject* found = nextRendererOf(m_contentElement, m_node))
165             return found;
166         return NodeRenderingContext(m_contentElement).nextRenderer();
167     }
168
169     // Avoid an O(n^2) problem with this function by not checking for
170     // nextRenderer() when the parent element hasn't attached yet.
171     if (m_node->parentOrHostNode() && !m_node->parentOrHostNode()->attached())
172         return 0;
173
174     for (Node* node = m_node->nextSibling(); node; node = node->nextSibling()) {
175         if (node->renderer())
176             return node->renderer();
177         if (node->isContentElement()) {
178             if (RenderObject* first = firstRendererOf(toShadowContentElement(node)))
179                 return first;
180         }
181     }
182
183     return 0;
184 }
185
186 RenderObject* NodeRenderingContext::previousRenderer() const
187 {
188     ASSERT(m_node->renderer() || m_location != LocationUndetermined);
189     if (RenderObject* renderer = m_node->renderer())
190         return renderer->previousSibling();
191
192     if (m_phase == AttachContentForwarded) {
193         if (RenderObject* found = previousRendererOf(m_contentElement, m_node))
194             return found;
195         return NodeRenderingContext(m_contentElement).previousRenderer();
196     }
197
198     // FIXME: We should have the same O(N^2) avoidance as nextRenderer does
199     // however, when I tried adding it, several tests failed.
200     for (Node* node = m_node->previousSibling(); node; node = node->previousSibling()) {
201         if (node->renderer())
202             return node->renderer();
203         if (node->isContentElement()) {
204             if (RenderObject* last = lastRendererOf(toShadowContentElement(node)))
205                 return last;
206         }
207     }
208
209     return 0;
210 }
211
212 RenderObject* NodeRenderingContext::parentRenderer() const
213 {
214     if (RenderObject* renderer = m_node->renderer()) {
215         ASSERT(m_location == LocationUndetermined);
216         return renderer->parent();
217     }
218
219     ASSERT(m_location != LocationUndetermined);
220     return m_parentNodeForRenderingAndStyle ? m_parentNodeForRenderingAndStyle->renderer() : 0;
221 }
222
223 void NodeRenderingContext::hostChildrenChanged()
224 {
225     if (m_phase == AttachContentLight)
226         m_visualParentShadowRoot->hostChildrenChanged();
227 }
228
229 bool NodeRenderingContext::shouldCreateRenderer() const
230 {
231     ASSERT(m_location != LocationUndetermined);
232     ASSERT(parentNodeForRenderingAndStyle());
233
234     if (m_location == LocationNotInTree || m_phase == AttachContentLight)
235         return false;
236
237     RenderObject* parentRenderer = this->parentRenderer();
238     if (!parentRenderer)
239         return false;
240
241     if (m_location == LocationLightChild && m_phase == AttachStraight) {
242         // FIXME: Ignoring canHaveChildren() in a case of shadow children might be wrong.
243         // See https://bugs.webkit.org/show_bug.cgi?id=52423
244         if (!parentRenderer->canHaveChildren())
245             return false;
246     
247         if (m_visualParentShadowRoot && !m_parentNodeForRenderingAndStyle->canHaveLightChildRendererWithShadow())
248             return false;
249     }
250
251     if (!m_parentNodeForRenderingAndStyle->childShouldCreateRenderer(m_node))
252         return false;
253
254     return true;
255 }
256
257
258 NodeRendererFactory::NodeRendererFactory(Node* node)
259     : m_context(node)
260 {
261 }
262
263 RenderObject* NodeRendererFactory::createRendererAndStyle()
264 {
265     Node* node = m_context.node();
266     Document* document = node->document();
267     ASSERT(!node->renderer());
268     ASSERT(document->shouldCreateRenderers());
269
270     if (!m_context.shouldCreateRenderer())
271         return 0;
272
273     m_context.setStyle(node->styleForRenderer(m_context));
274     if (!node->rendererIsNeeded(m_context)) {
275         if (node->isElementNode()) {
276             Element* element = toElement(node);
277             if (m_context.style()->affectedByEmpty())
278                 element->setStyleAffectedByEmpty();
279         }
280         return 0;
281     }
282
283     RenderObject* newRenderer = node->createRenderer(document->renderArena(), m_context.style());
284     if (!newRenderer)
285         return 0;
286
287     if (!m_context.parentRenderer()->isChildAllowed(newRenderer, m_context.style())) {
288         newRenderer->destroy();
289         return 0;
290     }
291
292     node->setRenderer(newRenderer);
293     newRenderer->setAnimatableStyle(m_context.releaseStyle()); // setAnimatableStyle() can depend on renderer() already being set.
294     return newRenderer;
295 }
296
297 #if ENABLE(FULLSCREEN_API)
298 static RenderObject* wrapWithRenderFullScreen(RenderObject* object, Document* document)
299 {
300     RenderFullScreen* fullscreenRenderer = new (document->renderArena()) RenderFullScreen(document);
301     fullscreenRenderer->setStyle(RenderFullScreen::createFullScreenStyle());
302     // It's possible that we failed to create the new render and end up wrapping nothing.
303     // We'll end up displaying a black screen, but Jer says this is expected.
304     if (object)
305         fullscreenRenderer->addChild(object);
306     document->setFullScreenRenderer(fullscreenRenderer);
307     if (fullscreenRenderer->placeholder())
308         return fullscreenRenderer->placeholder();
309     return fullscreenRenderer;
310 }
311 #endif
312
313 void NodeRendererFactory::createRendererIfNeeded()
314 {
315     Node* node = m_context.node();
316     Document* document = node->document();
317     if (!document->shouldCreateRenderers())
318         return;
319
320     RenderObject* parentRenderer = m_context.parentRenderer();
321     RenderObject* nextRenderer = m_context.nextRenderer();
322     RenderObject* newRenderer = createRendererAndStyle();
323
324 #if ENABLE(FULLSCREEN_API)
325     if (document->webkitIsFullScreen() && document->webkitCurrentFullScreenElement() == node)
326         newRenderer = wrapWithRenderFullScreen(newRenderer, document);
327 #endif
328
329     // FIXME: This side effect should be visible from attach() code.
330     m_context.hostChildrenChanged();
331
332     if (!newRenderer)
333         return;
334
335     // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
336     parentRenderer->addChild(newRenderer, nextRenderer);
337 }
338
339 }