Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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/NodeRenderingContext.h" |
| 28 | |
Ben Murdoch | 7757ec2 | 2013-07-23 11:17:36 +0100 | [diff] [blame] | 29 | #include "RuntimeEnabledFeatures.h" |
Torne (Richard Coles) | 81a5157 | 2013-05-13 16:52:28 +0100 | [diff] [blame] | 30 | #include "core/css/resolver/StyleResolver.h" |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 31 | #include "core/dom/ContainerNode.h" |
Torne (Richard Coles) | f5e4ad5 | 2013-08-05 13:57:57 +0100 | [diff] [blame] | 32 | #include "core/dom/FullscreenElementStack.h" |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 33 | #include "core/dom/Node.h" |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 34 | #include "core/dom/Text.h" |
Ben Murdoch | 8375017 | 2013-07-24 10:36:59 +0100 | [diff] [blame] | 35 | #include "core/dom/shadow/InsertionPoint.h" |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 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" |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 42 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 43 | namespace WebCore { |
| 44 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 45 | NodeRenderingContext::NodeRenderingContext(Node* node, RenderStyle* style) |
| 46 | : m_node(node) |
| 47 | , m_renderingParent(0) |
| 48 | , m_style(style) |
| 49 | , m_parentFlowRenderer(0) |
| 50 | { |
Torne (Richard Coles) | 521d96e | 2013-06-19 11:58:24 +0100 | [diff] [blame] | 51 | m_renderingParent = NodeRenderingTraversal::parent(node, &m_parentDetails); |
| 52 | } |
| 53 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 54 | static bool isRendererReparented(const RenderObject* renderer) |
| 55 | { |
| 56 | if (!renderer->node()->isElementNode()) |
| 57 | return false; |
| 58 | if (renderer->style() && !renderer->style()->flowThread().isEmpty()) |
| 59 | return true; |
Torne (Richard Coles) | e524955 | 2013-05-15 11:35:13 +0100 | [diff] [blame] | 60 | if (toElement(renderer->node())->shouldBeReparentedUnderRenderView(renderer->style())) |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 61 | return true; |
| 62 | return false; |
| 63 | } |
| 64 | |
| 65 | RenderObject* NodeRenderingContext::nextRenderer() const |
| 66 | { |
| 67 | if (RenderObject* renderer = m_node->renderer()) |
| 68 | return renderer->nextSibling(); |
| 69 | |
| 70 | Element* element = m_node->isElementNode() ? toElement(m_node) : 0; |
Torne (Richard Coles) | e524955 | 2013-05-15 11:35:13 +0100 | [diff] [blame] | 71 | if (element && element->shouldBeReparentedUnderRenderView(m_style.get())) { |
| 72 | // FIXME: Reparented renderers not in the top layer should probably be |
| 73 | // ordered in DOM tree order. We don't have a good way to do that yet, |
| 74 | // since NodeRenderingTraversal isn't aware of reparenting. It's safe to |
| 75 | // just append for now; it doesn't disrupt the top layer rendering as |
| 76 | // the layer collection in RenderLayer only requires that top layer |
| 77 | // renderers are orderered correctly relative to each other. |
| 78 | if (!element->isInTopLayer()) |
| 79 | return 0; |
| 80 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 81 | const Vector<RefPtr<Element> >& topLayerElements = element->document()->topLayerElements(); |
| 82 | size_t position = topLayerElements.find(element); |
| 83 | ASSERT(position != notFound); |
| 84 | for (size_t i = position + 1; i < topLayerElements.size(); ++i) { |
| 85 | if (RenderObject* renderer = topLayerElements[i]->renderer()) |
| 86 | return renderer; |
| 87 | } |
| 88 | return 0; |
| 89 | } |
| 90 | |
| 91 | if (m_parentFlowRenderer) |
| 92 | return m_parentFlowRenderer->nextRendererForNode(m_node); |
| 93 | |
| 94 | // Avoid an O(N^2) problem with this function by not checking for |
| 95 | // nextRenderer() when the parent element hasn't attached yet. |
| 96 | if (m_renderingParent && !m_renderingParent->attached()) |
| 97 | return 0; |
| 98 | |
| 99 | for (Node* sibling = NodeRenderingTraversal::nextSibling(m_node); sibling; sibling = NodeRenderingTraversal::nextSibling(sibling)) { |
| 100 | RenderObject* renderer = sibling->renderer(); |
| 101 | if (renderer && !isRendererReparented(renderer)) |
| 102 | return renderer; |
| 103 | } |
| 104 | |
| 105 | return 0; |
| 106 | } |
| 107 | |
| 108 | RenderObject* NodeRenderingContext::previousRenderer() const |
| 109 | { |
| 110 | if (RenderObject* renderer = m_node->renderer()) |
| 111 | return renderer->previousSibling(); |
| 112 | |
Torne (Richard Coles) | e524955 | 2013-05-15 11:35:13 +0100 | [diff] [blame] | 113 | // FIXME: This doesn't work correctly for reparented elements that are |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 114 | // display: none. We'd need to duplicate the logic in nextRenderer, but since |
| 115 | // nothing needs that yet just assert. |
Torne (Richard Coles) | e524955 | 2013-05-15 11:35:13 +0100 | [diff] [blame] | 116 | ASSERT(!m_node->isElementNode() || !toElement(m_node)->shouldBeReparentedUnderRenderView(m_style.get())); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 117 | |
| 118 | if (m_parentFlowRenderer) |
| 119 | return m_parentFlowRenderer->previousRendererForNode(m_node); |
| 120 | |
| 121 | // FIXME: We should have the same O(N^2) avoidance as nextRenderer does |
| 122 | // however, when I tried adding it, several tests failed. |
| 123 | for (Node* sibling = NodeRenderingTraversal::previousSibling(m_node); sibling; sibling = NodeRenderingTraversal::previousSibling(sibling)) { |
| 124 | RenderObject* renderer = sibling->renderer(); |
| 125 | if (renderer && !isRendererReparented(renderer)) |
| 126 | return renderer; |
| 127 | } |
| 128 | |
| 129 | return 0; |
| 130 | } |
| 131 | |
| 132 | RenderObject* NodeRenderingContext::parentRenderer() const |
| 133 | { |
| 134 | if (RenderObject* renderer = m_node->renderer()) |
| 135 | return renderer->parent(); |
| 136 | |
Torne (Richard Coles) | e524955 | 2013-05-15 11:35:13 +0100 | [diff] [blame] | 137 | if (m_node->isElementNode() && toElement(m_node)->shouldBeReparentedUnderRenderView(m_style.get())) { |
| 138 | // The parent renderer of reparented elements is the RenderView, but only |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 139 | // if the normal parent would have had a renderer. |
| 140 | // FIXME: This behavior isn't quite right as the spec for top layer |
| 141 | // only talks about display: none ancestors so putting a <dialog> inside |
| 142 | // an <optgroup> seems like it should still work even though this check |
| 143 | // will prevent it. |
| 144 | if (!m_renderingParent || !m_renderingParent->renderer()) |
| 145 | return 0; |
| 146 | return m_node->document()->renderView(); |
| 147 | } |
| 148 | |
| 149 | if (m_parentFlowRenderer) |
| 150 | return m_parentFlowRenderer; |
| 151 | |
| 152 | return m_renderingParent ? m_renderingParent->renderer() : 0; |
| 153 | } |
| 154 | |
| 155 | bool NodeRenderingContext::shouldCreateRenderer() const |
| 156 | { |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 157 | if (!m_renderingParent) |
| 158 | return false; |
| 159 | RenderObject* parentRenderer = this->parentRenderer(); |
| 160 | if (!parentRenderer) |
| 161 | return false; |
| 162 | if (!parentRenderer->canHaveChildren()) |
| 163 | return false; |
| 164 | if (!m_renderingParent->childShouldCreateRenderer(*this)) |
| 165 | return false; |
| 166 | return true; |
| 167 | } |
| 168 | |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 169 | // Check the specific case of elements that are children of regions but are flowed into a flow thread themselves. |
| 170 | bool NodeRenderingContext::elementInsideRegionNeedsRenderer() |
| 171 | { |
| 172 | Element* element = toElement(m_node); |
| 173 | bool elementInsideRegionNeedsRenderer = false; |
| 174 | RenderObject* parentRenderer = this->parentRenderer(); |
| 175 | if ((parentRenderer && !parentRenderer->canHaveChildren() && parentRenderer->isRenderRegion()) |
| 176 | || (!parentRenderer && element->parentElement() && element->parentElement()->isInsideRegion())) { |
| 177 | |
| 178 | if (!m_style) |
| 179 | m_style = element->styleForRenderer(); |
| 180 | |
| 181 | elementInsideRegionNeedsRenderer = element->shouldMoveToFlowThread(m_style.get()); |
| 182 | |
| 183 | // Children of this element will only be allowed to be flowed into other flow-threads if display is NOT none. |
| 184 | if (element->rendererIsNeeded(*this)) |
| 185 | element->setIsInsideRegion(true); |
| 186 | } |
| 187 | |
| 188 | return elementInsideRegionNeedsRenderer; |
| 189 | } |
| 190 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 191 | void NodeRenderingContext::moveToFlowThreadIfNeeded() |
| 192 | { |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 193 | if (!RuntimeEnabledFeatures::cssRegionsEnabled()) |
| 194 | return; |
| 195 | |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 196 | Element* element = toElement(m_node); |
| 197 | |
| 198 | if (!element->shouldMoveToFlowThread(m_style.get())) |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 199 | return; |
| 200 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 201 | ASSERT(m_node->document()->renderView()); |
| 202 | FlowThreadController* flowThreadController = m_node->document()->renderView()->flowThreadController(); |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 203 | m_parentFlowRenderer = flowThreadController->ensureRenderFlowThreadWithName(m_style->flowThread()); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 204 | flowThreadController->registerNamedFlowContentNode(m_node, m_parentFlowRenderer); |
| 205 | } |
| 206 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 207 | void NodeRenderingContext::createRendererForElementIfNeeded() |
| 208 | { |
| 209 | ASSERT(!m_node->renderer()); |
| 210 | |
| 211 | Element* element = toElement(m_node); |
| 212 | |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 213 | element->setIsInsideRegion(false); |
| 214 | |
| 215 | if (!shouldCreateRenderer() && !elementInsideRegionNeedsRenderer()) |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 216 | return; |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 217 | |
| 218 | if (!m_style) |
| 219 | m_style = element->styleForRenderer(); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 220 | ASSERT(m_style); |
| 221 | |
| 222 | moveToFlowThreadIfNeeded(); |
| 223 | |
| 224 | if (!element->rendererIsNeeded(*this)) |
| 225 | return; |
| 226 | |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 227 | RenderObject* newRenderer = element->createRenderer(m_style.get()); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 228 | if (!newRenderer) |
| 229 | return; |
Torne (Richard Coles) | 93ac45c | 2013-05-29 14:40:20 +0100 | [diff] [blame] | 230 | |
Ben Murdoch | 8375017 | 2013-07-24 10:36:59 +0100 | [diff] [blame] | 231 | RenderObject* parentRenderer = this->parentRenderer(); |
| 232 | |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 233 | if (!parentRenderer->isChildAllowed(newRenderer, m_style.get())) { |
| 234 | newRenderer->destroy(); |
| 235 | return; |
| 236 | } |
| 237 | |
| 238 | // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style |
| 239 | // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail. |
| 240 | newRenderer->setFlowThreadState(parentRenderer->flowThreadState()); |
| 241 | |
Ben Murdoch | 8375017 | 2013-07-24 10:36:59 +0100 | [diff] [blame] | 242 | RenderObject* nextRenderer = this->nextRenderer(); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 243 | element->setRenderer(newRenderer); |
| 244 | newRenderer->setAnimatableStyle(m_style.release()); // setAnimatableStyle() can depend on renderer() already being set. |
| 245 | |
Torne (Richard Coles) | f5e4ad5 | 2013-08-05 13:57:57 +0100 | [diff] [blame] | 246 | if (FullscreenElementStack::isActiveFullScreenElement(element)) { |
Ben Murdoch | 8375017 | 2013-07-24 10:36:59 +0100 | [diff] [blame] | 247 | newRenderer = RenderFullScreen::wrapRenderer(newRenderer, parentRenderer, element->document()); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 248 | if (!newRenderer) |
| 249 | return; |
| 250 | } |
| 251 | |
| 252 | // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer. |
| 253 | parentRenderer->addChild(newRenderer, nextRenderer); |
| 254 | } |
| 255 | |
| 256 | void NodeRenderingContext::createRendererForTextIfNeeded() |
| 257 | { |
| 258 | ASSERT(!m_node->renderer()); |
| 259 | |
| 260 | Text* textNode = toText(m_node); |
| 261 | |
| 262 | if (!shouldCreateRenderer()) |
| 263 | return; |
| 264 | |
| 265 | RenderObject* parentRenderer = this->parentRenderer(); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 266 | |
Ben Murdoch | 3464d02 | 2013-07-25 10:06:57 +0100 | [diff] [blame] | 267 | if (m_parentDetails.resetStyleInheritance()) |
Ben Murdoch | 8375017 | 2013-07-24 10:36:59 +0100 | [diff] [blame] | 268 | m_style = textNode->document()->styleResolver()->defaultStyleForElement(); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 269 | else |
| 270 | m_style = parentRenderer->style(); |
| 271 | |
| 272 | if (!textNode->textRendererIsNeeded(*this)) |
| 273 | return; |
Ben Murdoch | 8375017 | 2013-07-24 10:36:59 +0100 | [diff] [blame] | 274 | |
Ben Murdoch | 591b958 | 2013-07-10 11:41:44 +0100 | [diff] [blame] | 275 | RenderText* newRenderer = textNode->createTextRenderer(m_style.get()); |
Torne (Richard Coles) | 53e740f | 2013-05-09 18:38:43 +0100 | [diff] [blame] | 276 | if (!parentRenderer->isChildAllowed(newRenderer, m_style.get())) { |
| 277 | newRenderer->destroy(); |
| 278 | return; |
| 279 | } |
| 280 | |
| 281 | // Make sure the RenderObject already knows it is going to be added to a RenderFlowThread before we set the style |
| 282 | // for the first time. Otherwise code using inRenderFlowThread() in the styleWillChange and styleDidChange will fail. |
| 283 | newRenderer->setFlowThreadState(parentRenderer->flowThreadState()); |
| 284 | |
| 285 | RenderObject* nextRenderer = this->nextRenderer(); |
| 286 | textNode->setRenderer(newRenderer); |
| 287 | // Parent takes care of the animations, no need to call setAnimatableStyle. |
| 288 | newRenderer->setStyle(m_style.release()); |
| 289 | parentRenderer->addChild(newRenderer, nextRenderer); |
| 290 | } |
| 291 | |
| 292 | } |