OLD | NEW |
| (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/RenderLayer.h" | |
46 | |
47 #include "core/CSSPropertyNames.h" | |
48 #include "core/HTMLNames.h" | |
49 #include "core/css/PseudoStyleRequest.h" | |
50 #include "core/dom/Document.h" | |
51 #include "core/dom/shadow/ShadowRoot.h" | |
52 #include "core/frame/DeprecatedScheduleStyleRecalcDuringLayout.h" | |
53 #include "core/frame/FrameView.h" | |
54 #include "core/frame/LocalFrame.h" | |
55 #include "core/html/HTMLFrameElement.h" | |
56 #include "core/layout/HitTestRequest.h" | |
57 #include "core/layout/HitTestResult.h" | |
58 #include "core/layout/HitTestingTransformState.h" | |
59 #include "core/layout/LayoutTreeAsText.h" | |
60 #include "core/layout/compositing/CompositedLayerMapping.h" | |
61 #include "core/layout/compositing/RenderLayerCompositor.h" | |
62 #include "core/page/Page.h" | |
63 #include "core/page/scrolling/ScrollingCoordinator.h" | |
64 #include "core/rendering/ColumnInfo.h" | |
65 #include "core/rendering/FilterEffectRenderer.h" | |
66 #include "core/rendering/RenderFlowThread.h" | |
67 #include "core/rendering/RenderGeometryMap.h" | |
68 #include "core/rendering/RenderInline.h" | |
69 #include "core/rendering/RenderPart.h" | |
70 #include "core/rendering/RenderReplica.h" | |
71 #include "core/rendering/RenderScrollbar.h" | |
72 #include "core/rendering/RenderScrollbarPart.h" | |
73 #include "core/rendering/RenderView.h" | |
74 #include "core/rendering/svg/ReferenceFilterBuilder.h" | |
75 #include "core/rendering/svg/RenderSVGRoot.h" | |
76 #include "platform/LengthFunctions.h" | |
77 #include "platform/Partitions.h" | |
78 #include "platform/RuntimeEnabledFeatures.h" | |
79 #include "platform/TraceEvent.h" | |
80 #include "platform/geometry/FloatPoint3D.h" | |
81 #include "platform/geometry/FloatRect.h" | |
82 #include "platform/geometry/TransformState.h" | |
83 #include "platform/graphics/filters/ReferenceFilter.h" | |
84 #include "platform/graphics/filters/SourceGraphic.h" | |
85 #include "platform/transforms/ScaleTransformOperation.h" | |
86 #include "platform/transforms/TransformationMatrix.h" | |
87 #include "platform/transforms/TranslateTransformOperation.h" | |
88 #include "public/platform/Platform.h" | |
89 #include "wtf/StdLibExtras.h" | |
90 #include "wtf/text/CString.h" | |
91 | |
92 namespace blink { | |
93 | |
94 namespace { | |
95 | |
96 static CompositingQueryMode gCompositingQueryMode = | |
97 CompositingQueriesAreOnlyAllowedInCertainDocumentLifecyclePhases; | |
98 | |
99 } // namespace | |
100 | |
101 using namespace HTMLNames; | |
102 | |
103 RenderLayer::RenderLayer(RenderLayerModelObject* renderer, LayerType type) | |
104 : m_layerType(type) | |
105 , m_hasSelfPaintingLayerDescendant(false) | |
106 , m_hasSelfPaintingLayerDescendantDirty(false) | |
107 , m_isRootLayer(renderer->isRenderView()) | |
108 , m_visibleContentStatusDirty(true) | |
109 , m_hasVisibleContent(false) | |
110 , m_visibleDescendantStatusDirty(false) | |
111 , m_hasVisibleDescendant(false) | |
112 , m_hasVisibleNonLayerContent(false) | |
113 , m_isPaginated(false) | |
114 #if ENABLE(ASSERT) | |
115 , m_needsPositionUpdate(true) | |
116 #endif | |
117 , m_3DTransformedDescendantStatusDirty(true) | |
118 , m_has3DTransformedDescendant(false) | |
119 , m_containsDirtyOverlayScrollbars(false) | |
120 , m_hasFilterInfo(false) | |
121 , m_needsAncestorDependentCompositingInputsUpdate(true) | |
122 , m_needsDescendantDependentCompositingInputsUpdate(true) | |
123 , m_childNeedsCompositingInputsUpdate(true) | |
124 , m_hasCompositingDescendant(false) | |
125 , m_hasNonCompositedChild(false) | |
126 , m_shouldIsolateCompositedDescendants(false) | |
127 , m_lostGroupedMapping(false) | |
128 , m_renderer(renderer) | |
129 , m_parent(0) | |
130 , m_previous(0) | |
131 , m_next(0) | |
132 , m_first(0) | |
133 , m_last(0) | |
134 , m_staticInlinePosition(0) | |
135 , m_staticBlockPosition(0) | |
136 , m_enclosingPaginationLayer(0) | |
137 , m_potentialCompositingReasonsFromStyle(CompositingReasonNone) | |
138 , m_compositingReasons(CompositingReasonNone) | |
139 , m_groupedMapping(0) | |
140 , m_clipper(*renderer) | |
141 { | |
142 updateStackingNode(); | |
143 | |
144 m_isSelfPaintingLayer = shouldBeSelfPaintingLayer(); | |
145 | |
146 if (!renderer->slowFirstChild() && renderer->style()) { | |
147 m_visibleContentStatusDirty = false; | |
148 m_hasVisibleContent = renderer->style()->visibility() == VISIBLE; | |
149 } | |
150 | |
151 updateScrollableArea(); | |
152 } | |
153 | |
154 RenderLayer::~RenderLayer() | |
155 { | |
156 if (renderer()->frame() && renderer()->frame()->page()) { | |
157 if (ScrollingCoordinator* scrollingCoordinator = renderer()->frame()->pa
ge()->scrollingCoordinator()) | |
158 scrollingCoordinator->willDestroyRenderLayer(this); | |
159 } | |
160 | |
161 removeFilterInfoIfNeeded(); | |
162 | |
163 if (groupedMapping()) { | |
164 DisableCompositingQueryAsserts disabler; | |
165 groupedMapping()->removeRenderLayerFromSquashingGraphicsLayer(this); | |
166 setGroupedMapping(0); | |
167 } | |
168 | |
169 // Child layers will be deleted by their corresponding render objects, so | |
170 // we don't need to delete them ourselves. | |
171 | |
172 clearCompositedLayerMapping(true); | |
173 | |
174 if (m_reflectionInfo) | |
175 m_reflectionInfo->destroy(); | |
176 } | |
177 | |
178 String RenderLayer::debugName() const | |
179 { | |
180 if (isReflection()) { | |
181 return renderer()->parent()->debugName() + " (reflection)"; | |
182 } | |
183 return renderer()->debugName(); | |
184 } | |
185 | |
186 RenderLayerCompositor* RenderLayer::compositor() const | |
187 { | |
188 if (!renderer()->view()) | |
189 return 0; | |
190 return renderer()->view()->compositor(); | |
191 } | |
192 | |
193 void RenderLayer::contentChanged(ContentChangeType changeType) | |
194 { | |
195 // updateLayerCompositingState will query compositingReasons for accelerated
overflow scrolling. | |
196 // This is tripped by LayoutTests/compositing/content-changed-chicken-egg.ht
ml | |
197 DisableCompositingQueryAsserts disabler; | |
198 | |
199 if (changeType == CanvasChanged) | |
200 compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositin
gInputChange); | |
201 | |
202 if (changeType == CanvasContextChanged) { | |
203 compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositin
gInputChange); | |
204 | |
205 // Although we're missing test coverage, we need to call | |
206 // GraphicsLayer::setContentsToPlatformLayer with the new platform | |
207 // layer for this canvas. | |
208 // See http://crbug.com/349195 | |
209 if (hasCompositedLayerMapping()) | |
210 compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerU
pdateSubtree); | |
211 } | |
212 | |
213 if (m_compositedLayerMapping) | |
214 m_compositedLayerMapping->contentChanged(changeType); | |
215 } | |
216 | |
217 bool RenderLayer::paintsWithFilters() const | |
218 { | |
219 if (!renderer()->hasFilter()) | |
220 return false; | |
221 | |
222 // https://code.google.com/p/chromium/issues/detail?id=343759 | |
223 DisableCompositingQueryAsserts disabler; | |
224 return !m_compositedLayerMapping || compositingState() != PaintsIntoOwnBacki
ng; | |
225 } | |
226 | |
227 LayoutSize RenderLayer::subpixelAccumulation() const | |
228 { | |
229 return m_subpixelAccumulation; | |
230 } | |
231 | |
232 void RenderLayer::setSubpixelAccumulation(const LayoutSize& size) | |
233 { | |
234 m_subpixelAccumulation = size; | |
235 } | |
236 | |
237 void RenderLayer::updateLayerPositionsAfterLayout() | |
238 { | |
239 TRACE_EVENT0("blink,benchmark", "RenderLayer::updateLayerPositionsAfterLayou
t"); | |
240 | |
241 m_clipper.clearClipRectsIncludingDescendants(); | |
242 updateLayerPositionRecursive(); | |
243 | |
244 { | |
245 // FIXME: Remove incremental compositing updates after fixing the chicke
n/egg issues | |
246 // https://code.google.com/p/chromium/issues/detail?id=343756 | |
247 DisableCompositingQueryAsserts disabler; | |
248 bool needsPaginationUpdate = isPaginated() || enclosingPaginationLayer()
; | |
249 updatePaginationRecursive(needsPaginationUpdate); | |
250 } | |
251 } | |
252 | |
253 void RenderLayer::updateLayerPositionRecursive() | |
254 { | |
255 updateLayerPosition(); | |
256 | |
257 if (m_reflectionInfo) | |
258 m_reflectionInfo->reflection()->layout(); | |
259 | |
260 // FIXME: We should be able to remove this call because we don't care about | |
261 // any descendant-dependent flags, but code somewhere else is reading these | |
262 // flags and depending on us to update them. | |
263 updateDescendantDependentFlags(); | |
264 | |
265 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
266 child->updateLayerPositionRecursive(); | |
267 } | |
268 | |
269 void RenderLayer::updateHasSelfPaintingLayerDescendant() const | |
270 { | |
271 ASSERT(m_hasSelfPaintingLayerDescendantDirty); | |
272 | |
273 m_hasSelfPaintingLayerDescendant = false; | |
274 | |
275 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
{ | |
276 if (child->isSelfPaintingLayer() || child->hasSelfPaintingLayerDescendan
t()) { | |
277 m_hasSelfPaintingLayerDescendant = true; | |
278 break; | |
279 } | |
280 } | |
281 | |
282 m_hasSelfPaintingLayerDescendantDirty = false; | |
283 } | |
284 | |
285 void RenderLayer::dirtyAncestorChainHasSelfPaintingLayerDescendantStatus() | |
286 { | |
287 for (RenderLayer* layer = this; layer; layer = layer->parent()) { | |
288 layer->m_hasSelfPaintingLayerDescendantDirty = true; | |
289 // If we have reached a self-painting layer, we know our parent should h
ave a self-painting descendant | |
290 // in this case, there is no need to dirty our ancestors further. | |
291 if (layer->isSelfPaintingLayer()) { | |
292 ASSERT(!parent() || parent()->m_hasSelfPaintingLayerDescendantDirty
|| parent()->m_hasSelfPaintingLayerDescendant); | |
293 break; | |
294 } | |
295 } | |
296 } | |
297 | |
298 bool RenderLayer::scrollsWithViewport() const | |
299 { | |
300 return renderer()->style()->position() == FixedPosition && renderer()->conta
inerForFixedPosition() == renderer()->view(); | |
301 } | |
302 | |
303 bool RenderLayer::scrollsWithRespectTo(const RenderLayer* other) const | |
304 { | |
305 if (scrollsWithViewport() != other->scrollsWithViewport()) | |
306 return true; | |
307 return ancestorScrollingLayer() != other->ancestorScrollingLayer(); | |
308 } | |
309 | |
310 void RenderLayer::updateLayerPositionsAfterOverflowScroll() | |
311 { | |
312 m_clipper.clearClipRectsIncludingDescendants(); | |
313 updateLayerPositionsAfterScrollRecursive(); | |
314 } | |
315 | |
316 void RenderLayer::updateLayerPositionsAfterScrollRecursive() | |
317 { | |
318 if (updateLayerPosition()) | |
319 m_renderer->setPreviousPaintInvalidationRect(m_renderer->boundsRectForPa
intInvalidation(m_renderer->containerForPaintInvalidation())); | |
320 | |
321 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
322 child->updateLayerPositionsAfterScrollRecursive(); | |
323 } | |
324 | |
325 void RenderLayer::updateTransformationMatrix() | |
326 { | |
327 if (m_transform) { | |
328 RenderBox* box = renderBox(); | |
329 ASSERT(box); | |
330 m_transform->makeIdentity(); | |
331 box->style()->applyTransform(*m_transform, LayoutSize(box->pixelSnappedS
ize()), RenderStyle::IncludeTransformOrigin); | |
332 makeMatrixRenderable(*m_transform, compositor()->hasAcceleratedCompositi
ng()); | |
333 } | |
334 } | |
335 | |
336 void RenderLayer::updateTransform(const RenderStyle* oldStyle, RenderStyle* newS
tyle) | |
337 { | |
338 if (oldStyle && newStyle->transformDataEquivalent(*oldStyle)) | |
339 return; | |
340 | |
341 // hasTransform() on the renderer is also true when there is transform-style
: preserve-3d or perspective set, | |
342 // so check style too. | |
343 bool hasTransform = renderer()->hasTransformRelatedProperty() && newStyle->h
asTransform(); | |
344 bool had3DTransform = has3DTransform(); | |
345 | |
346 bool hadTransform = m_transform; | |
347 if (hasTransform != hadTransform) { | |
348 if (hasTransform) | |
349 m_transform = adoptPtr(new TransformationMatrix); | |
350 else | |
351 m_transform.clear(); | |
352 | |
353 // Layers with transforms act as clip rects roots, so clear the cached c
lip rects here. | |
354 m_clipper.clearClipRectsIncludingDescendants(); | |
355 } else if (hasTransform) { | |
356 m_clipper.clearClipRectsIncludingDescendants(AbsoluteClipRects); | |
357 } | |
358 | |
359 updateTransformationMatrix(); | |
360 | |
361 if (had3DTransform != has3DTransform()) | |
362 dirty3DTransformedDescendantStatus(); | |
363 } | |
364 | |
365 static RenderLayer* enclosingLayerForContainingBlock(RenderLayer* layer) | |
366 { | |
367 if (RenderObject* containingBlock = layer->renderer()->containingBlock()) | |
368 return containingBlock->enclosingLayer(); | |
369 return 0; | |
370 } | |
371 | |
372 RenderLayer* RenderLayer::renderingContextRoot() | |
373 { | |
374 RenderLayer* renderingContext = 0; | |
375 | |
376 if (shouldPreserve3D()) | |
377 renderingContext = this; | |
378 | |
379 for (RenderLayer* current = enclosingLayerForContainingBlock(this); current
&& current->shouldPreserve3D(); current = enclosingLayerForContainingBlock(curre
nt)) | |
380 renderingContext = current; | |
381 | |
382 return renderingContext; | |
383 } | |
384 | |
385 TransformationMatrix RenderLayer::currentTransform(RenderStyle::ApplyTransformOr
igin applyOrigin) const | |
386 { | |
387 if (!m_transform) | |
388 return TransformationMatrix(); | |
389 | |
390 // m_transform includes transform-origin, so we need to recompute the transf
orm here. | |
391 if (applyOrigin == RenderStyle::ExcludeTransformOrigin) { | |
392 RenderBox* box = renderBox(); | |
393 TransformationMatrix currTransform; | |
394 box->style()->applyTransform(currTransform, LayoutSize(box->pixelSnapped
Size()), RenderStyle::ExcludeTransformOrigin); | |
395 makeMatrixRenderable(currTransform, compositor()->hasAcceleratedComposit
ing()); | |
396 return currTransform; | |
397 } | |
398 | |
399 return *m_transform; | |
400 } | |
401 | |
402 TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavio
r) const | |
403 { | |
404 if (!m_transform) | |
405 return TransformationMatrix(); | |
406 | |
407 if (paintBehavior & PaintBehaviorFlattenCompositingLayers) { | |
408 TransformationMatrix matrix = *m_transform; | |
409 makeMatrixRenderable(matrix, false /* flatten 3d */); | |
410 return matrix; | |
411 } | |
412 | |
413 return *m_transform; | |
414 } | |
415 | |
416 static bool checkContainingBlockChainForPagination(RenderLayerModelObject* rende
rer, RenderBox* ancestorColumnsRenderer) | |
417 { | |
418 RenderView* view = renderer->view(); | |
419 RenderLayerModelObject* prevBlock = renderer; | |
420 RenderBlock* containingBlock; | |
421 for (containingBlock = renderer->containingBlock(); | |
422 containingBlock && containingBlock != view && containingBlock != ancest
orColumnsRenderer; | |
423 containingBlock = containingBlock->containingBlock()) | |
424 prevBlock = containingBlock; | |
425 | |
426 // If the columns block wasn't in our containing block chain, then we aren't
paginated by it. | |
427 if (containingBlock != ancestorColumnsRenderer) | |
428 return false; | |
429 | |
430 // If the previous block is absolutely positioned, then we can't be paginate
d by the columns block. | |
431 if (prevBlock->isOutOfFlowPositioned()) | |
432 return false; | |
433 | |
434 // Otherwise we are paginated by the columns block. | |
435 return true; | |
436 } | |
437 | |
438 // Convert a bounding box from flow thread coordinates, relative to |layer|, to
visual coordinates, relative to |ancestorLayer|. | |
439 // See http://www.chromium.org/developers/design-documents/multi-column-layout f
or more info on these coordinate types. | |
440 static void convertFromFlowThreadToVisualBoundingBoxInAncestor(const RenderLayer
* layer, const RenderLayer* ancestorLayer, LayoutRect& rect) | |
441 { | |
442 RenderLayer* paginationLayer = layer->enclosingPaginationLayer(); | |
443 ASSERT(paginationLayer); | |
444 RenderFlowThread* flowThread = toRenderFlowThread(paginationLayer->renderer(
)); | |
445 | |
446 // First make the flow thread rectangle relative to the flow thread, not to
|layer|. | |
447 LayoutPoint offsetWithinPaginationLayer; | |
448 layer->convertToLayerCoords(paginationLayer, offsetWithinPaginationLayer); | |
449 rect.moveBy(offsetWithinPaginationLayer); | |
450 | |
451 // Then make the rectangle visual, relative to the fragmentation context. Sp
lit our box up into | |
452 // the actual fragment boxes that render in the columns/pages and unite thos
e together to get | |
453 // our true bounding box. | |
454 rect = flowThread->fragmentsBoundingBox(rect); | |
455 | |
456 // Finally, make the visual rectangle relative to |ancestorLayer|. | |
457 if (ancestorLayer->enclosingPaginationLayer() != paginationLayer) { | |
458 rect.moveBy(paginationLayer->visualOffsetFromAncestor(ancestorLayer)); | |
459 return; | |
460 } | |
461 // The ancestor layer is inside the same pagination layer as |layer|, so we
need to subtract | |
462 // the visual distance from the ancestor layer to the pagination layer. | |
463 rect.moveBy(-ancestorLayer->visualOffsetFromAncestor(paginationLayer)); | |
464 } | |
465 | |
466 bool RenderLayer::useRegionBasedColumns() const | |
467 { | |
468 return renderer()->document().regionBasedColumnsEnabled(); | |
469 } | |
470 | |
471 void RenderLayer::updatePaginationRecursive(bool needsPaginationUpdate) | |
472 { | |
473 m_isPaginated = false; | |
474 m_enclosingPaginationLayer = 0; | |
475 | |
476 if (useRegionBasedColumns() && renderer()->isRenderFlowThread()) | |
477 needsPaginationUpdate = true; | |
478 | |
479 if (needsPaginationUpdate) | |
480 updatePagination(); | |
481 | |
482 if (renderer()->hasColumns()) | |
483 needsPaginationUpdate = true; | |
484 | |
485 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
486 child->updatePaginationRecursive(needsPaginationUpdate); | |
487 } | |
488 | |
489 void RenderLayer::updatePagination() | |
490 { | |
491 bool usesRegionBasedColumns = useRegionBasedColumns(); | |
492 if ((!usesRegionBasedColumns && compositingState() != NotComposited) || !par
ent()) | |
493 return; // FIXME: For now the RenderView can't be paginated. Eventually
printing will move to a model where it is though. | |
494 | |
495 // The main difference between the paginated booleans for the old column cod
e and the new column code | |
496 // is that each paginated layer has to paint on its own with the new code. T
here is no | |
497 // recurring into child layers. This means that the m_isPaginated bits for t
he new column code can't just be set on | |
498 // "roots" that get split and paint all their descendants. Instead each laye
r has to be checked individually and | |
499 // genuinely know if it is going to have to split itself up when painting on
ly its contents (and not any other descendant | |
500 // layers). We track an enclosingPaginationLayer instead of using a simple b
it, since we want to be able to get back | |
501 // to that layer easily. | |
502 if (usesRegionBasedColumns && renderer()->isRenderFlowThread()) { | |
503 m_enclosingPaginationLayer = this; | |
504 return; | |
505 } | |
506 | |
507 if (m_stackingNode->isNormalFlowOnly()) { | |
508 if (usesRegionBasedColumns) { | |
509 // Content inside a transform is not considered to be paginated, sin
ce we simply | |
510 // paint the transform multiple times in each column, so we don't ha
ve to use | |
511 // fragments for the transformed content. | |
512 m_enclosingPaginationLayer = parent()->enclosingPaginationLayer(); | |
513 if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->hasTra
nsformRelatedProperty()) | |
514 m_enclosingPaginationLayer = 0; | |
515 } else { | |
516 m_isPaginated = parent()->renderer()->hasColumns(); | |
517 } | |
518 return; | |
519 } | |
520 | |
521 // For the new columns code, we want to walk up our containing block chain l
ooking for an enclosing layer. Once | |
522 // we find one, then we just check its pagination status. | |
523 if (usesRegionBasedColumns) { | |
524 RenderView* view = renderer()->view(); | |
525 RenderBlock* containingBlock; | |
526 for (containingBlock = renderer()->containingBlock(); | |
527 containingBlock && containingBlock != view; | |
528 containingBlock = containingBlock->containingBlock()) { | |
529 if (containingBlock->hasLayer()) { | |
530 // Content inside a transform is not considered to be paginated,
since we simply | |
531 // paint the transform multiple times in each column, so we don'
t have to use | |
532 // fragments for the transformed content. | |
533 m_enclosingPaginationLayer = containingBlock->layer()->enclosing
PaginationLayer(); | |
534 if (m_enclosingPaginationLayer && m_enclosingPaginationLayer->ha
sTransformRelatedProperty()) | |
535 m_enclosingPaginationLayer = 0; | |
536 return; | |
537 } | |
538 } | |
539 return; | |
540 } | |
541 | |
542 // If we're not normal flow, then we need to look for a multi-column object
between us and our stacking container. | |
543 RenderLayerStackingNode* ancestorStackingContextNode = m_stackingNode->ances
torStackingContextNode(); | |
544 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) { | |
545 if (curr->renderer()->hasColumns()) { | |
546 m_isPaginated = checkContainingBlockChainForPagination(renderer(), c
urr->renderBox()); | |
547 return; | |
548 } | |
549 if (curr->stackingNode() == ancestorStackingContextNode) | |
550 return; | |
551 } | |
552 } | |
553 | |
554 void RenderLayer::clearPaginationRecursive() | |
555 { | |
556 m_enclosingPaginationLayer = 0; | |
557 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
558 child->clearPaginationRecursive(); | |
559 } | |
560 | |
561 LayoutPoint RenderLayer::positionFromPaintInvalidationBacking(const RenderObject
* renderObject, const RenderLayerModelObject* paintInvalidationContainer, const
PaintInvalidationState* paintInvalidationState) | |
562 { | |
563 FloatPoint point = renderObject->localToContainerPoint(FloatPoint(), paintIn
validationContainer, 0, 0, paintInvalidationState); | |
564 | |
565 // FIXME: Eventually we are going to unify coordinates in GraphicsLayer spac
e. | |
566 if (paintInvalidationContainer && paintInvalidationContainer->layer()->group
edMapping()) | |
567 mapPointToPaintBackingCoordinates(paintInvalidationContainer, point); | |
568 | |
569 return LayoutPoint(point); | |
570 } | |
571 | |
572 void RenderLayer::mapPointToPaintBackingCoordinates(const RenderLayerModelObject
* paintInvalidationContainer, FloatPoint& point) | |
573 { | |
574 RenderLayer* paintInvalidationLayer = paintInvalidationContainer->layer(); | |
575 if (!paintInvalidationLayer->groupedMapping()) { | |
576 point.move(paintInvalidationLayer->compositedLayerMapping()->contentOffs
etInCompositingLayer()); | |
577 return; | |
578 } | |
579 | |
580 RenderLayerModelObject* transformedAncestor = paintInvalidationLayer->enclos
ingTransformedAncestor()->renderer(); | |
581 if (!transformedAncestor) | |
582 return; | |
583 | |
584 // |paintInvalidationContainer| may have a local 2D transform on it, so take
that into account when mapping into the space of the | |
585 // transformed ancestor. | |
586 point = paintInvalidationContainer->localToContainerPoint(point, transformed
Ancestor); | |
587 | |
588 point.moveBy(-paintInvalidationLayer->groupedMapping()->squashingOffsetFromT
ransformedAncestor()); | |
589 } | |
590 | |
591 void RenderLayer::mapRectToPaintBackingCoordinates(const RenderLayerModelObject*
paintInvalidationContainer, LayoutRect& rect) | |
592 { | |
593 RenderLayer* paintInvalidationLayer = paintInvalidationContainer->layer(); | |
594 if (!paintInvalidationLayer->groupedMapping()) { | |
595 rect.move(paintInvalidationLayer->compositedLayerMapping()->contentOffse
tInCompositingLayer()); | |
596 return; | |
597 } | |
598 | |
599 RenderLayerModelObject* transformedAncestor = paintInvalidationLayer->enclos
ingTransformedAncestor()->renderer(); | |
600 if (!transformedAncestor) | |
601 return; | |
602 | |
603 // |paintInvalidationContainer| may have a local 2D transform on it, so take
that into account when mapping into the space of the | |
604 // transformed ancestor. | |
605 rect = LayoutRect(paintInvalidationContainer->localToContainerQuad(FloatRect
(rect), transformedAncestor).boundingBox()); | |
606 | |
607 rect.moveBy(-paintInvalidationLayer->groupedMapping()->squashingOffsetFromTr
ansformedAncestor()); | |
608 } | |
609 | |
610 void RenderLayer::mapRectToPaintInvalidationBacking(const RenderObject* renderOb
ject, const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect
, const PaintInvalidationState* paintInvalidationState) | |
611 { | |
612 if (!paintInvalidationContainer->layer()->groupedMapping()) { | |
613 renderObject->mapRectToPaintInvalidationBacking(paintInvalidationContain
er, rect, paintInvalidationState); | |
614 return; | |
615 } | |
616 | |
617 // This code adjusts the paint invalidation rectangle to be in the space of
the transformed ancestor of the grouped (i.e. squashed) | |
618 // layer. This is because all layers that squash together need to issue pain
t invalidations w.r.t. a single container that is | |
619 // an ancestor of all of them, in order to properly take into account any lo
cal transforms etc. | |
620 // FIXME: remove this special-case code that works around the paint invalida
tion code structure. | |
621 renderObject->mapRectToPaintInvalidationBacking(paintInvalidationContainer,
rect, paintInvalidationState); | |
622 | |
623 mapRectToPaintBackingCoordinates(paintInvalidationContainer, rect); | |
624 } | |
625 | |
626 LayoutRect RenderLayer::computePaintInvalidationRect(const RenderObject* renderO
bject, const RenderLayer* paintInvalidationContainer, const PaintInvalidationSta
te* paintInvalidationState) | |
627 { | |
628 if (!paintInvalidationContainer->groupedMapping()) | |
629 return renderObject->computePaintInvalidationRect(paintInvalidationConta
iner->renderer(), paintInvalidationState); | |
630 | |
631 LayoutRect rect = renderObject->clippedOverflowRectForPaintInvalidation(pain
tInvalidationContainer->renderer(), paintInvalidationState); | |
632 mapRectToPaintBackingCoordinates(paintInvalidationContainer->renderer(), rec
t); | |
633 return rect; | |
634 } | |
635 | |
636 void RenderLayer::dirtyVisibleContentStatus() | |
637 { | |
638 m_visibleContentStatusDirty = true; | |
639 if (parent()) | |
640 parent()->dirtyAncestorChainVisibleDescendantStatus(); | |
641 } | |
642 | |
643 void RenderLayer::potentiallyDirtyVisibleContentStatus(EVisibility visibility) | |
644 { | |
645 if (m_visibleContentStatusDirty) | |
646 return; | |
647 if (hasVisibleContent() == (visibility == VISIBLE)) | |
648 return; | |
649 dirtyVisibleContentStatus(); | |
650 } | |
651 | |
652 void RenderLayer::dirtyAncestorChainVisibleDescendantStatus() | |
653 { | |
654 for (RenderLayer* layer = this; layer; layer = layer->parent()) { | |
655 if (layer->m_visibleDescendantStatusDirty) | |
656 break; | |
657 | |
658 layer->m_visibleDescendantStatusDirty = true; | |
659 } | |
660 } | |
661 | |
662 // FIXME: this is quite brute-force. We could be more efficient if we were to | |
663 // track state and update it as appropriate as changes are made in the Render tr
ee. | |
664 void RenderLayer::updateScrollingStateAfterCompositingChange() | |
665 { | |
666 TRACE_EVENT0("blink", "RenderLayer::updateScrollingStateAfterCompositingChan
ge"); | |
667 m_hasVisibleNonLayerContent = false; | |
668 for (RenderObject* r = renderer()->slowFirstChild(); r; r = r->nextSibling()
) { | |
669 if (!r->hasLayer()) { | |
670 m_hasVisibleNonLayerContent = true; | |
671 break; | |
672 } | |
673 } | |
674 | |
675 m_hasNonCompositedChild = false; | |
676 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
{ | |
677 if (child->compositingState() == NotComposited) { | |
678 m_hasNonCompositedChild = true; | |
679 return; | |
680 } | |
681 } | |
682 } | |
683 | |
684 // The descendant-dependent flags system is badly broken because we clean dirty | |
685 // bits in upward tree walks, which means we need to call updateDescendantDepend
entFlags | |
686 // at every node in the tree to fully clean all the dirty bits. While we'll in | |
687 // the process of fixing this issue, updateDescendantDependentFlagsForEntireSubt
ree | |
688 // provides a big hammer for actually cleaning all the dirty bits in a subtree. | |
689 // | |
690 // FIXME: Remove this function once the descendant-dependent flags system keeps | |
691 // its dirty bits scoped to subtrees. | |
692 void RenderLayer::updateDescendantDependentFlagsForEntireSubtree() | |
693 { | |
694 updateDescendantDependentFlags(); | |
695 | |
696 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
697 child->updateDescendantDependentFlagsForEntireSubtree(); | |
698 } | |
699 | |
700 void RenderLayer::updateDescendantDependentFlags() | |
701 { | |
702 if (m_visibleDescendantStatusDirty) { | |
703 m_hasVisibleDescendant = false; | |
704 | |
705 for (RenderLayer* child = firstChild(); child; child = child->nextSiblin
g()) { | |
706 child->updateDescendantDependentFlags(); | |
707 | |
708 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) { | |
709 m_hasVisibleDescendant = true; | |
710 break; | |
711 } | |
712 } | |
713 | |
714 m_visibleDescendantStatusDirty = false; | |
715 } | |
716 | |
717 if (m_visibleContentStatusDirty) { | |
718 bool previouslyHasVisibleContent = m_hasVisibleContent; | |
719 if (renderer()->style()->visibility() == VISIBLE) | |
720 m_hasVisibleContent = true; | |
721 else { | |
722 // layer may be hidden but still have some visible content, check fo
r this | |
723 m_hasVisibleContent = false; | |
724 RenderObject* r = renderer()->slowFirstChild(); | |
725 while (r) { | |
726 if (r->style()->visibility() == VISIBLE && !r->hasLayer()) { | |
727 m_hasVisibleContent = true; | |
728 break; | |
729 } | |
730 RenderObject* rendererFirstChild = r->slowFirstChild(); | |
731 if (rendererFirstChild && !r->hasLayer()) | |
732 r = rendererFirstChild; | |
733 else if (r->nextSibling()) | |
734 r = r->nextSibling(); | |
735 else { | |
736 do { | |
737 r = r->parent(); | |
738 if (r == renderer()) | |
739 r = 0; | |
740 } while (r && !r->nextSibling()); | |
741 if (r) | |
742 r = r->nextSibling(); | |
743 } | |
744 } | |
745 } | |
746 m_visibleContentStatusDirty = false; | |
747 | |
748 if (hasVisibleContent() != previouslyHasVisibleContent) { | |
749 setNeedsCompositingInputsUpdate(); | |
750 // We need to tell m_renderer to recheck its rect because we | |
751 // pretend that invisible RenderObjects have 0x0 rects. Changing | |
752 // visibility therefore changes our rect and we need to visit | |
753 // this RenderObject during the invalidateTreeIfNeeded walk. | |
754 m_renderer->setMayNeedPaintInvalidation(); | |
755 } | |
756 } | |
757 } | |
758 | |
759 void RenderLayer::dirty3DTransformedDescendantStatus() | |
760 { | |
761 RenderLayerStackingNode* stackingNode = m_stackingNode->ancestorStackingCont
extNode(); | |
762 if (!stackingNode) | |
763 return; | |
764 | |
765 stackingNode->layer()->m_3DTransformedDescendantStatusDirty = true; | |
766 | |
767 // This propagates up through preserve-3d hierarchies to the enclosing flatt
ening layer. | |
768 // Note that preserves3D() creates stacking context, so we can just run up t
he stacking containers. | |
769 while (stackingNode && stackingNode->layer()->preserves3D()) { | |
770 stackingNode->layer()->m_3DTransformedDescendantStatusDirty = true; | |
771 stackingNode = stackingNode->ancestorStackingContextNode(); | |
772 } | |
773 } | |
774 | |
775 // Return true if this layer or any preserve-3d descendants have 3d. | |
776 bool RenderLayer::update3DTransformedDescendantStatus() | |
777 { | |
778 if (m_3DTransformedDescendantStatusDirty) { | |
779 m_has3DTransformedDescendant = false; | |
780 | |
781 m_stackingNode->updateZOrderLists(); | |
782 | |
783 // Transformed or preserve-3d descendants can only be in the z-order lis
ts, not | |
784 // in the normal flow list, so we only need to check those. | |
785 RenderLayerStackingNodeIterator iterator(*m_stackingNode.get(), Positive
ZOrderChildren | NegativeZOrderChildren); | |
786 while (RenderLayerStackingNode* node = iterator.next()) | |
787 m_has3DTransformedDescendant |= node->layer()->update3DTransformedDe
scendantStatus(); | |
788 | |
789 m_3DTransformedDescendantStatusDirty = false; | |
790 } | |
791 | |
792 // If we live in a 3d hierarchy, then the layer at the root of that hierarch
y needs | |
793 // the m_has3DTransformedDescendant set. | |
794 if (preserves3D()) | |
795 return has3DTransform() || m_has3DTransformedDescendant; | |
796 | |
797 return has3DTransform(); | |
798 } | |
799 | |
800 bool RenderLayer::updateLayerPosition() | |
801 { | |
802 LayoutPoint localPoint; | |
803 LayoutPoint inlineBoundingBoxOffset; // We don't put this into the RenderLay
er x/y for inlines, so we need to subtract it out when done. | |
804 | |
805 if (renderer()->isInline() && renderer()->isRenderInline()) { | |
806 RenderInline* inlineFlow = toRenderInline(renderer()); | |
807 IntRect lineBox = inlineFlow->linesBoundingBox(); | |
808 m_size = lineBox.size(); | |
809 inlineBoundingBoxOffset = lineBox.location(); | |
810 localPoint.moveBy(inlineBoundingBoxOffset); | |
811 } else if (RenderBox* box = renderBox()) { | |
812 m_size = pixelSnappedIntSize(box->size(), box->location()); | |
813 localPoint.moveBy(box->topLeftLocation()); | |
814 } | |
815 | |
816 if (!renderer()->isOutOfFlowPositioned() && !renderer()->isColumnSpanAll() &
& renderer()->parent()) { | |
817 // We must adjust our position by walking up the render tree looking for
the | |
818 // nearest enclosing object with a layer. | |
819 RenderObject* curr = renderer()->parent(); | |
820 while (curr && !curr->hasLayer()) { | |
821 if (curr->isBox() && !curr->isTableRow()) { | |
822 // Rows and cells share the same coordinate space (that of the s
ection). | |
823 // Omit them when computing our xpos/ypos. | |
824 localPoint.moveBy(toRenderBox(curr)->topLeftLocation()); | |
825 } | |
826 curr = curr->parent(); | |
827 } | |
828 if (curr->isBox() && curr->isTableRow()) { | |
829 // Put ourselves into the row coordinate space. | |
830 localPoint.moveBy(-toRenderBox(curr)->topLeftLocation()); | |
831 } | |
832 } | |
833 | |
834 // Subtract our parent's scroll offset. | |
835 if (renderer()->isOutOfFlowPositioned() && enclosingPositionedAncestor()) { | |
836 RenderLayer* positionedParent = enclosingPositionedAncestor(); | |
837 | |
838 // For positioned layers, we subtract out the enclosing positioned layer
's scroll offset. | |
839 if (positionedParent->renderer()->hasOverflowClip()) { | |
840 IntSize offset = positionedParent->renderBox()->scrolledContentOffse
t(); | |
841 localPoint -= offset; | |
842 } | |
843 | |
844 if (positionedParent->renderer()->isRelPositioned() && positionedParent-
>renderer()->isRenderInline()) { | |
845 LayoutSize offset = toRenderInline(positionedParent->renderer())->of
fsetForInFlowPositionedInline(*toRenderBox(renderer())); | |
846 localPoint += offset; | |
847 } | |
848 } else if (parent()) { | |
849 // FIXME: This code is very wrong, but luckily only needed in the old/cu
rrent multicol | |
850 // implementation. The compositing system doesn't understand columns and
we're hacking | |
851 // around that fact by faking the position of the RenderLayers when we t
hink we'll end up | |
852 // being composited. | |
853 if (hasStyleDeterminedDirectCompositingReasons() && !useRegionBasedColum
ns()) { | |
854 // FIXME: Composited layers ignore pagination, so about the best we
can do is make sure they're offset into the appropriate column. | |
855 // They won't split across columns properly. | |
856 if (!parent()->renderer()->hasColumns() && parent()->renderer()->isD
ocumentElement() && renderer()->view()->hasColumns()) | |
857 localPoint += renderer()->view()->columnOffset(localPoint); | |
858 else | |
859 localPoint += parent()->renderer()->columnOffset(localPoint); | |
860 } | |
861 | |
862 if (parent()->renderer()->hasOverflowClip()) { | |
863 IntSize scrollOffset = parent()->renderBox()->scrolledContentOffset(
); | |
864 localPoint -= scrollOffset; | |
865 } | |
866 } | |
867 | |
868 bool positionOrOffsetChanged = false; | |
869 if (renderer()->isRelPositioned()) { | |
870 LayoutSize newOffset = toRenderBoxModelObject(renderer())->offsetForInFl
owPosition(); | |
871 positionOrOffsetChanged = newOffset != m_offsetForInFlowPosition; | |
872 m_offsetForInFlowPosition = newOffset; | |
873 localPoint.move(m_offsetForInFlowPosition); | |
874 } else { | |
875 m_offsetForInFlowPosition = LayoutSize(); | |
876 } | |
877 | |
878 // FIXME: We'd really like to just get rid of the concept of a layer rectang
le and rely on the renderers. | |
879 localPoint.moveBy(-inlineBoundingBoxOffset); | |
880 | |
881 if (m_location != localPoint) | |
882 positionOrOffsetChanged = true; | |
883 m_location = localPoint; | |
884 | |
885 #if ENABLE(ASSERT) | |
886 m_needsPositionUpdate = false; | |
887 #endif | |
888 return positionOrOffsetChanged; | |
889 } | |
890 | |
891 TransformationMatrix RenderLayer::perspectiveTransform() const | |
892 { | |
893 if (!renderer()->hasTransformRelatedProperty()) | |
894 return TransformationMatrix(); | |
895 | |
896 RenderStyle* style = renderer()->style(); | |
897 if (!style->hasPerspective()) | |
898 return TransformationMatrix(); | |
899 | |
900 // Maybe fetch the perspective from the backing? | |
901 const IntRect borderBox = toRenderBox(renderer())->pixelSnappedBorderBoxRect
(); | |
902 const float boxWidth = borderBox.width(); | |
903 const float boxHeight = borderBox.height(); | |
904 | |
905 float perspectiveOriginX = floatValueForLength(style->perspectiveOriginX(),
boxWidth); | |
906 float perspectiveOriginY = floatValueForLength(style->perspectiveOriginY(),
boxHeight); | |
907 | |
908 // A perspective origin of 0,0 makes the vanishing point in the center of th
e element. | |
909 // We want it to be in the top-left, so subtract half the height and width. | |
910 perspectiveOriginX -= boxWidth / 2.0f; | |
911 perspectiveOriginY -= boxHeight / 2.0f; | |
912 | |
913 TransformationMatrix t; | |
914 t.translate(perspectiveOriginX, perspectiveOriginY); | |
915 t.applyPerspective(style->perspective()); | |
916 t.translate(-perspectiveOriginX, -perspectiveOriginY); | |
917 | |
918 return t; | |
919 } | |
920 | |
921 FloatPoint RenderLayer::perspectiveOrigin() const | |
922 { | |
923 if (!renderer()->hasTransformRelatedProperty()) | |
924 return FloatPoint(); | |
925 | |
926 const LayoutRect borderBox = toRenderBox(renderer())->borderBoxRect(); | |
927 RenderStyle* style = renderer()->style(); | |
928 | |
929 return FloatPoint(floatValueForLength(style->perspectiveOriginX(), borderBox
.width().toFloat()), floatValueForLength(style->perspectiveOriginY(), borderBox.
height().toFloat())); | |
930 } | |
931 | |
932 static inline bool isFixedPositionedContainer(RenderLayer* layer) | |
933 { | |
934 return layer->isRootLayer() || layer->hasTransformRelatedProperty(); | |
935 } | |
936 | |
937 RenderLayer* RenderLayer::enclosingPositionedAncestor() const | |
938 { | |
939 RenderLayer* curr = parent(); | |
940 while (curr && !curr->isPositionedContainer()) | |
941 curr = curr->parent(); | |
942 | |
943 return curr; | |
944 } | |
945 | |
946 RenderLayer* RenderLayer::enclosingTransformedAncestor() const | |
947 { | |
948 RenderLayer* curr = parent(); | |
949 while (curr && !curr->isRootLayer() && !curr->renderer()->hasTransformRelate
dProperty()) | |
950 curr = curr->parent(); | |
951 | |
952 return curr; | |
953 } | |
954 | |
955 LayoutPoint RenderLayer::computeOffsetFromTransformedAncestor() const | |
956 { | |
957 const AncestorDependentCompositingInputs& properties = ancestorDependentComp
ositingInputs(); | |
958 | |
959 TransformState transformState(TransformState::ApplyTransformDirection, Float
Point()); | |
960 // FIXME: add a test that checks flipped writing mode and ApplyContainerFlip
are correct. | |
961 renderer()->mapLocalToContainer(properties.transformAncestor ? properties.tr
ansformAncestor->renderer() : 0, transformState, ApplyContainerFlip); | |
962 transformState.flatten(); | |
963 return LayoutPoint(transformState.lastPlanarPoint()); | |
964 } | |
965 | |
966 const RenderLayer* RenderLayer::compositingContainer() const | |
967 { | |
968 if (stackingNode()->isNormalFlowOnly()) | |
969 return parent(); | |
970 if (RenderLayerStackingNode* ancestorStackingNode = stackingNode()->ancestor
StackingContextNode()) | |
971 return ancestorStackingNode->layer(); | |
972 return 0; | |
973 } | |
974 | |
975 bool RenderLayer::isPaintInvalidationContainer() const | |
976 { | |
977 return compositingState() == PaintsIntoOwnBacking || compositingState() == P
aintsIntoGroupedBacking; | |
978 } | |
979 | |
980 // Note: enclosingCompositingLayer does not include squashed layers. Compositing
stacking children of squashed layers | |
981 // receive graphics layers that are parented to the compositing ancestor of the
squashed layer. | |
982 RenderLayer* RenderLayer::enclosingLayerWithCompositedLayerMapping(IncludeSelfOr
Not includeSelf) const | |
983 { | |
984 ASSERT(isAllowedToQueryCompositingState()); | |
985 | |
986 if ((includeSelf == IncludeSelf) && compositingState() != NotComposited && c
ompositingState() != PaintsIntoGroupedBacking) | |
987 return const_cast<RenderLayer*>(this); | |
988 | |
989 for (const RenderLayer* curr = compositingContainer(); curr; curr = curr->co
mpositingContainer()) { | |
990 if (curr->compositingState() != NotComposited && curr->compositingState(
) != PaintsIntoGroupedBacking) | |
991 return const_cast<RenderLayer*>(curr); | |
992 } | |
993 | |
994 return 0; | |
995 } | |
996 | |
997 // Return the enclosingCompositedLayerForPaintInvalidation for the given RenderL
ayer | |
998 // including crossing frame boundaries. | |
999 RenderLayer* RenderLayer::enclosingLayerForPaintInvalidationCrossingFrameBoundar
ies() const | |
1000 { | |
1001 const RenderLayer* layer = this; | |
1002 RenderLayer* compositedLayer = 0; | |
1003 while (!compositedLayer) { | |
1004 compositedLayer = layer->enclosingLayerForPaintInvalidation(); | |
1005 if (!compositedLayer) { | |
1006 RenderObject* owner = layer->renderer()->frame()->ownerRenderer(); | |
1007 if (!owner) | |
1008 break; | |
1009 layer = owner->enclosingLayer(); | |
1010 } | |
1011 } | |
1012 return compositedLayer; | |
1013 } | |
1014 | |
1015 RenderLayer* RenderLayer::enclosingLayerForPaintInvalidation() const | |
1016 { | |
1017 ASSERT(isAllowedToQueryCompositingState()); | |
1018 | |
1019 if (isPaintInvalidationContainer()) | |
1020 return const_cast<RenderLayer*>(this); | |
1021 | |
1022 for (const RenderLayer* curr = compositingContainer(); curr; curr = curr->co
mpositingContainer()) { | |
1023 if (curr->isPaintInvalidationContainer()) | |
1024 return const_cast<RenderLayer*>(curr); | |
1025 } | |
1026 | |
1027 return 0; | |
1028 } | |
1029 | |
1030 void RenderLayer::setNeedsCompositingInputsUpdate() | |
1031 { | |
1032 m_needsAncestorDependentCompositingInputsUpdate = true; | |
1033 m_needsDescendantDependentCompositingInputsUpdate = true; | |
1034 | |
1035 for (RenderLayer* current = this; current && !current->m_childNeedsCompositi
ngInputsUpdate; current = current->parent()) | |
1036 current->m_childNeedsCompositingInputsUpdate = true; | |
1037 | |
1038 compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterCompositingInp
utChange); | |
1039 } | |
1040 | |
1041 void RenderLayer::updateAncestorDependentCompositingInputs(const AncestorDepende
ntCompositingInputs& compositingInputs) | |
1042 { | |
1043 m_ancestorDependentCompositingInputs = compositingInputs; | |
1044 m_needsAncestorDependentCompositingInputsUpdate = false; | |
1045 } | |
1046 | |
1047 void RenderLayer::updateDescendantDependentCompositingInputs(const DescendantDep
endentCompositingInputs& compositingInputs) | |
1048 { | |
1049 m_descendantDependentCompositingInputs = compositingInputs; | |
1050 m_needsDescendantDependentCompositingInputsUpdate = false; | |
1051 } | |
1052 | |
1053 void RenderLayer::didUpdateCompositingInputs() | |
1054 { | |
1055 ASSERT(!needsCompositingInputsUpdate()); | |
1056 m_childNeedsCompositingInputsUpdate = false; | |
1057 if (m_scrollableArea) | |
1058 m_scrollableArea->updateNeedsCompositedScrolling(); | |
1059 } | |
1060 | |
1061 bool RenderLayer::hasNonIsolatedDescendantWithBlendMode() const | |
1062 { | |
1063 if (descendantDependentCompositingInputs().hasNonIsolatedDescendantWithBlend
Mode) | |
1064 return true; | |
1065 if (renderer()->isSVGRoot()) | |
1066 return toRenderSVGRoot(renderer())->hasNonIsolatedBlendingDescendants(); | |
1067 return false; | |
1068 } | |
1069 | |
1070 void RenderLayer::setCompositingReasons(CompositingReasons reasons, CompositingR
easons mask) | |
1071 { | |
1072 if ((compositingReasons() & mask) == (reasons & mask)) | |
1073 return; | |
1074 m_compositingReasons = (reasons & mask) | (compositingReasons() & ~mask); | |
1075 } | |
1076 | |
1077 void RenderLayer::setHasCompositingDescendant(bool hasCompositingDescendant) | |
1078 { | |
1079 if (m_hasCompositingDescendant == static_cast<unsigned>(hasCompositingDescen
dant)) | |
1080 return; | |
1081 | |
1082 m_hasCompositingDescendant = hasCompositingDescendant; | |
1083 | |
1084 if (hasCompositedLayerMapping()) | |
1085 compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdat
eLocal); | |
1086 } | |
1087 | |
1088 void RenderLayer::setShouldIsolateCompositedDescendants(bool shouldIsolateCompos
itedDescendants) | |
1089 { | |
1090 if (m_shouldIsolateCompositedDescendants == static_cast<unsigned>(shouldIsol
ateCompositedDescendants)) | |
1091 return; | |
1092 | |
1093 m_shouldIsolateCompositedDescendants = shouldIsolateCompositedDescendants; | |
1094 | |
1095 if (hasCompositedLayerMapping()) | |
1096 compositedLayerMapping()->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdat
eLocal); | |
1097 } | |
1098 | |
1099 bool RenderLayer::hasAncestorWithFilterOutsets() const | |
1100 { | |
1101 for (const RenderLayer* curr = this; curr; curr = curr->parent()) { | |
1102 RenderLayerModelObject* renderer = curr->renderer(); | |
1103 if (renderer->style()->hasFilterOutsets()) | |
1104 return true; | |
1105 } | |
1106 return false; | |
1107 } | |
1108 | |
1109 static void expandClipRectForDescendantsAndReflection(LayoutRect& clipRect, cons
t RenderLayer* layer, const RenderLayer* rootLayer, | |
1110 RenderLayer::TransparencyClipBoxBehavior transparencyBehavior, const LayoutS
ize& subPixelAccumulation, PaintBehavior paintBehavior) | |
1111 { | |
1112 // If we have a mask, then the clip is limited to the border box area (and t
here is | |
1113 // no need to examine child layers). | |
1114 if (!layer->renderer()->hasMask()) { | |
1115 // Note: we don't have to walk z-order lists since transparent elements
always establish | |
1116 // a stacking container. This means we can just walk the layer tree dire
ctly. | |
1117 for (RenderLayer* curr = layer->firstChild(); curr; curr = curr->nextSib
ling()) { | |
1118 if (!layer->reflectionInfo() || layer->reflectionInfo()->reflectionL
ayer() != curr) | |
1119 clipRect.unite(RenderLayer::transparencyClipBox(curr, rootLayer,
transparencyBehavior, RenderLayer::DescendantsOfTransparencyClipBox, subPixelAc
cumulation, paintBehavior)); | |
1120 } | |
1121 } | |
1122 | |
1123 // If we have a reflection, then we need to account for that when we push th
e clip. Reflect our entire | |
1124 // current transparencyClipBox to catch all child layers. | |
1125 // FIXME: Accelerated compositing will eventually want to do something smart
here to avoid incorporating this | |
1126 // size into the parent layer. | |
1127 if (layer->renderer()->hasReflection()) { | |
1128 LayoutPoint delta; | |
1129 layer->convertToLayerCoords(rootLayer, delta); | |
1130 clipRect.move(-delta.x(), -delta.y()); | |
1131 clipRect.unite(layer->renderBox()->reflectedRect(clipRect)); | |
1132 clipRect.moveBy(delta); | |
1133 } | |
1134 } | |
1135 | |
1136 LayoutRect RenderLayer::transparencyClipBox(const RenderLayer* layer, const Rend
erLayer* rootLayer, TransparencyClipBoxBehavior transparencyBehavior, | |
1137 TransparencyClipBoxMode transparencyMode, const LayoutSize& subPixelAccumula
tion, PaintBehavior paintBehavior) | |
1138 { | |
1139 // FIXME: Although this function completely ignores CSS-imposed clipping, we
did already intersect with the | |
1140 // paintDirtyRect, and that should cut down on the amount we have to paint.
Still it | |
1141 // would be better to respect clips. | |
1142 | |
1143 if (rootLayer != layer && ((transparencyBehavior == PaintingTransparencyClip
Box && layer->paintsWithTransform(paintBehavior)) | |
1144 || (transparencyBehavior == HitTestingTransparencyClipBox && layer->hasT
ransformRelatedProperty()))) { | |
1145 // The best we can do here is to use enclosed bounding boxes to establis
h a "fuzzy" enough clip to encompass | |
1146 // the transformed layer and all of its children. | |
1147 const RenderLayer* paginationLayer = transparencyMode == DescendantsOfTr
ansparencyClipBox ? layer->enclosingPaginationLayer() : 0; | |
1148 const RenderLayer* rootLayerForTransform = paginationLayer ? paginationL
ayer : rootLayer; | |
1149 LayoutPoint delta; | |
1150 layer->convertToLayerCoords(rootLayerForTransform, delta); | |
1151 | |
1152 delta.move(subPixelAccumulation); | |
1153 IntPoint pixelSnappedDelta = roundedIntPoint(delta); | |
1154 TransformationMatrix transform; | |
1155 transform.translate(pixelSnappedDelta.x(), pixelSnappedDelta.y()); | |
1156 transform = transform * *layer->transform(); | |
1157 | |
1158 // We don't use fragment boxes when collecting a transformed layer's bou
nding box, since it always | |
1159 // paints unfragmented. | |
1160 LayoutRect clipRect = layer->physicalBoundingBox(layer); | |
1161 expandClipRectForDescendantsAndReflection(clipRect, layer, layer, transp
arencyBehavior, subPixelAccumulation, paintBehavior); | |
1162 clipRect.expand(layer->renderer()->style()->filterOutsets()); | |
1163 LayoutRect result = transform.mapRect(clipRect); | |
1164 if (!paginationLayer) | |
1165 return result; | |
1166 | |
1167 // We have to break up the transformed extent across our columns. | |
1168 // Split our box up into the actual fragment boxes that render in the co
lumns/pages and unite those together to | |
1169 // get our true bounding box. | |
1170 RenderFlowThread* enclosingFlowThread = toRenderFlowThread(paginationLay
er->renderer()); | |
1171 result = enclosingFlowThread->fragmentsBoundingBox(result); | |
1172 | |
1173 LayoutPoint rootLayerDelta; | |
1174 paginationLayer->convertToLayerCoords(rootLayer, rootLayerDelta); | |
1175 result.moveBy(rootLayerDelta); | |
1176 return result; | |
1177 } | |
1178 | |
1179 LayoutRect clipRect = layer->fragmentsBoundingBox(rootLayer); | |
1180 expandClipRectForDescendantsAndReflection(clipRect, layer, rootLayer, transp
arencyBehavior, subPixelAccumulation, paintBehavior); | |
1181 clipRect.expand(layer->renderer()->style()->filterOutsets()); | |
1182 clipRect.move(subPixelAccumulation); | |
1183 return clipRect; | |
1184 } | |
1185 | |
1186 LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const Layou
tRect& paintDirtyRect, const LayoutSize& subPixelAccumulation, PaintBehavior pai
ntBehavior) | |
1187 { | |
1188 return intersection(transparencyClipBox(this, rootLayer, PaintingTransparenc
yClipBox, RootOfTransparencyClipBox, subPixelAccumulation, paintBehavior), paint
DirtyRect); | |
1189 } | |
1190 | |
1191 void* RenderLayer::operator new(size_t sz) | |
1192 { | |
1193 return partitionAlloc(Partitions::getRenderingPartition(), sz); | |
1194 } | |
1195 | |
1196 void RenderLayer::operator delete(void* ptr) | |
1197 { | |
1198 partitionFree(ptr); | |
1199 } | |
1200 | |
1201 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild) | |
1202 { | |
1203 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : la
stChild(); | |
1204 if (prevSibling) { | |
1205 child->setPreviousSibling(prevSibling); | |
1206 prevSibling->setNextSibling(child); | |
1207 ASSERT(prevSibling != child); | |
1208 } else | |
1209 setFirstChild(child); | |
1210 | |
1211 if (beforeChild) { | |
1212 beforeChild->setPreviousSibling(child); | |
1213 child->setNextSibling(beforeChild); | |
1214 ASSERT(beforeChild != child); | |
1215 } else | |
1216 setLastChild(child); | |
1217 | |
1218 child->m_parent = this; | |
1219 | |
1220 setNeedsCompositingInputsUpdate(); | |
1221 | |
1222 if (child->stackingNode()->isNormalFlowOnly()) | |
1223 m_stackingNode->dirtyNormalFlowList(); | |
1224 | |
1225 if (!child->stackingNode()->isNormalFlowOnly() || child->firstChild()) { | |
1226 // Dirty the z-order list in which we are contained. The ancestorStackin
gContextNode() can be null in the | |
1227 // case where we're building up generated content layers. This is ok, si
nce the lists will start | |
1228 // off dirty in that case anyway. | |
1229 child->stackingNode()->dirtyStackingContextZOrderLists(); | |
1230 } | |
1231 | |
1232 dirtyAncestorChainVisibleDescendantStatus(); | |
1233 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); | |
1234 | |
1235 child->updateDescendantDependentFlags(); | |
1236 } | |
1237 | |
1238 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild) | |
1239 { | |
1240 if (oldChild->previousSibling()) | |
1241 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); | |
1242 if (oldChild->nextSibling()) | |
1243 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling())
; | |
1244 | |
1245 if (m_first == oldChild) | |
1246 m_first = oldChild->nextSibling(); | |
1247 if (m_last == oldChild) | |
1248 m_last = oldChild->previousSibling(); | |
1249 | |
1250 if (oldChild->stackingNode()->isNormalFlowOnly()) | |
1251 m_stackingNode->dirtyNormalFlowList(); | |
1252 if (!oldChild->stackingNode()->isNormalFlowOnly() || oldChild->firstChild())
{ | |
1253 // Dirty the z-order list in which we are contained. When called via th
e | |
1254 // reattachment process in removeOnlyThisLayer, the layer may already be
disconnected | |
1255 // from the main layer tree, so we need to null-check the | |
1256 // |stackingContext| value. | |
1257 oldChild->stackingNode()->dirtyStackingContextZOrderLists(); | |
1258 } | |
1259 | |
1260 if (renderer()->style()->visibility() != VISIBLE) | |
1261 dirtyVisibleContentStatus(); | |
1262 | |
1263 oldChild->setPreviousSibling(0); | |
1264 oldChild->setNextSibling(0); | |
1265 oldChild->m_parent = 0; | |
1266 | |
1267 dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); | |
1268 | |
1269 oldChild->updateDescendantDependentFlags(); | |
1270 | |
1271 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant) | |
1272 dirtyAncestorChainVisibleDescendantStatus(); | |
1273 | |
1274 if (oldChild->enclosingPaginationLayer()) | |
1275 oldChild->clearPaginationRecursive(); | |
1276 | |
1277 return oldChild; | |
1278 } | |
1279 | |
1280 void RenderLayer::removeOnlyThisLayer() | |
1281 { | |
1282 if (!m_parent) | |
1283 return; | |
1284 | |
1285 { | |
1286 DisableCompositingQueryAsserts disabler; // We need the current composit
ing status. | |
1287 if (isPaintInvalidationContainer()) { | |
1288 // Our children will be reparented and contained by a new paint inva
lidation container, | |
1289 // so need paint invalidation. CompositingUpdate can't see this laye
r (which has been | |
1290 // removed) so won't do this for us. | |
1291 setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants()
; | |
1292 } | |
1293 } | |
1294 | |
1295 m_clipper.clearClipRectsIncludingDescendants(); | |
1296 | |
1297 RenderLayer* nextSib = nextSibling(); | |
1298 | |
1299 // Remove the child reflection layer before moving other child layers. | |
1300 // The reflection layer should not be moved to the parent. | |
1301 if (m_reflectionInfo) | |
1302 removeChild(m_reflectionInfo->reflectionLayer()); | |
1303 | |
1304 // Now walk our kids and reattach them to our parent. | |
1305 RenderLayer* current = m_first; | |
1306 while (current) { | |
1307 RenderLayer* next = current->nextSibling(); | |
1308 removeChild(current); | |
1309 m_parent->addChild(current, nextSib); | |
1310 | |
1311 // FIXME: We should call a specialized version of this function. | |
1312 current->updateLayerPositionsAfterLayout(); | |
1313 current = next; | |
1314 } | |
1315 | |
1316 // Remove us from the parent. | |
1317 m_parent->removeChild(this); | |
1318 m_renderer->destroyLayer(); | |
1319 } | |
1320 | |
1321 void RenderLayer::insertOnlyThisLayer() | |
1322 { | |
1323 if (!m_parent && renderer()->parent()) { | |
1324 // We need to connect ourselves when our renderer() has a parent. | |
1325 // Find our enclosingLayer and add ourselves. | |
1326 RenderLayer* parentLayer = renderer()->parent()->enclosingLayer(); | |
1327 ASSERT(parentLayer); | |
1328 RenderLayer* beforeChild = !parentLayer->reflectionInfo() || parentLayer
->reflectionInfo()->reflectionLayer() != this ? renderer()->parent()->findNextLa
yer(parentLayer, renderer()) : 0; | |
1329 parentLayer->addChild(this, beforeChild); | |
1330 } | |
1331 | |
1332 // Remove all descendant layers from the hierarchy and add them to the new p
osition. | |
1333 for (RenderObject* curr = renderer()->slowFirstChild(); curr; curr = curr->n
extSibling()) | |
1334 curr->moveLayers(m_parent, this); | |
1335 | |
1336 // Clear out all the clip rects. | |
1337 m_clipper.clearClipRectsIncludingDescendants(); | |
1338 } | |
1339 | |
1340 // Returns the layer reached on the walk up towards the ancestor. | |
1341 static inline const RenderLayer* accumulateOffsetTowardsAncestor(const RenderLay
er* layer, const RenderLayer* ancestorLayer, LayoutPoint& location) | |
1342 { | |
1343 ASSERT(ancestorLayer != layer); | |
1344 | |
1345 const RenderLayerModelObject* renderer = layer->renderer(); | |
1346 EPosition position = renderer->style()->position(); | |
1347 | |
1348 // FIXME: Positioning of out-of-flow(fixed, absolute) elements collected in
a RenderFlowThread | |
1349 // may need to be revisited in a future patch. | |
1350 // If the fixed renderer is inside a RenderFlowThread, we should not compute
location using localToAbsolute, | |
1351 // since localToAbsolute maps the coordinates from flow thread to regions co
ordinates and regions can be | |
1352 // positioned in a completely different place in the viewport (RenderView). | |
1353 if (position == FixedPosition && (!ancestorLayer || ancestorLayer == rendere
r->view()->layer())) { | |
1354 // If the fixed layer's container is the root, just add in the offset of
the view. We can obtain this by calling | |
1355 // localToAbsolute() on the RenderView. | |
1356 FloatPoint absPos = renderer->localToAbsolute(FloatPoint(), IsFixed); | |
1357 location += LayoutSize(absPos.x(), absPos.y()); | |
1358 return ancestorLayer; | |
1359 } | |
1360 | |
1361 // For the fixed positioned elements inside a render flow thread, we should
also skip the code path below | |
1362 // Otherwise, for the case of ancestorLayer == rootLayer and fixed positione
d element child of a transformed | |
1363 // element in render flow thread, we will hit the fixed positioned container
before hitting the ancestor layer. | |
1364 if (position == FixedPosition) { | |
1365 // For a fixed layers, we need to walk up to the root to see if there's
a fixed position container | |
1366 // (e.g. a transformed layer). It's an error to call convertToLayerCoord
s() across a layer with a transform, | |
1367 // so we should always find the ancestor at or before we find the fixed
position container. | |
1368 RenderLayer* fixedPositionContainerLayer = 0; | |
1369 bool foundAncestor = false; | |
1370 for (RenderLayer* currLayer = layer->parent(); currLayer; currLayer = cu
rrLayer->parent()) { | |
1371 if (currLayer == ancestorLayer) | |
1372 foundAncestor = true; | |
1373 | |
1374 if (isFixedPositionedContainer(currLayer)) { | |
1375 fixedPositionContainerLayer = currLayer; | |
1376 ASSERT_UNUSED(foundAncestor, foundAncestor); | |
1377 break; | |
1378 } | |
1379 } | |
1380 | |
1381 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderVie
w's layer at least. | |
1382 | |
1383 if (fixedPositionContainerLayer != ancestorLayer) { | |
1384 LayoutPoint fixedContainerCoords; | |
1385 layer->convertToLayerCoords(fixedPositionContainerLayer, fixedContai
nerCoords); | |
1386 | |
1387 LayoutPoint ancestorCoords; | |
1388 ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, anc
estorCoords); | |
1389 | |
1390 location += (fixedContainerCoords - ancestorCoords); | |
1391 } else { | |
1392 // RenderView has been handled in the first top-level 'if' block abo
ve. | |
1393 ASSERT(ancestorLayer != renderer->view()->layer()); | |
1394 ASSERT(ancestorLayer->hasTransformRelatedProperty()); | |
1395 | |
1396 location += layer->location(); | |
1397 | |
1398 // The spec (http://dev.w3.org/csswg/css-transforms/#transform-rende
ring) doesn't say if a | |
1399 // fixed-position element under a scrollable transformed element sho
uld scroll. However, | |
1400 // other parts of blink scroll the fixed-position element, and the f
ollowing keeps the consistency. | |
1401 if (RenderLayerScrollableArea* scrollableArea = ancestorLayer->scrol
lableArea()) | |
1402 location -= LayoutSize(scrollableArea->scrollOffset()); | |
1403 } | |
1404 return ancestorLayer; | |
1405 } | |
1406 | |
1407 RenderLayer* parentLayer; | |
1408 if (position == AbsolutePosition) { | |
1409 // Do what enclosingPositionedAncestor() does, but check for ancestorLay
er along the way. | |
1410 parentLayer = layer->parent(); | |
1411 bool foundAncestorFirst = false; | |
1412 while (parentLayer) { | |
1413 // RenderFlowThread is a positioned container, child of RenderView,
positioned at (0,0). | |
1414 // This implies that, for out-of-flow positioned elements inside a R
enderFlowThread, | |
1415 // we are bailing out before reaching root layer. | |
1416 if (parentLayer->isPositionedContainer()) | |
1417 break; | |
1418 | |
1419 if (parentLayer == ancestorLayer) { | |
1420 foundAncestorFirst = true; | |
1421 break; | |
1422 } | |
1423 | |
1424 parentLayer = parentLayer->parent(); | |
1425 } | |
1426 | |
1427 // We should not reach RenderView layer past the RenderFlowThread layer
for any | |
1428 // children of the RenderFlowThread. | |
1429 ASSERT(!renderer->flowThreadContainingBlock() || parentLayer != renderer
->view()->layer()); | |
1430 | |
1431 if (foundAncestorFirst) { | |
1432 // Found ancestorLayer before the abs. positioned container, so comp
ute offset of both relative | |
1433 // to enclosingPositionedAncestor and subtract. | |
1434 RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAn
cestor(); | |
1435 | |
1436 LayoutPoint thisCoords; | |
1437 layer->convertToLayerCoords(positionedAncestor, thisCoords); | |
1438 | |
1439 LayoutPoint ancestorCoords; | |
1440 ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorCoor
ds); | |
1441 | |
1442 location += (thisCoords - ancestorCoords); | |
1443 return ancestorLayer; | |
1444 } | |
1445 } else if (renderer->isColumnSpanAll()) { | |
1446 RenderBlock* multicolContainer = renderer->containingBlock(); | |
1447 ASSERT(toRenderBlockFlow(multicolContainer)->multiColumnFlowThread()); | |
1448 parentLayer = multicolContainer->layer(); | |
1449 ASSERT(parentLayer); | |
1450 } else { | |
1451 parentLayer = layer->parent(); | |
1452 } | |
1453 | |
1454 if (!parentLayer) | |
1455 return 0; | |
1456 | |
1457 location += layer->location(); | |
1458 return parentLayer; | |
1459 } | |
1460 | |
1461 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutP
oint& location) const | |
1462 { | |
1463 if (ancestorLayer == this) | |
1464 return; | |
1465 | |
1466 const RenderLayer* currLayer = this; | |
1467 while (currLayer && currLayer != ancestorLayer) | |
1468 currLayer = accumulateOffsetTowardsAncestor(currLayer, ancestorLayer, lo
cation); | |
1469 } | |
1470 | |
1471 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutR
ect& rect) const | |
1472 { | |
1473 LayoutPoint delta; | |
1474 convertToLayerCoords(ancestorLayer, delta); | |
1475 rect.moveBy(delta); | |
1476 } | |
1477 | |
1478 LayoutPoint RenderLayer::visualOffsetFromAncestor(const RenderLayer* ancestorLay
er) const | |
1479 { | |
1480 LayoutPoint offset; | |
1481 if (ancestorLayer == this) | |
1482 return offset; | |
1483 RenderLayer* paginationLayer = enclosingPaginationLayer(); | |
1484 if (paginationLayer == this) | |
1485 paginationLayer = parent()->enclosingPaginationLayer(); | |
1486 if (!paginationLayer) { | |
1487 convertToLayerCoords(ancestorLayer, offset); | |
1488 return offset; | |
1489 } | |
1490 | |
1491 RenderFlowThread* flowThread = toRenderFlowThread(paginationLayer->renderer(
)); | |
1492 convertToLayerCoords(paginationLayer, offset); | |
1493 offset = flowThread->flowThreadPointToVisualPoint(offset); | |
1494 if (ancestorLayer == paginationLayer) | |
1495 return offset; | |
1496 | |
1497 if (ancestorLayer->enclosingPaginationLayer() != paginationLayer) { | |
1498 offset.moveBy(paginationLayer->visualOffsetFromAncestor(ancestorLayer)); | |
1499 } else { | |
1500 // The ancestor layer is also inside the pagination layer, so we need to
subtract the visual | |
1501 // distance from the ancestor layer to the pagination layer. | |
1502 offset.moveBy(-ancestorLayer->visualOffsetFromAncestor(paginationLayer))
; | |
1503 } | |
1504 return offset; | |
1505 } | |
1506 | |
1507 void RenderLayer::didUpdateNeedsCompositedScrolling() | |
1508 { | |
1509 updateSelfPaintingLayer(); | |
1510 } | |
1511 | |
1512 void RenderLayer::updateReflectionInfo(const RenderStyle* oldStyle) | |
1513 { | |
1514 ASSERT(!oldStyle || !renderer()->style()->reflectionDataEquivalent(oldStyle)
); | |
1515 if (renderer()->hasReflection()) { | |
1516 if (!m_reflectionInfo) | |
1517 m_reflectionInfo = adoptPtr(new RenderLayerReflectionInfo(*renderBox
())); | |
1518 m_reflectionInfo->updateAfterStyleChange(oldStyle); | |
1519 } else if (m_reflectionInfo) { | |
1520 m_reflectionInfo->destroy(); | |
1521 m_reflectionInfo = nullptr; | |
1522 } | |
1523 } | |
1524 | |
1525 void RenderLayer::updateStackingNode() | |
1526 { | |
1527 if (requiresStackingNode()) | |
1528 m_stackingNode = adoptPtr(new RenderLayerStackingNode(this)); | |
1529 else | |
1530 m_stackingNode = nullptr; | |
1531 } | |
1532 | |
1533 void RenderLayer::updateScrollableArea() | |
1534 { | |
1535 if (requiresScrollableArea()) | |
1536 m_scrollableArea = adoptPtr(new RenderLayerScrollableArea(*this)); | |
1537 else | |
1538 m_scrollableArea = nullptr; | |
1539 } | |
1540 | |
1541 bool RenderLayer::hasOverflowControls() const | |
1542 { | |
1543 return m_scrollableArea && (m_scrollableArea->hasScrollbar() || m_scrollable
Area->scrollCorner() || renderer()->style()->resize() != RESIZE_NONE); | |
1544 } | |
1545 | |
1546 void RenderLayer::collectFragments(LayerFragments& fragments, const RenderLayer*
rootLayer, const LayoutRect& dirtyRect, | |
1547 ClipRectsCacheSlot clipRectsCacheSlot, OverlayScrollbarSizeRelevancy inOverl
ayScrollbarSizeRelevancy, ShouldRespectOverflowClip respectOverflowClip, const L
ayoutPoint* offsetFromRoot, | |
1548 const LayoutSize& subPixelAccumulation, const LayoutRect* layerBoundingBox) | |
1549 { | |
1550 if (!enclosingPaginationLayer() || hasTransformRelatedProperty()) { | |
1551 // For unpaginated layers, there is only one fragment. | |
1552 LayerFragment fragment; | |
1553 ClipRectsContext clipRectsContext(rootLayer, clipRectsCacheSlot, inOverl
ayScrollbarSizeRelevancy, subPixelAccumulation); | |
1554 if (respectOverflowClip == IgnoreOverflowClip) | |
1555 clipRectsContext.setIgnoreOverflowClip(); | |
1556 clipper().calculateRects(clipRectsContext, dirtyRect, fragment.layerBoun
ds, fragment.backgroundRect, fragment.foregroundRect, fragment.outlineRect, offs
etFromRoot); | |
1557 fragments.append(fragment); | |
1558 return; | |
1559 } | |
1560 | |
1561 // Compute our offset within the enclosing pagination layer. | |
1562 LayoutPoint offsetWithinPaginatedLayer; | |
1563 convertToLayerCoords(enclosingPaginationLayer(), offsetWithinPaginatedLayer)
; | |
1564 | |
1565 // Calculate clip rects relative to the enclosingPaginationLayer. The purpos
e of this call is to determine our bounds clipped to intermediate | |
1566 // layers between us and the pagination context. It's important to minimize
the number of fragments we need to create and this helps with that. | |
1567 ClipRectsContext paginationClipRectsContext(enclosingPaginationLayer(), clip
RectsCacheSlot, inOverlayScrollbarSizeRelevancy); | |
1568 if (respectOverflowClip == IgnoreOverflowClip) | |
1569 paginationClipRectsContext.setIgnoreOverflowClip(); | |
1570 LayoutRect layerBoundsInFlowThread; | |
1571 ClipRect backgroundRectInFlowThread; | |
1572 ClipRect foregroundRectInFlowThread; | |
1573 ClipRect outlineRectInFlowThread; | |
1574 clipper().calculateRects(paginationClipRectsContext, LayoutRect::infiniteInt
Rect(), layerBoundsInFlowThread, backgroundRectInFlowThread, foregroundRectInFlo
wThread, | |
1575 outlineRectInFlowThread, &offsetWithinPaginatedLayer); | |
1576 | |
1577 // Take our bounding box within the flow thread and clip it. | |
1578 LayoutRect layerBoundingBoxInFlowThread = layerBoundingBox ? *layerBoundingB
ox : physicalBoundingBox(enclosingPaginationLayer(), &offsetWithinPaginatedLayer
); | |
1579 layerBoundingBoxInFlowThread.intersect(backgroundRectInFlowThread.rect()); | |
1580 | |
1581 // Make the dirty rect relative to the fragmentation context (multicol conta
iner, etc.). | |
1582 RenderFlowThread* enclosingFlowThread = toRenderFlowThread(enclosingPaginati
onLayer()->renderer()); | |
1583 LayoutPoint offsetOfPaginationLayerFromRoot; // Visual offset from the root
layer to the nearest fragmentation context. | |
1584 bool rootLayerIsInsidePaginationLayer = rootLayer->enclosingPaginationLayer(
) == enclosingPaginationLayer(); | |
1585 if (rootLayerIsInsidePaginationLayer) { | |
1586 // The root layer is in the same fragmentation context as this layer, so
we need to look | |
1587 // inside it and subtract the offset between the fragmentation context a
nd the root layer. | |
1588 offsetOfPaginationLayerFromRoot = -rootLayer->visualOffsetFromAncestor(e
nclosingPaginationLayer()); | |
1589 } else { | |
1590 offsetOfPaginationLayerFromRoot = enclosingPaginationLayer()->visualOffs
etFromAncestor(rootLayer); | |
1591 } | |
1592 LayoutRect dirtyRectInFlowThread(dirtyRect); | |
1593 dirtyRectInFlowThread.moveBy(-offsetOfPaginationLayerFromRoot); | |
1594 | |
1595 // Tell the flow thread to collect the fragments. We pass enough information
to create a minimal number of fragments based off the pages/columns | |
1596 // that intersect the actual dirtyRect as well as the pages/columns that int
ersect our layer's bounding box. | |
1597 enclosingFlowThread->collectLayerFragments(fragments, layerBoundingBoxInFlow
Thread, dirtyRectInFlowThread); | |
1598 | |
1599 if (fragments.isEmpty()) | |
1600 return; | |
1601 | |
1602 // Get the parent clip rects of the pagination layer, since we need to inter
sect with that when painting column contents. | |
1603 ClipRect ancestorClipRect = dirtyRect; | |
1604 if (const RenderLayer* paginationParentLayer = enclosingPaginationLayer()->p
arent()) { | |
1605 const RenderLayer* ancestorLayer = rootLayerIsInsidePaginationLayer ? pa
ginationParentLayer : rootLayer; | |
1606 ClipRectsContext clipRectsContext(ancestorLayer, clipRectsCacheSlot, inO
verlayScrollbarSizeRelevancy); | |
1607 if (respectOverflowClip == IgnoreOverflowClip) | |
1608 clipRectsContext.setIgnoreOverflowClip(); | |
1609 ancestorClipRect = enclosingPaginationLayer()->clipper().backgroundClipR
ect(clipRectsContext); | |
1610 if (rootLayerIsInsidePaginationLayer) | |
1611 ancestorClipRect.moveBy(-rootLayer->visualOffsetFromAncestor(ancesto
rLayer)); | |
1612 ancestorClipRect.intersect(dirtyRect); | |
1613 } | |
1614 | |
1615 for (size_t i = 0; i < fragments.size(); ++i) { | |
1616 LayerFragment& fragment = fragments.at(i); | |
1617 | |
1618 // Set our four rects with all clipping applied that was internal to the
flow thread. | |
1619 fragment.setRects(layerBoundsInFlowThread, backgroundRectInFlowThread, f
oregroundRectInFlowThread, outlineRectInFlowThread); | |
1620 | |
1621 // Shift to the root-relative physical position used when painting the f
low thread in this fragment. | |
1622 fragment.moveBy(fragment.paginationOffset + offsetOfPaginationLayerFromR
oot); | |
1623 | |
1624 // Intersect the fragment with our ancestor's background clip so that e.
g., columns in an overflow:hidden block are | |
1625 // properly clipped by the overflow. | |
1626 fragment.intersect(ancestorClipRect.rect()); | |
1627 | |
1628 // Now intersect with our pagination clip. This will typically mean we'r
e just intersecting the dirty rect with the column | |
1629 // clip, so the column clip ends up being all we apply. | |
1630 fragment.intersect(fragment.paginationClip); | |
1631 } | |
1632 } | |
1633 | |
1634 static inline LayoutRect frameVisibleRect(RenderObject* renderer) | |
1635 { | |
1636 FrameView* frameView = renderer->document().view(); | |
1637 if (!frameView) | |
1638 return LayoutRect(); | |
1639 | |
1640 return frameView->visibleContentRect(); | |
1641 } | |
1642 | |
1643 bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result) | |
1644 { | |
1645 return hitTest(request, result.hitTestLocation(), result); | |
1646 } | |
1647 | |
1648 bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestLocation&
hitTestLocation, HitTestResult& result) | |
1649 { | |
1650 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant()); | |
1651 | |
1652 // RenderView should make sure to update layout before entering hit testing | |
1653 ASSERT(!renderer()->frame()->view()->layoutPending()); | |
1654 ASSERT(!renderer()->document().renderView()->needsLayout()); | |
1655 | |
1656 // Start with frameVisibleRect to ensure we include the scrollbars. | |
1657 LayoutRect hitTestArea = frameVisibleRect(renderer()); | |
1658 if (request.ignoreClipping()) | |
1659 hitTestArea.unite(renderer()->view()->documentRect()); | |
1660 | |
1661 RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, hitTestAre
a, hitTestLocation, false); | |
1662 if (!insideLayer) { | |
1663 // We didn't hit any layer. If we are the root layer and the mouse is --
or just was -- down, | |
1664 // return ourselves. We do this so mouse events continue getting deliver
ed after a drag has | |
1665 // exited the WebView, and so hit testing over a scrollbar hits the cont
ent document. | |
1666 // In addtion, it is possible for the mouse to stay in the document but
there is no element. | |
1667 // At that time, the events of the mouse should be fired. | |
1668 LayoutPoint hitPoint = hitTestLocation.point(); | |
1669 if (!request.isChildFrameHitTest() && ((request.active() || request.rele
ase()) || (request.move() && hitTestArea.contains(hitPoint.x(), hitPoint.y())))
&& isRootLayer()) { | |
1670 renderer()->updateHitTestResult(result, toRenderView(renderer())->fl
ipForWritingMode(hitTestLocation.point())); | |
1671 insideLayer = this; | |
1672 } | |
1673 } | |
1674 | |
1675 // Now determine if the result is inside an anchor - if the urlElement isn't
already set. | |
1676 Node* node = result.innerNode(); | |
1677 if (node && !result.URLElement()) | |
1678 result.setURLElement(node->enclosingLinkEventParentOrSelf()); | |
1679 | |
1680 // Now return whether we were inside this layer (this will always be true fo
r the root | |
1681 // layer). | |
1682 return insideLayer; | |
1683 } | |
1684 | |
1685 Node* RenderLayer::enclosingElement() const | |
1686 { | |
1687 for (RenderObject* r = renderer(); r; r = r->parent()) { | |
1688 if (Node* e = r->node()) | |
1689 return e; | |
1690 } | |
1691 ASSERT_NOT_REACHED(); | |
1692 return 0; | |
1693 } | |
1694 | |
1695 bool RenderLayer::isInTopLayer() const | |
1696 { | |
1697 Node* node = renderer()->node(); | |
1698 return node && node->isElementNode() && toElement(node)->isInTopLayer(); | |
1699 } | |
1700 | |
1701 // Compute the z-offset of the point in the transformState. | |
1702 // This is effectively projecting a ray normal to the plane of ancestor, finding
where that | |
1703 // ray intersects target, and computing the z delta between those two points. | |
1704 static double computeZOffset(const HitTestingTransformState& transformState) | |
1705 { | |
1706 // We got an affine transform, so no z-offset | |
1707 if (transformState.m_accumulatedTransform.isAffine()) | |
1708 return 0; | |
1709 | |
1710 // Flatten the point into the target plane | |
1711 FloatPoint targetPoint = transformState.mappedPoint(); | |
1712 | |
1713 // Now map the point back through the transform, which computes Z. | |
1714 FloatPoint3D backmappedPoint = transformState.m_accumulatedTransform.mapPoin
t(FloatPoint3D(targetPoint)); | |
1715 return backmappedPoint.z(); | |
1716 } | |
1717 | |
1718 PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(Rend
erLayer* rootLayer, RenderLayer* containerLayer, | |
1719 const LayoutRect& hitTestRect, const Hit
TestLocation& hitTestLocation, | |
1720 const HitTestingTransformState* containe
rTransformState, | |
1721 const LayoutPoint& translationOffset) co
nst | |
1722 { | |
1723 RefPtr<HitTestingTransformState> transformState; | |
1724 LayoutPoint offset; | |
1725 if (containerTransformState) { | |
1726 // If we're already computing transform state, then it's relative to the
container (which we know is non-null). | |
1727 transformState = HitTestingTransformState::create(*containerTransformSta
te); | |
1728 convertToLayerCoords(containerLayer, offset); | |
1729 } else { | |
1730 // If this is the first time we need to make transform state, then base
it off of hitTestLocation, | |
1731 // which is relative to rootLayer. | |
1732 transformState = HitTestingTransformState::create(hitTestLocation.transf
ormedPoint(), hitTestLocation.transformedRect(), FloatQuad(hitTestRect)); | |
1733 convertToLayerCoords(rootLayer, offset); | |
1734 } | |
1735 offset.moveBy(translationOffset); | |
1736 | |
1737 RenderObject* containerRenderer = containerLayer ? containerLayer->renderer(
) : 0; | |
1738 if (renderer()->shouldUseTransformFromContainer(containerRenderer)) { | |
1739 TransformationMatrix containerTransform; | |
1740 renderer()->getTransformFromContainer(containerRenderer, toLayoutSize(of
fset), containerTransform); | |
1741 transformState->applyTransform(containerTransform, HitTestingTransformSt
ate::AccumulateTransform); | |
1742 } else { | |
1743 transformState->translate(offset.x(), offset.y(), HitTestingTransformSta
te::AccumulateTransform); | |
1744 } | |
1745 | |
1746 return transformState; | |
1747 } | |
1748 | |
1749 | |
1750 static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, doubl
e* zOffset, const HitTestingTransformState* transformState) | |
1751 { | |
1752 if (!hitLayer) | |
1753 return false; | |
1754 | |
1755 // The hit layer is depth-sorting with other layers, so just say that it was
hit. | |
1756 if (canDepthSort) | |
1757 return true; | |
1758 | |
1759 // We need to look at z-depth to decide if this layer was hit. | |
1760 if (zOffset) { | |
1761 ASSERT(transformState); | |
1762 // This is actually computing our z, but that's OK because the hitLayer
is coplanar with us. | |
1763 double childZOffset = computeZOffset(*transformState); | |
1764 if (childZOffset > *zOffset) { | |
1765 *zOffset = childZOffset; | |
1766 return true; | |
1767 } | |
1768 return false; | |
1769 } | |
1770 | |
1771 return true; | |
1772 } | |
1773 | |
1774 // hitTestLocation and hitTestRect are relative to rootLayer. | |
1775 // A 'flattening' layer is one preserves3D() == false. | |
1776 // transformState.m_accumulatedTransform holds the transform from the containing
flattening layer. | |
1777 // transformState.m_lastPlanarPoint is the hitTestLocation in the plane of the c
ontaining flattening layer. | |
1778 // transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of
the containing flattening layer. | |
1779 // | |
1780 // If zOffset is non-null (which indicates that the caller wants z offset inform
ation), | |
1781 // *zOffset on return is the z offset of the hit point relative to the containi
ng flattening layer. | |
1782 RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont
ainerLayer, const HitTestRequest& request, HitTestResult& result, | |
1783 const LayoutRect& hitTestRect, const HitT
estLocation& hitTestLocation, bool appliedTransform, | |
1784 const HitTestingTransformState* transform
State, double* zOffset) | |
1785 { | |
1786 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant()) | |
1787 return 0; | |
1788 | |
1789 // The natural thing would be to keep HitTestingTransformState on the stack,
but it's big, so we heap-allocate. | |
1790 | |
1791 // Apply a transform if we have one. | |
1792 if (transform() && !appliedTransform) { | |
1793 if (enclosingPaginationLayer()) | |
1794 return hitTestTransformedLayerInFragments(rootLayer, containerLayer,
request, result, hitTestRect, hitTestLocation, transformState, zOffset); | |
1795 | |
1796 // Make sure the parent's clip rects have been calculated. | |
1797 if (parent()) { | |
1798 ClipRect clipRect = clipper().backgroundClipRect(ClipRectsContext(ro
otLayer, RootRelativeClipRects, IncludeOverlayScrollbarSize)); | |
1799 // Go ahead and test the enclosing clip now. | |
1800 if (!clipRect.intersects(hitTestLocation)) | |
1801 return 0; | |
1802 } | |
1803 | |
1804 return hitTestLayerByApplyingTransform(rootLayer, containerLayer, reques
t, result, hitTestRect, hitTestLocation, transformState, zOffset); | |
1805 } | |
1806 | |
1807 // Ensure our lists and 3d status are up-to-date. | |
1808 m_stackingNode->updateLayerListsIfNeeded(); | |
1809 update3DTransformedDescendantStatus(); | |
1810 | |
1811 RefPtr<HitTestingTransformState> localTransformState; | |
1812 if (appliedTransform) { | |
1813 // We computed the correct state in the caller (above code), so just ref
erence it. | |
1814 ASSERT(transformState); | |
1815 localTransformState = const_cast<HitTestingTransformState*>(transformSta
te); | |
1816 } else if (transformState || m_has3DTransformedDescendant || preserves3D())
{ | |
1817 // We need transform state for the first time, or to offset the containe
r state, so create it here. | |
1818 localTransformState = createLocalTransformState(rootLayer, containerLaye
r, hitTestRect, hitTestLocation, transformState); | |
1819 } | |
1820 | |
1821 // Check for hit test on backface if backface-visibility is 'hidden' | |
1822 if (localTransformState && renderer()->style()->backfaceVisibility() == Back
faceVisibilityHidden) { | |
1823 TransformationMatrix invertedMatrix = localTransformState->m_accumulated
Transform.inverse(); | |
1824 // If the z-vector of the matrix is negative, the back is facing towards
the viewer. | |
1825 if (invertedMatrix.m33() < 0) | |
1826 return 0; | |
1827 } | |
1828 | |
1829 RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformS
tate; | |
1830 if (localTransformState && !preserves3D()) { | |
1831 // Keep a copy of the pre-flattening state, for computing z-offsets for
the container | |
1832 unflattenedTransformState = HitTestingTransformState::create(*localTrans
formState); | |
1833 // This layer is flattening, so flatten the state passed to descendants. | |
1834 localTransformState->flatten(); | |
1835 } | |
1836 | |
1837 // The following are used for keeping track of the z-depth of the hit point
of 3d-transformed | |
1838 // descendants. | |
1839 double localZOffset = -std::numeric_limits<double>::infinity(); | |
1840 double* zOffsetForDescendantsPtr = 0; | |
1841 double* zOffsetForContentsPtr = 0; | |
1842 | |
1843 bool depthSortDescendants = false; | |
1844 if (preserves3D()) { | |
1845 depthSortDescendants = true; | |
1846 // Our layers can depth-test with our container, so share the z depth po
inter with the container, if it passed one down. | |
1847 zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset; | |
1848 zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset; | |
1849 } else if (zOffset) { | |
1850 zOffsetForDescendantsPtr = 0; | |
1851 // Container needs us to give back a z offset for the hit layer. | |
1852 zOffsetForContentsPtr = zOffset; | |
1853 } | |
1854 | |
1855 // This variable tracks which layer the mouse ends up being inside. | |
1856 RenderLayer* candidateLayer = 0; | |
1857 | |
1858 // Begin by walking our list of positive layers from highest z-index down to
the lowest z-index. | |
1859 RenderLayer* hitLayer = hitTestChildren(PositiveZOrderChildren, rootLayer, r
equest, result, hitTestRect, hitTestLocation, | |
1860 localTransformState.get(), zOffsetForDes
cendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants); | |
1861 if (hitLayer) { | |
1862 if (!depthSortDescendants) | |
1863 return hitLayer; | |
1864 candidateLayer = hitLayer; | |
1865 } | |
1866 | |
1867 // Now check our overflow objects. | |
1868 hitLayer = hitTestChildren(NormalFlowChildren, rootLayer, request, result, h
itTestRect, hitTestLocation, | |
1869 localTransformState.get(), zOffsetForDescendantsPtr,
zOffset, unflattenedTransformState.get(), depthSortDescendants); | |
1870 if (hitLayer) { | |
1871 if (!depthSortDescendants) | |
1872 return hitLayer; | |
1873 candidateLayer = hitLayer; | |
1874 } | |
1875 | |
1876 // Collect the fragments. This will compute the clip rectangles for each lay
er fragment. | |
1877 LayerFragments layerFragments; | |
1878 collectFragments(layerFragments, rootLayer, hitTestRect, RootRelativeClipRec
ts, IncludeOverlayScrollbarSize); | |
1879 | |
1880 if (m_scrollableArea && m_scrollableArea->hitTestResizerInFragments(layerFra
gments, hitTestLocation)) { | |
1881 renderer()->updateHitTestResult(result, hitTestLocation.point()); | |
1882 return this; | |
1883 } | |
1884 | |
1885 // Next we want to see if the mouse pos is inside the child RenderObjects of
the layer. Check | |
1886 // every fragment in reverse order. | |
1887 if (isSelfPaintingLayer()) { | |
1888 // Hit test with a temporary HitTestResult, because we only want to comm
it to 'result' if we know we're frontmost. | |
1889 HitTestResult tempResult(result.hitTestLocation()); | |
1890 bool insideFragmentForegroundRect = false; | |
1891 if (hitTestContentsForFragments(layerFragments, request, tempResult, hit
TestLocation, HitTestDescendants, insideFragmentForegroundRect) | |
1892 && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTra
nsformState.get())) { | |
1893 if (result.isRectBasedTest()) | |
1894 result.append(tempResult); | |
1895 else | |
1896 result = tempResult; | |
1897 if (!depthSortDescendants) | |
1898 return this; | |
1899 // Foreground can depth-sort with descendant layers, so keep this as
a candidate. | |
1900 candidateLayer = this; | |
1901 } else if (insideFragmentForegroundRect && result.isRectBasedTest()) | |
1902 result.append(tempResult); | |
1903 } | |
1904 | |
1905 // Now check our negative z-index children. | |
1906 hitLayer = hitTestChildren(NegativeZOrderChildren, rootLayer, request, resul
t, hitTestRect, hitTestLocation, | |
1907 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattene
dTransformState.get(), depthSortDescendants); | |
1908 if (hitLayer) { | |
1909 if (!depthSortDescendants) | |
1910 return hitLayer; | |
1911 candidateLayer = hitLayer; | |
1912 } | |
1913 | |
1914 // If we found a layer, return. Child layers, and foreground always render i
n front of background. | |
1915 if (candidateLayer) | |
1916 return candidateLayer; | |
1917 | |
1918 if (isSelfPaintingLayer()) { | |
1919 HitTestResult tempResult(result.hitTestLocation()); | |
1920 bool insideFragmentBackgroundRect = false; | |
1921 if (hitTestContentsForFragments(layerFragments, request, tempResult, hit
TestLocation, HitTestSelf, insideFragmentBackgroundRect) | |
1922 && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTra
nsformState.get())) { | |
1923 if (result.isRectBasedTest()) | |
1924 result.append(tempResult); | |
1925 else | |
1926 result = tempResult; | |
1927 return this; | |
1928 } | |
1929 if (insideFragmentBackgroundRect && result.isRectBasedTest()) | |
1930 result.append(tempResult); | |
1931 } | |
1932 | |
1933 return 0; | |
1934 } | |
1935 | |
1936 bool RenderLayer::hitTestContentsForFragments(const LayerFragments& layerFragmen
ts, const HitTestRequest& request, HitTestResult& result, | |
1937 const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter, bool& i
nsideClipRect) const | |
1938 { | |
1939 if (layerFragments.isEmpty()) | |
1940 return false; | |
1941 | |
1942 for (int i = layerFragments.size() - 1; i >= 0; --i) { | |
1943 const LayerFragment& fragment = layerFragments.at(i); | |
1944 if ((hitTestFilter == HitTestSelf && !fragment.backgroundRect.intersects
(hitTestLocation)) | |
1945 || (hitTestFilter == HitTestDescendants && !fragment.foregroundRect.
intersects(hitTestLocation))) | |
1946 continue; | |
1947 insideClipRect = true; | |
1948 if (hitTestContents(request, result, fragment.layerBounds, hitTestLocati
on, hitTestFilter)) | |
1949 return true; | |
1950 } | |
1951 | |
1952 return false; | |
1953 } | |
1954 | |
1955 RenderLayer* RenderLayer::hitTestTransformedLayerInFragments(RenderLayer* rootLa
yer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult&
result, | |
1956 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const
HitTestingTransformState* transformState, double* zOffset) | |
1957 { | |
1958 LayerFragments enclosingPaginationFragments; | |
1959 LayoutPoint offsetOfPaginationLayerFromRoot; | |
1960 // FIXME: We're missing a sub-pixel offset here crbug.com/348728 | |
1961 LayoutRect transformedExtent = transparencyClipBox(this, enclosingPagination
Layer(), HitTestingTransparencyClipBox, RenderLayer::RootOfTransparencyClipBox,
LayoutSize()); | |
1962 enclosingPaginationLayer()->collectFragments(enclosingPaginationFragments, r
ootLayer, hitTestRect, | |
1963 RootRelativeClipRects, IncludeOverlayScrollbarSize, RespectOverflowClip,
&offsetOfPaginationLayerFromRoot, LayoutSize(), &transformedExtent); | |
1964 | |
1965 for (int i = enclosingPaginationFragments.size() - 1; i >= 0; --i) { | |
1966 const LayerFragment& fragment = enclosingPaginationFragments.at(i); | |
1967 | |
1968 // Apply the page/column clip for this fragment, as well as any clips es
tablished by layers in between us and | |
1969 // the enclosing pagination layer. | |
1970 LayoutRect clipRect = fragment.backgroundRect.rect(); | |
1971 | |
1972 // Now compute the clips within a given fragment | |
1973 if (parent() != enclosingPaginationLayer()) { | |
1974 enclosingPaginationLayer()->convertToLayerCoords(rootLayer, offsetOf
PaginationLayerFromRoot); | |
1975 LayoutRect parentClipRect = clipper().backgroundClipRect(ClipRectsCo
ntext(enclosingPaginationLayer(), RootRelativeClipRects, IncludeOverlayScrollbar
Size)).rect(); | |
1976 parentClipRect.moveBy(fragment.paginationOffset + offsetOfPagination
LayerFromRoot); | |
1977 clipRect.intersect(parentClipRect); | |
1978 } | |
1979 | |
1980 if (!hitTestLocation.intersects(clipRect)) | |
1981 continue; | |
1982 | |
1983 RenderLayer* hitLayer = hitTestLayerByApplyingTransform(rootLayer, conta
inerLayer, request, result, hitTestRect, hitTestLocation, | |
1984 transformState, zOffset, fragment.paginationOffset); | |
1985 if (hitLayer) | |
1986 return hitLayer; | |
1987 } | |
1988 | |
1989 return 0; | |
1990 } | |
1991 | |
1992 RenderLayer* RenderLayer::hitTestLayerByApplyingTransform(RenderLayer* rootLayer
, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& res
ult, | |
1993 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const
HitTestingTransformState* transformState, double* zOffset, | |
1994 const LayoutPoint& translationOffset) | |
1995 { | |
1996 // Create a transform state to accumulate this transform. | |
1997 RefPtr<HitTestingTransformState> newTransformState = createLocalTransformSta
te(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState, tran
slationOffset); | |
1998 | |
1999 // If the transform can't be inverted, then don't hit test this layer at all
. | |
2000 if (!newTransformState->m_accumulatedTransform.isInvertible()) | |
2001 return 0; | |
2002 | |
2003 // Compute the point and the hit test rect in the coords of this layer by us
ing the values | |
2004 // from the transformState, which store the point and quad in the coords of
the last flattened | |
2005 // layer, and the accumulated transform which lets up map through preserve-3
d layers. | |
2006 // | |
2007 // We can't just map hitTestLocation and hitTestRect because they may have b
een flattened (losing z) | |
2008 // by our container. | |
2009 FloatPoint localPoint = newTransformState->mappedPoint(); | |
2010 FloatQuad localPointQuad = newTransformState->mappedQuad(); | |
2011 LayoutRect localHitTestRect = newTransformState->boundsOfMappedArea(); | |
2012 HitTestLocation newHitTestLocation; | |
2013 if (hitTestLocation.isRectBasedTest()) | |
2014 newHitTestLocation = HitTestLocation(localPoint, localPointQuad); | |
2015 else | |
2016 newHitTestLocation = HitTestLocation(localPoint); | |
2017 | |
2018 // Now do a hit test with the root layer shifted to be us. | |
2019 return hitTestLayer(this, containerLayer, request, result, localHitTestRect,
newHitTestLocation, true, newTransformState.get(), zOffset); | |
2020 } | |
2021 | |
2022 bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult&
result, const LayoutRect& layerBounds, const HitTestLocation& hitTestLocation, H
itTestFilter hitTestFilter) const | |
2023 { | |
2024 ASSERT(isSelfPaintingLayer() || hasSelfPaintingLayerDescendant()); | |
2025 | |
2026 if (!renderer()->hitTest(request, result, hitTestLocation, toLayoutPoint(lay
erBounds.location() - renderBoxLocation()), hitTestFilter)) { | |
2027 // It's wrong to set innerNode, but then claim that you didn't hit anyth
ing, unless it is | |
2028 // a rect-based test. | |
2029 ASSERT(!result.innerNode() || (result.isRectBasedTest() && result.rectBa
sedTestResult().size())); | |
2030 return false; | |
2031 } | |
2032 | |
2033 // For positioned generated content, we might still not have a | |
2034 // node by the time we get to the layer level, since none of | |
2035 // the content in the layer has an element. So just walk up | |
2036 // the tree. | |
2037 if (!result.innerNode() || !result.innerNonSharedNode()) { | |
2038 Node* e = enclosingElement(); | |
2039 if (!result.innerNode()) | |
2040 result.setInnerNode(e); | |
2041 if (!result.innerNonSharedNode()) | |
2042 result.setInnerNonSharedNode(e); | |
2043 } | |
2044 | |
2045 return true; | |
2046 } | |
2047 | |
2048 RenderLayer* RenderLayer::hitTestChildren(ChildrenIteration childrentoVisit, Ren
derLayer* rootLayer, | |
2049 const HitTestRequest& request, HitTestResult& result, | |
2050 const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, | |
2051 const HitTestingTransformState* transformState, | |
2052 double* zOffsetForDescendants, double* zOffset, | |
2053 const HitTestingTransformState* unflattenedTransformState, | |
2054 bool depthSortDescendants) | |
2055 { | |
2056 if (!hasSelfPaintingLayerDescendant()) | |
2057 return 0; | |
2058 | |
2059 RenderLayer* resultLayer = 0; | |
2060 RenderLayerStackingNodeReverseIterator iterator(*m_stackingNode, childrentoV
isit); | |
2061 while (RenderLayerStackingNode* child = iterator.next()) { | |
2062 RenderLayer* childLayer = child->layer(); | |
2063 RenderLayer* hitLayer = 0; | |
2064 HitTestResult tempResult(result.hitTestLocation()); | |
2065 if (childLayer->isPaginated()) | |
2066 hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request
, tempResult, hitTestRect, hitTestLocation, transformState, zOffsetForDescendant
s); | |
2067 else | |
2068 hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempRe
sult, hitTestRect, hitTestLocation, false, transformState, zOffsetForDescendants
); | |
2069 | |
2070 // If it a rect-based test, we can safely append the temporary result si
nce it might had hit | |
2071 // nodes but not necesserily had hitLayer set. | |
2072 if (result.isRectBasedTest()) | |
2073 result.append(tempResult); | |
2074 | |
2075 if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedT
ransformState)) { | |
2076 resultLayer = hitLayer; | |
2077 if (!result.isRectBasedTest()) | |
2078 result = tempResult; | |
2079 if (!depthSortDescendants) | |
2080 break; | |
2081 } | |
2082 } | |
2083 | |
2084 return resultLayer; | |
2085 } | |
2086 | |
2087 RenderLayer* RenderLayer::hitTestPaginatedChildLayer(RenderLayer* childLayer, Re
nderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, | |
2088 const LayoutRect& hitTestRe
ct, const HitTestLocation& hitTestLocation, const HitTestingTransformState* tran
sformState, double* zOffset) | |
2089 { | |
2090 Vector<RenderLayer*> columnLayers; | |
2091 RenderLayerStackingNode* ancestorNode = m_stackingNode->isNormalFlowOnly() ?
parent()->stackingNode() : m_stackingNode->ancestorStackingContextNode(); | |
2092 for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent())
{ | |
2093 if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagina
tion(childLayer->renderer(), curr->renderBox())) | |
2094 columnLayers.append(curr); | |
2095 if (curr->stackingNode() == ancestorNode) | |
2096 break; | |
2097 } | |
2098 | |
2099 ASSERT(columnLayers.size()); | |
2100 return hitTestChildLayerColumns(childLayer, rootLayer, request, result, hitT
estRect, hitTestLocation, transformState, zOffset, | |
2101 columnLayers, columnLayers.size() - 1); | |
2102 } | |
2103 | |
2104 RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend
erLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, | |
2105 const LayoutRect& hitTestRect
, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transf
ormState, double* zOffset, | |
2106 const Vector<RenderLayer*>& c
olumnLayers, size_t columnIndex) | |
2107 { | |
2108 RenderBlock* columnBlock = toRenderBlock(columnLayers[columnIndex]->renderer
()); | |
2109 | |
2110 ASSERT(columnBlock && columnBlock->hasColumns()); | |
2111 if (!columnBlock || !columnBlock->hasColumns()) | |
2112 return 0; | |
2113 | |
2114 LayoutPoint layerOffset; | |
2115 columnBlock->layer()->convertToLayerCoords(rootLayer, layerOffset); | |
2116 | |
2117 ColumnInfo* colInfo = columnBlock->columnInfo(); | |
2118 int colCount = columnBlock->columnCount(colInfo); | |
2119 | |
2120 // We have to go backwards from the last column to the first. | |
2121 bool isHorizontal = columnBlock->style()->isHorizontalWritingMode(); | |
2122 LayoutUnit logicalLeft = columnBlock->logicalLeftOffsetForContent(); | |
2123 LayoutUnit currLogicalTopOffset = 0; | |
2124 int i; | |
2125 for (i = 0; i < colCount; i++) { | |
2126 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i); | |
2127 LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.widt
h()); | |
2128 if (columnBlock->style()->isFlippedBlocksWritingMode()) | |
2129 currLogicalTopOffset += blockDelta; | |
2130 else | |
2131 currLogicalTopOffset -= blockDelta; | |
2132 } | |
2133 for (i = colCount - 1; i >= 0; i--) { | |
2134 // For each rect, we clip to the rect, and then we adjust our coords. | |
2135 LayoutRect colRect = columnBlock->columnRectAt(colInfo, i); | |
2136 columnBlock->flipForWritingMode(colRect); | |
2137 LayoutUnit currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect
.y()) - logicalLeft; | |
2138 LayoutUnit blockDelta = (isHorizontal ? colRect.height() : colRect.widt
h()); | |
2139 if (columnBlock->style()->isFlippedBlocksWritingMode()) | |
2140 currLogicalTopOffset -= blockDelta; | |
2141 else | |
2142 currLogicalTopOffset += blockDelta; | |
2143 | |
2144 LayoutSize offset; | |
2145 if (isHorizontal) { | |
2146 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) | |
2147 offset = LayoutSize(currLogicalLeftOffset, currLogicalTopOffset)
; | |
2148 else | |
2149 offset = LayoutSize(0, colRect.y() + currLogicalTopOffset - colu
mnBlock->borderTop() - columnBlock->paddingTop()); | |
2150 } else { | |
2151 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) | |
2152 offset = LayoutSize(currLogicalTopOffset, currLogicalLeftOffset)
; | |
2153 else | |
2154 offset = LayoutSize(colRect.x() + currLogicalTopOffset - columnB
lock->borderLeft() - columnBlock->paddingLeft(), 0); | |
2155 } | |
2156 | |
2157 colRect.moveBy(layerOffset); | |
2158 | |
2159 LayoutRect localClipRect(hitTestRect); | |
2160 localClipRect.intersect(colRect); | |
2161 | |
2162 if (!localClipRect.isEmpty() && hitTestLocation.intersects(localClipRect
)) { | |
2163 RenderLayer* hitLayer = 0; | |
2164 if (!columnIndex) { | |
2165 // Apply a translation transform to change where the layer paint
s. | |
2166 TransformationMatrix oldTransform; | |
2167 bool oldHasTransform = childLayer->transform(); | |
2168 if (oldHasTransform) | |
2169 oldTransform = *childLayer->transform(); | |
2170 TransformationMatrix newTransform(oldTransform); | |
2171 newTransform.translateRight(offset.width(), offset.height()); | |
2172 | |
2173 childLayer->m_transform = adoptPtr(new TransformationMatrix(newT
ransform)); | |
2174 hitLayer = childLayer->hitTestLayer(rootLayer, columnLayers[0],
request, result, localClipRect, hitTestLocation, false, transformState, zOffset)
; | |
2175 if (oldHasTransform) | |
2176 childLayer->m_transform = adoptPtr(new TransformationMatrix(
oldTransform)); | |
2177 else | |
2178 childLayer->m_transform.clear(); | |
2179 } else { | |
2180 // Adjust the transform such that the renderer's upper left corn
er will be at (0,0) in user space. | |
2181 // This involves subtracting out the position of the layer in ou
r current coordinate space. | |
2182 RenderLayer* nextLayer = columnLayers[columnIndex - 1]; | |
2183 RefPtr<HitTestingTransformState> newTransformState = nextLayer->
createLocalTransformState(rootLayer, nextLayer, localClipRect, hitTestLocation,
transformState); | |
2184 newTransformState->translate(offset.width(), offset.height(), Hi
tTestingTransformState::AccumulateTransform); | |
2185 FloatPoint localPoint = newTransformState->mappedPoint(); | |
2186 FloatQuad localPointQuad = newTransformState->mappedQuad(); | |
2187 LayoutRect localHitTestRect = newTransformState->mappedArea().en
closingBoundingBox(); | |
2188 HitTestLocation newHitTestLocation; | |
2189 if (hitTestLocation.isRectBasedTest()) | |
2190 newHitTestLocation = HitTestLocation(localPoint, localPointQ
uad); | |
2191 else | |
2192 newHitTestLocation = HitTestLocation(localPoint); | |
2193 newTransformState->flatten(); | |
2194 | |
2195 hitLayer = hitTestChildLayerColumns(childLayer, columnLayers[col
umnIndex - 1], request, result, localHitTestRect, newHitTestLocation, | |
2196 newTransformState.get(), zOf
fset, columnLayers, columnIndex - 1); | |
2197 } | |
2198 | |
2199 if (hitLayer) | |
2200 return hitLayer; | |
2201 } | |
2202 } | |
2203 | |
2204 return 0; | |
2205 } | |
2206 | |
2207 void RenderLayer::blockSelectionGapsBoundsChanged() | |
2208 { | |
2209 setNeedsCompositingInputsUpdate(); | |
2210 } | |
2211 | |
2212 void RenderLayer::addBlockSelectionGapsBounds(const LayoutRect& bounds) | |
2213 { | |
2214 m_blockSelectionGapsBounds.unite(enclosingIntRect(bounds)); | |
2215 blockSelectionGapsBoundsChanged(); | |
2216 } | |
2217 | |
2218 void RenderLayer::clearBlockSelectionGapsBounds() | |
2219 { | |
2220 m_blockSelectionGapsBounds = IntRect(); | |
2221 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
2222 child->clearBlockSelectionGapsBounds(); | |
2223 blockSelectionGapsBoundsChanged(); | |
2224 } | |
2225 | |
2226 void RenderLayer::invalidatePaintForBlockSelectionGaps() | |
2227 { | |
2228 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
2229 child->invalidatePaintForBlockSelectionGaps(); | |
2230 | |
2231 if (m_blockSelectionGapsBounds.isEmpty()) | |
2232 return; | |
2233 | |
2234 LayoutRect rect = m_blockSelectionGapsBounds; | |
2235 if (renderer()->hasOverflowClip()) { | |
2236 RenderBox* box = renderBox(); | |
2237 rect.move(-box->scrolledContentOffset()); | |
2238 if (!scrollableArea()->usesCompositedScrolling()) | |
2239 rect.intersect(box->overflowClipRect(LayoutPoint())); | |
2240 } | |
2241 if (renderer()->hasClip()) | |
2242 rect.intersect(toRenderBox(renderer())->clipRect(LayoutPoint())); | |
2243 if (!rect.isEmpty()) | |
2244 renderer()->invalidatePaintRectangle(rect); | |
2245 } | |
2246 | |
2247 IntRect RenderLayer::blockSelectionGapsBounds() const | |
2248 { | |
2249 if (!renderer()->isRenderBlockFlow()) | |
2250 return IntRect(); | |
2251 | |
2252 RenderBlockFlow* renderBlockFlow = toRenderBlockFlow(renderer()); | |
2253 LayoutRect gapRects = renderBlockFlow->selectionGapRectsForPaintInvalidation
(renderBlockFlow); | |
2254 | |
2255 return pixelSnappedIntRect(gapRects); | |
2256 } | |
2257 | |
2258 bool RenderLayer::hasBlockSelectionGapBounds() const | |
2259 { | |
2260 // FIXME: it would be more accurate to return !blockSelectionGapsBounds().is
Empty(), but this is impossible | |
2261 // at the moment because it causes invalid queries to layout-dependent code
(crbug.com/372802). | |
2262 // ASSERT(renderer()->document().lifecycle().state() >= DocumentLifecycle::L
ayoutClean); | |
2263 | |
2264 if (!renderer()->isRenderBlock()) | |
2265 return false; | |
2266 | |
2267 return toRenderBlock(renderer())->shouldPaintSelectionGaps(); | |
2268 } | |
2269 | |
2270 bool RenderLayer::intersectsDamageRect(const LayoutRect& layerBounds, const Layo
utRect& damageRect, const RenderLayer* rootLayer, const LayoutPoint* offsetFromR
oot) const | |
2271 { | |
2272 // Always examine the canvas and the root. | |
2273 // FIXME: Could eliminate the isDocumentElement() check if we fix background
painting so that the RenderView | |
2274 // paints the root's background. | |
2275 if (isRootLayer() || renderer()->isDocumentElement()) | |
2276 return true; | |
2277 | |
2278 // If we aren't an inline flow, and our layer bounds do intersect the damage
rect, then we | |
2279 // can go ahead and return true. | |
2280 RenderView* view = renderer()->view(); | |
2281 ASSERT(view); | |
2282 if (view && !renderer()->isRenderInline()) { | |
2283 if (layerBounds.intersects(damageRect)) | |
2284 return true; | |
2285 } | |
2286 | |
2287 // Otherwise we need to compute the bounding box of this single layer and se
e if it intersects | |
2288 // the damage rect. | |
2289 return physicalBoundingBox(rootLayer, offsetFromRoot).intersects(damageRect)
; | |
2290 } | |
2291 | |
2292 LayoutRect RenderLayer::logicalBoundingBox() const | |
2293 { | |
2294 // There are three special cases we need to consider. | |
2295 // (1) Inline Flows. For inline flows we will create a bounding box that fu
lly encompasses all of the lines occupied by the | |
2296 // inline. In other words, if some <span> wraps to three lines, we'll creat
e a bounding box that fully encloses the | |
2297 // line boxes of all three lines (including overflow on those lines). | |
2298 // (2) Left/Top Overflow. The width/height of layers already includes right
/bottom overflow. However, in the case of left/top | |
2299 // overflow, we have to create a bounding box that will extend to include th
is overflow. | |
2300 // (3) Floats. When a layer has overhanging floats that it paints, we need
to make sure to include these overhanging floats | |
2301 // as part of our bounding box. We do this because we are the responsible l
ayer for both hit testing and painting those | |
2302 // floats. | |
2303 LayoutRect result; | |
2304 if (renderer()->isInline() && renderer()->isRenderInline()) { | |
2305 result = toRenderInline(renderer())->linesVisualOverflowBoundingBox(); | |
2306 } else if (renderer()->isTableRow()) { | |
2307 // Our bounding box is just the union of all of our cells' border/overfl
ow rects. | |
2308 for (RenderObject* child = renderer()->slowFirstChild(); child; child =
child->nextSibling()) { | |
2309 if (child->isTableCell()) { | |
2310 LayoutRect bbox = toRenderBox(child)->borderBoxRect(); | |
2311 result.unite(bbox); | |
2312 LayoutRect overflowRect = renderBox()->visualOverflowRect(); | |
2313 if (bbox != overflowRect) | |
2314 result.unite(overflowRect); | |
2315 } | |
2316 } | |
2317 } else { | |
2318 RenderBox* box = renderBox(); | |
2319 ASSERT(box); | |
2320 result = box->borderBoxRect(); | |
2321 result.unite(box->visualOverflowRect()); | |
2322 } | |
2323 | |
2324 ASSERT(renderer()->view()); | |
2325 return result; | |
2326 } | |
2327 | |
2328 static inline LayoutRect flippedLogicalBoundingBox(LayoutRect boundingBox, Rende
rObject* renderer) | |
2329 { | |
2330 LayoutRect result = boundingBox; | |
2331 if (renderer->isBox()) | |
2332 toRenderBox(renderer)->flipForWritingMode(result); | |
2333 else | |
2334 renderer->containingBlock()->flipForWritingMode(result); | |
2335 return result; | |
2336 } | |
2337 | |
2338 LayoutRect RenderLayer::physicalBoundingBox(const RenderLayer* ancestorLayer, co
nst LayoutPoint* offsetFromRoot) const | |
2339 { | |
2340 LayoutRect result = flippedLogicalBoundingBox(logicalBoundingBox(), renderer
()); | |
2341 if (offsetFromRoot) | |
2342 result.moveBy(*offsetFromRoot); | |
2343 else | |
2344 convertToLayerCoords(ancestorLayer, result); | |
2345 return result; | |
2346 } | |
2347 | |
2348 LayoutRect RenderLayer::fragmentsBoundingBox(const RenderLayer* ancestorLayer) c
onst | |
2349 { | |
2350 if (!enclosingPaginationLayer()) | |
2351 return physicalBoundingBox(ancestorLayer); | |
2352 | |
2353 LayoutRect result = flippedLogicalBoundingBox(logicalBoundingBox(), renderer
()); | |
2354 convertFromFlowThreadToVisualBoundingBoxInAncestor(this, ancestorLayer, resu
lt); | |
2355 return result; | |
2356 } | |
2357 | |
2358 LayoutRect RenderLayer::boundingBoxForCompositingOverlapTest() const | |
2359 { | |
2360 return overlapBoundsIncludeChildren() ? boundingBoxForCompositing() : fragme
ntsBoundingBox(this); | |
2361 } | |
2362 | |
2363 static void expandRectForReflectionAndStackingChildren(const RenderLayer* ancest
orLayer, RenderLayer::CalculateBoundsOptions options, LayoutRect& result) | |
2364 { | |
2365 if (ancestorLayer->reflectionInfo() && !ancestorLayer->reflectionInfo()->ref
lectionLayer()->hasCompositedLayerMapping()) | |
2366 result.unite(ancestorLayer->reflectionInfo()->reflectionLayer()->boundin
gBoxForCompositing(ancestorLayer)); | |
2367 | |
2368 ASSERT(ancestorLayer->stackingNode()->isStackingContext() || !ancestorLayer-
>stackingNode()->hasPositiveZOrderList()); | |
2369 | |
2370 #if ENABLE(ASSERT) | |
2371 LayerListMutationDetector mutationChecker(const_cast<RenderLayer*>(ancestorL
ayer)->stackingNode()); | |
2372 #endif | |
2373 | |
2374 RenderLayerStackingNodeIterator iterator(*ancestorLayer->stackingNode(), All
Children); | |
2375 while (RenderLayerStackingNode* node = iterator.next()) { | |
2376 // Here we exclude both directly composited layers and squashing layers | |
2377 // because those RenderLayers don't paint into the graphics layer | |
2378 // for this RenderLayer. For example, the bounds of squashed RenderLayer
s | |
2379 // will be included in the computation of the appropriate squashing | |
2380 // GraphicsLayer. | |
2381 if (options != RenderLayer::ApplyBoundsChickenEggHacks && node->layer()-
>compositingState() != NotComposited) | |
2382 continue; | |
2383 result.unite(node->layer()->boundingBoxForCompositing(ancestorLayer, opt
ions)); | |
2384 } | |
2385 } | |
2386 | |
2387 LayoutRect RenderLayer::physicalBoundingBoxIncludingReflectionAndStackingChildre
n(const RenderLayer* ancestorLayer, const LayoutPoint& offsetFromRoot) const | |
2388 { | |
2389 LayoutPoint origin; | |
2390 LayoutRect result = physicalBoundingBox(ancestorLayer, &origin); | |
2391 | |
2392 const_cast<RenderLayer*>(this)->stackingNode()->updateLayerListsIfNeeded(); | |
2393 | |
2394 expandRectForReflectionAndStackingChildren(this, DoNotApplyBoundsChickenEggH
acks, result); | |
2395 | |
2396 result.moveBy(offsetFromRoot); | |
2397 return result; | |
2398 } | |
2399 | |
2400 LayoutRect RenderLayer::boundingBoxForCompositing(const RenderLayer* ancestorLay
er, CalculateBoundsOptions options) const | |
2401 { | |
2402 if (!isSelfPaintingLayer()) | |
2403 return LayoutRect(); | |
2404 | |
2405 if (!ancestorLayer) | |
2406 ancestorLayer = this; | |
2407 | |
2408 // FIXME: This could be improved to do a check like hasVisibleNonCompositing
DescendantLayers() (bug 92580). | |
2409 if (this != ancestorLayer && !hasVisibleContent() && !hasVisibleDescendant()
) | |
2410 return LayoutRect(); | |
2411 | |
2412 // The root layer is always just the size of the document. | |
2413 if (isRootLayer()) | |
2414 return m_renderer->view()->unscaledDocumentRect(); | |
2415 | |
2416 // The layer created for the RenderFlowThread is just a helper for painting
and hit-testing, | |
2417 // and should not contribute to the bounding box. The RenderMultiColumnSets
will contribute | |
2418 // the correct size for the rendered content of the multicol container. | |
2419 if (useRegionBasedColumns() && renderer()->isRenderFlowThread()) | |
2420 return LayoutRect(); | |
2421 | |
2422 LayoutRect result = clipper().localClipRect(); | |
2423 if (result == LayoutRect::infiniteIntRect()) { | |
2424 LayoutPoint origin; | |
2425 result = physicalBoundingBox(ancestorLayer, &origin); | |
2426 | |
2427 const_cast<RenderLayer*>(this)->stackingNode()->updateLayerListsIfNeeded
(); | |
2428 | |
2429 // Reflections are implemented with RenderLayers that hang off of the re
flected layer. However, | |
2430 // the reflection layer subtree does not include the subtree of the pare
nt RenderLayer, so | |
2431 // a recursive computation of stacking children yields no results. This
breaks cases when there are stacking | |
2432 // children of the parent, that need to be included in reflected composi
ted bounds. | |
2433 // Fix this by including composited bounds of stacking children of the r
eflected RenderLayer. | |
2434 if (hasCompositedLayerMapping() && parent() && parent()->reflectionInfo(
) && parent()->reflectionInfo()->reflectionLayer() == this) | |
2435 expandRectForReflectionAndStackingChildren(parent(), options, result
); | |
2436 else | |
2437 expandRectForReflectionAndStackingChildren(this, options, result); | |
2438 | |
2439 // FIXME: We can optimize the size of the composited layers, by not enla
rging | |
2440 // filtered areas with the outsets if we know that the filter is going t
o render in hardware. | |
2441 // https://bugs.webkit.org/show_bug.cgi?id=81239 | |
2442 result.expand(m_renderer->style()->filterOutsets()); | |
2443 } | |
2444 | |
2445 if (paintsWithTransform(PaintBehaviorNormal) || (options == ApplyBoundsChick
enEggHacks && transform())) | |
2446 result = transform()->mapRect(result); | |
2447 | |
2448 if (enclosingPaginationLayer()) { | |
2449 convertFromFlowThreadToVisualBoundingBoxInAncestor(this, ancestorLayer,
result); | |
2450 return result; | |
2451 } | |
2452 LayoutPoint delta; | |
2453 convertToLayerCoords(ancestorLayer, delta); | |
2454 result.moveBy(delta); | |
2455 return result; | |
2456 } | |
2457 | |
2458 CompositingState RenderLayer::compositingState() const | |
2459 { | |
2460 ASSERT(isAllowedToQueryCompositingState()); | |
2461 | |
2462 // This is computed procedurally so there is no redundant state variable tha
t | |
2463 // can get out of sync from the real actual compositing state. | |
2464 | |
2465 if (m_groupedMapping) { | |
2466 ASSERT(!m_compositedLayerMapping); | |
2467 return PaintsIntoGroupedBacking; | |
2468 } | |
2469 | |
2470 if (!m_compositedLayerMapping) | |
2471 return NotComposited; | |
2472 | |
2473 return PaintsIntoOwnBacking; | |
2474 } | |
2475 | |
2476 bool RenderLayer::isAllowedToQueryCompositingState() const | |
2477 { | |
2478 if (gCompositingQueryMode == CompositingQueriesAreAllowed) | |
2479 return true; | |
2480 return renderer()->document().lifecycle().state() >= DocumentLifecycle::InCo
mpositingUpdate; | |
2481 } | |
2482 | |
2483 CompositedLayerMapping* RenderLayer::compositedLayerMapping() const | |
2484 { | |
2485 ASSERT(isAllowedToQueryCompositingState()); | |
2486 return m_compositedLayerMapping.get(); | |
2487 } | |
2488 | |
2489 GraphicsLayer* RenderLayer::graphicsLayerBacking() const | |
2490 { | |
2491 switch (compositingState()) { | |
2492 case NotComposited: | |
2493 return 0; | |
2494 case PaintsIntoGroupedBacking: | |
2495 return groupedMapping()->squashingLayer(); | |
2496 default: | |
2497 return compositedLayerMapping()->mainGraphicsLayer(); | |
2498 } | |
2499 } | |
2500 | |
2501 GraphicsLayer* RenderLayer::graphicsLayerBackingForScrolling() const | |
2502 { | |
2503 switch (compositingState()) { | |
2504 case NotComposited: | |
2505 return 0; | |
2506 case PaintsIntoGroupedBacking: | |
2507 return groupedMapping()->squashingLayer(); | |
2508 default: | |
2509 return compositedLayerMapping()->scrollingContentsLayer() ? compositedLa
yerMapping()->scrollingContentsLayer() : compositedLayerMapping()->mainGraphicsL
ayer(); | |
2510 } | |
2511 } | |
2512 | |
2513 void RenderLayer::ensureCompositedLayerMapping() | |
2514 { | |
2515 if (m_compositedLayerMapping) | |
2516 return; | |
2517 | |
2518 m_compositedLayerMapping = adoptPtr(new CompositedLayerMapping(*this)); | |
2519 m_compositedLayerMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSub
tree); | |
2520 | |
2521 updateOrRemoveFilterEffectRenderer(); | |
2522 } | |
2523 | |
2524 void RenderLayer::clearCompositedLayerMapping(bool layerBeingDestroyed) | |
2525 { | |
2526 if (!layerBeingDestroyed) { | |
2527 // We need to make sure our decendants get a geometry update. In princip
le, | |
2528 // we could call setNeedsGraphicsLayerUpdate on our children, but that w
ould | |
2529 // require walking the z-order lists to find them. Instead, we over-inva
lidate | |
2530 // by marking our parent as needing a geometry update. | |
2531 if (RenderLayer* compositingParent = enclosingLayerWithCompositedLayerMa
pping(ExcludeSelf)) | |
2532 compositingParent->compositedLayerMapping()->setNeedsGraphicsLayerUp
date(GraphicsLayerUpdateSubtree); | |
2533 } | |
2534 | |
2535 m_compositedLayerMapping.clear(); | |
2536 | |
2537 if (!layerBeingDestroyed) | |
2538 updateOrRemoveFilterEffectRenderer(); | |
2539 } | |
2540 | |
2541 void RenderLayer::setGroupedMapping(CompositedLayerMapping* groupedMapping, bool
layerBeingDestroyed) | |
2542 { | |
2543 if (groupedMapping == m_groupedMapping) | |
2544 return; | |
2545 | |
2546 if (!layerBeingDestroyed && m_groupedMapping) { | |
2547 m_groupedMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree
); | |
2548 m_groupedMapping->removeRenderLayerFromSquashingGraphicsLayer(this); | |
2549 } | |
2550 m_groupedMapping = groupedMapping; | |
2551 if (!layerBeingDestroyed && m_groupedMapping) | |
2552 m_groupedMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateSubtree
); | |
2553 } | |
2554 | |
2555 bool RenderLayer::hasCompositedMask() const | |
2556 { | |
2557 return m_compositedLayerMapping && m_compositedLayerMapping->hasMaskLayer(); | |
2558 } | |
2559 | |
2560 bool RenderLayer::hasCompositedClippingMask() const | |
2561 { | |
2562 return m_compositedLayerMapping && m_compositedLayerMapping->hasChildClippin
gMaskLayer(); | |
2563 } | |
2564 | |
2565 bool RenderLayer::paintsWithTransform(PaintBehavior paintBehavior) const | |
2566 { | |
2567 return transform() && ((paintBehavior & PaintBehaviorFlattenCompositingLayer
s) || compositingState() != PaintsIntoOwnBacking); | |
2568 } | |
2569 | |
2570 bool RenderLayer::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect)
const | |
2571 { | |
2572 if (!isSelfPaintingLayer() && !hasSelfPaintingLayerDescendant()) | |
2573 return false; | |
2574 | |
2575 if (paintsWithTransparency(PaintBehaviorNormal)) | |
2576 return false; | |
2577 | |
2578 // We can't use hasVisibleContent(), because that will be true if our render
er is hidden, but some child | |
2579 // is visible and that child doesn't cover the entire rect. | |
2580 if (renderer()->style()->visibility() != VISIBLE) | |
2581 return false; | |
2582 | |
2583 if (paintsWithFilters() && renderer()->style()->filter().hasFilterThatAffect
sOpacity()) | |
2584 return false; | |
2585 | |
2586 // FIXME: Handle simple transforms. | |
2587 if (paintsWithTransform(PaintBehaviorNormal)) | |
2588 return false; | |
2589 | |
2590 // FIXME: Remove this check. | |
2591 // This function should not be called when layer-lists are dirty. | |
2592 // It is somehow getting triggered during style update. | |
2593 if (m_stackingNode->zOrderListsDirty() || m_stackingNode->normalFlowListDirt
y()) | |
2594 return false; | |
2595 | |
2596 // FIXME: We currently only check the immediate renderer, | |
2597 // which will miss many cases. | |
2598 if (renderer()->backgroundIsKnownToBeOpaqueInRect(localRect)) | |
2599 return true; | |
2600 | |
2601 // We can't consult child layers if we clip, since they might cover | |
2602 // parts of the rect that are clipped out. | |
2603 if (renderer()->hasOverflowClip()) | |
2604 return false; | |
2605 | |
2606 return childBackgroundIsKnownToBeOpaqueInRect(localRect); | |
2607 } | |
2608 | |
2609 bool RenderLayer::childBackgroundIsKnownToBeOpaqueInRect(const LayoutRect& local
Rect) const | |
2610 { | |
2611 RenderLayerStackingNodeReverseIterator revertseIterator(*m_stackingNode, Pos
itiveZOrderChildren | NormalFlowChildren | NegativeZOrderChildren); | |
2612 while (RenderLayerStackingNode* child = revertseIterator.next()) { | |
2613 const RenderLayer* childLayer = child->layer(); | |
2614 // Stop at composited paint boundaries. | |
2615 if (childLayer->isPaintInvalidationContainer()) | |
2616 continue; | |
2617 | |
2618 if (!childLayer->canUseConvertToLayerCoords()) | |
2619 continue; | |
2620 | |
2621 LayoutPoint childOffset; | |
2622 LayoutRect childLocalRect(localRect); | |
2623 childLayer->convertToLayerCoords(this, childOffset); | |
2624 childLocalRect.moveBy(-childOffset); | |
2625 | |
2626 if (childLayer->backgroundIsKnownToBeOpaqueInRect(childLocalRect)) | |
2627 return true; | |
2628 } | |
2629 return false; | |
2630 } | |
2631 | |
2632 bool RenderLayer::shouldBeSelfPaintingLayer() const | |
2633 { | |
2634 if (renderer()->isRenderPart() && toRenderPart(renderer())->requiresAccelera
tedCompositing()) | |
2635 return true; | |
2636 return m_layerType == NormalLayer | |
2637 || (m_scrollableArea && m_scrollableArea->hasOverlayScrollbars()) | |
2638 || needsCompositedScrolling(); | |
2639 } | |
2640 | |
2641 void RenderLayer::updateSelfPaintingLayer() | |
2642 { | |
2643 bool isSelfPaintingLayer = shouldBeSelfPaintingLayer(); | |
2644 if (this->isSelfPaintingLayer() == isSelfPaintingLayer) | |
2645 return; | |
2646 | |
2647 m_isSelfPaintingLayer = isSelfPaintingLayer; | |
2648 | |
2649 if (parent()) | |
2650 parent()->dirtyAncestorChainHasSelfPaintingLayerDescendantStatus(); | |
2651 } | |
2652 | |
2653 bool RenderLayer::hasNonEmptyChildRenderers() const | |
2654 { | |
2655 // Some HTML can cause whitespace text nodes to have renderers, like: | |
2656 // <div> | |
2657 // <img src=...> | |
2658 // </div> | |
2659 // so test for 0x0 RenderTexts here | |
2660 for (RenderObject* child = renderer()->slowFirstChild(); child; child = chil
d->nextSibling()) { | |
2661 if (!child->hasLayer()) { | |
2662 if (child->isRenderInline() || !child->isBox()) | |
2663 return true; | |
2664 | |
2665 if (!toRenderBox(child)->size().isEmpty()) | |
2666 return true; | |
2667 } | |
2668 } | |
2669 return false; | |
2670 } | |
2671 | |
2672 bool RenderLayer::hasBoxDecorationsOrBackground() const | |
2673 { | |
2674 return renderer()->style()->hasBoxDecorations() || renderer()->style()->hasB
ackground(); | |
2675 } | |
2676 | |
2677 bool RenderLayer::hasVisibleBoxDecorations() const | |
2678 { | |
2679 if (!hasVisibleContent()) | |
2680 return false; | |
2681 | |
2682 return hasBoxDecorationsOrBackground() || hasOverflowControls(); | |
2683 } | |
2684 | |
2685 void RenderLayer::updateFilters(const RenderStyle* oldStyle, const RenderStyle*
newStyle) | |
2686 { | |
2687 if (!newStyle->hasFilter() && (!oldStyle || !oldStyle->hasFilter())) | |
2688 return; | |
2689 | |
2690 updateOrRemoveFilterClients(); | |
2691 updateOrRemoveFilterEffectRenderer(); | |
2692 } | |
2693 | |
2694 bool RenderLayer::attemptDirectCompositingUpdate(StyleDifference diff, const Ren
derStyle* oldStyle) | |
2695 { | |
2696 CompositingReasons oldPotentialCompositingReasonsFromStyle = m_potentialComp
ositingReasonsFromStyle; | |
2697 compositor()->updatePotentialCompositingReasonsFromStyle(this); | |
2698 | |
2699 // This function implements an optimization for transforms and opacity. | |
2700 // A common pattern is for a touchmove handler to update the transform | |
2701 // and/or an opacity of an element every frame while the user moves their | |
2702 // finger across the screen. The conditions below recognize when the | |
2703 // compositing state is set up to receive a direct transform or opacity | |
2704 // update. | |
2705 | |
2706 if (!diff.hasAtMostPropertySpecificDifferences(StyleDifference::TransformCha
nged | StyleDifference::OpacityChanged)) | |
2707 return false; | |
2708 // The potentialCompositingReasonsFromStyle could have changed without | |
2709 // a corresponding StyleDifference if an animation started or ended. | |
2710 if (m_potentialCompositingReasonsFromStyle != oldPotentialCompositingReasons
FromStyle) | |
2711 return false; | |
2712 // We could add support for reflections if we updated the transform on | |
2713 // the reflection layers. | |
2714 if (renderer()->hasReflection()) | |
2715 return false; | |
2716 // If we're unwinding a scheduleSVGFilterLayerUpdateHack(), then we can't | |
2717 // perform a direct compositing update because the filters code is going | |
2718 // to produce different output this time around. We can remove this code | |
2719 // once we fix the chicken/egg bugs in the filters code and delete the | |
2720 // scheduleSVGFilterLayerUpdateHack(). | |
2721 if (renderer()->node() && renderer()->node()->svgFilterNeedsLayerUpdate()) | |
2722 return false; | |
2723 if (!m_compositedLayerMapping) | |
2724 return false; | |
2725 | |
2726 // To cut off almost all the work in the compositing update for | |
2727 // this case, we treat inline transforms has having assumed overlap | |
2728 // (similar to how we treat animated transforms). Notice that we read | |
2729 // CompositingReasonInlineTransform from the m_compositingReasons, which | |
2730 // means that the inline transform actually triggered assumed overlap in | |
2731 // the overlap map. | |
2732 if (diff.transformChanged() && !(m_compositingReasons & CompositingReasonInl
ineTransform)) | |
2733 return false; | |
2734 | |
2735 // We composite transparent RenderLayers differently from non-transparent | |
2736 // RenderLayers even when the non-transparent RenderLayers are already a | |
2737 // stacking context. | |
2738 if (diff.opacityChanged() && m_renderer->style()->hasOpacity() != oldStyle->
hasOpacity()) | |
2739 return false; | |
2740 | |
2741 updateTransform(oldStyle, renderer()->style()); | |
2742 | |
2743 // FIXME: Consider introducing a smaller graphics layer update scope | |
2744 // that just handles transforms and opacity. GraphicsLayerUpdateLocal | |
2745 // will also program bounds, clips, and many other properties that could | |
2746 // not possibly have changed. | |
2747 m_compositedLayerMapping->setNeedsGraphicsLayerUpdate(GraphicsLayerUpdateLoc
al); | |
2748 compositor()->setNeedsCompositingUpdate(CompositingUpdateAfterGeometryChange
); | |
2749 return true; | |
2750 } | |
2751 | |
2752 void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle
) | |
2753 { | |
2754 if (attemptDirectCompositingUpdate(diff, oldStyle)) | |
2755 return; | |
2756 | |
2757 m_stackingNode->updateIsNormalFlowOnly(); | |
2758 m_stackingNode->updateStackingNodesAfterStyleChange(oldStyle); | |
2759 | |
2760 if (m_scrollableArea) | |
2761 m_scrollableArea->updateAfterStyleChange(oldStyle); | |
2762 | |
2763 // Overlay scrollbars can make this layer self-painting so we need | |
2764 // to recompute the bit once scrollbars have been updated. | |
2765 updateSelfPaintingLayer(); | |
2766 | |
2767 if (!oldStyle || !renderer()->style()->reflectionDataEquivalent(oldStyle)) { | |
2768 ASSERT(!oldStyle || diff.needsFullLayout()); | |
2769 updateReflectionInfo(oldStyle); | |
2770 } | |
2771 | |
2772 updateDescendantDependentFlags(); | |
2773 | |
2774 updateTransform(oldStyle, renderer()->style()); | |
2775 updateFilters(oldStyle, renderer()->style()); | |
2776 | |
2777 setNeedsCompositingInputsUpdate(); | |
2778 } | |
2779 | |
2780 bool RenderLayer::scrollsOverflow() const | |
2781 { | |
2782 if (RenderLayerScrollableArea* scrollableArea = this->scrollableArea()) | |
2783 return scrollableArea->scrollsOverflow(); | |
2784 | |
2785 return false; | |
2786 } | |
2787 | |
2788 FilterOperations RenderLayer::computeFilterOperations(const RenderStyle* style) | |
2789 { | |
2790 const FilterOperations& filters = style->filter(); | |
2791 if (filters.hasReferenceFilter()) { | |
2792 for (size_t i = 0; i < filters.size(); ++i) { | |
2793 FilterOperation* filterOperation = filters.operations().at(i).get(); | |
2794 if (filterOperation->type() != FilterOperation::REFERENCE) | |
2795 continue; | |
2796 ReferenceFilterOperation* referenceOperation = toReferenceFilterOper
ation(filterOperation); | |
2797 // FIXME: Cache the ReferenceFilter if it didn't change. | |
2798 RefPtrWillBeRawPtr<ReferenceFilter> referenceFilter = ReferenceFilte
r::create(style->effectiveZoom()); | |
2799 referenceFilter->setLastEffect(ReferenceFilterBuilder::build(referen
ceFilter.get(), renderer(), referenceFilter->sourceGraphic(), | |
2800 referenceOperation)); | |
2801 referenceOperation->setFilter(referenceFilter.release()); | |
2802 } | |
2803 } | |
2804 | |
2805 return filters; | |
2806 } | |
2807 | |
2808 void RenderLayer::updateOrRemoveFilterClients() | |
2809 { | |
2810 if (!hasFilter()) { | |
2811 removeFilterInfoIfNeeded(); | |
2812 return; | |
2813 } | |
2814 | |
2815 if (renderer()->style()->filter().hasReferenceFilter()) | |
2816 ensureFilterInfo()->updateReferenceFilterClients(renderer()->style()->fi
lter()); | |
2817 else if (hasFilterInfo()) | |
2818 filterInfo()->removeReferenceFilterClients(); | |
2819 } | |
2820 | |
2821 void RenderLayer::updateOrRemoveFilterEffectRenderer() | |
2822 { | |
2823 // FilterEffectRenderer is only used to render the filters in software mode, | |
2824 // so we always need to run updateOrRemoveFilterEffectRenderer after the com
posited | |
2825 // mode might have changed for this layer. | |
2826 if (!paintsWithFilters()) { | |
2827 // Don't delete the whole filter info here, because we might use it | |
2828 // for loading CSS shader files. | |
2829 if (RenderLayerFilterInfo* filterInfo = this->filterInfo()) | |
2830 filterInfo->setRenderer(nullptr); | |
2831 | |
2832 return; | |
2833 } | |
2834 | |
2835 RenderLayerFilterInfo* filterInfo = ensureFilterInfo(); | |
2836 if (!filterInfo->renderer()) { | |
2837 RefPtrWillBeRawPtr<FilterEffectRenderer> filterRenderer = FilterEffectRe
nderer::create(); | |
2838 filterInfo->setRenderer(filterRenderer.release()); | |
2839 } | |
2840 | |
2841 // If the filter fails to build, remove it from the layer. It will still att
empt to | |
2842 // go through regular processing (e.g. compositing), but never apply anythin
g. | |
2843 if (!filterInfo->renderer()->build(renderer(), computeFilterOperations(rende
rer()->style()))) | |
2844 filterInfo->setRenderer(nullptr); | |
2845 } | |
2846 | |
2847 void RenderLayer::filterNeedsPaintInvalidation() | |
2848 { | |
2849 { | |
2850 DeprecatedScheduleStyleRecalcDuringLayout marker(renderer()->document().
lifecycle()); | |
2851 // It's possible for scheduleSVGFilterLayerUpdateHack to schedule a styl
e recalc, which | |
2852 // is a problem because this function can be called while performing lay
out. | |
2853 // Presumably this represents an illegal data flow of layout or composit
ing | |
2854 // information into the style system. | |
2855 toElement(renderer()->node())->scheduleSVGFilterLayerUpdateHack(); | |
2856 } | |
2857 | |
2858 renderer()->setShouldDoFullPaintInvalidation(); | |
2859 } | |
2860 | |
2861 void RenderLayer::addLayerHitTestRects(LayerHitTestRects& rects) const | |
2862 { | |
2863 computeSelfHitTestRects(rects); | |
2864 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) | |
2865 child->addLayerHitTestRects(rects); | |
2866 } | |
2867 | |
2868 void RenderLayer::computeSelfHitTestRects(LayerHitTestRects& rects) const | |
2869 { | |
2870 if (!size().isEmpty()) { | |
2871 Vector<LayoutRect> rect; | |
2872 | |
2873 if (renderBox() && renderBox()->scrollsOverflow()) { | |
2874 // For scrolling layers, rects are taken to be in the space of the c
ontents. | |
2875 // We need to include the bounding box of the layer in the space of
its parent | |
2876 // (eg. for border / scroll bars) and if it's composited then the en
tire contents | |
2877 // as well as they may be on another composited layer. Skip reportin
g contents | |
2878 // for non-composited layers as they'll get projected to the same la
yer as the | |
2879 // bounding box. | |
2880 if (compositingState() != NotComposited) | |
2881 rect.append(m_scrollableArea->overflowRect()); | |
2882 | |
2883 rects.set(this, rect); | |
2884 if (const RenderLayer* parentLayer = parent()) { | |
2885 LayerHitTestRects::iterator iter = rects.find(parentLayer); | |
2886 if (iter == rects.end()) { | |
2887 rects.add(parentLayer, Vector<LayoutRect>()).storedValue->va
lue.append(physicalBoundingBox(parentLayer)); | |
2888 } else { | |
2889 iter->value.append(physicalBoundingBox(parentLayer)); | |
2890 } | |
2891 } | |
2892 } else { | |
2893 rect.append(logicalBoundingBox()); | |
2894 rects.set(this, rect); | |
2895 } | |
2896 } | |
2897 } | |
2898 | |
2899 void RenderLayer::setShouldDoFullPaintInvalidationIncludingNonCompositingDescend
ants() | |
2900 { | |
2901 renderer()->setShouldDoFullPaintInvalidation(); | |
2902 | |
2903 // Disable for reading compositingState() in isPaintInvalidationContainer()
below. | |
2904 DisableCompositingQueryAsserts disabler; | |
2905 | |
2906 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
{ | |
2907 if (!child->isPaintInvalidationContainer()) | |
2908 child->setShouldDoFullPaintInvalidationIncludingNonCompositingDescen
dants(); | |
2909 } | |
2910 } | |
2911 | |
2912 DisableCompositingQueryAsserts::DisableCompositingQueryAsserts() | |
2913 : m_disabler(gCompositingQueryMode, CompositingQueriesAreAllowed) { } | |
2914 | |
2915 } // namespace blink | |
2916 | |
2917 #ifndef NDEBUG | |
2918 void showLayerTree(const blink::RenderLayer* layer) | |
2919 { | |
2920 if (!layer) | |
2921 return; | |
2922 | |
2923 if (blink::LocalFrame* frame = layer->renderer()->frame()) { | |
2924 WTF::String output = externalRepresentation(frame, blink::LayoutAsTextSh
owAllLayers | blink::LayoutAsTextShowLayerNesting | blink::LayoutAsTextShowCompo
sitedLayers | blink::LayoutAsTextShowAddresses | blink::LayoutAsTextShowIDAndCla
ss | blink::LayoutAsTextDontUpdateLayout | blink::LayoutAsTextShowLayoutState); | |
2925 fprintf(stderr, "%s\n", output.utf8().data()); | |
2926 } | |
2927 } | |
2928 | |
2929 void showLayerTree(const blink::RenderObject* renderer) | |
2930 { | |
2931 if (!renderer) | |
2932 return; | |
2933 showLayerTree(renderer->enclosingLayer()); | |
2934 } | |
2935 #endif | |
OLD | NEW |