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 "core/HTMLNames.h"
30#include "core/SVGNames.h"
31#include "core/css/resolver/StyleResolver.h"
32#include "core/dom/FullscreenElementStack.h"
33#include "core/dom/Node.h"
34#include "core/dom/Text.h"
35#include "core/rendering/RenderFullScreen.h"
36#include "core/rendering/RenderObject.h"
37#include "core/rendering/RenderText.h"
38#include "core/rendering/RenderView.h"
39#include "core/svg/SVGElement.h"
40#include "platform/RuntimeEnabledFeatures.h"
41
42namespace WebCore {
43
44RenderObject* RenderTreeBuilder::nextRenderer() const
45{
46    ASSERT(m_renderingParent);
47
48    Element* element = m_node->isElementNode() ? toElement(m_node) : 0;
49
50    if (element && element->isInTopLayer())
51        return NodeRenderingTraversal::nextInTopLayer(element);
52
53    // Avoid an O(N^2) walk over the children when reattaching all children of a node.
54    if (m_renderingParent->needsAttach())
55        return 0;
56
57    return NodeRenderingTraversal::nextSiblingRenderer(m_node);
58}
59
60RenderObject* RenderTreeBuilder::parentRenderer() const
61{
62    ASSERT(m_renderingParent);
63
64    Element* element = m_node->isElementNode() ? toElement(m_node) : 0;
65
66    if (element && m_renderingParent->renderer()) {
67        // FIXME: Guarding this by m_renderingParent->renderer() isn't quite right as the spec for
68        // top layer only talks about display: none ancestors so putting a <dialog> inside an
69        // <optgroup> seems like it should still work even though this check will prevent it.
70        if (element->isInTopLayer())
71            return m_node->document().renderView();
72    }
73
74    return m_renderingParent->renderer();
75}
76
77bool RenderTreeBuilder::shouldCreateRenderer() const
78{
79    if (!m_renderingParent)
80        return false;
81    if (m_node->isSVGElement()) {
82        // SVG elements only render when inside <svg>, or if the element is an <svg> itself.
83        if (!isSVGSVGElement(*m_node) && !m_renderingParent->isSVGElement())
84            return false;
85        if (!toSVGElement(m_node)->isValid())
86            return false;
87    }
88    RenderObject* parentRenderer = this->parentRenderer();
89    if (!parentRenderer)
90        return false;
91    if (!parentRenderer->canHaveChildren())
92        return false;
93    return true;
94}
95
96RenderStyle& RenderTreeBuilder::style() const
97{
98    if (!m_style)
99        m_style = toElement(m_node)->styleForRenderer();
100    return *m_style;
101}
102
103void RenderTreeBuilder::createRendererForElementIfNeeded()
104{
105    ASSERT(!m_node->renderer());
106
107    if (!shouldCreateRenderer())
108        return;
109
110    Element* element = toElement(m_node);
111    RenderStyle& style = this->style();
112
113    if (!element->rendererIsNeeded(style))
114        return;
115
116    RenderObject* newRenderer = element->createRenderer(&style);
117    if (!newRenderer)
118        return;
119
120    RenderObject* parentRenderer = this->parentRenderer();
121
122    if (!parentRenderer->isChildAllowed(newRenderer, &style)) {
123        newRenderer->destroy();
124        return;
125    }
126
127    // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
128    // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
129    newRenderer->setFlowThreadState(parentRenderer->flowThreadState());
130
131    RenderObject* nextRenderer = this->nextRenderer();
132    element->setRenderer(newRenderer);
133    newRenderer->setStyle(&style); // setStyle() can depend on renderer() already being set.
134
135    if (FullscreenElementStack::isActiveFullScreenElement(element)) {
136        newRenderer = RenderFullScreen::wrapRenderer(newRenderer, parentRenderer, &element->document());
137        if (!newRenderer)
138            return;
139    }
140
141    // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer.
142    parentRenderer->addChild(newRenderer, nextRenderer);
143}
144
145void RenderTreeBuilder::createRendererForTextIfNeeded()
146{
147    ASSERT(!m_node->renderer());
148
149    if (!shouldCreateRenderer())
150        return;
151
152    Text* textNode = toText(m_node);
153    RenderObject* parentRenderer = this->parentRenderer();
154
155    m_style = parentRenderer->style();
156
157    if (!textNode->textRendererIsNeeded(*m_style, *parentRenderer))
158        return;
159
160    RenderText* newRenderer = textNode->createTextRenderer(m_style.get());
161    if (!parentRenderer->isChildAllowed(newRenderer, m_style.get())) {
162        newRenderer->destroy();
163        return;
164    }
165
166    // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style
167    // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail.
168    newRenderer->setFlowThreadState(parentRenderer->flowThreadState());
169
170    RenderObject* nextRenderer = this->nextRenderer();
171    textNode->setRenderer(newRenderer);
172    // Parent takes care of the animations, no need to call setAnimatableStyle.
173    newRenderer->setStyle(m_style.release());
174    parentRenderer->addChild(newRenderer, nextRenderer);
175}
176
177}
178