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.
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.
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.
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.
27 #include "core/dom/RenderTreeBuilder.h"
29 #include "HTMLNames.h"
30 #include "RuntimeEnabledFeatures.h"
32 #include "core/css/resolver/StyleResolver.h"
33 #include "core/dom/FullscreenElementStack.h"
34 #include "core/dom/Node.h"
35 #include "core/dom/Text.h"
36 #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"
42 #include "core/svg/SVGElement.h"
46 RenderObject* RenderTreeBuilder::nextRenderer() const
48 ASSERT(m_renderingParent);
50 Element* element = m_node->isElementNode() ? toElement(m_node) : 0;
53 if (element->isInTopLayer())
54 return NodeRenderingTraversal::nextInTopLayer(element);
55 // FIXME: Reparented dialogs not in the top layer need to be in DOM tree order.
56 // FIXME: The spec should not require magical behavior for <dialog>.
57 if (element->hasTagName(HTMLNames::dialogTag) && m_style->position() == AbsolutePosition)
61 if (m_parentFlowRenderer)
62 return m_parentFlowRenderer->nextRendererForNode(m_node);
64 // Avoid an O(N^2) walk over the children when reattaching all children of a node.
65 if (m_renderingParent->needsAttach())
68 return NodeRenderingTraversal::nextSiblingRenderer(m_node);
71 RenderObject* RenderTreeBuilder::parentRenderer() const
73 ASSERT(m_renderingParent);
75 Element* element = m_node->isElementNode() ? toElement(m_node) : 0;
77 if (element && m_renderingParent->renderer()) {
78 // FIXME: The spec should not require magical behavior for <dialog>. Note that the first
79 // time we enter here the m_style might be null because of a call in shouldCreateRenderer()
80 // which means we return the wrong wrong renderer for that check and then return a totally
81 // different renderer (the RenderView) later when this method is called after setting m_style.
82 if (element->hasTagName(HTMLNames::dialogTag) && m_style && m_style->position() == AbsolutePosition)
83 return m_node->document().renderView();
85 // FIXME: Guarding this by m_renderingParent->renderer() isn't quite right as the spec for
86 // top layer only talks about display: none ancestors so putting a <dialog> inside an
87 // <optgroup> seems like it should still work even though this check will prevent it.
88 if (element->isInTopLayer())
89 return m_node->document().renderView();
92 // Even if the normal parent has no renderer we still can be flowed into a named flow.
93 // FIXME: This is bad, it breaks the assumption that if you have a renderer then
94 // NodeRenderingTraversal::parent(this) also has one which likely means lots of bugs
96 if (m_parentFlowRenderer)
97 return m_parentFlowRenderer;
99 return m_renderingParent->renderer();
102 bool RenderTreeBuilder::shouldCreateRenderer() const
104 if (!m_renderingParent)
106 if (m_node->isSVGElement()) {
107 // SVG elements only render when inside <svg>, or if the element is an <svg> itself.
108 if (!m_node->hasTagName(SVGNames::svgTag) && !m_renderingParent->isSVGElement())
110 if (!toSVGElement(m_node)->isValid())
113 if (m_renderingParent->isSVGElement() && !toSVGElement(m_renderingParent)->childShouldCreateRenderer(*m_node))
115 RenderObject* parentRenderer = this->parentRenderer();
118 if (!parentRenderer->canHaveChildren())
123 // Check the specific case of elements that are children of regions but are flowed into a flow thread themselves.
124 bool RenderTreeBuilder::elementInsideRegionNeedsRenderer()
126 if (!RuntimeEnabledFeatures::cssRegionsEnabled())
128 Element& element = toElement(*m_node);
129 RenderObject* parentRenderer = this->parentRenderer();
130 if ((parentRenderer && !parentRenderer->canHaveChildren() && parentRenderer->isRenderNamedFlowFragmentContainer())
131 || (!parentRenderer && element.parentElement() && element.parentElement()->isInsideRegion())) {
133 // Children of this element will only be allowed to be flowed into other flow-threads if display is NOT none.
134 if (element.rendererIsNeeded(style()))
135 element.setIsInsideRegion(true);
137 return shouldMoveToFlowThread();
143 bool RenderTreeBuilder::shouldMoveToFlowThread() const
145 Element& element = toElement(*m_node);
146 RenderStyle& style = this->style();
148 if (style.flowThread().isEmpty())
151 if (FullscreenElementStack::isActiveFullScreenElement(&element))
154 if (element.isInShadowTree())
157 // As per http://dev.w3.org/csswg/css3-regions/#flow-into, pseudo-elements such as
158 // ::first-line, ::first-letter, ::before or ::after cannot be directly collected
159 // into a named flow.
160 if (element.isPseudoElement())
163 // Allow only svg root elements to be directly collected by a render flow thread.
164 if (element.isSVGElement()) {
165 if (!element.hasTagName(SVGNames::svgTag))
167 if (!element.parentNode())
169 if (element.parentNode()->isSVGElement())
173 return !element.isRegisteredWithNamedFlow();
176 void RenderTreeBuilder::moveToFlowThreadIfNeeded()
178 if (!RuntimeEnabledFeatures::cssRegionsEnabled())
181 if (!shouldMoveToFlowThread())
184 FlowThreadController* flowThreadController = m_node->document().renderView()->flowThreadController();
185 m_parentFlowRenderer = flowThreadController->ensureRenderFlowThreadWithName(style().flowThread());
186 flowThreadController->registerNamedFlowContentNode(m_node, m_parentFlowRenderer);
189 RenderStyle& RenderTreeBuilder::style() const
192 m_style = toElement(m_node)->styleForRenderer();
196 void RenderTreeBuilder::createRendererForElementIfNeeded()
198 ASSERT(!m_node->renderer());
200 // If we're out of composition then we can't render since there's no parent to inherit from.
201 if (!m_renderingParent)
204 Element* element = toElement(m_node);
206 if (!shouldCreateRenderer() && !elementInsideRegionNeedsRenderer())
209 moveToFlowThreadIfNeeded();
211 RenderStyle& style = this->style();
213 if (!element->rendererIsNeeded(style))
216 RenderObject* newRenderer = element->createRenderer(&style);
220 RenderObject* parentRenderer = this->parentRenderer();
222 if (!parentRenderer->isChildAllowed(newRenderer, &style)) {
223 newRenderer->destroy();
227 // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
228 // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
229 newRenderer->setFlowThreadState(parentRenderer->flowThreadState());
231 RenderObject* nextRenderer = this->nextRenderer();
232 element->setRenderer(newRenderer);
233 newRenderer->setAnimatableStyle(&style); // setAnimatableStyle() can depend on renderer() already being set.
235 if (FullscreenElementStack::isActiveFullScreenElement(element)) {
236 newRenderer = RenderFullScreen::wrapRenderer(newRenderer, parentRenderer, &element->document());
241 // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
242 parentRenderer->addChild(newRenderer, nextRenderer);
245 void RenderTreeBuilder::createRendererForTextIfNeeded()
247 ASSERT(!m_node->renderer());
249 // If we're out of composition then we can't render since there's no parent to inherit from.
250 if (!m_renderingParent)
253 if (!shouldCreateRenderer())
256 Text* textNode = toText(m_node);
257 RenderObject* parentRenderer = this->parentRenderer();
259 if (m_parentDetails.resetStyleInheritance())
260 m_style = textNode->document().ensureStyleResolver().defaultStyleForElement();
262 m_style = parentRenderer->style();
264 if (!textNode->textRendererIsNeeded(*m_style, *parentRenderer))
267 RenderText* newRenderer = textNode->createTextRenderer(m_style.get());
268 if (!parentRenderer->isChildAllowed(newRenderer, m_style.get())) {
269 newRenderer->destroy();
273 // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
274 // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
275 newRenderer->setFlowThreadState(parentRenderer->flowThreadState());
277 RenderObject* nextRenderer = this->nextRenderer();
278 textNode->setRenderer(newRenderer);
279 // Parent takes care of the animations, no need to call setAnimatableStyle.
280 newRenderer->setStyle(m_style.release());
281 parentRenderer->addChild(newRenderer, nextRenderer);