blob: c66ae3c484e41f6006902bb3d4a09449b67bbe2c [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
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 "core/dom/NodeRenderingContext.h"
28
Ben Murdoch7757ec22013-07-23 11:17:36 +010029#include "RuntimeEnabledFeatures.h"
Torne (Richard Coles)81a51572013-05-13 16:52:28 +010030#include "core/css/resolver/StyleResolver.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010031#include "core/dom/ContainerNode.h"
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +010032#include "core/dom/FullscreenElementStack.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010033#include "core/dom/Node.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010034#include "core/dom/Text.h"
Ben Murdoch83750172013-07-24 10:36:59 +010035#include "core/dom/shadow/InsertionPoint.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010036#include "core/rendering/FlowThreadController.h"
37#include "core/rendering/RenderFullScreen.h"
38#include "core/rendering/RenderNamedFlowThread.h"
39#include "core/rendering/RenderObject.h"
40#include "core/rendering/RenderText.h"
41#include "core/rendering/RenderView.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010042
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010043namespace WebCore {
44
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010045NodeRenderingContext::NodeRenderingContext(Node* node, RenderStyle* style)
46 : m_node(node)
47 , m_renderingParent(0)
48 , m_style(style)
49 , m_parentFlowRenderer(0)
50{
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +010051 m_renderingParent = NodeRenderingTraversal::parent(node, &m_parentDetails);
52}
53
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010054static bool isRendererReparented(const RenderObject* renderer)
55{
56 if (!renderer->node()->isElementNode())
57 return false;
58 if (renderer->style() && !renderer->style()->flowThread().isEmpty())
59 return true;
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010060 if (toElement(renderer->node())->shouldBeReparentedUnderRenderView(renderer->style()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010061 return true;
62 return false;
63}
64
65RenderObject* NodeRenderingContext::nextRenderer() const
66{
67 if (RenderObject* renderer = m_node->renderer())
68 return renderer->nextSibling();
69
70 Element* element = m_node->isElementNode() ? toElement(m_node) : 0;
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010071 if (element && element->shouldBeReparentedUnderRenderView(m_style.get())) {
72 // FIXME: Reparented renderers not in the top layer should probably be
73 // ordered in DOM tree order. We don't have a good way to do that yet,
74 // since NodeRenderingTraversal isn't aware of reparenting. It's safe to
75 // just append for now; it doesn't disrupt the top layer rendering as
76 // the layer collection in RenderLayer only requires that top layer
77 // renderers are orderered correctly relative to each other.
78 if (!element->isInTopLayer())
79 return 0;
80
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010081 const Vector<RefPtr<Element> >& topLayerElements = element->document()->topLayerElements();
82 size_t position = topLayerElements.find(element);
83 ASSERT(position != notFound);
84 for (size_t i = position + 1; i < topLayerElements.size(); ++i) {
85 if (RenderObject* renderer = topLayerElements[i]->renderer())
86 return renderer;
87 }
88 return 0;
89 }
90
91 if (m_parentFlowRenderer)
92 return m_parentFlowRenderer->nextRendererForNode(m_node);
93
94 // Avoid an O(N^2) problem with this function by not checking for
95 // nextRenderer() when the parent element hasn't attached yet.
96 if (m_renderingParent && !m_renderingParent->attached())
97 return 0;
98
99 for (Node* sibling = NodeRenderingTraversal::nextSibling(m_node); sibling; sibling = NodeRenderingTraversal::nextSibling(sibling)) {
100 RenderObject* renderer = sibling->renderer();
101 if (renderer && !isRendererReparented(renderer))
102 return renderer;
103 }
104
105 return 0;
106}
107
108RenderObject* NodeRenderingContext::previousRenderer() const
109{
110 if (RenderObject* renderer = m_node->renderer())
111 return renderer->previousSibling();
112
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100113 // FIXME: This doesn't work correctly for reparented elements that are
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100114 // display: none. We'd need to duplicate the logic in nextRenderer, but since
115 // nothing needs that yet just assert.
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100116 ASSERT(!m_node->isElementNode() || !toElement(m_node)->shouldBeReparentedUnderRenderView(m_style.get()));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100117
118 if (m_parentFlowRenderer)
119 return m_parentFlowRenderer->previousRendererForNode(m_node);
120
121 // FIXME: We should have the same O(N^2) avoidance as nextRenderer does
122 // however, when I tried adding it, several tests failed.
123 for (Node* sibling = NodeRenderingTraversal::previousSibling(m_node); sibling; sibling = NodeRenderingTraversal::previousSibling(sibling)) {
124 RenderObject* renderer = sibling->renderer();
125 if (renderer && !isRendererReparented(renderer))
126 return renderer;
127 }
128
129 return 0;
130}
131
132RenderObject* NodeRenderingContext::parentRenderer() const
133{
134 if (RenderObject* renderer = m_node->renderer())
135 return renderer->parent();
136
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100137 if (m_node->isElementNode() && toElement(m_node)->shouldBeReparentedUnderRenderView(m_style.get())) {
138 // The parent renderer of reparented elements is the RenderView, but only
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100139 // if the normal parent would have had a renderer.
140 // FIXME: This behavior isn't quite right as the spec for top layer
141 // only talks about display: none ancestors so putting a <dialog> inside
142 // an <optgroup> seems like it should still work even though this check
143 // will prevent it.
144 if (!m_renderingParent || !m_renderingParent->renderer())
145 return 0;
146 return m_node->document()->renderView();
147 }
148
149 if (m_parentFlowRenderer)
150 return m_parentFlowRenderer;
151
152 return m_renderingParent ? m_renderingParent->renderer() : 0;
153}
154
155bool NodeRenderingContext::shouldCreateRenderer() const
156{
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100157 if (!m_renderingParent)
158 return false;
159 RenderObject* parentRenderer = this->parentRenderer();
160 if (!parentRenderer)
161 return false;
162 if (!parentRenderer->canHaveChildren())
163 return false;
164 if (!m_renderingParent->childShouldCreateRenderer(*this))
165 return false;
166 return true;
167}
168
Ben Murdoch591b9582013-07-10 11:41:44 +0100169// Check the specific case of elements that are children of regions but are flowed into a flow thread themselves.
170bool NodeRenderingContext::elementInsideRegionNeedsRenderer()
171{
172 Element* element = toElement(m_node);
173 bool elementInsideRegionNeedsRenderer = false;
174 RenderObject* parentRenderer = this->parentRenderer();
175 if ((parentRenderer && !parentRenderer->canHaveChildren() && parentRenderer->isRenderRegion())
176 || (!parentRenderer && element->parentElement() && element->parentElement()->isInsideRegion())) {
177
178 if (!m_style)
179 m_style = element->styleForRenderer();
180
181 elementInsideRegionNeedsRenderer = element->shouldMoveToFlowThread(m_style.get());
182
183 // Children of this element will only be allowed to be flowed into other flow-threads if display is NOT none.
184 if (element->rendererIsNeeded(*this))
185 element->setIsInsideRegion(true);
186 }
187
188 return elementInsideRegionNeedsRenderer;
189}
190
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100191void NodeRenderingContext::moveToFlowThreadIfNeeded()
192{
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100193 if (!RuntimeEnabledFeatures::cssRegionsEnabled())
194 return;
195
Ben Murdoch591b9582013-07-10 11:41:44 +0100196 Element* element = toElement(m_node);
197
198 if (!element->shouldMoveToFlowThread(m_style.get()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100199 return;
200
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100201 ASSERT(m_node->document()->renderView());
202 FlowThreadController* flowThreadController = m_node->document()->renderView()->flowThreadController();
Ben Murdoch591b9582013-07-10 11:41:44 +0100203 m_parentFlowRenderer = flowThreadController->ensureRenderFlowThreadWithName(m_style->flowThread());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100204 flowThreadController->registerNamedFlowContentNode(m_node, m_parentFlowRenderer);
205}
206
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100207void NodeRenderingContext::createRendererForElementIfNeeded()
208{
209 ASSERT(!m_node->renderer());
210
211 Element* element = toElement(m_node);
212
Ben Murdoch591b9582013-07-10 11:41:44 +0100213 element->setIsInsideRegion(false);
214
215 if (!shouldCreateRenderer() && !elementInsideRegionNeedsRenderer())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100216 return;
Ben Murdoch591b9582013-07-10 11:41:44 +0100217
218 if (!m_style)
219 m_style = element->styleForRenderer();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100220 ASSERT(m_style);
221
222 moveToFlowThreadIfNeeded();
223
224 if (!element->rendererIsNeeded(*this))
225 return;
226
Ben Murdoch591b9582013-07-10 11:41:44 +0100227 RenderObject* newRenderer = element->createRenderer(m_style.get());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100228 if (!newRenderer)
229 return;
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100230
Ben Murdoch83750172013-07-24 10:36:59 +0100231 RenderObject* parentRenderer = this->parentRenderer();
232
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100233 if (!parentRenderer->isChildAllowed(newRenderer, m_style.get())) {
234 newRenderer->destroy();
235 return;
236 }
237
238 // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
239 // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
240 newRenderer->setFlowThreadState(parentRenderer->flowThreadState());
241
Ben Murdoch83750172013-07-24 10:36:59 +0100242 RenderObject* nextRenderer = this->nextRenderer();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100243 element->setRenderer(newRenderer);
244 newRenderer->setAnimatableStyle(m_style.release()); // setAnimatableStyle() can depend on renderer() already being set.
245
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100246 if (FullscreenElementStack::isActiveFullScreenElement(element)) {
Ben Murdoch83750172013-07-24 10:36:59 +0100247 newRenderer = RenderFullScreen::wrapRenderer(newRenderer, parentRenderer, element->document());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100248 if (!newRenderer)
249 return;
250 }
251
252 // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
253 parentRenderer->addChild(newRenderer, nextRenderer);
254}
255
256void NodeRenderingContext::createRendererForTextIfNeeded()
257{
258 ASSERT(!m_node->renderer());
259
260 Text* textNode = toText(m_node);
261
262 if (!shouldCreateRenderer())
263 return;
264
265 RenderObject* parentRenderer = this->parentRenderer();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100266
Ben Murdoch3464d022013-07-25 10:06:57 +0100267 if (m_parentDetails.resetStyleInheritance())
Ben Murdoch83750172013-07-24 10:36:59 +0100268 m_style = textNode->document()->styleResolver()->defaultStyleForElement();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100269 else
270 m_style = parentRenderer->style();
271
272 if (!textNode->textRendererIsNeeded(*this))
273 return;
Ben Murdoch83750172013-07-24 10:36:59 +0100274
Ben Murdoch591b9582013-07-10 11:41:44 +0100275 RenderText* newRenderer = textNode->createTextRenderer(m_style.get());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100276 if (!parentRenderer->isChildAllowed(newRenderer, m_style.get())) {
277 newRenderer->destroy();
278 return;
279 }
280
281 // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
282 // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
283 newRenderer->setFlowThreadState(parentRenderer->flowThreadState());
284
285 RenderObject* nextRenderer = this->nextRenderer();
286 textNode->setRenderer(newRenderer);
287 // Parent takes care of the animations, no need to call setAnimatableStyle.
288 newRenderer->setStyle(m_style.release());
289 parentRenderer->addChild(newRenderer, nextRenderer);
290}
291
292}