Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved.
      3  *
      4  * Portions are Copyright (C) 1998 Netscape Communications Corporation.
      5  *
      6  * Other contributors:
      7  *   Robert O'Callahan <roc+@cs.cmu.edu>
      8  *   David Baron <dbaron (at) fas.harvard.edu>
      9  *   Christian Biesinger <cbiesinger (at) web.de>
     10  *   Randall Jesup <rjesup (at) wgate.com>
     11  *   Roland Mainz <roland.mainz (at) informatik.med.uni-giessen.de>
     12  *   Josh Soref <timeless (at) mac.com>
     13  *   Boris Zbarsky <bzbarsky (at) mit.edu>
     14  *
     15  * This library is free software; you can redistribute it and/or
     16  * modify it under the terms of the GNU Lesser General Public
     17  * License as published by the Free Software Foundation; either
     18  * version 2.1 of the License, or (at your option) any later version.
     19  *
     20  * This library is distributed in the hope that it will be useful,
     21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     23  * Lesser General Public License for more details.
     24  *
     25  * You should have received a copy of the GNU Lesser General Public
     26  * License along with this library; if not, write to the Free Software
     27  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     28  *
     29  * Alternatively, the contents of this file may be used under the terms
     30  * of either the Mozilla Public License Version 1.1, found at
     31  * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
     32  * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
     33  * (the "GPL"), in which case the provisions of the MPL or the GPL are
     34  * applicable instead of those above.  If you wish to allow use of your
     35  * version of this file only under the terms of one of those two
     36  * licenses (the MPL or the GPL) and not to allow others to use your
     37  * version of this file under the LGPL, indicate your decision by
     38  * deletingthe provisions above and replace them with the notice and
     39  * other provisions required by the MPL or the GPL, as the case may be.
     40  * If you do not delete the provisions above, a recipient may use your
     41  * version of this file under any of the LGPL, the MPL or the GPL.
     42  */
     43 
     44 #include "config.h"
     45 #include "core/rendering/RenderLayerClipper.h"
     46 
     47 #include "core/rendering/RenderLayer.h"
     48 #include "core/rendering/RenderView.h"
     49 
     50 namespace WebCore {
     51 
     52 void RenderLayerClipper::updateClipRects(const ClipRectsContext& clipRectsContext)
     53 {
     54     ClipRectsType clipRectsType = clipRectsContext.clipRectsType;
     55     ASSERT(clipRectsType < NumCachedClipRectsTypes);
     56     if (m_clipRectsCache && m_clipRectsCache->getClipRects(clipRectsType, clipRectsContext.respectOverflowClip)) {
     57         // FIXME: these asserts trigger for squashing. Need to update this code to support squashing as appropriate.
     58         ASSERT(clipRectsContext.rootLayer == m_clipRectsCache->m_clipRectsRoot[clipRectsType]);
     59         ASSERT(m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] == clipRectsContext.overlayScrollbarSizeRelevancy);
     60 
     61 #ifdef CHECK_CACHED_CLIP_RECTS
     62         // This code is useful to check cached clip rects, but is too expensive to leave enabled in debug builds by default.
     63         ClipRectsContext tempContext(clipRectsContext);
     64         tempContext.clipRectsType = TemporaryClipRects;
     65         ClipRects clipRects;
     66         calculateClipRects(tempContext, clipRects);
     67         ASSERT(clipRects == *m_clipRectsCache->getClipRects(clipRectsType, clipRectsContext.respectOverflowClip).get());
     68 #endif
     69         return; // We have the correct cached value.
     70     }
     71 
     72     // For transformed layers, the root layer was shifted to be us, so there is no need to
     73     // examine the parent. We want to cache clip rects with us as the root.
     74     RenderLayer* parentLayer = clipRectsContext.rootLayer != m_renderer->layer() ? m_renderer->layer()->parent() : 0;
     75     if (parentLayer)
     76         parentLayer->clipper().updateClipRects(clipRectsContext);
     77 
     78     ClipRects clipRects;
     79     calculateClipRects(clipRectsContext, clipRects);
     80 
     81     if (!m_clipRectsCache)
     82         m_clipRectsCache = adoptPtr(new ClipRectsCache);
     83 
     84     if (parentLayer && parentLayer->clipper().clipRects(clipRectsContext) && clipRects == *parentLayer->clipper().clipRects(clipRectsContext))
     85         m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, parentLayer->clipper().clipRects(clipRectsContext));
     86     else
     87         m_clipRectsCache->setClipRects(clipRectsType, clipRectsContext.respectOverflowClip, ClipRects::create(clipRects));
     88 
     89 #ifndef NDEBUG
     90     m_clipRectsCache->m_clipRectsRoot[clipRectsType] = clipRectsContext.rootLayer;
     91     m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] = clipRectsContext.overlayScrollbarSizeRelevancy;
     92 #endif
     93 }
     94 
     95 void RenderLayerClipper::clearClipRectsIncludingDescendants(ClipRectsType typeToClear)
     96 {
     97     // FIXME: it's not clear how this layer not having clip rects guarantees that no descendants have any.
     98     if (!m_clipRectsCache)
     99         return;
    100 
    101     clearClipRects(typeToClear);
    102 
    103     for (RenderLayer* layer = m_renderer->layer()->firstChild(); layer; layer = layer->nextSibling())
    104         layer->clipper().clearClipRectsIncludingDescendants(typeToClear);
    105 }
    106 
    107 void RenderLayerClipper::clearClipRects(ClipRectsType typeToClear)
    108 {
    109     if (typeToClear == AllClipRectTypes) {
    110         m_clipRectsCache = nullptr;
    111     } else {
    112         ASSERT(typeToClear < NumCachedClipRectsTypes);
    113         RefPtr<ClipRects> dummy;
    114         m_clipRectsCache->setClipRects(typeToClear, RespectOverflowClip, dummy);
    115         m_clipRectsCache->setClipRects(typeToClear, IgnoreOverflowClip, dummy);
    116     }
    117 }
    118 
    119 void RenderLayerClipper::calculateClipRects(const ClipRectsContext& clipRectsContext, ClipRects& clipRects) const
    120 {
    121     if (!m_renderer->layer()->parent()) {
    122         // The root layer's clip rect is always infinite.
    123         clipRects.reset(PaintInfo::infiniteRect());
    124         return;
    125     }
    126 
    127     ClipRectsType clipRectsType = clipRectsContext.clipRectsType;
    128     bool useCached = clipRectsType != TemporaryClipRects;
    129 
    130     // For transformed layers, the root layer was shifted to be us, so there is no need to
    131     // examine the parent. We want to cache clip rects with us as the root.
    132     RenderLayer* parentLayer = clipRectsContext.rootLayer != m_renderer->layer() ? m_renderer->layer()->parent() : 0;
    133 
    134     // Ensure that our parent's clip has been calculated so that we can examine the values.
    135     if (parentLayer) {
    136         if (useCached && parentLayer->clipper().clipRects(clipRectsContext)) {
    137             clipRects = *parentLayer->clipper().clipRects(clipRectsContext);
    138         } else {
    139             ClipRectsContext parentContext(clipRectsContext);
    140             parentContext.overlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize; // FIXME: why?
    141             parentLayer->clipper().calculateClipRects(parentContext, clipRects);
    142         }
    143     } else {
    144         clipRects.reset(PaintInfo::infiniteRect());
    145     }
    146 
    147     // A fixed object is essentially the root of its containing block hierarchy, so when
    148     // we encounter such an object, we reset our clip rects to the fixedClipRect.
    149     if (m_renderer->style()->position() == FixedPosition) {
    150         clipRects.setPosClipRect(clipRects.fixedClipRect());
    151         clipRects.setOverflowClipRect(clipRects.fixedClipRect());
    152         clipRects.setFixed(true);
    153     } else if (m_renderer->style()->hasInFlowPosition()) {
    154         clipRects.setPosClipRect(clipRects.overflowClipRect());
    155     } else if (m_renderer->style()->position() == AbsolutePosition) {
    156         clipRects.setOverflowClipRect(clipRects.posClipRect());
    157     }
    158 
    159     // Update the clip rects that will be passed to child layers.
    160     if ((m_renderer->hasOverflowClip() && (clipRectsContext.respectOverflowClip == RespectOverflowClip || m_renderer->layer() != clipRectsContext.rootLayer)) || m_renderer->hasClip()) {
    161         // This layer establishes a clip of some kind.
    162 
    163         // This offset cannot use convertToLayerCoords, because sometimes our rootLayer may be across
    164         // some transformed layer boundary, for example, in the RenderLayerCompositor overlapMap, where
    165         // clipRects are needed in view space.
    166         LayoutPoint offset;
    167         offset = roundedLayoutPoint(m_renderer->localToContainerPoint(FloatPoint(), clipRectsContext.rootLayer->renderer()));
    168         RenderView* view = m_renderer->view();
    169         ASSERT(view);
    170         if (view && clipRects.fixed() && clipRectsContext.rootLayer->renderer() == view) {
    171             offset -= view->frameView()->scrollOffsetForFixedPosition();
    172         }
    173 
    174         if (m_renderer->hasOverflowClip()) {
    175             ClipRect newOverflowClip = toRenderBox(m_renderer)->overflowClipRect(offset, clipRectsContext.region, clipRectsContext.overlayScrollbarSizeRelevancy);
    176             if (m_renderer->style()->hasBorderRadius())
    177                 newOverflowClip.setHasRadius(true);
    178             clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect()));
    179             if (m_renderer->isPositioned())
    180                 clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect()));
    181         }
    182         if (m_renderer->hasClip()) {
    183             LayoutRect newPosClip = toRenderBox(m_renderer)->clipRect(offset, clipRectsContext.region);
    184             clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect()));
    185             clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect()));
    186             clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect()));
    187         }
    188     }
    189 }
    190 
    191 } // namespace WebCore
    192