Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / dom / RenderTreeBuilder.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 "core/dom/RenderTreeBuilder.h"
28
29 #include "HTMLNames.h"
30 #include "RuntimeEnabledFeatures.h"
31 #include "SVGNames.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"
43
44 namespace WebCore {
45
46 RenderObject* RenderTreeBuilder::nextRenderer() const
47 {
48     ASSERT(m_renderingParent);
49
50     Element* element = m_node->isElementNode() ? toElement(m_node) : 0;
51
52     if (element) {
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)
58             return 0;
59     }
60
61     if (m_parentFlowRenderer)
62         return m_parentFlowRenderer->nextRendererForNode(m_node);
63
64     // Avoid an O(N^2) walk over the children when reattaching all children of a node.
65     if (m_renderingParent->needsAttach())
66         return 0;
67
68     return NodeRenderingTraversal::nextSiblingRenderer(m_node);
69 }
70
71 RenderObject* RenderTreeBuilder::parentRenderer() const
72 {
73     ASSERT(m_renderingParent);
74
75     Element* element = m_node->isElementNode() ? toElement(m_node) : 0;
76
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();
84
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();
90     }
91
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
95     // with regions.
96     if (m_parentFlowRenderer)
97         return m_parentFlowRenderer;
98
99     return m_renderingParent->renderer();
100 }
101
102 bool RenderTreeBuilder::shouldCreateRenderer() const
103 {
104     if (!m_renderingParent)
105         return false;
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())
109             return false;
110         if (!toSVGElement(m_node)->isValid())
111             return false;
112     }
113     if (m_renderingParent->isSVGElement() && !toSVGElement(m_renderingParent)->childShouldCreateRenderer(*m_node))
114         return false;
115     RenderObject* parentRenderer = this->parentRenderer();
116     if (!parentRenderer)
117         return false;
118     if (!parentRenderer->canHaveChildren())
119         return false;
120     return true;
121 }
122
123 // Check the specific case of elements that are children of regions but are flowed into a flow thread themselves.
124 bool RenderTreeBuilder::elementInsideRegionNeedsRenderer()
125 {
126     if (!RuntimeEnabledFeatures::cssRegionsEnabled())
127         return false;
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())) {
132
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);
136
137         return shouldMoveToFlowThread();
138     }
139
140     return false;
141 }
142
143 bool RenderTreeBuilder::shouldMoveToFlowThread() const
144 {
145     Element& element = toElement(*m_node);
146     RenderStyle& style = this->style();
147
148     if (style.flowThread().isEmpty())
149         return false;
150
151     if (FullscreenElementStack::isActiveFullScreenElement(&element))
152         return false;
153
154     if (element.isInShadowTree())
155         return false;
156
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())
161         return false;
162
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))
166             return false;
167         if (!element.parentNode())
168             return false;
169         if (element.parentNode()->isSVGElement())
170             return false;
171     }
172
173     return !element.isRegisteredWithNamedFlow();
174 }
175
176 void RenderTreeBuilder::moveToFlowThreadIfNeeded()
177 {
178     if (!RuntimeEnabledFeatures::cssRegionsEnabled())
179         return;
180
181     if (!shouldMoveToFlowThread())
182         return;
183
184     FlowThreadController* flowThreadController = m_node->document().renderView()->flowThreadController();
185     m_parentFlowRenderer = flowThreadController->ensureRenderFlowThreadWithName(style().flowThread());
186     flowThreadController->registerNamedFlowContentNode(m_node, m_parentFlowRenderer);
187 }
188
189 RenderStyle& RenderTreeBuilder::style() const
190 {
191     if (!m_style)
192         m_style = toElement(m_node)->styleForRenderer();
193     return *m_style;
194 }
195
196 void RenderTreeBuilder::createRendererForElementIfNeeded()
197 {
198     ASSERT(!m_node->renderer());
199
200     // If we're out of composition then we can't render since there's no parent to inherit from.
201     if (!m_renderingParent)
202         return;
203
204     Element* element = toElement(m_node);
205
206     if (!shouldCreateRenderer() && !elementInsideRegionNeedsRenderer())
207         return;
208
209     moveToFlowThreadIfNeeded();
210
211     RenderStyle& style = this->style();
212
213     if (!element->rendererIsNeeded(style))
214         return;
215
216     RenderObject* newRenderer = element->createRenderer(&style);
217     if (!newRenderer)
218         return;
219
220     RenderObject* parentRenderer = this->parentRenderer();
221
222     if (!parentRenderer->isChildAllowed(newRenderer, &style)) {
223         newRenderer->destroy();
224         return;
225     }
226
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());
230
231     RenderObject* nextRenderer = this->nextRenderer();
232     element->setRenderer(newRenderer);
233     newRenderer->setAnimatableStyle(&style); // setAnimatableStyle() can depend on renderer() already being set.
234
235     if (FullscreenElementStack::isActiveFullScreenElement(element)) {
236         newRenderer = RenderFullScreen::wrapRenderer(newRenderer, parentRenderer, &element->document());
237         if (!newRenderer)
238             return;
239     }
240
241     // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
242     parentRenderer->addChild(newRenderer, nextRenderer);
243 }
244
245 void RenderTreeBuilder::createRendererForTextIfNeeded()
246 {
247     ASSERT(!m_node->renderer());
248
249     // If we're out of composition then we can't render since there's no parent to inherit from.
250     if (!m_renderingParent)
251         return;
252
253     if (!shouldCreateRenderer())
254         return;
255
256     Text* textNode = toText(m_node);
257     RenderObject* parentRenderer = this->parentRenderer();
258
259     if (m_parentDetails.resetStyleInheritance())
260         m_style = textNode->document().ensureStyleResolver().defaultStyleForElement();
261     else
262         m_style = parentRenderer->style();
263
264     if (!textNode->textRendererIsNeeded(*m_style, *parentRenderer))
265         return;
266
267     RenderText* newRenderer = textNode->createTextRenderer(m_style.get());
268     if (!parentRenderer->isChildAllowed(newRenderer, m_style.get())) {
269         newRenderer->destroy();
270         return;
271     }
272
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());
276
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);
282 }
283
284 }