OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
4 * (C) 2001 Dirk Mueller (mueller@kde.org) | 4 * (C) 2001 Dirk Mueller (mueller@kde.org) |
5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r
ights reserved. | 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All r
ights reserved. |
6 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t
orchmobile.com/) | 6 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.t
orchmobile.com/) |
7 * Copyright (C) 2011 Google Inc. All rights reserved. | 7 * Copyright (C) 2011 Google Inc. All rights reserved. |
8 * | 8 * |
9 * This library is free software; you can redistribute it and/or | 9 * This library is free software; you can redistribute it and/or |
10 * modify it under the terms of the GNU Library General Public | 10 * modify it under the terms of the GNU Library General Public |
(...skipping 15 matching lines...) Expand all Loading... |
26 #include "config.h" | 26 #include "config.h" |
27 #include "core/dom/RenderTreeBuilder.h" | 27 #include "core/dom/RenderTreeBuilder.h" |
28 | 28 |
29 #include "HTMLNames.h" | 29 #include "HTMLNames.h" |
30 #include "RuntimeEnabledFeatures.h" | 30 #include "RuntimeEnabledFeatures.h" |
31 #include "SVGNames.h" | 31 #include "SVGNames.h" |
32 #include "core/css/resolver/StyleResolver.h" | 32 #include "core/css/resolver/StyleResolver.h" |
33 #include "core/dom/FullscreenElementStack.h" | 33 #include "core/dom/FullscreenElementStack.h" |
34 #include "core/dom/Node.h" | 34 #include "core/dom/Node.h" |
35 #include "core/dom/Text.h" | 35 #include "core/dom/Text.h" |
36 #include "core/rendering/FlowThreadController.h" | |
37 #include "core/rendering/RenderFullScreen.h" | 36 #include "core/rendering/RenderFullScreen.h" |
38 #include "core/rendering/RenderNamedFlowThread.h" | |
39 #include "core/rendering/RenderObject.h" | 37 #include "core/rendering/RenderObject.h" |
40 #include "core/rendering/RenderText.h" | 38 #include "core/rendering/RenderText.h" |
41 #include "core/rendering/RenderView.h" | 39 #include "core/rendering/RenderView.h" |
42 | 40 |
43 namespace WebCore { | 41 namespace WebCore { |
44 | 42 |
45 RenderObject* RenderTreeBuilder::nextRenderer() const | 43 RenderObject* RenderTreeBuilder::nextRenderer() const |
46 { | 44 { |
47 ASSERT(m_renderingParent); | 45 ASSERT(m_renderingParent); |
48 | 46 |
49 Element* element = m_node->isElementNode() ? toElement(m_node) : 0; | 47 Element* element = m_node->isElementNode() ? toElement(m_node) : 0; |
50 | 48 |
51 if (element) { | 49 if (element) { |
52 if (element->isInTopLayer()) | 50 if (element->isInTopLayer()) |
53 return NodeRenderingTraversal::nextInTopLayer(element); | 51 return NodeRenderingTraversal::nextInTopLayer(element); |
54 // FIXME: Reparented dialogs not in the top layer need to be in DOM tree
order. | 52 // FIXME: Reparented dialogs not in the top layer need to be in DOM tree
order. |
55 // FIXME: The spec should not require magical behavior for <dialog>. | 53 // FIXME: The spec should not require magical behavior for <dialog>. |
56 if (element->hasTagName(HTMLNames::dialogTag) && m_style->position() ==
AbsolutePosition) | 54 if (element->hasTagName(HTMLNames::dialogTag) && m_style->position() ==
AbsolutePosition) |
57 return 0; | 55 return 0; |
58 } | 56 } |
59 | 57 |
60 if (m_parentFlowRenderer) | |
61 return m_parentFlowRenderer->nextRendererForNode(m_node); | |
62 | |
63 // Avoid an O(N^2) walk over the children when reattaching all children of a
node. | 58 // Avoid an O(N^2) walk over the children when reattaching all children of a
node. |
64 if (m_renderingParent->needsAttach()) | 59 if (m_renderingParent->needsAttach()) |
65 return 0; | 60 return 0; |
66 | 61 |
67 return NodeRenderingTraversal::nextSiblingRenderer(m_node); | 62 return NodeRenderingTraversal::nextSiblingRenderer(m_node); |
68 } | 63 } |
69 | 64 |
70 RenderObject* RenderTreeBuilder::parentRenderer() const | 65 RenderObject* RenderTreeBuilder::parentRenderer() const |
71 { | 66 { |
72 ASSERT(m_renderingParent); | 67 ASSERT(m_renderingParent); |
73 | 68 |
74 Element* element = m_node->isElementNode() ? toElement(m_node) : 0; | 69 Element* element = m_node->isElementNode() ? toElement(m_node) : 0; |
75 | 70 |
76 if (element && m_renderingParent->renderer()) { | 71 if (element && m_renderingParent->renderer()) { |
77 // FIXME: The spec should not require magical behavior for <dialog>. Not
e that the first | 72 // FIXME: The spec should not require magical behavior for <dialog>. Not
e that the first |
78 // time we enter here the m_style might be null because of a call in sho
uldCreateRenderer() | 73 // time we enter here the m_style might be null because of a call in sho
uldCreateRenderer() |
79 // which means we return the wrong wrong renderer for that check and the
n return a totally | 74 // which means we return the wrong wrong renderer for that check and the
n return a totally |
80 // different renderer (the RenderView) later when this method is called
after setting m_style. | 75 // different renderer (the RenderView) later when this method is called
after setting m_style. |
81 if (element->hasTagName(HTMLNames::dialogTag) && m_style && m_style->pos
ition() == AbsolutePosition) | 76 if (element->hasTagName(HTMLNames::dialogTag) && m_style && m_style->pos
ition() == AbsolutePosition) |
82 return m_node->document().renderView(); | 77 return m_node->document().renderView(); |
83 | 78 |
84 // FIXME: Guarding this by m_renderingParent->renderer() isn't quite rig
ht as the spec for | 79 // FIXME: Guarding this by m_renderingParent->renderer() isn't quite rig
ht as the spec for |
85 // top layer only talks about display: none ancestors so putting a <dial
og> inside an | 80 // top layer only talks about display: none ancestors so putting a <dial
og> inside an |
86 // <optgroup> seems like it should still work even though this check wil
l prevent it. | 81 // <optgroup> seems like it should still work even though this check wil
l prevent it. |
87 if (element->isInTopLayer()) | 82 if (element->isInTopLayer()) |
88 return m_node->document().renderView(); | 83 return m_node->document().renderView(); |
89 } | 84 } |
90 | 85 |
91 // Even if the normal parent has no renderer we still can be flowed into a n
amed flow. | |
92 // FIXME: This is bad, it breaks the assumption that if you have a renderer
then | |
93 // NodeRenderingTraversal::parent(this) also has one which likely means lots
of bugs | |
94 // with regions. | |
95 if (m_parentFlowRenderer) | |
96 return m_parentFlowRenderer; | |
97 | |
98 return m_renderingParent->renderer(); | 86 return m_renderingParent->renderer(); |
99 } | 87 } |
100 | 88 |
101 bool RenderTreeBuilder::shouldCreateRenderer() const | 89 bool RenderTreeBuilder::shouldCreateRenderer() const |
102 { | 90 { |
103 if (!m_renderingParent) | 91 if (!m_renderingParent) |
104 return false; | 92 return false; |
105 // SVG elements only render when inside <svg>, or if the element is an <svg>
itself. | 93 // SVG elements only render when inside <svg>, or if the element is an <svg>
itself. |
106 if (m_node->isSVGElement() && !m_node->hasTagName(SVGNames::svgTag) && !m_re
nderingParent->isSVGElement()) | 94 if (m_node->isSVGElement() && !m_node->hasTagName(SVGNames::svgTag) && !m_re
nderingParent->isSVGElement()) |
107 return false; | 95 return false; |
108 RenderObject* parentRenderer = this->parentRenderer(); | 96 RenderObject* parentRenderer = this->parentRenderer(); |
109 if (!parentRenderer) | 97 if (!parentRenderer) |
110 return false; | 98 return false; |
111 if (!parentRenderer->canHaveChildren()) | 99 if (!parentRenderer->canHaveChildren()) |
112 return false; | 100 return false; |
113 if (!m_renderingParent->childShouldCreateRenderer(*m_node)) | 101 if (!m_renderingParent->childShouldCreateRenderer(*m_node)) |
114 return false; | 102 return false; |
115 return true; | 103 return true; |
116 } | 104 } |
117 | 105 |
118 // Check the specific case of elements that are children of regions but are flow
ed into a flow thread themselves. | |
119 bool RenderTreeBuilder::elementInsideRegionNeedsRenderer() | |
120 { | |
121 if (!RuntimeEnabledFeatures::cssRegionsEnabled()) | |
122 return false; | |
123 Element& element = toElement(*m_node); | |
124 RenderObject* parentRenderer = this->parentRenderer(); | |
125 if ((parentRenderer && !parentRenderer->canHaveChildren() && parentRenderer-
>isRenderNamedFlowFragmentContainer()) | |
126 || (!parentRenderer && element.parentElement() && element.parentElement(
)->isInsideRegion())) { | |
127 | |
128 // Children of this element will only be allowed to be flowed into other
flow-threads if display is NOT none. | |
129 if (element.rendererIsNeeded(style())) | |
130 element.setIsInsideRegion(true); | |
131 | |
132 return shouldMoveToFlowThread(); | |
133 } | |
134 | |
135 return false; | |
136 } | |
137 | |
138 bool RenderTreeBuilder::shouldMoveToFlowThread() const | |
139 { | |
140 Element& element = toElement(*m_node); | |
141 RenderStyle& style = this->style(); | |
142 | |
143 if (style.flowThread().isEmpty()) | |
144 return false; | |
145 | |
146 if (FullscreenElementStack::isActiveFullScreenElement(&element)) | |
147 return false; | |
148 | |
149 if (element.isInShadowTree()) | |
150 return false; | |
151 | |
152 // As per http://dev.w3.org/csswg/css3-regions/#flow-into, pseudo-elements s
uch as | |
153 // ::first-line, ::first-letter, ::before or ::after cannot be directly coll
ected | |
154 // into a named flow. | |
155 if (element.isPseudoElement()) | |
156 return false; | |
157 | |
158 // Allow only svg root elements to be directly collected by a render flow th
read. | |
159 if (element.isSVGElement()) { | |
160 if (!element.hasTagName(SVGNames::svgTag)) | |
161 return false; | |
162 if (!element.parentNode()) | |
163 return false; | |
164 if (element.parentNode()->isSVGElement()) | |
165 return false; | |
166 } | |
167 | |
168 return !element.isRegisteredWithNamedFlow(); | |
169 } | |
170 | |
171 void RenderTreeBuilder::moveToFlowThreadIfNeeded() | |
172 { | |
173 if (!RuntimeEnabledFeatures::cssRegionsEnabled()) | |
174 return; | |
175 | |
176 if (!shouldMoveToFlowThread()) | |
177 return; | |
178 | |
179 FlowThreadController* flowThreadController = m_node->document().renderView()
->flowThreadController(); | |
180 m_parentFlowRenderer = flowThreadController->ensureRenderFlowThreadWithName(
style().flowThread()); | |
181 flowThreadController->registerNamedFlowContentNode(m_node, m_parentFlowRende
rer); | |
182 } | |
183 | |
184 RenderStyle& RenderTreeBuilder::style() const | 106 RenderStyle& RenderTreeBuilder::style() const |
185 { | 107 { |
186 if (!m_style) | 108 if (!m_style) |
187 m_style = toElement(m_node)->styleForRenderer(); | 109 m_style = toElement(m_node)->styleForRenderer(); |
188 return *m_style; | 110 return *m_style; |
189 } | 111 } |
190 | 112 |
191 void RenderTreeBuilder::createRendererForElementIfNeeded() | 113 void RenderTreeBuilder::createRendererForElementIfNeeded() |
192 { | 114 { |
193 ASSERT(!m_node->renderer()); | 115 ASSERT(!m_node->renderer()); |
194 | 116 |
195 // If we're out of composition then we can't render since there's no parent
to inherit from. | 117 // If we're out of composition then we can't render since there's no parent
to inherit from. |
196 if (!m_renderingParent) | 118 if (!m_renderingParent) |
197 return; | 119 return; |
198 | 120 |
199 Element* element = toElement(m_node); | 121 Element* element = toElement(m_node); |
200 | 122 |
201 if (!shouldCreateRenderer() && !elementInsideRegionNeedsRenderer()) | 123 if (!shouldCreateRenderer()) |
202 return; | 124 return; |
203 | 125 |
204 moveToFlowThreadIfNeeded(); | |
205 | |
206 RenderStyle& style = this->style(); | 126 RenderStyle& style = this->style(); |
207 | 127 |
208 if (!element->rendererIsNeeded(style)) | 128 if (!element->rendererIsNeeded(style)) |
209 return; | 129 return; |
210 | 130 |
211 RenderObject* newRenderer = element->createRenderer(&style); | 131 RenderObject* newRenderer = element->createRenderer(&style); |
212 if (!newRenderer) | 132 if (!newRenderer) |
213 return; | 133 return; |
214 | 134 |
215 RenderObject* parentRenderer = this->parentRenderer(); | 135 RenderObject* parentRenderer = this->parentRenderer(); |
216 | 136 |
217 if (!parentRenderer->isChildAllowed(newRenderer, &style)) { | 137 if (!parentRenderer->isChildAllowed(newRenderer, &style)) { |
218 newRenderer->destroy(); | 138 newRenderer->destroy(); |
219 return; | 139 return; |
220 } | 140 } |
221 | 141 |
222 // Make sure the RenderObject already knows it is going to be added to a Ren
derFlowThread before we set the style | |
223 // for the first time. Otherwise code using inRenderFlowThread() in the styl
eWillChange and styleDidChange will fail. | |
224 newRenderer->setFlowThreadState(parentRenderer->flowThreadState()); | |
225 | |
226 RenderObject* nextRenderer = this->nextRenderer(); | 142 RenderObject* nextRenderer = this->nextRenderer(); |
227 element->setRenderer(newRenderer); | 143 element->setRenderer(newRenderer); |
228 newRenderer->setAnimatableStyle(&style); // setAnimatableStyle() can depend
on renderer() already being set. | 144 newRenderer->setAnimatableStyle(&style); // setAnimatableStyle() can depend
on renderer() already being set. |
229 | 145 |
230 if (FullscreenElementStack::isActiveFullScreenElement(element)) { | 146 if (FullscreenElementStack::isActiveFullScreenElement(element)) { |
231 newRenderer = RenderFullScreen::wrapRenderer(newRenderer, parentRenderer
, &element->document()); | 147 newRenderer = RenderFullScreen::wrapRenderer(newRenderer, parentRenderer
, &element->document()); |
232 if (!newRenderer) | 148 if (!newRenderer) |
233 return; | 149 return; |
234 } | 150 } |
235 | 151 |
(...skipping 22 matching lines...) Expand all Loading... |
258 | 174 |
259 if (!textNode->textRendererIsNeeded(*m_style, *parentRenderer)) | 175 if (!textNode->textRendererIsNeeded(*m_style, *parentRenderer)) |
260 return; | 176 return; |
261 | 177 |
262 RenderText* newRenderer = textNode->createTextRenderer(m_style.get()); | 178 RenderText* newRenderer = textNode->createTextRenderer(m_style.get()); |
263 if (!parentRenderer->isChildAllowed(newRenderer, m_style.get())) { | 179 if (!parentRenderer->isChildAllowed(newRenderer, m_style.get())) { |
264 newRenderer->destroy(); | 180 newRenderer->destroy(); |
265 return; | 181 return; |
266 } | 182 } |
267 | 183 |
268 // Make sure the RenderObject already knows it is going to be added to a Ren
derFlowThread before we set the style | |
269 // for the first time. Otherwise code using inRenderFlowThread() in the styl
eWillChange and styleDidChange will fail. | |
270 newRenderer->setFlowThreadState(parentRenderer->flowThreadState()); | |
271 | |
272 RenderObject* nextRenderer = this->nextRenderer(); | 184 RenderObject* nextRenderer = this->nextRenderer(); |
273 textNode->setRenderer(newRenderer); | 185 textNode->setRenderer(newRenderer); |
274 // Parent takes care of the animations, no need to call setAnimatableStyle. | 186 // Parent takes care of the animations, no need to call setAnimatableStyle. |
275 newRenderer->setStyle(m_style.release()); | 187 newRenderer->setStyle(m_style.release()); |
276 parentRenderer->addChild(newRenderer, nextRenderer); | 188 parentRenderer->addChild(newRenderer, nextRenderer); |
277 } | 189 } |
278 | 190 |
279 } | 191 } |
OLD | NEW |