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@fas.harvard.edu>
9 * Christian Biesinger <cbiesinger@web.de>
10 * Randall Jesup <rjesup@wgate.com>
11 * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
12 * Josh Soref <timeless@mac.com>
13 * Boris Zbarsky <bzbarsky@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
updateClipRects(const ClipRectsContext & clipRectsContext)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
clearClipRectsIncludingDescendants(ClipRectsType typeToClear)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
clearClipRects(ClipRectsType typeToClear)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
calculateClipRects(const ClipRectsContext & clipRectsContext,ClipRects & clipRects) const119 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