| 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 |