diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
commit | 40736c5763bf61337c8c14e16d8587db021a87d4 (patch) | |
tree | b17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/WebCore/dom/NodeRenderingContext.cpp | |
download | qtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz |
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/WebCore/dom/NodeRenderingContext.cpp')
-rw-r--r-- | Source/WebCore/dom/NodeRenderingContext.cpp | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/Source/WebCore/dom/NodeRenderingContext.cpp b/Source/WebCore/dom/NodeRenderingContext.cpp new file mode 100644 index 000000000..96529fb86 --- /dev/null +++ b/Source/WebCore/dom/NodeRenderingContext.cpp @@ -0,0 +1,353 @@ +/* + * Copyright (C) 1999 Lars Knoll (knoll@kde.org) + * (C) 1999 Antti Koivisto (koivisto@kde.org) + * (C) 2001 Dirk Mueller (mueller@kde.org) + * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "NodeRenderingContext.h" + +#include "ContainerNode.h" +#include "Node.h" +#include "RenderFlowThread.h" +#include "RenderFullScreen.h" +#include "RenderObject.h" +#include "RenderView.h" +#include "ShadowContentElement.h" +#include "ShadowInclusionSelector.h" +#include "ShadowRoot.h" + +namespace WebCore { + +NodeRenderingContext::NodeRenderingContext(Node* node) + : m_location(LocationNotInTree) + , m_phase(AttachStraight) + , m_node(node) + , m_parentNodeForRenderingAndStyle(0) + , m_visualParentShadowRoot(0) + , m_includer(0) + , m_style(0) + , m_parentFlowRenderer(0) +{ + ContainerNode* parent = m_node->parentOrHostNode(); + if (!parent) + return; + + if (parent->isShadowRoot()) { + m_location = LocationShadowChild; + m_parentNodeForRenderingAndStyle = parent->shadowHost(); + return; + } + + m_location = LocationLightChild; + + if (parent->isElementNode()) { + m_visualParentShadowRoot = toElement(parent)->shadowRoot(); + + if (m_visualParentShadowRoot) { + if ((m_includer = m_visualParentShadowRoot->includerFor(m_node)) + && m_visualParentShadowRoot->isInclusionSelectorActive()) { + m_phase = AttachContentForwarded; + m_parentNodeForRenderingAndStyle = NodeRenderingContext(m_includer).parentNodeForRenderingAndStyle(); + return; + } + + m_phase = AttachContentLight; + m_parentNodeForRenderingAndStyle = parent; + return; + } + } + + m_parentNodeForRenderingAndStyle = parent; +} + +NodeRenderingContext::NodeRenderingContext(Node* node, RenderStyle* style) + : m_location(LocationUndetermined) + , m_phase(AttachStraight) + , m_node(node) + , m_parentNodeForRenderingAndStyle(0) + , m_visualParentShadowRoot(0) + , m_includer(0) + , m_style(style) + , m_parentFlowRenderer(0) +{ +} + +NodeRenderingContext::~NodeRenderingContext() +{ +} + +void NodeRenderingContext::setStyle(PassRefPtr<RenderStyle> style) +{ + m_style = style; + moveToFlowThreadIfNeeded(); +} + +PassRefPtr<RenderStyle> NodeRenderingContext::releaseStyle() +{ + return m_style.release(); +} + +static RenderObject* nextRendererOf(ShadowContentElement* parent, Node* current) +{ + ShadowInclusion* currentInclusion = parent->inclusions()->find(current); + if (!currentInclusion) + return 0; + + for (ShadowInclusion* inclusion = currentInclusion->next(); inclusion; inclusion = inclusion->next()) { + if (RenderObject* renderer = inclusion->content()->renderer()) + return renderer; + } + + return 0; +} + +static RenderObject* previousRendererOf(ShadowContentElement* parent, Node* current) +{ + RenderObject* lastRenderer = 0; + + for (ShadowInclusion* inclusion = parent->inclusions()->first(); inclusion; inclusion = inclusion->next()) { + if (inclusion->content() == current) + break; + if (RenderObject* renderer = inclusion->content()->renderer()) + lastRenderer = renderer; + } + + return lastRenderer; +} + +static RenderObject* firstRendererOf(ShadowContentElement* parent) +{ + for (ShadowInclusion* inclusion = parent->inclusions()->first(); inclusion; inclusion = inclusion->next()) { + if (RenderObject* renderer = inclusion->content()->renderer()) + return renderer; + } + + return 0; +} + +static RenderObject* lastRendererOf(ShadowContentElement* parent) +{ + for (ShadowInclusion* inclusion = parent->inclusions()->last(); inclusion; inclusion = inclusion->previous()) { + if (RenderObject* renderer = inclusion->content()->renderer()) + return renderer; + } + + return 0; +} + +RenderObject* NodeRenderingContext::nextRenderer() const +{ + ASSERT(m_node->renderer() || m_location != LocationUndetermined); + if (RenderObject* renderer = m_node->renderer()) + return renderer->nextSibling(); + + if (m_parentFlowRenderer) + return m_parentFlowRenderer->nextRendererForNode(m_node); + + if (m_phase == AttachContentForwarded) { + if (RenderObject* found = nextRendererOf(m_includer, m_node)) + return found; + return NodeRenderingContext(m_includer).nextRenderer(); + } + + // Avoid an O(n^2) problem with this function by not checking for + // nextRenderer() when the parent element hasn't attached yet. + if (m_node->parentOrHostNode() && !m_node->parentOrHostNode()->attached()) + return 0; + + for (Node* node = m_node->nextSibling(); node; node = node->nextSibling()) { + if (node->renderer()) { + // Do not return elements that are attached to a different flow-thread. + if (node->renderer()->style() && !node->renderer()->style()->flowThread().isEmpty()) + continue; + return node->renderer(); + } + if (node->isContentElement()) { + if (RenderObject* first = firstRendererOf(toShadowContentElement(node))) + return first; + } + } + + return 0; +} + +RenderObject* NodeRenderingContext::previousRenderer() const +{ + ASSERT(m_node->renderer() || m_location != LocationUndetermined); + if (RenderObject* renderer = m_node->renderer()) + return renderer->previousSibling(); + + if (m_parentFlowRenderer) + return m_parentFlowRenderer->previousRendererForNode(m_node); + + if (m_phase == AttachContentForwarded) { + if (RenderObject* found = previousRendererOf(m_includer, m_node)) + return found; + return NodeRenderingContext(m_includer).previousRenderer(); + } + + // FIXME: We should have the same O(N^2) avoidance as nextRenderer does + // however, when I tried adding it, several tests failed. + for (Node* node = m_node->previousSibling(); node; node = node->previousSibling()) { + if (node->renderer()) { + // Do not return elements that are attached to a different flow-thread. + if (node->renderer()->style() && !node->renderer()->style()->flowThread().isEmpty()) + continue; + return node->renderer(); + } + if (node->isContentElement()) { + if (RenderObject* last = lastRendererOf(toShadowContentElement(node))) + return last; + } + } + + return 0; +} + +RenderObject* NodeRenderingContext::parentRenderer() const +{ + if (RenderObject* renderer = m_node->renderer()) { + ASSERT(m_location == LocationUndetermined); + return renderer->parent(); + } + + if (m_parentFlowRenderer) + return m_parentFlowRenderer; + + ASSERT(m_location != LocationUndetermined); + return m_parentNodeForRenderingAndStyle ? m_parentNodeForRenderingAndStyle->renderer() : 0; +} + +void NodeRenderingContext::hostChildrenChanged() +{ + if (m_phase == AttachContentLight) + m_visualParentShadowRoot->hostChildrenChanged(); +} + +bool NodeRenderingContext::shouldCreateRenderer() const +{ + ASSERT(m_location != LocationUndetermined); + ASSERT(parentNodeForRenderingAndStyle()); + + if (m_location == LocationNotInTree || m_phase == AttachContentLight) + return false; + + RenderObject* parentRenderer = this->parentRenderer(); + if (!parentRenderer) + return false; + + if (m_location == LocationLightChild && m_phase == AttachStraight) { + // FIXME: Ignoring canHaveChildren() in a case of shadow children might be wrong. + // See https://bugs.webkit.org/show_bug.cgi?id=52423 + if (!parentRenderer->canHaveChildren()) + return false; + + if (m_visualParentShadowRoot && !m_parentNodeForRenderingAndStyle->canHaveLightChildRendererWithShadow()) + return false; + } + + if (!m_parentNodeForRenderingAndStyle->childShouldCreateRenderer(m_node)) + return false; + + return true; +} + +void NodeRenderingContext::moveToFlowThreadIfNeeded() +{ + if (!m_node->isElementNode() || !m_style || m_style->flowThread().isEmpty()) + return; + + m_flowThread = m_style->flowThread(); + ASSERT(m_node->document()->renderView()); + m_parentFlowRenderer = m_node->document()->renderView()->ensureRenderFlowThreadWithName(m_flowThread); +} + +NodeRendererFactory::NodeRendererFactory(Node* node) + : m_context(node) +{ +} + +RenderObject* NodeRendererFactory::createRenderer() +{ + Node* node = m_context.node(); + RenderObject* newRenderer = node->createRenderer(node->document()->renderArena(), m_context.style()); + if (!newRenderer) + return 0; + + if (!m_context.parentRenderer()->isChildAllowed(newRenderer, m_context.style())) { + newRenderer->destroy(); + return 0; + } + + node->setRenderer(newRenderer); + newRenderer->setAnimatableStyle(m_context.releaseStyle()); // setAnimatableStyle() can depend on renderer() already being set. + return newRenderer; +} + +void NodeRendererFactory::createRendererIfNeeded() +{ + Node* node = m_context.node(); + Document* document = node->document(); + if (!document->shouldCreateRenderers()) + return; + + ASSERT(!node->renderer()); + ASSERT(document->shouldCreateRenderers()); + + // FIXME: This side effect should be visible from attach() code. + m_context.hostChildrenChanged(); + + if (!m_context.shouldCreateRenderer()) + return; + + Element* element = node->isElementNode() ? toElement(node) : 0; + if (element) + m_context.setStyle(element->styleForRenderer()); + else if (RenderObject* parentRenderer = m_context.parentRenderer()) + m_context.setStyle(parentRenderer->style()); + + if (!node->rendererIsNeeded(m_context)) { + if (element && m_context.style()->affectedByEmpty()) + element->setStyleAffectedByEmpty(); + return; + } + + RenderObject* parentRenderer = m_context.hasFlowThreadParent() ? m_context.parentFlowRenderer() : m_context.parentRenderer(); + // Do not call m_context.nextRenderer() here in the first clause, because it expects to have + // the renderer added to its parent already. + RenderObject* nextRenderer = m_context.hasFlowThreadParent() ? m_context.parentFlowRenderer()->nextRendererForNode(node) : m_context.nextRenderer(); + RenderObject* newRenderer = createRenderer(); + +#if ENABLE(FULLSCREEN_API) + if (document->webkitIsFullScreen() && document->webkitCurrentFullScreenElement() == node) + newRenderer = RenderFullScreen::wrapRenderer(newRenderer, document); +#endif + + if (!newRenderer) + return; + + // Note: Adding newRenderer instead of renderer(). renderer() may be a child of newRenderer. + parentRenderer->addChild(newRenderer, nextRenderer); +} + +} |