Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: Source/core/rendering/RenderLayerClipper.cpp

Issue 898783003: Move rendering/RenderLayer* to layout/ (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 US A
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/frame/Settings.h"
48 #include "core/rendering/RenderLayer.h"
49 #include "core/rendering/RenderView.h"
50
51 namespace blink {
52
53 static void adjustClipRectsForChildren(const RenderObject& renderer, ClipRects& clipRects)
54 {
55 EPosition position = renderer.style()->position();
56 // A fixed object is essentially the root of its containing block hierarchy, so when
57 // we encounter such an object, we reset our clip rects to the fixedClipRect .
58 if (position == FixedPosition) {
59 clipRects.setPosClipRect(clipRects.fixedClipRect());
60 clipRects.setOverflowClipRect(clipRects.fixedClipRect());
61 clipRects.setFixed(true);
62 } else if (position == RelativePosition) {
63 clipRects.setPosClipRect(clipRects.overflowClipRect());
64 } else if (position == AbsolutePosition) {
65 clipRects.setOverflowClipRect(clipRects.posClipRect());
66 }
67 }
68
69 static void applyClipRects(const ClipRectsContext& context, RenderObject& render er, LayoutPoint offset, ClipRects& clipRects)
70 {
71 ASSERT(renderer.hasOverflowClip() || renderer.hasClip());
72
73 RenderView* view = renderer.view();
74 ASSERT(view);
75 if (clipRects.fixed() && context.rootLayer->renderer() == view)
76 offset -= view->frameView()->scrollOffsetForViewportConstrainedObjects() ;
77
78 if (renderer.hasOverflowClip()) {
79 ClipRect newOverflowClip = toRenderBox(renderer).overflowClipRect(offset , context.scrollbarRelevancy);
80 newOverflowClip.setHasRadius(renderer.style()->hasBorderRadius());
81 clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.ov erflowClipRect()));
82 if (renderer.isPositioned())
83 clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.pos ClipRect()));
84 }
85
86 if (renderer.hasClip()) {
87 LayoutRect newClip = toRenderBox(renderer).clipRect(offset);
88 clipRects.setPosClipRect(intersection(newClip, clipRects.posClipRect())) ;
89 clipRects.setOverflowClipRect(intersection(newClip, clipRects.overflowCl ipRect()));
90 clipRects.setFixedClipRect(intersection(newClip, clipRects.fixedClipRect ()));
91 }
92 }
93
94 RenderLayerClipper::RenderLayerClipper(RenderLayerModelObject& renderer)
95 : m_renderer(renderer)
96 {
97 }
98
99 ClipRects* RenderLayerClipper::clipRectsIfCached(const ClipRectsContext& context ) const
100 {
101 ASSERT(context.usesCache());
102 if (!m_cache)
103 return 0;
104 ClipRectsCache::Entry& entry = m_cache->get(context.cacheSlot);
105 // FIXME: We used to ASSERT that we always got a consistent root layer.
106 // We should add a test that has an inconsistent root. See
107 // http://crbug.com/366118 for an example.
108 if (context.rootLayer != entry.root)
109 return 0;
110 ASSERT(entry.scrollbarRelevancy == context.scrollbarRelevancy);
111
112 #ifdef CHECK_CACHED_CLIP_RECTS
113 // This code is useful to check cached clip rects, but is too expensive to l eave enabled in debug builds by default.
114 ClipRectsContext tempContext(context);
115 tempContext.cacheSlot = UncachedClipRects;
116 RefPtr<ClipRects> clipRects = ClipRects::create();
117 calculateClipRects(tempContext, *clipRects);
118 ASSERT(clipRects == *entry.clipRects);
119 #endif
120
121 return entry.clipRects.get();
122 }
123
124 ClipRects* RenderLayerClipper::storeClipRectsInCache(const ClipRectsContext& con text, ClipRects* parentClipRects, const ClipRects& clipRects) const
125 {
126 ClipRectsCache::Entry& entry = cache().get(context.cacheSlot);
127 entry.root = context.rootLayer;
128 #if ENABLE(ASSERT)
129 entry.scrollbarRelevancy = context.scrollbarRelevancy;
130 #endif
131
132 if (parentClipRects) {
133 // If our clip rects match the clip rects of our parent, we share storag e.
134 if (clipRects == *parentClipRects) {
135 entry.clipRects = parentClipRects;
136 return parentClipRects;
137 }
138 }
139
140 entry.clipRects = ClipRects::create(clipRects);
141 return entry.clipRects.get();
142 }
143
144 ClipRects* RenderLayerClipper::getClipRects(const ClipRectsContext& context) con st
145 {
146 if (ClipRects* result = clipRectsIfCached(context))
147 return result;
148
149 // Note that it's important that we call getClipRects on our parent
150 // before we call calculateClipRects so that calculateClipRects will hit
151 // the cache.
152 ClipRects* parentClipRects = 0;
153 if (context.rootLayer != m_renderer.layer() && m_renderer.layer()->parent())
154 parentClipRects = m_renderer.layer()->parent()->clipper().getClipRects(c ontext);
155
156 RefPtr<ClipRects> clipRects = ClipRects::create();
157 calculateClipRects(context, *clipRects);
158 return storeClipRectsInCache(context, parentClipRects, *clipRects);
159 }
160
161 void RenderLayerClipper::clearClipRectsIncludingDescendants()
162 {
163 m_cache = nullptr;
164
165 for (RenderLayer* layer = m_renderer.layer()->firstChild(); layer; layer = l ayer->nextSibling())
166 layer->clipper().clearClipRectsIncludingDescendants();
167 }
168
169 void RenderLayerClipper::clearClipRectsIncludingDescendants(ClipRectsCacheSlot c acheSlot)
170 {
171 if (m_cache)
172 m_cache->clear(cacheSlot);
173
174 for (RenderLayer* layer = m_renderer.layer()->firstChild(); layer; layer = l ayer->nextSibling())
175 layer->clipper().clearClipRectsIncludingDescendants(cacheSlot);
176 }
177
178 LayoutRect RenderLayerClipper::childrenClipRect() const
179 {
180 // FIXME: border-radius not accounted for.
181 // FIXME: Regions not accounted for.
182 RenderLayer* clippingRootLayer = clippingRootForPainting();
183 LayoutRect layerBounds;
184 ClipRect backgroundRect, foregroundRect, outlineRect;
185 // Need to use uncached clip rects, because the value of 'dontClipToOverflow ' may be different from the painting path (<rdar://problem/11844909>).
186 ClipRectsContext context(clippingRootLayer, UncachedClipRects);
187 calculateRects(context, m_renderer.view()->unscaledDocumentRect(), layerBoun ds, backgroundRect, foregroundRect, outlineRect);
188 return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregrou ndRect.rect())).enclosingBoundingBox();
189 }
190
191 LayoutRect RenderLayerClipper::localClipRect() const
192 {
193 // FIXME: border-radius not accounted for.
194 RenderLayer* clippingRootLayer = clippingRootForPainting();
195 LayoutRect layerBounds;
196 ClipRect backgroundRect, foregroundRect, outlineRect;
197 ClipRectsContext context(clippingRootLayer, PaintingClipRects);
198 calculateRects(context, LayoutRect::infiniteIntRect(), layerBounds, backgrou ndRect, foregroundRect, outlineRect);
199
200 LayoutRect clipRect = backgroundRect.rect();
201 if (clipRect == LayoutRect::infiniteIntRect())
202 return clipRect;
203
204 LayoutPoint clippingRootOffset;
205 m_renderer.layer()->convertToLayerCoords(clippingRootLayer, clippingRootOffs et);
206 clipRect.moveBy(-clippingRootOffset);
207
208 return clipRect;
209 }
210
211 void RenderLayerClipper::calculateRects(const ClipRectsContext& context, const L ayoutRect& paintDirtyRect, LayoutRect& layerBounds,
212 ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, c onst LayoutPoint* offsetFromRoot) const
213 {
214 bool isClippingRoot = m_renderer.layer() == context.rootLayer;
215
216 if (!isClippingRoot && m_renderer.layer()->parent()) {
217 backgroundRect = backgroundClipRect(context);
218 backgroundRect.move(roundedIntSize(context.subPixelAccumulation));
219 backgroundRect.intersect(paintDirtyRect);
220 } else {
221 backgroundRect = paintDirtyRect;
222 }
223
224 foregroundRect = backgroundRect;
225 outlineRect = backgroundRect;
226
227 LayoutPoint offset;
228 if (offsetFromRoot)
229 offset = *offsetFromRoot;
230 else
231 m_renderer.layer()->convertToLayerCoords(context.rootLayer, offset);
232 layerBounds = LayoutRect(offset, LayoutSize(m_renderer.layer()->size()));
233
234 // Update the clip rects that will be passed to child layers.
235 if (m_renderer.hasOverflowClip()) {
236 // This layer establishes a clip of some kind.
237 if (!isClippingRoot || context.respectOverflowClip == RespectOverflowCli p) {
238 foregroundRect.intersect(toRenderBox(m_renderer).overflowClipRect(of fset, context.scrollbarRelevancy));
239 if (m_renderer.style()->hasBorderRadius())
240 foregroundRect.setHasRadius(true);
241 }
242
243 // If we establish an overflow clip at all, then go ahead and make sure our background
244 // rect is intersected with our layer's bounds including our visual over flow,
245 // since any visual overflow like box-shadow or border-outset is not cli pped by overflow:auto/hidden.
246 if (toRenderBox(m_renderer).hasVisualOverflow()) {
247 // FIXME: Perhaps we should be propagating the borderbox as the clip rect for children, even though
248 // we may need to inflate our clip specifically for shadows o r outsets.
249 // FIXME: Does not do the right thing with CSS regions yet, since we don't yet factor in the
250 // individual region boxes as overflow.
251 LayoutRect layerBoundsWithVisualOverflow = toRenderBox(m_renderer).v isualOverflowRect();
252 toRenderBox(m_renderer).flipForWritingMode(layerBoundsWithVisualOver flow); // Layers are in physical coordinates, so the overflow has to be flipped.
253 layerBoundsWithVisualOverflow.moveBy(offset);
254 if (!isClippingRoot || context.respectOverflowClip == RespectOverflo wClip)
255 backgroundRect.intersect(layerBoundsWithVisualOverflow);
256 } else {
257 LayoutRect bounds = toRenderBox(m_renderer).borderBoxRect();
258 bounds.moveBy(offset);
259 if (!isClippingRoot || context.respectOverflowClip == RespectOverflo wClip)
260 backgroundRect.intersect(bounds);
261 }
262 }
263
264 // CSS clip (different than clipping due to overflow) can clip to any box, e ven if it falls outside of the border box.
265 if (m_renderer.hasClip()) {
266 // Clip applies to *us* as well, so go ahead and update the damageRect.
267 LayoutRect newPosClip = toRenderBox(m_renderer).clipRect(offset);
268 backgroundRect.intersect(newPosClip);
269 foregroundRect.intersect(newPosClip);
270 outlineRect.intersect(newPosClip);
271 }
272 }
273
274 void RenderLayerClipper::calculateClipRects(const ClipRectsContext& context, Cli pRects& clipRects) const
275 {
276 bool rootLayerScrolls = m_renderer.document().settings() && m_renderer.docum ent().settings()->rootLayerScrolls();
277 if (!m_renderer.layer()->parent() && !rootLayerScrolls) {
278 // The root layer's clip rect is always infinite.
279 clipRects.reset(LayoutRect::infiniteIntRect());
280 return;
281 }
282
283 bool isClippingRoot = m_renderer.layer() == context.rootLayer;
284
285 // For transformed layers, the root layer was shifted to be us, so there is no need to
286 // examine the parent. We want to cache clip rects with us as the root.
287 RenderLayer* parentLayer = !isClippingRoot ? m_renderer.layer()->parent() : 0;
288
289 // Ensure that our parent's clip has been calculated so that we can examine the values.
290 if (parentLayer) {
291 // FIXME: Why don't we just call getClipRects here?
292 if (context.usesCache() && parentLayer->clipper().cachedClipRects(contex t)) {
293 clipRects = *parentLayer->clipper().cachedClipRects(context);
294 } else {
295 parentLayer->clipper().calculateClipRects(context, clipRects);
296 }
297 } else {
298 clipRects.reset(LayoutRect::infiniteIntRect());
299 }
300
301 adjustClipRectsForChildren(m_renderer, clipRects);
302
303 if ((m_renderer.hasOverflowClip() && (context.respectOverflowClip == Respect OverflowClip || !isClippingRoot)) || m_renderer.hasClip()) {
304 // This offset cannot use convertToLayerCoords, because sometimes our ro otLayer may be across
305 // some transformed layer boundary, for example, in the RenderLayerCompo sitor overlapMap, where
306 // clipRects are needed in view space.
307 applyClipRects(context, m_renderer, roundedLayoutPoint(m_renderer.localT oContainerPoint(FloatPoint(), context.rootLayer->renderer())), clipRects);
308 }
309 }
310
311 static ClipRect backgroundClipRectForPosition(const ClipRects& parentRects, EPos ition position)
312 {
313 if (position == FixedPosition)
314 return parentRects.fixedClipRect();
315
316 if (position == AbsolutePosition)
317 return parentRects.posClipRect();
318
319 return parentRects.overflowClipRect();
320 }
321
322 ClipRect RenderLayerClipper::backgroundClipRect(const ClipRectsContext& context) const
323 {
324 ASSERT(m_renderer.layer()->parent());
325 ASSERT(m_renderer.view());
326
327 RefPtr<ClipRects> parentClipRects = ClipRects::create();
328 if (m_renderer.layer() == context.rootLayer)
329 parentClipRects->reset(LayoutRect::infiniteIntRect());
330 else
331 m_renderer.layer()->parent()->clipper().getOrCalculateClipRects(context, *parentClipRects);
332
333 ClipRect result = backgroundClipRectForPosition(*parentClipRects, m_renderer .style()->position());
334
335 // Note: infinite clipRects should not be scrolled here, otherwise they will accidentally no longer be considered infinite.
336 if (parentClipRects->fixed() && context.rootLayer->renderer() == m_renderer. view() && result != LayoutRect::infiniteIntRect())
337 result.move(m_renderer.view()->frameView()->scrollOffsetForViewportConst rainedObjects());
338
339 return result;
340 }
341
342 void RenderLayerClipper::getOrCalculateClipRects(const ClipRectsContext& context , ClipRects& clipRects) const
343 {
344 if (context.usesCache())
345 clipRects = *getClipRects(context);
346 else
347 calculateClipRects(context, clipRects);
348 }
349
350 RenderLayer* RenderLayerClipper::clippingRootForPainting() const
351 {
352 const RenderLayer* current = m_renderer.layer();
353 // FIXME: getting rid of current->hasCompositedLayerMapping() here breaks th e
354 // compositing/backing/no-backing-for-clip.html layout test, because there i s a
355 // "composited but paints into ancestor" layer involved. However, it doesn't make sense that
356 // that check would be appropriate here but not inside the while loop below.
357 if (current->isPaintInvalidationContainer() || current->hasCompositedLayerMa pping())
358 return const_cast<RenderLayer*>(current);
359
360 while (current) {
361 if (current->isRootLayer())
362 return const_cast<RenderLayer*>(current);
363
364 current = current->compositingContainer();
365 ASSERT(current);
366 if (current->transform() || current->isPaintInvalidationContainer())
367 return const_cast<RenderLayer*>(current);
368 }
369
370 ASSERT_NOT_REACHED();
371 return 0;
372 }
373
374 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/rendering/RenderLayerClipper.h ('k') | Source/core/rendering/RenderLayerFilterInfo.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698