|  | /* | 
|  | * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. | 
|  | * | 
|  | * Portions are Copyright (C) 1998 Netscape Communications Corporation. | 
|  | * | 
|  | * Other contributors: | 
|  | *   Robert O'Callahan <roc+@cs.cmu.edu> | 
|  | *   David Baron <dbaron@fas.harvard.edu> | 
|  | *   Christian Biesinger <cbiesinger@web.de> | 
|  | *   Randall Jesup <rjesup@wgate.com> | 
|  | *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de> | 
|  | *   Josh Soref <timeless@mac.com> | 
|  | *   Boris Zbarsky <bzbarsky@mit.edu> | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 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 | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA | 
|  | * | 
|  | * Alternatively, the contents of this file may be used under the terms | 
|  | * of either the Mozilla Public License Version 1.1, found at | 
|  | * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public | 
|  | * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html | 
|  | * (the "GPL"), in which case the provisions of the MPL or the GPL are | 
|  | * applicable instead of those above.  If you wish to allow use of your | 
|  | * version of this file only under the terms of one of those two | 
|  | * licenses (the MPL or the GPL) and not to allow others to use your | 
|  | * version of this file under the LGPL, indicate your decision by | 
|  | * deletingthe provisions above and replace them with the notice and | 
|  | * other provisions required by the MPL or the GPL, as the case may be. | 
|  | * If you do not delete the provisions above, a recipient may use your | 
|  | * version of this file under any of the LGPL, the MPL or the GPL. | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "core/rendering/RenderLayerStackingNode.h" | 
|  |  | 
|  | #include "core/rendering/RenderLayer.h" | 
|  | #include "core/rendering/RenderView.h" | 
|  | #include "core/rendering/compositing/RenderLayerCompositor.h" | 
|  | #include "public/platform/Platform.h" | 
|  |  | 
|  | namespace blink { | 
|  |  | 
|  | // FIXME: This should not require RenderLayer. There is currently a cycle where | 
|  | // in order to determine if we shoulBeNormalFlowOnly() we have to ask the render | 
|  | // layer about some of its state. | 
|  | RenderLayerStackingNode::RenderLayerStackingNode(RenderLayer* layer) | 
|  | : m_layer(layer) | 
|  | , m_normalFlowListDirty(true) | 
|  | #if ENABLE(ASSERT) | 
|  | , m_layerListMutationAllowed(true) | 
|  | , m_stackingParent(0) | 
|  | #endif | 
|  | { | 
|  | m_isNormalFlowOnly = shouldBeNormalFlowOnly(); | 
|  |  | 
|  | // Non-stacking contexts should have empty z-order lists. As this is already the case, | 
|  | // there is no need to dirty / recompute these lists. | 
|  | m_zOrderListsDirty = isStackingContext(); | 
|  | } | 
|  |  | 
|  | RenderLayerStackingNode::~RenderLayerStackingNode() | 
|  | { | 
|  | #if ENABLE(ASSERT) | 
|  | if (!renderer()->documentBeingDestroyed()) { | 
|  | ASSERT(!isInStackingParentZOrderLists()); | 
|  | ASSERT(!isInStackingParentNormalFlowList()); | 
|  |  | 
|  | updateStackingParentForZOrderLists(0); | 
|  | updateStackingParentForNormalFlowList(0); | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | // Helper for the sorting of layers by z-index. | 
|  | static inline bool compareZIndex(RenderLayerStackingNode* first, RenderLayerStackingNode* second) | 
|  | { | 
|  | return first->zIndex() < second->zIndex(); | 
|  | } | 
|  |  | 
|  | RenderLayerCompositor* RenderLayerStackingNode::compositor() const | 
|  | { | 
|  | ASSERT(renderer()->view()); | 
|  | return renderer()->view()->compositor(); | 
|  | } | 
|  |  | 
|  | void RenderLayerStackingNode::dirtyZOrderLists() | 
|  | { | 
|  | ASSERT(m_layerListMutationAllowed); | 
|  | ASSERT(isStackingContext()); | 
|  |  | 
|  | #if ENABLE(ASSERT) | 
|  | updateStackingParentForZOrderLists(0); | 
|  | #endif | 
|  |  | 
|  | if (m_posZOrderList) | 
|  | m_posZOrderList->clear(); | 
|  | if (m_negZOrderList) | 
|  | m_negZOrderList->clear(); | 
|  | m_zOrderListsDirty = true; | 
|  |  | 
|  | if (!renderer()->documentBeingDestroyed()) | 
|  | compositor()->setNeedsCompositingUpdate(CompositingUpdateRebuildTree); | 
|  | } | 
|  |  | 
|  | void RenderLayerStackingNode::dirtyStackingContextZOrderLists() | 
|  | { | 
|  | if (RenderLayerStackingNode* stackingNode = ancestorStackingContextNode()) | 
|  | stackingNode->dirtyZOrderLists(); | 
|  | } | 
|  |  | 
|  | void RenderLayerStackingNode::dirtyNormalFlowList() | 
|  | { | 
|  | ASSERT(m_layerListMutationAllowed); | 
|  |  | 
|  | #if ENABLE(ASSERT) | 
|  | updateStackingParentForNormalFlowList(0); | 
|  | #endif | 
|  |  | 
|  | if (m_normalFlowList) | 
|  | m_normalFlowList->clear(); | 
|  | m_normalFlowListDirty = true; | 
|  |  | 
|  | if (!renderer()->documentBeingDestroyed()) | 
|  | compositor()->setNeedsCompositingUpdate(CompositingUpdateRebuildTree); | 
|  | } | 
|  |  | 
|  | void RenderLayerStackingNode::rebuildZOrderLists() | 
|  | { | 
|  | ASSERT(m_layerListMutationAllowed); | 
|  | ASSERT(isDirtyStackingContext()); | 
|  |  | 
|  | for (RenderLayer* child = layer()->firstChild(); child; child = child->nextSibling()) { | 
|  | if (!layer()->reflectionInfo() || layer()->reflectionInfo()->reflectionLayer() != child) | 
|  | child->stackingNode()->collectLayers(m_posZOrderList, m_negZOrderList); | 
|  | } | 
|  |  | 
|  | // Sort the two lists. | 
|  | if (m_posZOrderList) | 
|  | std::stable_sort(m_posZOrderList->begin(), m_posZOrderList->end(), compareZIndex); | 
|  |  | 
|  | if (m_negZOrderList) | 
|  | std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(), compareZIndex); | 
|  |  | 
|  | // Append layers for top layer elements after normal layer collection, to ensure they are on top regardless of z-indexes. | 
|  | // The renderers of top layer elements are children of the view, sorted in top layer stacking order. | 
|  | if (layer()->isRootLayer()) { | 
|  | RenderView* view = renderer()->view(); | 
|  | for (RenderObject* child = view->firstChild(); child; child = child->nextSibling()) { | 
|  | Element* childElement = (child->node() && child->node()->isElementNode()) ? toElement(child->node()) : 0; | 
|  | if (childElement && childElement->isInTopLayer()) { | 
|  | RenderLayer* layer = toRenderLayerModelObject(child)->layer(); | 
|  | // Create the buffer if it doesn't exist yet. | 
|  | if (!m_posZOrderList) | 
|  | m_posZOrderList = adoptPtr(new Vector<RenderLayerStackingNode*>); | 
|  | m_posZOrderList->append(layer->stackingNode()); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #if ENABLE(ASSERT) | 
|  | updateStackingParentForZOrderLists(this); | 
|  | #endif | 
|  |  | 
|  | m_zOrderListsDirty = false; | 
|  | } | 
|  |  | 
|  | void RenderLayerStackingNode::updateNormalFlowList() | 
|  | { | 
|  | if (!m_normalFlowListDirty) | 
|  | return; | 
|  |  | 
|  | ASSERT(m_layerListMutationAllowed); | 
|  |  | 
|  | for (RenderLayer* child = layer()->firstChild(); child; child = child->nextSibling()) { | 
|  | if (child->stackingNode()->isNormalFlowOnly() && (!layer()->reflectionInfo() || layer()->reflectionInfo()->reflectionLayer() != child)) { | 
|  | if (!m_normalFlowList) | 
|  | m_normalFlowList = adoptPtr(new Vector<RenderLayerStackingNode*>); | 
|  | m_normalFlowList->append(child->stackingNode()); | 
|  | } | 
|  | } | 
|  |  | 
|  | #if ENABLE(ASSERT) | 
|  | updateStackingParentForNormalFlowList(this); | 
|  | #endif | 
|  |  | 
|  | m_normalFlowListDirty = false; | 
|  | } | 
|  |  | 
|  | void RenderLayerStackingNode::collectLayers(OwnPtr<Vector<RenderLayerStackingNode*> >& posBuffer, OwnPtr<Vector<RenderLayerStackingNode*> >& negBuffer) | 
|  | { | 
|  | if (layer()->isInTopLayer()) | 
|  | return; | 
|  |  | 
|  | if (!isNormalFlowOnly()) { | 
|  | OwnPtr<Vector<RenderLayerStackingNode*> >& buffer = (zIndex() >= 0) ? posBuffer : negBuffer; | 
|  | if (!buffer) | 
|  | buffer = adoptPtr(new Vector<RenderLayerStackingNode*>); | 
|  | buffer->append(this); | 
|  | } | 
|  |  | 
|  | if (!isStackingContext()) { | 
|  | for (RenderLayer* child = layer()->firstChild(); child; child = child->nextSibling()) { | 
|  | if (!layer()->reflectionInfo() || layer()->reflectionInfo()->reflectionLayer() != child) | 
|  | child->stackingNode()->collectLayers(posBuffer, negBuffer); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | #if ENABLE(ASSERT) | 
|  | bool RenderLayerStackingNode::isInStackingParentZOrderLists() const | 
|  | { | 
|  | if (!m_stackingParent || m_stackingParent->zOrderListsDirty()) | 
|  | return false; | 
|  |  | 
|  | if (m_stackingParent->posZOrderList() && m_stackingParent->posZOrderList()->find(this) != kNotFound) | 
|  | return true; | 
|  |  | 
|  | if (m_stackingParent->negZOrderList() && m_stackingParent->negZOrderList()->find(this) != kNotFound) | 
|  | return true; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool RenderLayerStackingNode::isInStackingParentNormalFlowList() const | 
|  | { | 
|  | if (!m_stackingParent || m_stackingParent->normalFlowListDirty()) | 
|  | return false; | 
|  |  | 
|  | return (m_stackingParent->normalFlowList() && m_stackingParent->normalFlowList()->find(this) != kNotFound); | 
|  | } | 
|  |  | 
|  | void RenderLayerStackingNode::updateStackingParentForZOrderLists(RenderLayerStackingNode* stackingParent) | 
|  | { | 
|  | if (m_posZOrderList) { | 
|  | for (size_t i = 0; i < m_posZOrderList->size(); ++i) | 
|  | m_posZOrderList->at(i)->setStackingParent(stackingParent); | 
|  | } | 
|  |  | 
|  | if (m_negZOrderList) { | 
|  | for (size_t i = 0; i < m_negZOrderList->size(); ++i) | 
|  | m_negZOrderList->at(i)->setStackingParent(stackingParent); | 
|  | } | 
|  | } | 
|  |  | 
|  | void RenderLayerStackingNode::updateStackingParentForNormalFlowList(RenderLayerStackingNode* stackingParent) | 
|  | { | 
|  | if (m_normalFlowList) { | 
|  | for (size_t i = 0; i < m_normalFlowList->size(); ++i) | 
|  | m_normalFlowList->at(i)->setStackingParent(stackingParent); | 
|  | } | 
|  | } | 
|  | #endif | 
|  |  | 
|  | void RenderLayerStackingNode::updateLayerListsIfNeeded() | 
|  | { | 
|  | updateZOrderLists(); | 
|  | updateNormalFlowList(); | 
|  |  | 
|  | if (!layer()->reflectionInfo()) | 
|  | return; | 
|  |  | 
|  | RenderLayer* reflectionLayer = layer()->reflectionInfo()->reflectionLayer(); | 
|  | reflectionLayer->stackingNode()->updateZOrderLists(); | 
|  | reflectionLayer->stackingNode()->updateNormalFlowList(); | 
|  | } | 
|  |  | 
|  | void RenderLayerStackingNode::updateStackingNodesAfterStyleChange(const RenderStyle* oldStyle) | 
|  | { | 
|  | bool wasStackingContext = oldStyle ? !oldStyle->hasAutoZIndex() : false; | 
|  | int oldZIndex = oldStyle ? oldStyle->zIndex() : 0; | 
|  |  | 
|  | bool isStackingContext = this->isStackingContext(); | 
|  | if (isStackingContext == wasStackingContext && oldZIndex == zIndex()) | 
|  | return; | 
|  |  | 
|  | dirtyStackingContextZOrderLists(); | 
|  |  | 
|  | if (isStackingContext) | 
|  | dirtyZOrderLists(); | 
|  | else | 
|  | clearZOrderLists(); | 
|  | } | 
|  |  | 
|  | // FIXME: Rename shouldBeNormalFlowOnly to something more accurate now that CSS | 
|  | // 2.1 defines the term "normal flow". | 
|  | bool RenderLayerStackingNode::shouldBeNormalFlowOnly() const | 
|  | { | 
|  | return !isStackingContext() && !renderer()->isPositioned(); | 
|  | } | 
|  |  | 
|  | void RenderLayerStackingNode::updateIsNormalFlowOnly() | 
|  | { | 
|  | bool isNormalFlowOnly = shouldBeNormalFlowOnly(); | 
|  | if (isNormalFlowOnly == this->isNormalFlowOnly()) | 
|  | return; | 
|  |  | 
|  | m_isNormalFlowOnly = isNormalFlowOnly; | 
|  | if (RenderLayer* p = layer()->parent()) | 
|  | p->stackingNode()->dirtyNormalFlowList(); | 
|  | dirtyStackingContextZOrderLists(); | 
|  | } | 
|  |  | 
|  | RenderLayerStackingNode* RenderLayerStackingNode::ancestorStackingContextNode() const | 
|  | { | 
|  | for (RenderLayer* ancestor = layer()->parent(); ancestor; ancestor = ancestor->parent()) { | 
|  | RenderLayerStackingNode* stackingNode = ancestor->stackingNode(); | 
|  | if (stackingNode->isStackingContext()) | 
|  | return stackingNode; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | RenderLayerModelObject* RenderLayerStackingNode::renderer() const | 
|  | { | 
|  | return m_layer->renderer(); | 
|  | } | 
|  |  | 
|  | } // namespace blink |