2011-06-01 Jer Noble <jer.noble@apple.com>
[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 "ShadowRoot.h"
34
35 namespace WebCore {
36
37 NodeRenderingContext::NodeRenderingContext(Node* node)
38     : m_location(LocationNotInTree)
39     , m_phase(AttachStraight)
40     , m_node(node)
41     , m_parentNodeForRenderingAndStyle(0)
42     , m_visualParentShadowRoot(0)
43     , m_style(0)
44 {
45     ContainerNode* parent = m_node->parentOrHostNode();
46     if (!parent)
47         return;
48
49     if (parent->isShadowBoundary()) {
50         m_location = LocationShadowChild;
51         m_parentNodeForRenderingAndStyle = parent->shadowHost();
52         return;
53     }
54
55     m_location = LocationLightChild;
56
57     if (parent->isElementNode()) {
58         m_visualParentShadowRoot = toElement(parent)->shadowRoot();
59
60         if (m_visualParentShadowRoot) {
61             if (ContainerNode* contentContainer = m_visualParentShadowRoot->activeContentContainer()) {
62                 m_phase = AttachContentForwarded;
63                 m_parentNodeForRenderingAndStyle = NodeRenderingContext(contentContainer).parentNodeForRenderingAndStyle();
64                 return;
65             } 
66                 
67             m_phase = AttachContentLight;
68             m_parentNodeForRenderingAndStyle = parent;
69             return;
70         }
71     }
72
73     m_parentNodeForRenderingAndStyle = parent;
74 }
75
76 NodeRenderingContext::NodeRenderingContext(Node* node, RenderStyle* style)
77     : m_location(LocationUndetermined)
78     , m_phase(AttachStraight)
79     , m_node(node)
80     , m_parentNodeForRenderingAndStyle(0)
81     , m_visualParentShadowRoot(0)
82     , m_style(style)
83 {
84 }
85
86 NodeRenderingContext::~NodeRenderingContext()
87 {
88 }
89
90 void NodeRenderingContext::setStyle(PassRefPtr<RenderStyle> style)
91 {
92     m_style = style;
93 }
94
95 PassRefPtr<RenderStyle> NodeRenderingContext::releaseStyle()
96 {
97     return m_style.release();
98 }
99
100 RenderObject* NodeRenderingContext::nextRenderer() const
101 {
102     ASSERT(m_node->renderer() || m_location != LocationUndetermined);
103     if (RenderObject* renderer = m_node->renderer())
104         return renderer->nextSibling();
105
106     if (m_phase == AttachContentForwarded) {
107         // Returns 0 here to insert renderer at the end of child list.
108         // We assume content children are always attached in tree order and
109         // there is no partial render tree creation.
110         return 0;
111     }
112
113     // Avoid an O(n^2) problem with this function by not checking for
114     // nextRenderer() when the parent element hasn't attached yet.
115     if (m_node->parentOrHostNode() && !m_node->parentOrHostNode()->attached())
116         return 0;
117
118     for (Node* node = m_node->nextSibling(); node; node = node->nextSibling()) {
119         if (node->renderer())
120             return node->renderer();
121     }
122
123     return 0;
124 }
125
126 RenderObject* NodeRenderingContext::previousRenderer() const
127 {
128     ASSERT(m_node->renderer() || m_location != LocationUndetermined);
129     if (RenderObject* renderer = m_node->renderer())
130         return renderer->previousSibling();
131
132     if (m_phase == AttachContentForwarded) {
133         // Returns lastChild() here to insert renderer at the end of child list.
134         // We assume content children are always attached in tree order and
135         // there is no partial render tree creation.
136         if (RenderObject* parent = parentRenderer())
137             return parent->lastChild();
138         return 0;
139     }
140
141     // FIXME: We should have the same O(N^2) avoidance as nextRenderer does
142     // however, when I tried adding it, several tests failed.
143     for (Node* node = m_node->previousSibling(); node; node = node->previousSibling()) {
144         if (node->renderer())
145             return node->renderer();
146     }
147
148     return 0;
149 }
150
151 RenderObject* NodeRenderingContext::parentRenderer() const
152 {
153     if (RenderObject* renderer = m_node->renderer()) {
154         ASSERT(m_location == LocationUndetermined);
155         return renderer->parent();
156     }
157
158     ASSERT(m_location != LocationUndetermined);
159     return m_parentNodeForRenderingAndStyle ? m_parentNodeForRenderingAndStyle->renderer() : 0;
160 }
161
162 void NodeRenderingContext::hostChildrenChanged()
163 {
164     if (m_phase == AttachContentLight)
165         m_visualParentShadowRoot->hostChildrenChanged();
166 }
167
168 bool NodeRenderingContext::shouldCreateRenderer() const
169 {
170     ASSERT(m_location != LocationUndetermined);
171     ASSERT(parentNodeForRenderingAndStyle());
172
173     if (m_location == LocationNotInTree || m_phase == AttachContentLight)
174         return false;
175
176     RenderObject* parentRenderer = this->parentRenderer();
177     if (!parentRenderer)
178         return false;
179
180     if (m_location == LocationLightChild && m_phase == AttachStraight) {
181         // FIXME: Ignoring canHaveChildren() in a case of shadow children might be wrong.
182         // See https://bugs.webkit.org/show_bug.cgi?id=52423
183         if (!parentRenderer->canHaveChildren())
184             return false;
185     
186         if (m_visualParentShadowRoot && !m_parentNodeForRenderingAndStyle->canHaveLightChildRendererWithShadow())
187             return false;
188     }
189
190     if (!m_parentNodeForRenderingAndStyle->childShouldCreateRenderer(m_node))
191         return false;
192
193     return true;
194 }
195
196
197 NodeRendererFactory::NodeRendererFactory(Node* node)
198     : m_context(node)
199 {
200 }
201
202 RenderObject* NodeRendererFactory::createRendererAndStyle()
203 {
204     Node* node = m_context.node();
205     Document* document = node->document();
206     ASSERT(!node->renderer());
207     ASSERT(document->shouldCreateRenderers());
208
209     if (!m_context.shouldCreateRenderer())
210         return 0;
211
212     m_context.setStyle(node->styleForRenderer());
213     if (!node->rendererIsNeeded(m_context))
214         return 0;
215
216     RenderObject* newRenderer = node->createRenderer(document->renderArena(), m_context.style());
217     if (!newRenderer)
218         return 0;
219
220     if (!m_context.parentRenderer()->isChildAllowed(newRenderer, m_context.style())) {
221         newRenderer->destroy();
222         return 0;
223     }
224
225     node->setRenderer(newRenderer);
226     newRenderer->setAnimatableStyle(m_context.releaseStyle()); // setAnimatableStyle() can depend on renderer() already being set.
227     return newRenderer;
228 }
229
230 #if ENABLE(FULLSCREEN_API)
231 static RenderObject* wrapWithRenderFullScreen(RenderObject* object, Document* document)
232 {
233     RenderFullScreen* fullscreenRenderer = new (document->renderArena()) RenderFullScreen(document);
234     fullscreenRenderer->setStyle(RenderFullScreen::createFullScreenStyle());
235     // It's possible that we failed to create the new render and end up wrapping nothing.
236     // We'll end up displaying a black screen, but Jer says this is expected.
237     if (object)
238         fullscreenRenderer->addChild(object);
239     document->setFullScreenRenderer(fullscreenRenderer);
240     if (fullscreenRenderer->placeholder())
241         return fullscreenRenderer->placeholder();
242     return fullscreenRenderer;
243 }
244 #endif
245
246 void NodeRendererFactory::createRendererIfNeeded()
247 {
248     Node* node = m_context.node();
249     Document* document = node->document();
250     if (!document->shouldCreateRenderers())
251         return;
252
253     RenderObject* parentRenderer = m_context.parentRenderer();
254     RenderObject* nextRenderer = m_context.nextRenderer();
255     RenderObject* newRenderer = createRendererAndStyle();
256
257 #if ENABLE(FULLSCREEN_API)
258     if (document->webkitIsFullScreen() && document->webkitCurrentFullScreenElement() == node)
259         newRenderer = wrapWithRenderFullScreen(newRenderer, document);
260 #endif
261
262     // FIXME: This side effect should be visible from attach() code.
263     m_context.hostChildrenChanged();
264
265     if (!newRenderer)
266         return;
267
268     // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
269     parentRenderer->addChild(newRenderer, nextRenderer);
270 }
271
272 }