1 /*
2 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
3 *
4 * Portions are Copyright (C) 1998 Netscape Communications Corporation.
5 *
6 * Other contributors:
7 * Robert O'Callahan <roc+@cs.cmu.edu>
8 * David Baron <dbaron@fas.harvard.edu>
9 * Christian Biesinger <cbiesinger@web.de>
10 * Randall Jesup <rjesup@wgate.com>
11 * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
12 * Josh Soref <timeless@mac.com>
13 * Boris Zbarsky <bzbarsky@mit.edu>
14 *
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
28 *
29 * Alternatively, the contents of this file may be used under the terms
30 * of either the Mozilla Public License Version 1.1, found at
31 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
32 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
33 * (the "GPL"), in which case the provisions of the MPL or the GPL are
34 * applicable instead of those above. If you wish to allow use of your
35 * version of this file only under the terms of one of those two
36 * licenses (the MPL or the GPL) and not to allow others to use your
37 * version of this file under the LGPL, indicate your decision by
38 * deletingthe provisions above and replace them with the notice and
39 * other provisions required by the MPL or the GPL, as the case may be.
40 * If you do not delete the provisions above, a recipient may use your
41 * version of this file under any of the LGPL, the MPL or the GPL.
42 */
43
44 #include "config.h"
45 #include "RenderLayer.h"
46
47 #include "ColumnInfo.h"
48 #include "CSSPropertyNames.h"
49 #include "CSSStyleDeclaration.h"
50 #include "CSSStyleSelector.h"
51 #include "Chrome.h"
52 #include "Document.h"
53 #include "EventHandler.h"
54 #include "EventQueue.h"
55 #include "FloatPoint3D.h"
56 #include "FloatRect.h"
57 #include "FocusController.h"
58 #include "Frame.h"
59 #include "FrameTree.h"
60 #include "FrameView.h"
61 #include "Gradient.h"
62 #include "GraphicsContext.h"
63 #include "HTMLFrameOwnerElement.h"
64 #include "HTMLNames.h"
65 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
66 #include "HTMLTextAreaElement.h"
67 #endif
68 #include "HitTestRequest.h"
69 #include "HitTestResult.h"
70 #include "OverflowEvent.h"
71 #include "OverlapTestRequestClient.h"
72 #include "Page.h"
73 #include "PlatformMouseEvent.h"
74 #include "RenderArena.h"
75 #include "RenderInline.h"
76 #include "RenderMarquee.h"
77 #include "RenderReplica.h"
78 #include "RenderScrollbar.h"
79 #include "RenderScrollbarPart.h"
80 #include "RenderTheme.h"
81 #include "RenderTreeAsText.h"
82 #include "RenderView.h"
83 #include "ScaleTransformOperation.h"
84 #include "Scrollbar.h"
85 #include "ScrollbarTheme.h"
86 #include "SelectionController.h"
87 #include "TextStream.h"
88 #include "TransformState.h"
89 #include "TransformationMatrix.h"
90 #include "TranslateTransformOperation.h"
91 #include <wtf/StdLibExtras.h>
92 #include <wtf/UnusedParam.h>
93 #include <wtf/text/CString.h>
94
95 #if USE(ACCELERATED_COMPOSITING)
96 #include "RenderLayerBacking.h"
97 #include "RenderLayerCompositor.h"
98 #endif
99
100 #if ENABLE(SVG)
101 #include "SVGNames.h"
102 #endif
103
104 #define MIN_INTERSECT_FOR_REVEAL 32
105
106 using namespace std;
107
108 namespace WebCore {
109
110 using namespace HTMLNames;
111
112 const int MinimumWidthWhileResizing = 100;
113 const int MinimumHeightWhileResizing = 40;
114
operator new(size_t sz,RenderArena * renderArena)115 void* ClipRects::operator new(size_t sz, RenderArena* renderArena) throw()
116 {
117 return renderArena->allocate(sz);
118 }
119
operator delete(void * ptr,size_t sz)120 void ClipRects::operator delete(void* ptr, size_t sz)
121 {
122 // Stash size where destroy can find it.
123 *(size_t *)ptr = sz;
124 }
125
destroy(RenderArena * renderArena)126 void ClipRects::destroy(RenderArena* renderArena)
127 {
128 delete this;
129
130 // Recover the size left there for us by operator delete and free the memory.
131 renderArena->free(*(size_t *)this, this);
132 }
133
RenderLayer(RenderBoxModelObject * renderer)134 RenderLayer::RenderLayer(RenderBoxModelObject* renderer)
135 : m_renderer(renderer)
136 , m_parent(0)
137 , m_previous(0)
138 , m_next(0)
139 , m_first(0)
140 , m_last(0)
141 , m_relX(0)
142 , m_relY(0)
143 , m_x(0)
144 , m_y(0)
145 , m_width(0)
146 , m_height(0)
147 , m_scrollX(0)
148 , m_scrollY(0)
149 , m_scrollLeftOverflow(0)
150 , m_scrollTopOverflow(0)
151 , m_scrollWidth(0)
152 , m_scrollHeight(0)
153 , m_inResizeMode(false)
154 , m_posZOrderList(0)
155 , m_negZOrderList(0)
156 , m_normalFlowList(0)
157 , m_clipRects(0)
158 #ifndef NDEBUG
159 , m_clipRectsRoot(0)
160 #endif
161 , m_scrollDimensionsDirty(true)
162 , m_zOrderListsDirty(true)
163 , m_normalFlowListDirty(true)
164 , m_isNormalFlowOnly(shouldBeNormalFlowOnly())
165 , m_usedTransparency(false)
166 , m_paintingInsideReflection(false)
167 , m_inOverflowRelayout(false)
168 , m_needsFullRepaint(false)
169 , m_overflowStatusDirty(true)
170 , m_visibleContentStatusDirty(true)
171 , m_hasVisibleContent(false)
172 , m_visibleDescendantStatusDirty(false)
173 , m_hasVisibleDescendant(false)
174 , m_isPaginated(false)
175 , m_3DTransformedDescendantStatusDirty(true)
176 , m_has3DTransformedDescendant(false)
177 #if USE(ACCELERATED_COMPOSITING)
178 , m_hasCompositingDescendant(false)
179 , m_mustOverlapCompositedLayers(false)
180 #if ENABLE(COMPOSITED_FIXED_ELEMENTS)
181 , m_shouldComposite(false)
182 #endif
183 #endif
184 , m_containsDirtyOverlayScrollbars(false)
185 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
186 , m_hasOverflowScroll(false)
187 #endif
188 , m_marquee(0)
189 , m_staticInlinePosition(0)
190 , m_staticBlockPosition(0)
191 , m_reflection(0)
192 , m_scrollCorner(0)
193 , m_resizer(0)
194 {
195 ScrollableArea::setConstrainsScrollingToContentEdge(false);
196
197 if (!renderer->firstChild() && renderer->style()) {
198 m_visibleContentStatusDirty = false;
199 m_hasVisibleContent = renderer->style()->visibility() == VISIBLE;
200 }
201
202 if (Frame* frame = renderer->frame()) {
203 if (Page* page = frame->page()) {
204 m_page = page;
205 m_page->addScrollableArea(this);
206 }
207 }
208 }
209
~RenderLayer()210 RenderLayer::~RenderLayer()
211 {
212 if (inResizeMode() && !renderer()->documentBeingDestroyed()) {
213 if (Frame* frame = renderer()->frame())
214 frame->eventHandler()->resizeLayerDestroyed();
215 }
216
217 if (m_page)
218 m_page->removeScrollableArea(this);
219
220 destroyScrollbar(HorizontalScrollbar);
221 destroyScrollbar(VerticalScrollbar);
222
223 if (m_reflection)
224 removeReflection();
225
226 // Child layers will be deleted by their corresponding render objects, so
227 // we don't need to delete them ourselves.
228
229 delete m_posZOrderList;
230 delete m_negZOrderList;
231 delete m_normalFlowList;
232 delete m_marquee;
233
234 #if USE(ACCELERATED_COMPOSITING)
235 clearBacking();
236 #endif
237
238 // Make sure we have no lingering clip rects.
239 ASSERT(!m_clipRects);
240
241 if (m_scrollCorner)
242 m_scrollCorner->destroy();
243 if (m_resizer)
244 m_resizer->destroy();
245 }
246
247 #if USE(ACCELERATED_COMPOSITING)
compositor() const248 RenderLayerCompositor* RenderLayer::compositor() const
249 {
250 ASSERT(renderer()->view());
251 return renderer()->view()->compositor();
252 }
253
contentChanged(ContentChangeType changeType)254 void RenderLayer::contentChanged(ContentChangeType changeType)
255 {
256 // This can get called when video becomes accelerated, so the layers may change.
257 if ((changeType == CanvasChanged || changeType == VideoChanged || changeType == FullScreenChanged) && compositor()->updateLayerCompositingState(this))
258 compositor()->setCompositingLayersNeedRebuild();
259
260 if (m_backing)
261 m_backing->contentChanged(changeType);
262 }
263 #endif // USE(ACCELERATED_COMPOSITING)
264
hasAcceleratedCompositing() const265 bool RenderLayer::hasAcceleratedCompositing() const
266 {
267 #if USE(ACCELERATED_COMPOSITING)
268 return compositor()->hasAcceleratedCompositing();
269 #else
270 return false;
271 #endif
272 }
273
canRender3DTransforms() const274 bool RenderLayer::canRender3DTransforms() const
275 {
276 #if USE(ACCELERATED_COMPOSITING)
277 return compositor()->canRender3DTransforms();
278 #else
279 return false;
280 #endif
281 }
282
updateLayerPositions(UpdateLayerPositionsFlags flags,IntPoint * cachedOffset)283 void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags, IntPoint* cachedOffset)
284 {
285 updateLayerPosition(); // For relpositioned layers or non-positioned layers,
286 // we need to keep in sync, since we may have shifted relative
287 // to our parent layer.
288 IntPoint oldCachedOffset;
289 if (cachedOffset) {
290 // We can't cache our offset to the repaint container if the mapping is anything more complex than a simple translation
291 bool disableOffsetCache = renderer()->hasColumns() || renderer()->hasTransform() || isComposited();
292 #if ENABLE(SVG)
293 disableOffsetCache = disableOffsetCache || renderer()->isSVGRoot();
294 #endif
295 if (disableOffsetCache)
296 cachedOffset = 0; // If our cached offset is invalid make sure it's not passed to any of our children
297 else {
298 oldCachedOffset = *cachedOffset;
299 // Frequently our parent layer's renderer will be the same as our renderer's containing block. In that case,
300 // we just update the cache using our offset to our parent (which is m_x / m_y). Otherwise, regenerated cached
301 // offsets to the root from the render tree.
302 if (!m_parent || m_parent->renderer() == renderer()->containingBlock())
303 cachedOffset->move(m_x, m_y); // Fast case
304 else {
305 int x = 0;
306 int y = 0;
307 convertToLayerCoords(root(), x, y);
308 *cachedOffset = IntPoint(x, y);
309 }
310 }
311 }
312
313 int x = 0;
314 int y = 0;
315 if (cachedOffset) {
316 x += cachedOffset->x();
317 y += cachedOffset->y();
318 #ifndef NDEBUG
319 int nonCachedX = 0;
320 int nonCachedY = 0;
321 convertToLayerCoords(root(), nonCachedX, nonCachedY);
322 ASSERT(x == nonCachedX);
323 ASSERT(y == nonCachedY);
324 #endif
325 } else
326 convertToLayerCoords(root(), x, y);
327 positionOverflowControls(x, y);
328
329 updateVisibilityStatus();
330
331 if (flags & UpdatePagination)
332 updatePagination();
333 else
334 m_isPaginated = false;
335
336 if (m_hasVisibleContent) {
337 RenderView* view = renderer()->view();
338 ASSERT(view);
339 // FIXME: Optimize using LayoutState and remove the disableLayoutState() call
340 // from updateScrollInfoAfterLayout().
341 ASSERT(!view->layoutStateEnabled());
342
343 RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint();
344 IntRect newRect = renderer()->clippedOverflowRectForRepaint(repaintContainer);
345 IntRect newOutlineBox = renderer()->outlineBoundsForRepaint(repaintContainer, cachedOffset);
346 // FIXME: Should ASSERT that value calculated for newOutlineBox using the cached offset is the same
347 // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048
348 if (flags & CheckForRepaint) {
349 if (view && !view->printing()) {
350 if (m_needsFullRepaint) {
351 renderer()->repaintUsingContainer(repaintContainer, m_repaintRect);
352 if (newRect != m_repaintRect)
353 renderer()->repaintUsingContainer(repaintContainer, newRect);
354 } else
355 renderer()->repaintAfterLayoutIfNeeded(repaintContainer, m_repaintRect, m_outlineBox, &newRect, &newOutlineBox);
356 }
357 }
358 m_repaintRect = newRect;
359 m_outlineBox = newOutlineBox;
360 } else {
361 m_repaintRect = IntRect();
362 m_outlineBox = IntRect();
363 }
364
365 m_needsFullRepaint = false;
366
367 // Go ahead and update the reflection's position and size.
368 if (m_reflection)
369 m_reflection->layout();
370
371 #if USE(ACCELERATED_COMPOSITING)
372 // Clear the IsCompositingUpdateRoot flag once we've found the first compositing layer in this update.
373 bool isUpdateRoot = (flags & IsCompositingUpdateRoot);
374 if (isComposited())
375 flags &= ~IsCompositingUpdateRoot;
376 #endif
377
378 if (renderer()->hasColumns())
379 flags |= UpdatePagination;
380
381 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
382 child->updateLayerPositions(flags, cachedOffset);
383
384 #if USE(ACCELERATED_COMPOSITING)
385 if ((flags & UpdateCompositingLayers) && isComposited())
386 backing()->updateAfterLayout(RenderLayerBacking::CompositingChildren, isUpdateRoot);
387 #endif
388
389 // With all our children positioned, now update our marquee if we need to.
390 if (m_marquee)
391 m_marquee->updateMarqueePosition();
392
393 if (cachedOffset)
394 *cachedOffset = oldCachedOffset;
395 }
396
repaintRectIncludingDescendants() const397 IntRect RenderLayer::repaintRectIncludingDescendants() const
398 {
399 IntRect repaintRect = m_repaintRect;
400 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
401 repaintRect.unite(child->repaintRectIncludingDescendants());
402 return repaintRect;
403 }
404
computeRepaintRects()405 void RenderLayer::computeRepaintRects()
406 {
407 RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint();
408 m_repaintRect = renderer()->clippedOverflowRectForRepaint(repaintContainer);
409 m_outlineBox = renderer()->outlineBoundsForRepaint(repaintContainer);
410 }
411
updateRepaintRectsAfterScroll(bool fixed)412 void RenderLayer::updateRepaintRectsAfterScroll(bool fixed)
413 {
414 if (fixed || renderer()->style()->position() == FixedPosition) {
415 computeRepaintRects();
416 fixed = true;
417 } else if (renderer()->hasTransform() && !renderer()->isRenderView()) {
418 // Transforms act as fixed position containers, so nothing inside a
419 // transformed element can be fixed relative to the viewport if the
420 // transformed element is not fixed itself or child of a fixed element.
421 return;
422 }
423
424 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
425 child->updateRepaintRectsAfterScroll(fixed);
426 }
427
updateTransform()428 void RenderLayer::updateTransform()
429 {
430 // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set,
431 // so check style too.
432 bool hasTransform = renderer()->hasTransform() && renderer()->style()->hasTransform();
433 bool had3DTransform = has3DTransform();
434
435 bool hadTransform = m_transform;
436 if (hasTransform != hadTransform) {
437 if (hasTransform)
438 m_transform.set(new TransformationMatrix);
439 else
440 m_transform.clear();
441 }
442
443 if (hasTransform) {
444 RenderBox* box = renderBox();
445 ASSERT(box);
446 m_transform->makeIdentity();
447 box->style()->applyTransform(*m_transform, box->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
448 makeMatrixRenderable(*m_transform, canRender3DTransforms());
449 }
450
451 if (had3DTransform != has3DTransform())
452 dirty3DTransformedDescendantStatus();
453 }
454
currentTransform() const455 TransformationMatrix RenderLayer::currentTransform() const
456 {
457 if (!m_transform)
458 return TransformationMatrix();
459
460 #if USE(ACCELERATED_COMPOSITING)
461 if (renderer()->style()->isRunningAcceleratedAnimation()) {
462 TransformationMatrix currTransform;
463 RefPtr<RenderStyle> style = renderer()->animation()->getAnimatedStyleForRenderer(renderer());
464 style->applyTransform(currTransform, renderBox()->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
465 makeMatrixRenderable(currTransform, canRender3DTransforms());
466 return currTransform;
467 }
468 #endif
469
470 return *m_transform;
471 }
472
renderableTransform(PaintBehavior paintBehavior) const473 TransformationMatrix RenderLayer::renderableTransform(PaintBehavior paintBehavior) const
474 {
475 if (!m_transform)
476 return TransformationMatrix();
477
478 if (paintBehavior & PaintBehaviorFlattenCompositingLayers) {
479 TransformationMatrix matrix = *m_transform;
480 makeMatrixRenderable(matrix, false /* flatten 3d */);
481 return matrix;
482 }
483
484 return *m_transform;
485 }
486
checkContainingBlockChainForPagination(RenderBoxModelObject * renderer,RenderBox * ancestorColumnsRenderer)487 static bool checkContainingBlockChainForPagination(RenderBoxModelObject* renderer, RenderBox* ancestorColumnsRenderer)
488 {
489 RenderView* view = renderer->view();
490 RenderBoxModelObject* prevBlock = renderer;
491 RenderBlock* containingBlock;
492 for (containingBlock = renderer->containingBlock();
493 containingBlock && containingBlock != view && containingBlock != ancestorColumnsRenderer;
494 containingBlock = containingBlock->containingBlock())
495 prevBlock = containingBlock;
496
497 // If the columns block wasn't in our containing block chain, then we aren't paginated by it.
498 if (containingBlock != ancestorColumnsRenderer)
499 return false;
500
501 // If the previous block is absolutely positioned, then we can't be paginated by the columns block.
502 if (prevBlock->isPositioned())
503 return false;
504
505 // Otherwise we are paginated by the columns block.
506 return true;
507 }
508
updatePagination()509 void RenderLayer::updatePagination()
510 {
511 m_isPaginated = false;
512 if (isComposited() || !parent())
513 return; // FIXME: We will have to deal with paginated compositing layers someday.
514 // FIXME: For now the RenderView can't be paginated. Eventually printing will move to a model where it is though.
515
516 if (isNormalFlowOnly()) {
517 m_isPaginated = parent()->renderer()->hasColumns();
518 return;
519 }
520
521 // If we're not normal flow, then we need to look for a multi-column object between us and our stacking context.
522 RenderLayer* ancestorStackingContext = stackingContext();
523 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
524 if (curr->renderer()->hasColumns()) {
525 m_isPaginated = checkContainingBlockChainForPagination(renderer(), curr->renderBox());
526 return;
527 }
528 if (curr == ancestorStackingContext)
529 return;
530 }
531 }
532
setHasVisibleContent(bool b)533 void RenderLayer::setHasVisibleContent(bool b)
534 {
535 if (m_hasVisibleContent == b && !m_visibleContentStatusDirty)
536 return;
537 m_visibleContentStatusDirty = false;
538 m_hasVisibleContent = b;
539 if (m_hasVisibleContent) {
540 RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint();
541 m_repaintRect = renderer()->clippedOverflowRectForRepaint(repaintContainer);
542 m_outlineBox = renderer()->outlineBoundsForRepaint(repaintContainer);
543 if (!isNormalFlowOnly()) {
544 for (RenderLayer* sc = stackingContext(); sc; sc = sc->stackingContext()) {
545 sc->dirtyZOrderLists();
546 if (sc->hasVisibleContent())
547 break;
548 }
549 }
550 }
551 if (parent())
552 parent()->childVisibilityChanged(m_hasVisibleContent);
553 }
554
dirtyVisibleContentStatus()555 void RenderLayer::dirtyVisibleContentStatus()
556 {
557 m_visibleContentStatusDirty = true;
558 if (parent())
559 parent()->dirtyVisibleDescendantStatus();
560 }
561
childVisibilityChanged(bool newVisibility)562 void RenderLayer::childVisibilityChanged(bool newVisibility)
563 {
564 if (m_hasVisibleDescendant == newVisibility || m_visibleDescendantStatusDirty)
565 return;
566 if (newVisibility) {
567 RenderLayer* l = this;
568 while (l && !l->m_visibleDescendantStatusDirty && !l->m_hasVisibleDescendant) {
569 l->m_hasVisibleDescendant = true;
570 l = l->parent();
571 }
572 } else
573 dirtyVisibleDescendantStatus();
574 }
575
dirtyVisibleDescendantStatus()576 void RenderLayer::dirtyVisibleDescendantStatus()
577 {
578 RenderLayer* l = this;
579 while (l && !l->m_visibleDescendantStatusDirty) {
580 l->m_visibleDescendantStatusDirty = true;
581 l = l->parent();
582 }
583 }
584
updateVisibilityStatus()585 void RenderLayer::updateVisibilityStatus()
586 {
587 if (m_visibleDescendantStatusDirty) {
588 m_hasVisibleDescendant = false;
589 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
590 child->updateVisibilityStatus();
591 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) {
592 m_hasVisibleDescendant = true;
593 break;
594 }
595 }
596 m_visibleDescendantStatusDirty = false;
597 }
598
599 if (m_visibleContentStatusDirty) {
600 if (renderer()->style()->visibility() == VISIBLE)
601 m_hasVisibleContent = true;
602 else {
603 // layer may be hidden but still have some visible content, check for this
604 m_hasVisibleContent = false;
605 RenderObject* r = renderer()->firstChild();
606 while (r) {
607 if (r->style()->visibility() == VISIBLE && !r->hasLayer()) {
608 m_hasVisibleContent = true;
609 break;
610 }
611 if (r->firstChild() && !r->hasLayer())
612 r = r->firstChild();
613 else if (r->nextSibling())
614 r = r->nextSibling();
615 else {
616 do {
617 r = r->parent();
618 if (r == renderer())
619 r = 0;
620 } while (r && !r->nextSibling());
621 if (r)
622 r = r->nextSibling();
623 }
624 }
625 }
626 m_visibleContentStatusDirty = false;
627 }
628 }
629
dirty3DTransformedDescendantStatus()630 void RenderLayer::dirty3DTransformedDescendantStatus()
631 {
632 RenderLayer* curr = stackingContext();
633 if (curr)
634 curr->m_3DTransformedDescendantStatusDirty = true;
635
636 // This propagates up through preserve-3d hierarchies to the enclosing flattening layer.
637 // Note that preserves3D() creates stacking context, so we can just run up the stacking contexts.
638 while (curr && curr->preserves3D()) {
639 curr->m_3DTransformedDescendantStatusDirty = true;
640 curr = curr->stackingContext();
641 }
642 }
643
644 // Return true if this layer or any preserve-3d descendants have 3d.
update3DTransformedDescendantStatus()645 bool RenderLayer::update3DTransformedDescendantStatus()
646 {
647 if (m_3DTransformedDescendantStatusDirty) {
648 m_has3DTransformedDescendant = false;
649
650 // Transformed or preserve-3d descendants can only be in the z-order lists, not
651 // in the normal flow list, so we only need to check those.
652 if (m_posZOrderList) {
653 for (unsigned i = 0; i < m_posZOrderList->size(); ++i)
654 m_has3DTransformedDescendant |= m_posZOrderList->at(i)->update3DTransformedDescendantStatus();
655 }
656
657 // Now check our negative z-index children.
658 if (m_negZOrderList) {
659 for (unsigned i = 0; i < m_negZOrderList->size(); ++i)
660 m_has3DTransformedDescendant |= m_negZOrderList->at(i)->update3DTransformedDescendantStatus();
661 }
662
663 m_3DTransformedDescendantStatusDirty = false;
664 }
665
666 // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs
667 // the m_has3DTransformedDescendant set.
668 if (preserves3D())
669 return has3DTransform() || m_has3DTransformedDescendant;
670
671 return has3DTransform();
672 }
673
updateLayerPosition()674 void RenderLayer::updateLayerPosition()
675 {
676 IntPoint localPoint;
677 IntSize inlineBoundingBoxOffset; // We don't put this into the RenderLayer x/y for inlines, so we need to subtract it out when done.
678 if (renderer()->isRenderInline()) {
679 RenderInline* inlineFlow = toRenderInline(renderer());
680 IntRect lineBox = inlineFlow->linesBoundingBox();
681 setWidth(lineBox.width());
682 setHeight(lineBox.height());
683 inlineBoundingBoxOffset = IntSize(lineBox.x(), lineBox.y());
684 localPoint += inlineBoundingBoxOffset;
685 } else if (RenderBox* box = renderBox()) {
686 setWidth(box->width());
687 setHeight(box->height());
688 localPoint += box->locationOffsetIncludingFlipping();
689 }
690
691 // Clear our cached clip rect information.
692 clearClipRects();
693
694 if (!renderer()->isPositioned() && renderer()->parent()) {
695 // We must adjust our position by walking up the render tree looking for the
696 // nearest enclosing object with a layer.
697 RenderObject* curr = renderer()->parent();
698 while (curr && !curr->hasLayer()) {
699 if (curr->isBox() && !curr->isTableRow()) {
700 // Rows and cells share the same coordinate space (that of the section).
701 // Omit them when computing our xpos/ypos.
702 localPoint += toRenderBox(curr)->locationOffsetIncludingFlipping();
703 }
704 curr = curr->parent();
705 }
706 if (curr->isBox() && curr->isTableRow()) {
707 // Put ourselves into the row coordinate space.
708 localPoint -= toRenderBox(curr)->locationOffsetIncludingFlipping();
709 }
710 }
711
712 // Subtract our parent's scroll offset.
713 if (renderer()->isPositioned() && enclosingPositionedAncestor()) {
714 RenderLayer* positionedParent = enclosingPositionedAncestor();
715
716 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
717 IntSize offset = positionedParent->scrolledContentOffset();
718 localPoint -= offset;
719
720 if (renderer()->isPositioned() && positionedParent->renderer()->isRelPositioned() && positionedParent->renderer()->isRenderInline()) {
721 IntSize offset = toRenderInline(positionedParent->renderer())->relativePositionedInlineOffset(toRenderBox(renderer()));
722 localPoint += offset;
723 }
724 } else if (parent()) {
725 if (isComposited()) {
726 // FIXME: Composited layers ignore pagination, so about the best we can do is make sure they're offset into the appropriate column.
727 // They won't split across columns properly.
728 IntSize columnOffset;
729 parent()->renderer()->adjustForColumns(columnOffset, localPoint);
730 localPoint += columnOffset;
731 }
732
733 IntSize scrollOffset = parent()->scrolledContentOffset();
734 localPoint -= scrollOffset;
735 }
736
737 m_relX = m_relY = 0;
738 if (renderer()->isRelPositioned()) {
739 m_relX = renderer()->relativePositionOffsetX();
740 m_relY = renderer()->relativePositionOffsetY();
741 localPoint.move(m_relX, m_relY);
742 }
743
744 // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
745 localPoint -= inlineBoundingBoxOffset;
746 setLocation(localPoint.x(), localPoint.y());
747 }
748
perspectiveTransform() const749 TransformationMatrix RenderLayer::perspectiveTransform() const
750 {
751 if (!renderer()->hasTransform())
752 return TransformationMatrix();
753
754 RenderStyle* style = renderer()->style();
755 if (!style->hasPerspective())
756 return TransformationMatrix();
757
758 // Maybe fetch the perspective from the backing?
759 const IntRect borderBox = toRenderBox(renderer())->borderBoxRect();
760 const float boxWidth = borderBox.width();
761 const float boxHeight = borderBox.height();
762
763 float perspectiveOriginX = style->perspectiveOriginX().calcFloatValue(boxWidth);
764 float perspectiveOriginY = style->perspectiveOriginY().calcFloatValue(boxHeight);
765
766 // A perspective origin of 0,0 makes the vanishing point in the center of the element.
767 // We want it to be in the top-left, so subtract half the height and width.
768 perspectiveOriginX -= boxWidth / 2.0f;
769 perspectiveOriginY -= boxHeight / 2.0f;
770
771 TransformationMatrix t;
772 t.translate(perspectiveOriginX, perspectiveOriginY);
773 t.applyPerspective(style->perspective());
774 t.translate(-perspectiveOriginX, -perspectiveOriginY);
775
776 return t;
777 }
778
perspectiveOrigin() const779 FloatPoint RenderLayer::perspectiveOrigin() const
780 {
781 if (!renderer()->hasTransform())
782 return FloatPoint();
783
784 const IntRect borderBox = toRenderBox(renderer())->borderBoxRect();
785 RenderStyle* style = renderer()->style();
786
787 return FloatPoint(style->perspectiveOriginX().calcFloatValue(borderBox.width()),
788 style->perspectiveOriginY().calcFloatValue(borderBox.height()));
789 }
790
stackingContext() const791 RenderLayer* RenderLayer::stackingContext() const
792 {
793 RenderLayer* layer = parent();
794 #if ENABLE(COMPOSITED_FIXED_ELEMENTS) || ENABLE(ANDROID_OVERFLOW_SCROLL)
795 // When using composited fixed elements, they are turned into a stacking
796 // context and we thus need to return them.
797 // We can simplify the while loop by using isStackingContext(); with
798 // composited fixed elements turned on, this will return true for them,
799 // and is otherwise equivalent to the replaced statements.
800 while (layer && !layer->renderer()->isRoot() && !layer->isStackingContext())
801 #else
802 while (layer && !layer->renderer()->isRenderView() && !layer->renderer()->isRoot() && layer->renderer()->style()->hasAutoZIndex())
803 #endif
804 layer = layer->parent();
805 return layer;
806 }
807
isPositionedContainer(RenderLayer * layer)808 static inline bool isPositionedContainer(RenderLayer* layer)
809 {
810 RenderObject* o = layer->renderer();
811 return o->isRenderView() || o->isPositioned() || o->isRelPositioned() || layer->hasTransform();
812 }
813
isFixedPositionedContainer(RenderLayer * layer)814 static inline bool isFixedPositionedContainer(RenderLayer* layer)
815 {
816 RenderObject* o = layer->renderer();
817 return o->isRenderView() || layer->hasTransform();
818 }
819
enclosingPositionedAncestor() const820 RenderLayer* RenderLayer::enclosingPositionedAncestor() const
821 {
822 RenderLayer* curr = parent();
823 while (curr && !isPositionedContainer(curr))
824 curr = curr->parent();
825
826 return curr;
827 }
828
enclosingTransformedAncestor() const829 RenderLayer* RenderLayer::enclosingTransformedAncestor() const
830 {
831 RenderLayer* curr = parent();
832 while (curr && !curr->renderer()->isRenderView() && !curr->transform())
833 curr = curr->parent();
834
835 return curr;
836 }
837
compositingContainer(const RenderLayer * layer)838 static inline const RenderLayer* compositingContainer(const RenderLayer* layer)
839 {
840 return layer->isNormalFlowOnly() ? layer->parent() : layer->stackingContext();
841 }
842
843 #if USE(ACCELERATED_COMPOSITING)
enclosingCompositingLayer(bool includeSelf) const844 RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const
845 {
846 if (includeSelf && isComposited())
847 return const_cast<RenderLayer*>(this);
848
849 for (const RenderLayer* curr = compositingContainer(this); curr; curr = compositingContainer(curr)) {
850 if (curr->isComposited())
851 return const_cast<RenderLayer*>(curr);
852 }
853
854 return 0;
855 }
856 #endif
857
clippingRoot() const858 RenderLayer* RenderLayer::clippingRoot() const
859 {
860 #if USE(ACCELERATED_COMPOSITING)
861 if (isComposited())
862 return const_cast<RenderLayer*>(this);
863 #endif
864
865 const RenderLayer* current = this;
866 while (current) {
867 if (current->renderer()->isRenderView())
868 return const_cast<RenderLayer*>(current);
869
870 current = compositingContainer(current);
871 ASSERT(current);
872 if (current->transform()
873 #if USE(ACCELERATED_COMPOSITING)
874 || current->isComposited()
875 #endif
876 )
877 return const_cast<RenderLayer*>(current);
878 }
879
880 ASSERT_NOT_REACHED();
881 return 0;
882 }
883
absoluteToContents(const IntPoint & absolutePoint) const884 IntPoint RenderLayer::absoluteToContents(const IntPoint& absolutePoint) const
885 {
886 // We don't use convertToLayerCoords because it doesn't know about transforms
887 return roundedIntPoint(renderer()->absoluteToLocal(absolutePoint, false, true));
888 }
889
requiresSlowRepaints() const890 bool RenderLayer::requiresSlowRepaints() const
891 {
892 if (isTransparent() || hasReflection() || hasTransform())
893 return true;
894 if (!parent())
895 return false;
896 return parent()->requiresSlowRepaints();
897 }
898
isTransparent() const899 bool RenderLayer::isTransparent() const
900 {
901 #if ENABLE(SVG)
902 if (renderer()->node() && renderer()->node()->namespaceURI() == SVGNames::svgNamespaceURI)
903 return false;
904 #endif
905 return renderer()->isTransparent() || renderer()->hasMask();
906 }
907
transparentPaintingAncestor()908 RenderLayer* RenderLayer::transparentPaintingAncestor()
909 {
910 if (isComposited())
911 return 0;
912
913 for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
914 if (curr->isComposited())
915 return 0;
916 if (curr->isTransparent())
917 return curr;
918 }
919 return 0;
920 }
921
922 static IntRect transparencyClipBox(const RenderLayer* l, const RenderLayer* rootLayer, PaintBehavior paintBehavior);
923
expandClipRectForDescendantsAndReflection(IntRect & clipRect,const RenderLayer * l,const RenderLayer * rootLayer,PaintBehavior paintBehavior)924 static void expandClipRectForDescendantsAndReflection(IntRect& clipRect, const RenderLayer* l, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
925 {
926 // If we have a mask, then the clip is limited to the border box area (and there is
927 // no need to examine child layers).
928 if (!l->renderer()->hasMask()) {
929 // Note: we don't have to walk z-order lists since transparent elements always establish
930 // a stacking context. This means we can just walk the layer tree directly.
931 for (RenderLayer* curr = l->firstChild(); curr; curr = curr->nextSibling()) {
932 if (!l->reflection() || l->reflectionLayer() != curr)
933 clipRect.unite(transparencyClipBox(curr, rootLayer, paintBehavior));
934 }
935 }
936
937 // If we have a reflection, then we need to account for that when we push the clip. Reflect our entire
938 // current transparencyClipBox to catch all child layers.
939 // FIXME: Accelerated compositing will eventually want to do something smart here to avoid incorporating this
940 // size into the parent layer.
941 if (l->renderer()->hasReflection()) {
942 int deltaX = 0;
943 int deltaY = 0;
944 l->convertToLayerCoords(rootLayer, deltaX, deltaY);
945 clipRect.move(-deltaX, -deltaY);
946 clipRect.unite(l->renderBox()->reflectedRect(clipRect));
947 clipRect.move(deltaX, deltaY);
948 }
949 }
950
transparencyClipBox(const RenderLayer * l,const RenderLayer * rootLayer,PaintBehavior paintBehavior)951 static IntRect transparencyClipBox(const RenderLayer* l, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
952 {
953 // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
954 // paintDirtyRect, and that should cut down on the amount we have to paint. Still it
955 // would be better to respect clips.
956
957 if (rootLayer != l && l->paintsWithTransform(paintBehavior)) {
958 // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
959 // the transformed layer and all of its children.
960 int x = 0;
961 int y = 0;
962 l->convertToLayerCoords(rootLayer, x, y);
963
964 TransformationMatrix transform;
965 transform.translate(x, y);
966 transform = transform * *l->transform();
967
968 IntRect clipRect = l->boundingBox(l);
969 expandClipRectForDescendantsAndReflection(clipRect, l, l, paintBehavior);
970 return transform.mapRect(clipRect);
971 }
972
973 IntRect clipRect = l->boundingBox(rootLayer);
974 expandClipRectForDescendantsAndReflection(clipRect, l, rootLayer, paintBehavior);
975 return clipRect;
976 }
977
beginTransparencyLayers(GraphicsContext * p,const RenderLayer * rootLayer,PaintBehavior paintBehavior)978 void RenderLayer::beginTransparencyLayers(GraphicsContext* p, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
979 {
980 if (p->paintingDisabled() || (paintsWithTransparency(paintBehavior) && m_usedTransparency))
981 return;
982
983 RenderLayer* ancestor = transparentPaintingAncestor();
984 if (ancestor)
985 ancestor->beginTransparencyLayers(p, rootLayer, paintBehavior);
986
987 if (paintsWithTransparency(paintBehavior)) {
988 m_usedTransparency = true;
989 p->save();
990 IntRect clipRect = transparencyClipBox(this, rootLayer, paintBehavior);
991 p->clip(clipRect);
992 p->beginTransparencyLayer(renderer()->opacity());
993 #ifdef REVEAL_TRANSPARENCY_LAYERS
994 p->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f), ColorSpaceDeviceRGB);
995 p->fillRect(clipRect);
996 #endif
997 }
998 }
999
operator new(size_t sz,RenderArena * renderArena)1000 void* RenderLayer::operator new(size_t sz, RenderArena* renderArena) throw()
1001 {
1002 return renderArena->allocate(sz);
1003 }
1004
operator delete(void * ptr,size_t sz)1005 void RenderLayer::operator delete(void* ptr, size_t sz)
1006 {
1007 // Stash size where destroy can find it.
1008 *(size_t *)ptr = sz;
1009 }
1010
destroy(RenderArena * renderArena)1011 void RenderLayer::destroy(RenderArena* renderArena)
1012 {
1013 delete this;
1014
1015 // Recover the size left there for us by operator delete and free the memory.
1016 renderArena->free(*(size_t *)this, this);
1017 }
1018
addChild(RenderLayer * child,RenderLayer * beforeChild)1019 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
1020 {
1021 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
1022 if (prevSibling) {
1023 child->setPreviousSibling(prevSibling);
1024 prevSibling->setNextSibling(child);
1025 ASSERT(prevSibling != child);
1026 } else
1027 setFirstChild(child);
1028
1029 if (beforeChild) {
1030 beforeChild->setPreviousSibling(child);
1031 child->setNextSibling(beforeChild);
1032 ASSERT(beforeChild != child);
1033 } else
1034 setLastChild(child);
1035
1036 child->setParent(this);
1037
1038 if (child->isNormalFlowOnly())
1039 dirtyNormalFlowList();
1040
1041 if (!child->isNormalFlowOnly() || child->firstChild()) {
1042 // Dirty the z-order list in which we are contained. The stackingContext() can be null in the
1043 // case where we're building up generated content layers. This is ok, since the lists will start
1044 // off dirty in that case anyway.
1045 child->dirtyStackingContextZOrderLists();
1046 }
1047
1048 child->updateVisibilityStatus();
1049 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
1050 childVisibilityChanged(true);
1051
1052 #if USE(ACCELERATED_COMPOSITING)
1053 compositor()->layerWasAdded(this, child);
1054 #endif
1055 }
1056
removeChild(RenderLayer * oldChild)1057 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
1058 {
1059 #if USE(ACCELERATED_COMPOSITING)
1060 if (!renderer()->documentBeingDestroyed())
1061 compositor()->layerWillBeRemoved(this, oldChild);
1062 #endif
1063
1064 // remove the child
1065 if (oldChild->previousSibling())
1066 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
1067 if (oldChild->nextSibling())
1068 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
1069
1070 if (m_first == oldChild)
1071 m_first = oldChild->nextSibling();
1072 if (m_last == oldChild)
1073 m_last = oldChild->previousSibling();
1074
1075 if (oldChild->isNormalFlowOnly())
1076 dirtyNormalFlowList();
1077 if (!oldChild->isNormalFlowOnly() || oldChild->firstChild()) {
1078 // Dirty the z-order list in which we are contained. When called via the
1079 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
1080 // from the main layer tree, so we need to null-check the |stackingContext| value.
1081 oldChild->dirtyStackingContextZOrderLists();
1082 }
1083
1084 oldChild->setPreviousSibling(0);
1085 oldChild->setNextSibling(0);
1086 oldChild->setParent(0);
1087
1088 oldChild->updateVisibilityStatus();
1089 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
1090 childVisibilityChanged(false);
1091
1092 return oldChild;
1093 }
1094
removeOnlyThisLayer()1095 void RenderLayer::removeOnlyThisLayer()
1096 {
1097 if (!m_parent)
1098 return;
1099
1100 // Mark that we are about to lose our layer. This makes render tree
1101 // walks ignore this layer while we're removing it.
1102 m_renderer->setHasLayer(false);
1103
1104 #if USE(ACCELERATED_COMPOSITING)
1105 compositor()->layerWillBeRemoved(m_parent, this);
1106 #endif
1107
1108 // Dirty the clip rects.
1109 clearClipRectsIncludingDescendants();
1110
1111 // Remove us from the parent.
1112 RenderLayer* parent = m_parent;
1113 RenderLayer* nextSib = nextSibling();
1114 parent->removeChild(this);
1115
1116 if (reflection())
1117 removeChild(reflectionLayer());
1118
1119 // Now walk our kids and reattach them to our parent.
1120 RenderLayer* current = m_first;
1121 while (current) {
1122 RenderLayer* next = current->nextSibling();
1123 removeChild(current);
1124 parent->addChild(current, nextSib);
1125 current->setNeedsFullRepaint();
1126 current->updateLayerPositions(); // Depends on hasLayer() already being false for proper layout.
1127 current = next;
1128 }
1129
1130 m_renderer->destroyLayer();
1131 }
1132
insertOnlyThisLayer()1133 void RenderLayer::insertOnlyThisLayer()
1134 {
1135 if (!m_parent && renderer()->parent()) {
1136 // We need to connect ourselves when our renderer() has a parent.
1137 // Find our enclosingLayer and add ourselves.
1138 RenderLayer* parentLayer = renderer()->parent()->enclosingLayer();
1139 ASSERT(parentLayer);
1140 RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer()->parent()->findNextLayer(parentLayer, renderer()) : 0;
1141 parentLayer->addChild(this, beforeChild);
1142 }
1143
1144 // Remove all descendant layers from the hierarchy and add them to the new position.
1145 for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
1146 curr->moveLayers(m_parent, this);
1147
1148 // Clear out all the clip rects.
1149 clearClipRectsIncludingDescendants();
1150 }
1151
1152 void
convertToLayerCoords(const RenderLayer * ancestorLayer,int & xPos,int & yPos) const1153 RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& xPos, int& yPos) const
1154 {
1155 if (ancestorLayer == this)
1156 return;
1157
1158 EPosition position = renderer()->style()->position();
1159 if (position == FixedPosition && (!ancestorLayer || ancestorLayer == renderer()->view()->layer())) {
1160 // If the fixed layer's container is the root, just add in the offset of the view. We can obtain this by calling
1161 // localToAbsolute() on the RenderView.
1162 FloatPoint absPos = renderer()->localToAbsolute(FloatPoint(), true);
1163 xPos += absPos.x();
1164 yPos += absPos.y();
1165 return;
1166 }
1167
1168 if (position == FixedPosition) {
1169 // For a fixed layers, we need to walk up to the root to see if there's a fixed position container
1170 // (e.g. a transformed layer). It's an error to call convertToLayerCoords() across a layer with a transform,
1171 // so we should always find the ancestor at or before we find the fixed position container.
1172 RenderLayer* fixedPositionContainerLayer = 0;
1173 bool foundAncestor = false;
1174 for (RenderLayer* currLayer = parent(); currLayer; currLayer = currLayer->parent()) {
1175 if (currLayer == ancestorLayer)
1176 foundAncestor = true;
1177
1178 if (isFixedPositionedContainer(currLayer)) {
1179 fixedPositionContainerLayer = currLayer;
1180 ASSERT(foundAncestor);
1181 break;
1182 }
1183 }
1184
1185 ASSERT(fixedPositionContainerLayer); // We should have hit the RenderView's layer at least.
1186
1187 if (fixedPositionContainerLayer != ancestorLayer) {
1188 int fixedContainerX = 0;
1189 int fixedContainerY = 0;
1190 convertToLayerCoords(fixedPositionContainerLayer, fixedContainerX, fixedContainerY);
1191
1192 int ancestorX = 0;
1193 int ancestorY = 0;
1194 ancestorLayer->convertToLayerCoords(fixedPositionContainerLayer, ancestorX, ancestorY);
1195
1196 xPos += (fixedContainerX - ancestorX);
1197 yPos += (fixedContainerY - ancestorY);
1198 return;
1199 }
1200 }
1201
1202
1203 RenderLayer* parentLayer;
1204 if (position == AbsolutePosition || position == FixedPosition) {
1205 // Do what enclosingPositionedAncestor() does, but check for ancestorLayer along the way.
1206 parentLayer = parent();
1207 bool foundAncestorFirst = false;
1208 while (parentLayer) {
1209 if (isPositionedContainer(parentLayer))
1210 break;
1211
1212 if (parentLayer == ancestorLayer) {
1213 foundAncestorFirst = true;
1214 break;
1215 }
1216
1217 parentLayer = parentLayer->parent();
1218 }
1219
1220 if (foundAncestorFirst) {
1221 // Found ancestorLayer before the abs. positioned container, so compute offset of both relative
1222 // to enclosingPositionedAncestor and subtract.
1223 RenderLayer* positionedAncestor = parentLayer->enclosingPositionedAncestor();
1224
1225 int thisX = 0;
1226 int thisY = 0;
1227 convertToLayerCoords(positionedAncestor, thisX, thisY);
1228
1229 int ancestorX = 0;
1230 int ancestorY = 0;
1231 ancestorLayer->convertToLayerCoords(positionedAncestor, ancestorX, ancestorY);
1232
1233 xPos += (thisX - ancestorX);
1234 yPos += (thisY - ancestorY);
1235 return;
1236 }
1237 } else
1238 parentLayer = parent();
1239
1240 if (!parentLayer)
1241 return;
1242
1243 parentLayer->convertToLayerCoords(ancestorLayer, xPos, yPos);
1244
1245 xPos += x();
1246 yPos += y();
1247 }
1248
adjustedScrollDelta(int beginningDelta)1249 static inline int adjustedScrollDelta(int beginningDelta) {
1250 // This implemention matches Firefox's.
1251 // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856.
1252 const int speedReducer = 12;
1253
1254 int adjustedDelta = beginningDelta / speedReducer;
1255 if (adjustedDelta > 1)
1256 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(adjustedDelta))) - 1;
1257 else if (adjustedDelta < -1)
1258 adjustedDelta = static_cast<int>(adjustedDelta * sqrt(static_cast<double>(-adjustedDelta))) + 1;
1259
1260 return adjustedDelta;
1261 }
1262
panScrollFromPoint(const IntPoint & sourcePoint)1263 void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint)
1264 {
1265 Frame* frame = renderer()->frame();
1266 if (!frame)
1267 return;
1268
1269 IntPoint currentMousePosition = frame->eventHandler()->currentMousePosition();
1270
1271 // We need to check if the current mouse position is out of the window. When the mouse is out of the window, the position is incoherent
1272 static IntPoint previousMousePosition;
1273 if (currentMousePosition.x() < 0 || currentMousePosition.y() < 0)
1274 currentMousePosition = previousMousePosition;
1275 else
1276 previousMousePosition = currentMousePosition;
1277
1278 int xDelta = currentMousePosition.x() - sourcePoint.x();
1279 int yDelta = currentMousePosition.y() - sourcePoint.y();
1280
1281 if (abs(xDelta) <= ScrollView::noPanScrollRadius) // at the center we let the space for the icon
1282 xDelta = 0;
1283 if (abs(yDelta) <= ScrollView::noPanScrollRadius)
1284 yDelta = 0;
1285
1286 scrollByRecursively(adjustedScrollDelta(xDelta), adjustedScrollDelta(yDelta));
1287 }
1288
scrollByRecursively(int xDelta,int yDelta)1289 void RenderLayer::scrollByRecursively(int xDelta, int yDelta)
1290 {
1291 if (!xDelta && !yDelta)
1292 return;
1293
1294 bool restrictedByLineClamp = false;
1295 if (renderer()->parent())
1296 restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone();
1297
1298 if (renderer()->hasOverflowClip() && !restrictedByLineClamp) {
1299 int newOffsetX = scrollXOffset() + xDelta;
1300 int newOffsetY = scrollYOffset() + yDelta;
1301 scrollToOffset(newOffsetX, newOffsetY);
1302
1303 // If this layer can't do the scroll we ask the next layer up that can scroll to try
1304 int leftToScrollX = newOffsetX - scrollXOffset();
1305 int leftToScrollY = newOffsetY - scrollYOffset();
1306 if ((leftToScrollX || leftToScrollY) && renderer()->parent()) {
1307 RenderObject* nextRenderer = renderer()->parent();
1308 while (nextRenderer) {
1309 if (nextRenderer->isBox() && toRenderBox(nextRenderer)->canBeScrolledAndHasScrollableArea()) {
1310 nextRenderer->enclosingLayer()->scrollByRecursively(leftToScrollX, leftToScrollY);
1311 break;
1312 }
1313 nextRenderer = nextRenderer->parent();
1314 }
1315
1316 Frame* frame = renderer()->frame();
1317 if (frame)
1318 frame->eventHandler()->updateAutoscrollRenderer();
1319 }
1320 } else if (renderer()->view()->frameView()) {
1321 // If we are here, we were called on a renderer that can be programmatically scrolled, but doesn't
1322 // have an overflow clip. Which means that it is a document node that can be scrolled.
1323 renderer()->view()->frameView()->scrollBy(IntSize(xDelta, yDelta));
1324 // FIXME: If we didn't scroll the whole way, do we want to try looking at the frames ownerElement?
1325 // https://bugs.webkit.org/show_bug.cgi?id=28237
1326 }
1327 }
1328
scrollToOffset(int x,int y)1329 void RenderLayer::scrollToOffset(int x, int y)
1330 {
1331 ScrollableArea::scrollToOffsetWithoutAnimation(IntPoint(x, y));
1332 }
1333
scrollTo(int x,int y)1334 void RenderLayer::scrollTo(int x, int y)
1335 {
1336 RenderBox* box = renderBox();
1337 if (!box)
1338 return;
1339
1340 if (box->style()->overflowX() != OMARQUEE) {
1341 if (x < 0)
1342 x = 0;
1343 if (y < 0)
1344 y = 0;
1345
1346 // Call the scrollWidth/Height functions so that the dimensions will be computed if they need
1347 // to be (for overflow:hidden blocks).
1348 int maxX = scrollWidth() - box->clientWidth();
1349 if (maxX < 0)
1350 maxX = 0;
1351 int maxY = scrollHeight() - box->clientHeight();
1352 if (maxY < 0)
1353 maxY = 0;
1354
1355 if (x > maxX)
1356 x = maxX;
1357 if (y > maxY)
1358 y = maxY;
1359 }
1360
1361 // FIXME: Eventually, we will want to perform a blit. For now never
1362 // blit, since the check for blitting is going to be very
1363 // complicated (since it will involve testing whether our layer
1364 // is either occluded by another layer or clipped by an enclosing
1365 // layer or contains fixed backgrounds, etc.).
1366 int newScrollX = x - m_scrollOrigin.x();
1367 int newScrollY = y - m_scrollOrigin.y();
1368 if (m_scrollY == newScrollY && m_scrollX == newScrollX)
1369 return;
1370 m_scrollX = newScrollX;
1371 m_scrollY = newScrollY;
1372
1373 // Update the positions of our child layers. Don't have updateLayerPositions() update
1374 // compositing layers, because we need to do a deep update from the compositing ancestor.
1375 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
1376 child->updateLayerPositions(0);
1377
1378 RenderView* view = renderer()->view();
1379
1380 // We should have a RenderView if we're trying to scroll.
1381 ASSERT(view);
1382 if (view) {
1383 #if ENABLE(DASHBOARD_SUPPORT)
1384 // Update dashboard regions, scrolling may change the clip of a
1385 // particular region.
1386 view->frameView()->updateDashboardRegions();
1387 #endif
1388
1389 view->updateWidgetPositions();
1390 }
1391
1392 #if USE(ACCELERATED_COMPOSITING)
1393 if (compositor()->inCompositingMode()) {
1394 // Our stacking context is guaranteed to contain all of our descendants that may need
1395 // repositioning, so update compositing layers from there.
1396 if (RenderLayer* compositingAncestor = stackingContext()->enclosingCompositingLayer()) {
1397 if (compositor()->compositingConsultsOverlap())
1398 compositor()->updateCompositingLayers(CompositingUpdateOnScroll, compositingAncestor);
1399 else {
1400 bool isUpdateRoot = true;
1401 compositingAncestor->backing()->updateAfterLayout(RenderLayerBacking::AllDescendants, isUpdateRoot);
1402 }
1403 }
1404 }
1405 #endif
1406
1407 RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint();
1408 IntRect rectForRepaint = renderer()->clippedOverflowRectForRepaint(repaintContainer);
1409
1410 Frame* frame = renderer()->frame();
1411 if (frame) {
1412 // The caret rect needs to be invalidated after scrolling
1413 frame->selection()->setCaretRectNeedsUpdate();
1414
1415 FloatQuad quadForFakeMouseMoveEvent = FloatQuad(rectForRepaint);
1416 if (repaintContainer)
1417 quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent);
1418 frame->eventHandler()->dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent);
1419 }
1420
1421 // Just schedule a full repaint of our object.
1422 if (view)
1423 renderer()->repaintUsingContainer(repaintContainer, rectForRepaint);
1424
1425 // Schedule the scroll DOM event.
1426 renderer()->node()->document()->eventQueue()->enqueueOrDispatchScrollEvent(renderer()->node(), EventQueue::ScrollEventElementTarget);
1427 }
1428
scrollRectToVisible(const IntRect & rect,bool scrollToAnchor,const ScrollAlignment & alignX,const ScrollAlignment & alignY)1429 void RenderLayer::scrollRectToVisible(const IntRect& rect, bool scrollToAnchor, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
1430 {
1431 RenderLayer* parentLayer = 0;
1432 IntRect newRect = rect;
1433 int xOffset = 0, yOffset = 0;
1434
1435 // We may end up propagating a scroll event. It is important that we suspend events until
1436 // the end of the function since they could delete the layer or the layer's renderer().
1437 FrameView* frameView = renderer()->document()->view();
1438 if (frameView)
1439 frameView->pauseScheduledEvents();
1440
1441 bool restrictedByLineClamp = false;
1442 if (renderer()->parent()) {
1443 parentLayer = renderer()->parent()->enclosingLayer();
1444 restrictedByLineClamp = !renderer()->parent()->style()->lineClamp().isNone();
1445 }
1446
1447 if (renderer()->hasOverflowClip() && !restrictedByLineClamp) {
1448 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
1449 // This will prevent us from revealing text hidden by the slider in Safari RSS.
1450 RenderBox* box = renderBox();
1451 ASSERT(box);
1452 FloatPoint absPos = box->localToAbsolute();
1453 absPos.move(box->borderLeft(), box->borderTop());
1454
1455 IntRect layerBounds = IntRect(absPos.x() + scrollXOffset(), absPos.y() + scrollYOffset(), box->clientWidth(), box->clientHeight());
1456 IntRect exposeRect = IntRect(rect.x() + scrollXOffset(), rect.y() + scrollYOffset(), rect.width(), rect.height());
1457 IntRect r = getRectToExpose(layerBounds, exposeRect, alignX, alignY);
1458
1459 xOffset = r.x() - absPos.x();
1460 yOffset = r.y() - absPos.y();
1461 // Adjust offsets if they're outside of the allowable range.
1462 xOffset = max(0, min(scrollWidth() - layerBounds.width(), xOffset));
1463 yOffset = max(0, min(scrollHeight() - layerBounds.height(), yOffset));
1464
1465 if (xOffset != scrollXOffset() || yOffset != scrollYOffset()) {
1466 int diffX = scrollXOffset();
1467 int diffY = scrollYOffset();
1468 scrollToOffset(xOffset, yOffset);
1469 diffX = scrollXOffset() - diffX;
1470 diffY = scrollYOffset() - diffY;
1471 newRect.setX(rect.x() - diffX);
1472 newRect.setY(rect.y() - diffY);
1473 }
1474 } else if (!parentLayer && renderer()->isBox() && renderBox()->canBeProgramaticallyScrolled(scrollToAnchor)) {
1475 if (frameView) {
1476 if (renderer()->document() && renderer()->document()->ownerElement() && renderer()->document()->ownerElement()->renderer()) {
1477 IntRect viewRect = frameView->visibleContentRect();
1478 IntRect r = getRectToExpose(viewRect, rect, alignX, alignY);
1479
1480 xOffset = r.x();
1481 yOffset = r.y();
1482 // Adjust offsets if they're outside of the allowable range.
1483 xOffset = max(0, min(frameView->contentsWidth(), xOffset));
1484 yOffset = max(0, min(frameView->contentsHeight(), yOffset));
1485
1486 frameView->setScrollPosition(IntPoint(xOffset, yOffset));
1487 parentLayer = renderer()->document()->ownerElement()->renderer()->enclosingLayer();
1488 newRect.setX(rect.x() - frameView->scrollX() + frameView->x());
1489 newRect.setY(rect.y() - frameView->scrollY() + frameView->y());
1490 } else {
1491 IntRect viewRect = frameView->visibleContentRect();
1492 IntRect r = getRectToExpose(viewRect, rect, alignX, alignY);
1493
1494 frameView->setScrollPosition(r.location());
1495
1496 // This is the outermost view of a web page, so after scrolling this view we
1497 // scroll its container by calling Page::scrollRectIntoView.
1498 // This only has an effect on the Mac platform in applications
1499 // that put web views into scrolling containers, such as Mac OS X Mail.
1500 // The canAutoscroll function in EventHandler also knows about this.
1501 if (Frame* frame = frameView->frame()) {
1502 if (Page* page = frame->page())
1503 page->chrome()->scrollRectIntoView(rect);
1504 }
1505 }
1506 }
1507 }
1508
1509 if (parentLayer)
1510 parentLayer->scrollRectToVisible(newRect, scrollToAnchor, alignX, alignY);
1511
1512 if (frameView)
1513 frameView->resumeScheduledEvents();
1514 }
1515
getRectToExpose(const IntRect & visibleRect,const IntRect & exposeRect,const ScrollAlignment & alignX,const ScrollAlignment & alignY)1516 IntRect RenderLayer::getRectToExpose(const IntRect &visibleRect, const IntRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
1517 {
1518 // Determine the appropriate X behavior.
1519 ScrollBehavior scrollX;
1520 IntRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
1521 int intersectWidth = intersection(visibleRect, exposeRectX).width();
1522 if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL)
1523 // If the rectangle is fully visible, use the specified visible behavior.
1524 // If the rectangle is partially visible, but over a certain threshold,
1525 // then treat it as fully visible to avoid unnecessary horizontal scrolling
1526 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
1527 else if (intersectWidth == visibleRect.width()) {
1528 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
1529 scrollX = ScrollAlignment::getVisibleBehavior(alignX);
1530 if (scrollX == alignCenter)
1531 scrollX = noScroll;
1532 } else if (intersectWidth > 0)
1533 // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
1534 scrollX = ScrollAlignment::getPartialBehavior(alignX);
1535 else
1536 scrollX = ScrollAlignment::getHiddenBehavior(alignX);
1537 // If we're trying to align to the closest edge, and the exposeRect is further right
1538 // than the visibleRect, and not bigger than the visible area, then align with the right.
1539 if (scrollX == alignToClosestEdge && exposeRect.maxX() > visibleRect.maxX() && exposeRect.width() < visibleRect.width())
1540 scrollX = alignRight;
1541
1542 // Given the X behavior, compute the X coordinate.
1543 int x;
1544 if (scrollX == noScroll)
1545 x = visibleRect.x();
1546 else if (scrollX == alignRight)
1547 x = exposeRect.maxX() - visibleRect.width();
1548 else if (scrollX == alignCenter)
1549 x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2;
1550 else
1551 x = exposeRect.x();
1552
1553 // Determine the appropriate Y behavior.
1554 ScrollBehavior scrollY;
1555 IntRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height());
1556 int intersectHeight = intersection(visibleRect, exposeRectY).height();
1557 if (intersectHeight == exposeRect.height())
1558 // If the rectangle is fully visible, use the specified visible behavior.
1559 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
1560 else if (intersectHeight == visibleRect.height()) {
1561 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
1562 scrollY = ScrollAlignment::getVisibleBehavior(alignY);
1563 if (scrollY == alignCenter)
1564 scrollY = noScroll;
1565 } else if (intersectHeight > 0)
1566 // If the rectangle is partially visible, use the specified partial behavior
1567 scrollY = ScrollAlignment::getPartialBehavior(alignY);
1568 else
1569 scrollY = ScrollAlignment::getHiddenBehavior(alignY);
1570 // If we're trying to align to the closest edge, and the exposeRect is further down
1571 // than the visibleRect, and not bigger than the visible area, then align with the bottom.
1572 if (scrollY == alignToClosestEdge && exposeRect.maxY() > visibleRect.maxY() && exposeRect.height() < visibleRect.height())
1573 scrollY = alignBottom;
1574
1575 // Given the Y behavior, compute the Y coordinate.
1576 int y;
1577 if (scrollY == noScroll)
1578 y = visibleRect.y();
1579 else if (scrollY == alignBottom)
1580 y = exposeRect.maxY() - visibleRect.height();
1581 else if (scrollY == alignCenter)
1582 y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2;
1583 else
1584 y = exposeRect.y();
1585
1586 return IntRect(IntPoint(x, y), visibleRect.size());
1587 }
1588
autoscroll()1589 void RenderLayer::autoscroll()
1590 {
1591 Frame* frame = renderer()->frame();
1592 if (!frame)
1593 return;
1594
1595 FrameView* frameView = frame->view();
1596 if (!frameView)
1597 return;
1598
1599 #if ENABLE(DRAG_SUPPORT)
1600 frame->eventHandler()->updateSelectionForMouseDrag();
1601 #endif
1602
1603 IntPoint currentDocumentPosition = frameView->windowToContents(frame->eventHandler()->currentMousePosition());
1604 scrollRectToVisible(IntRect(currentDocumentPosition, IntSize(1, 1)), false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
1605 }
1606
resize(const PlatformMouseEvent & evt,const IntSize & oldOffset)1607 void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset)
1608 {
1609 // FIXME: This should be possible on generated content but is not right now.
1610 if (!inResizeMode() || !renderer()->hasOverflowClip() || !renderer()->node())
1611 return;
1612
1613 // Set the width and height of the shadow ancestor node if there is one.
1614 // This is necessary for textarea elements since the resizable layer is in the shadow content.
1615 Element* element = static_cast<Element*>(renderer()->node()->shadowAncestorNode());
1616 RenderBox* renderer = toRenderBox(element->renderer());
1617
1618 EResize resize = renderer->style()->resize();
1619 if (resize == RESIZE_NONE)
1620 return;
1621
1622 Document* document = element->document();
1623 if (!document->frame()->eventHandler()->mousePressed())
1624 return;
1625
1626 float zoomFactor = renderer->style()->effectiveZoom();
1627
1628 IntSize newOffset = offsetFromResizeCorner(document->view()->windowToContents(evt.pos()));
1629 newOffset.setWidth(newOffset.width() / zoomFactor);
1630 newOffset.setHeight(newOffset.height() / zoomFactor);
1631
1632 IntSize currentSize = IntSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor);
1633 IntSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize);
1634 element->setMinimumSizeForResizing(minimumSize);
1635
1636 IntSize adjustedOldOffset = IntSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
1637
1638 IntSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize;
1639
1640 CSSStyleDeclaration* style = element->style();
1641 bool isBoxSizingBorder = renderer->style()->boxSizing() == BORDER_BOX;
1642
1643 ExceptionCode ec;
1644
1645 if (resize != RESIZE_VERTICAL && difference.width()) {
1646 if (element->isFormControlElement()) {
1647 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
1648 style->setProperty(CSSPropertyMarginLeft, String::number(renderer->marginLeft() / zoomFactor) + "px", false, ec);
1649 style->setProperty(CSSPropertyMarginRight, String::number(renderer->marginRight() / zoomFactor) + "px", false, ec);
1650 }
1651 int baseWidth = renderer->width() - (isBoxSizingBorder ? 0 : renderer->borderAndPaddingWidth());
1652 baseWidth = baseWidth / zoomFactor;
1653 style->setProperty(CSSPropertyWidth, String::number(baseWidth + difference.width()) + "px", false, ec);
1654 }
1655
1656 if (resize != RESIZE_HORIZONTAL && difference.height()) {
1657 if (element->isFormControlElement()) {
1658 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
1659 style->setProperty(CSSPropertyMarginTop, String::number(renderer->marginTop() / zoomFactor) + "px", false, ec);
1660 style->setProperty(CSSPropertyMarginBottom, String::number(renderer->marginBottom() / zoomFactor) + "px", false, ec);
1661 }
1662 int baseHeight = renderer->height() - (isBoxSizingBorder ? 0 : renderer->borderAndPaddingHeight());
1663 baseHeight = baseHeight / zoomFactor;
1664 style->setProperty(CSSPropertyHeight, String::number(baseHeight + difference.height()) + "px", false, ec);
1665 }
1666
1667 document->updateLayout();
1668
1669 // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
1670 }
1671
scrollSize(ScrollbarOrientation orientation) const1672 int RenderLayer::scrollSize(ScrollbarOrientation orientation) const
1673 {
1674 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_hBar : m_vBar).get();
1675 return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
1676 }
1677
setScrollOffset(const IntPoint & offset)1678 void RenderLayer::setScrollOffset(const IntPoint& offset)
1679 {
1680 scrollTo(offset.x(), offset.y());
1681 }
1682
scrollPosition(Scrollbar * scrollbar) const1683 int RenderLayer::scrollPosition(Scrollbar* scrollbar) const
1684 {
1685 if (scrollbar->orientation() == HorizontalScrollbar)
1686 return scrollXOffset();
1687 if (scrollbar->orientation() == VerticalScrollbar)
1688 return scrollYOffset();
1689 return 0;
1690 }
1691
isActive() const1692 bool RenderLayer::isActive() const
1693 {
1694 Page* page = renderer()->frame()->page();
1695 return page && page->focusController()->isActive();
1696 }
1697
cornerRect(const RenderLayer * layer,const IntRect & bounds)1698 static IntRect cornerRect(const RenderLayer* layer, const IntRect& bounds)
1699 {
1700 int horizontalThickness;
1701 int verticalThickness;
1702 if (!layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
1703 // FIXME: This isn't right. We need to know the thickness of custom scrollbars
1704 // even when they don't exist in order to set the resizer square size properly.
1705 horizontalThickness = ScrollbarTheme::nativeTheme()->scrollbarThickness();
1706 verticalThickness = horizontalThickness;
1707 } else if (layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
1708 horizontalThickness = layer->verticalScrollbar()->width();
1709 verticalThickness = horizontalThickness;
1710 } else if (layer->horizontalScrollbar() && !layer->verticalScrollbar()) {
1711 verticalThickness = layer->horizontalScrollbar()->height();
1712 horizontalThickness = verticalThickness;
1713 } else {
1714 horizontalThickness = layer->verticalScrollbar()->width();
1715 verticalThickness = layer->horizontalScrollbar()->height();
1716 }
1717 return IntRect(bounds.maxX() - horizontalThickness - layer->renderer()->style()->borderRightWidth(),
1718 bounds.maxY() - verticalThickness - layer->renderer()->style()->borderBottomWidth(),
1719 horizontalThickness, verticalThickness);
1720 }
1721
scrollCornerRect() const1722 IntRect RenderLayer::scrollCornerRect() const
1723 {
1724 // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box.
1725 // This happens when:
1726 // (a) A resizer is present and at least one scrollbar is present
1727 // (b) Both scrollbars are present.
1728 bool hasHorizontalBar = horizontalScrollbar();
1729 bool hasVerticalBar = verticalScrollbar();
1730 bool hasResizer = renderer()->style()->resize() != RESIZE_NONE;
1731 if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
1732 return cornerRect(this, renderBox()->borderBoxRect());
1733 return IntRect();
1734 }
1735
resizerCornerRect(const RenderLayer * layer,const IntRect & bounds)1736 static IntRect resizerCornerRect(const RenderLayer* layer, const IntRect& bounds)
1737 {
1738 ASSERT(layer->renderer()->isBox());
1739 if (layer->renderer()->style()->resize() == RESIZE_NONE)
1740 return IntRect();
1741 return cornerRect(layer, bounds);
1742 }
1743
scrollCornerAndResizerRect() const1744 IntRect RenderLayer::scrollCornerAndResizerRect() const
1745 {
1746 RenderBox* box = renderBox();
1747 if (!box)
1748 return IntRect();
1749 IntRect scrollCornerAndResizer = scrollCornerRect();
1750 if (scrollCornerAndResizer.isEmpty())
1751 scrollCornerAndResizer = resizerCornerRect(this, box->borderBoxRect());
1752 return scrollCornerAndResizer;
1753 }
1754
isScrollCornerVisible() const1755 bool RenderLayer::isScrollCornerVisible() const
1756 {
1757 ASSERT(renderer()->isBox());
1758 return !scrollCornerRect().isEmpty();
1759 }
1760
convertFromScrollbarToContainingView(const Scrollbar * scrollbar,const IntRect & scrollbarRect) const1761 IntRect RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& scrollbarRect) const
1762 {
1763 RenderView* view = renderer()->view();
1764 if (!view)
1765 return scrollbarRect;
1766
1767 IntRect rect = scrollbarRect;
1768 rect.move(scrollbarOffset(scrollbar));
1769
1770 return view->frameView()->convertFromRenderer(renderer(), rect);
1771 }
1772
convertFromContainingViewToScrollbar(const Scrollbar * scrollbar,const IntRect & parentRect) const1773 IntRect RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
1774 {
1775 RenderView* view = renderer()->view();
1776 if (!view)
1777 return parentRect;
1778
1779 IntRect rect = view->frameView()->convertToRenderer(renderer(), parentRect);
1780 rect.move(-scrollbarOffset(scrollbar));
1781 return rect;
1782 }
1783
convertFromScrollbarToContainingView(const Scrollbar * scrollbar,const IntPoint & scrollbarPoint) const1784 IntPoint RenderLayer::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const
1785 {
1786 RenderView* view = renderer()->view();
1787 if (!view)
1788 return scrollbarPoint;
1789
1790 IntPoint point = scrollbarPoint;
1791 point.move(scrollbarOffset(scrollbar));
1792 return view->frameView()->convertFromRenderer(renderer(), point);
1793 }
1794
convertFromContainingViewToScrollbar(const Scrollbar * scrollbar,const IntPoint & parentPoint) const1795 IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
1796 {
1797 RenderView* view = renderer()->view();
1798 if (!view)
1799 return parentPoint;
1800
1801 IntPoint point = view->frameView()->convertToRenderer(renderer(), parentPoint);
1802
1803 point.move(-scrollbarOffset(scrollbar));
1804 return point;
1805 }
1806
contentsSize() const1807 IntSize RenderLayer::contentsSize() const
1808 {
1809 return IntSize(const_cast<RenderLayer*>(this)->scrollWidth(), const_cast<RenderLayer*>(this)->scrollHeight());
1810 }
1811
visibleHeight() const1812 int RenderLayer::visibleHeight() const
1813 {
1814 return m_height;
1815 }
1816
visibleWidth() const1817 int RenderLayer::visibleWidth() const
1818 {
1819 return m_width;
1820 }
1821
shouldSuspendScrollAnimations() const1822 bool RenderLayer::shouldSuspendScrollAnimations() const
1823 {
1824 RenderView* view = renderer()->view();
1825 if (!view)
1826 return true;
1827 return view->frameView()->shouldSuspendScrollAnimations();
1828 }
1829
currentMousePosition() const1830 IntPoint RenderLayer::currentMousePosition() const
1831 {
1832 return renderer()->frame() ? renderer()->frame()->eventHandler()->currentMousePosition() : IntPoint();
1833 }
1834
scrollbarOffset(const Scrollbar * scrollbar) const1835 IntSize RenderLayer::scrollbarOffset(const Scrollbar* scrollbar) const
1836 {
1837 RenderBox* box = renderBox();
1838
1839 if (scrollbar == m_vBar.get())
1840 return IntSize(box->width() - box->borderRight() - scrollbar->width(), box->borderTop());
1841
1842 if (scrollbar == m_hBar.get())
1843 return IntSize(box->borderLeft(), box->height() - box->borderBottom() - scrollbar->height());
1844
1845 ASSERT_NOT_REACHED();
1846 return IntSize();
1847 }
1848
invalidateScrollbarRect(Scrollbar * scrollbar,const IntRect & rect)1849 void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
1850 {
1851 #if USE(ACCELERATED_COMPOSITING)
1852 if (scrollbar == m_vBar.get()) {
1853 if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
1854 layer->setNeedsDisplayInRect(rect);
1855 return;
1856 }
1857 } else {
1858 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
1859 layer->setNeedsDisplayInRect(rect);
1860 return;
1861 }
1862 }
1863 #endif
1864 IntRect scrollRect = rect;
1865 RenderBox* box = renderBox();
1866 ASSERT(box);
1867 if (scrollbar == m_vBar.get())
1868 scrollRect.move(box->width() - box->borderRight() - scrollbar->width(), box->borderTop());
1869 else
1870 scrollRect.move(box->borderLeft(), box->height() - box->borderBottom() - scrollbar->height());
1871 renderer()->repaintRectangle(scrollRect);
1872 }
1873
invalidateScrollCornerRect(const IntRect & rect)1874 void RenderLayer::invalidateScrollCornerRect(const IntRect& rect)
1875 {
1876 #if USE(ACCELERATED_COMPOSITING)
1877 if (GraphicsLayer* layer = layerForScrollCorner()) {
1878 layer->setNeedsDisplayInRect(rect);
1879 return;
1880 }
1881 #endif
1882 if (m_scrollCorner)
1883 m_scrollCorner->repaintRectangle(rect);
1884 if (m_resizer)
1885 m_resizer->repaintRectangle(rect);
1886 }
1887
createScrollbar(ScrollbarOrientation orientation)1888 PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
1889 {
1890 RefPtr<Scrollbar> widget;
1891 RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
1892 bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR);
1893 if (hasCustomScrollbarStyle)
1894 widget = RenderScrollbar::createCustomScrollbar(this, orientation, toRenderBox(actualRenderer));
1895 else {
1896 widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
1897 if (orientation == HorizontalScrollbar)
1898 didAddHorizontalScrollbar(widget.get());
1899 else
1900 didAddVerticalScrollbar(widget.get());
1901 }
1902 renderer()->document()->view()->addChild(widget.get());
1903 return widget.release();
1904 }
1905
destroyScrollbar(ScrollbarOrientation orientation)1906 void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
1907 {
1908 RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar;
1909 if (scrollbar) {
1910 if (scrollbar->isCustomScrollbar())
1911 static_cast<RenderScrollbar*>(scrollbar.get())->clearOwningRenderer();
1912 else {
1913 if (orientation == HorizontalScrollbar)
1914 willRemoveHorizontalScrollbar(scrollbar.get());
1915 else
1916 willRemoveVerticalScrollbar(scrollbar.get());
1917 }
1918
1919 scrollbar->removeFromParent();
1920 scrollbar->disconnectFromScrollableArea();
1921 scrollbar = 0;
1922 }
1923 }
1924
setHasHorizontalScrollbar(bool hasScrollbar)1925 void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
1926 {
1927 if (hasScrollbar == (m_hBar != 0))
1928 return;
1929
1930 if (hasScrollbar)
1931 m_hBar = createScrollbar(HorizontalScrollbar);
1932 else
1933 destroyScrollbar(HorizontalScrollbar);
1934
1935 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
1936 if (m_hBar)
1937 m_hBar->styleChanged();
1938 if (m_vBar)
1939 m_vBar->styleChanged();
1940
1941 #if ENABLE(DASHBOARD_SUPPORT)
1942 // Force an update since we know the scrollbars have changed things.
1943 if (renderer()->document()->hasDashboardRegions())
1944 renderer()->document()->setDashboardRegionsDirty(true);
1945 #endif
1946 }
1947
setHasVerticalScrollbar(bool hasScrollbar)1948 void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
1949 {
1950 if (hasScrollbar == (m_vBar != 0))
1951 return;
1952
1953 if (hasScrollbar)
1954 m_vBar = createScrollbar(VerticalScrollbar);
1955 else
1956 destroyScrollbar(VerticalScrollbar);
1957
1958 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
1959 if (m_hBar)
1960 m_hBar->styleChanged();
1961 if (m_vBar)
1962 m_vBar->styleChanged();
1963
1964 #if ENABLE(DASHBOARD_SUPPORT)
1965 // Force an update since we know the scrollbars have changed things.
1966 if (renderer()->document()->hasDashboardRegions())
1967 renderer()->document()->setDashboardRegionsDirty(true);
1968 #endif
1969 }
1970
verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const1971 int RenderLayer::verticalScrollbarWidth(OverlayScrollbarSizeRelevancy relevancy) const
1972 {
1973 if (!m_vBar || (m_vBar->isOverlayScrollbar() && relevancy == IgnoreOverlayScrollbarSize))
1974 return 0;
1975 return m_vBar->width();
1976 }
1977
horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const1978 int RenderLayer::horizontalScrollbarHeight(OverlayScrollbarSizeRelevancy relevancy) const
1979 {
1980 if (!m_hBar || (m_hBar->isOverlayScrollbar() && relevancy == IgnoreOverlayScrollbarSize))
1981 return 0;
1982 return m_hBar->height();
1983 }
1984
offsetFromResizeCorner(const IntPoint & absolutePoint) const1985 IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const
1986 {
1987 // Currently the resize corner is always the bottom right corner
1988 IntPoint bottomRight(width(), height());
1989 IntPoint localPoint = absoluteToContents(absolutePoint);
1990 return localPoint - bottomRight;
1991 }
1992
hasOverflowControls() const1993 bool RenderLayer::hasOverflowControls() const
1994 {
1995 return m_hBar || m_vBar || m_scrollCorner || renderer()->style()->resize() != RESIZE_NONE;
1996 }
1997 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
hasOverflowParent() const1998 bool RenderLayer::hasOverflowParent() const
1999 {
2000 const RenderLayer* layer = this;
2001 while (layer && !layer->hasOverflowScroll())
2002 layer = layer->parent();
2003 return layer;
2004 }
2005 #endif
2006
positionOverflowControls(int tx,int ty)2007 void RenderLayer::positionOverflowControls(int tx, int ty)
2008 {
2009 if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
2010 return;
2011
2012 RenderBox* box = renderBox();
2013 if (!box)
2014 return;
2015
2016 const IntRect& borderBox = box->borderBoxRect();
2017 const IntRect& scrollCorner = scrollCornerRect();
2018 IntRect absBounds(borderBox.x() + tx, borderBox.y() + ty, borderBox.width(), borderBox.height());
2019 if (m_vBar)
2020 m_vBar->setFrameRect(IntRect(absBounds.maxX() - box->borderRight() - m_vBar->width(),
2021 absBounds.y() + box->borderTop(),
2022 m_vBar->width(),
2023 absBounds.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height()));
2024
2025 if (m_hBar)
2026 m_hBar->setFrameRect(IntRect(absBounds.x() + box->borderLeft(),
2027 absBounds.maxY() - box->borderBottom() - m_hBar->height(),
2028 absBounds.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(),
2029 m_hBar->height()));
2030
2031 #if USE(ACCELERATED_COMPOSITING)
2032 if (GraphicsLayer* layer = layerForHorizontalScrollbar()) {
2033 if (m_hBar) {
2034 layer->setPosition(IntPoint(m_hBar->frameRect().x() - tx, m_hBar->frameRect().y() - ty));
2035 layer->setSize(m_hBar->frameRect().size());
2036 }
2037 layer->setDrawsContent(m_hBar);
2038 }
2039 if (GraphicsLayer* layer = layerForVerticalScrollbar()) {
2040 if (m_vBar) {
2041 layer->setPosition(IntPoint(m_vBar->frameRect().x() - tx, m_vBar->frameRect().y() - ty));
2042 layer->setSize(m_vBar->frameRect().size());
2043 }
2044 layer->setDrawsContent(m_vBar);
2045 }
2046
2047 if (GraphicsLayer* layer = layerForScrollCorner()) {
2048 const IntRect& scrollCornerAndResizer = scrollCornerAndResizerRect();
2049 layer->setPosition(scrollCornerAndResizer.location());
2050 layer->setSize(scrollCornerAndResizer.size());
2051 layer->setDrawsContent(!scrollCornerAndResizer.isEmpty());
2052 }
2053 #endif
2054
2055 if (m_scrollCorner)
2056 m_scrollCorner->setFrameRect(scrollCorner);
2057 if (m_resizer)
2058 m_resizer->setFrameRect(resizerCornerRect(this, borderBox));
2059 }
2060
2061 #if PLATFORM(ANDROID)
2062 // When width/height change, the scrollWidth/scrollHeight should be dirty.
2063 // And this should be upstreamed to webkit.
setWidth(int w)2064 void RenderLayer::setWidth(int w)
2065 {
2066 if (m_width != w) {
2067 m_scrollDimensionsDirty = true;
2068 m_width = w;
2069 }
2070 }
2071
setHeight(int h)2072 void RenderLayer::setHeight(int h)
2073 {
2074 if (m_height != h) {
2075 m_scrollDimensionsDirty = true;
2076 m_height = h;
2077 }
2078 }
2079 #endif
2080
scrollWidth()2081 int RenderLayer::scrollWidth()
2082 {
2083 if (m_scrollDimensionsDirty)
2084 computeScrollDimensions();
2085 return m_scrollWidth;
2086 }
2087
scrollHeight()2088 int RenderLayer::scrollHeight()
2089 {
2090 if (m_scrollDimensionsDirty)
2091 computeScrollDimensions();
2092 return m_scrollHeight;
2093 }
2094
overflowTop() const2095 int RenderLayer::overflowTop() const
2096 {
2097 RenderBox* box = renderBox();
2098 IntRect overflowRect(box->layoutOverflowRect());
2099 box->flipForWritingMode(overflowRect);
2100 return overflowRect.y();
2101 }
2102
overflowBottom() const2103 int RenderLayer::overflowBottom() const
2104 {
2105 RenderBox* box = renderBox();
2106 IntRect overflowRect(box->layoutOverflowRect());
2107 box->flipForWritingMode(overflowRect);
2108 return overflowRect.maxY();
2109 }
2110
overflowLeft() const2111 int RenderLayer::overflowLeft() const
2112 {
2113 RenderBox* box = renderBox();
2114 IntRect overflowRect(box->layoutOverflowRect());
2115 box->flipForWritingMode(overflowRect);
2116 return overflowRect.x();
2117 }
2118
overflowRight() const2119 int RenderLayer::overflowRight() const
2120 {
2121 RenderBox* box = renderBox();
2122 IntRect overflowRect(box->layoutOverflowRect());
2123 box->flipForWritingMode(overflowRect);
2124 return overflowRect.maxX();
2125 }
2126
computeScrollDimensions(bool * needHBar,bool * needVBar)2127 void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar)
2128 {
2129 RenderBox* box = renderBox();
2130 ASSERT(box);
2131
2132 m_scrollDimensionsDirty = false;
2133
2134 m_scrollLeftOverflow = overflowLeft() - box->borderLeft();
2135 m_scrollTopOverflow = overflowTop() - box->borderTop();
2136
2137 m_scrollWidth = overflowRight() - overflowLeft();
2138 m_scrollHeight = overflowBottom() - overflowTop();
2139
2140 m_scrollOrigin = IntPoint(-m_scrollLeftOverflow, -m_scrollTopOverflow);
2141
2142 if (needHBar)
2143 *needHBar = m_scrollWidth > box->clientWidth();
2144 if (needVBar)
2145 *needVBar = m_scrollHeight > box->clientHeight();
2146 }
2147
updateOverflowStatus(bool horizontalOverflow,bool verticalOverflow)2148 void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
2149 {
2150 if (m_overflowStatusDirty) {
2151 m_horizontalOverflow = horizontalOverflow;
2152 m_verticalOverflow = verticalOverflow;
2153 m_overflowStatusDirty = false;
2154 return;
2155 }
2156
2157 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
2158 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
2159
2160 if (horizontalOverflowChanged || verticalOverflowChanged) {
2161 m_horizontalOverflow = horizontalOverflow;
2162 m_verticalOverflow = verticalOverflow;
2163
2164 if (FrameView* frameView = renderer()->document()->view()) {
2165 frameView->scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow),
2166 renderer()->node());
2167 }
2168 }
2169 }
2170
updateScrollInfoAfterLayout()2171 void RenderLayer::updateScrollInfoAfterLayout()
2172 {
2173 RenderBox* box = renderBox();
2174 if (!box)
2175 return;
2176
2177 m_scrollDimensionsDirty = true;
2178
2179 bool horizontalOverflow, verticalOverflow;
2180 computeScrollDimensions(&horizontalOverflow, &verticalOverflow);
2181
2182 if (box->style()->overflowX() != OMARQUEE) {
2183 // Layout may cause us to be in an invalid scroll position. In this case we need
2184 // to pull our scroll offsets back to the max (or push them up to the min).
2185 int newX = max(0, min(scrollXOffset(), scrollWidth() - box->clientWidth()));
2186 int newY = max(0, min(scrollYOffset(), scrollHeight() - box->clientHeight()));
2187 if (newX != scrollXOffset() || newY != scrollYOffset()) {
2188 RenderView* view = renderer()->view();
2189 ASSERT(view);
2190 // scrollToOffset() may call updateLayerPositions(), which doesn't work
2191 // with LayoutState.
2192 // FIXME: Remove the disableLayoutState/enableLayoutState if the above changes.
2193 if (view)
2194 view->disableLayoutState();
2195 scrollToOffset(newX, newY);
2196 if (view)
2197 view->enableLayoutState();
2198 }
2199 }
2200
2201 bool haveHorizontalBar = m_hBar;
2202 bool haveVerticalBar = m_vBar;
2203
2204 // overflow:scroll should just enable/disable.
2205 if (renderer()->style()->overflowX() == OSCROLL)
2206 m_hBar->setEnabled(horizontalOverflow);
2207 if (renderer()->style()->overflowY() == OSCROLL)
2208 m_vBar->setEnabled(verticalOverflow);
2209
2210 // A dynamic change from a scrolling overflow to overflow:hidden means we need to get rid of any
2211 // scrollbars that may be present.
2212 if (renderer()->style()->overflowX() == OHIDDEN && haveHorizontalBar)
2213 setHasHorizontalScrollbar(false);
2214 if (renderer()->style()->overflowY() == OHIDDEN && haveVerticalBar)
2215 setHasVerticalScrollbar(false);
2216
2217 // overflow:auto may need to lay out again if scrollbars got added/removed.
2218 bool scrollbarsChanged = (box->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) ||
2219 (box->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow);
2220 if (scrollbarsChanged) {
2221 if (box->hasAutoHorizontalScrollbar())
2222 setHasHorizontalScrollbar(horizontalOverflow);
2223 if (box->hasAutoVerticalScrollbar())
2224 setHasVerticalScrollbar(verticalOverflow);
2225
2226 #if ENABLE(DASHBOARD_SUPPORT)
2227 // Force an update since we know the scrollbars have changed things.
2228 if (renderer()->document()->hasDashboardRegions())
2229 renderer()->document()->setDashboardRegionsDirty(true);
2230 #endif
2231
2232 renderer()->repaint();
2233
2234 if (renderer()->style()->overflowX() == OAUTO || renderer()->style()->overflowY() == OAUTO) {
2235 if (!m_inOverflowRelayout) {
2236 // Our proprietary overflow: overlay value doesn't trigger a layout.
2237 m_inOverflowRelayout = true;
2238 renderer()->setNeedsLayout(true, false);
2239 if (renderer()->isRenderBlock()) {
2240 RenderBlock* block = toRenderBlock(renderer());
2241 block->scrollbarsChanged(box->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow,
2242 box->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow);
2243 block->layoutBlock(true);
2244 } else
2245 renderer()->layout();
2246 m_inOverflowRelayout = false;
2247 }
2248 }
2249 }
2250
2251 // If overflow:scroll is turned into overflow:auto a bar might still be disabled (Bug 11985).
2252 if (m_hBar && box->hasAutoHorizontalScrollbar())
2253 m_hBar->setEnabled(true);
2254 if (m_vBar && box->hasAutoVerticalScrollbar())
2255 m_vBar->setEnabled(true);
2256
2257 // Set up the range (and page step/line step).
2258 if (m_hBar) {
2259 int clientWidth = box->clientWidth();
2260 int pageStep = max(max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
2261 m_hBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
2262 m_hBar->setProportion(clientWidth, m_scrollWidth);
2263 }
2264 if (m_vBar) {
2265 int clientHeight = box->clientHeight();
2266 int pageStep = max(max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
2267 m_vBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
2268 m_vBar->setProportion(clientHeight, m_scrollHeight);
2269 }
2270
2271 RenderView* view = renderer()->view();
2272 view->disableLayoutState();
2273 scrollToOffset(scrollXOffset(), scrollYOffset());
2274 view->enableLayoutState();
2275
2276 if (renderer()->node() && renderer()->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
2277 updateOverflowStatus(horizontalOverflow, verticalOverflow);
2278
2279 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
2280 bool hasOverflowScroll = ((horizontalOverflow && m_hBar) || (verticalOverflow && m_vBar));
2281 if (hasOverflowScroll) {
2282 // Disable UI side scrolling for non-readonly textareas.
2283 if (renderer()->isTextArea() && (!renderer()->node()
2284 || !static_cast<HTMLTextAreaElement*>(renderer()->node())->readOnly()))
2285 hasOverflowScroll = false;
2286 }
2287 if (hasOverflowScroll != m_hasOverflowScroll) {
2288 m_hasOverflowScroll = hasOverflowScroll;
2289 dirtyZOrderLists();
2290 dirtyStackingContextZOrderLists();
2291 if (renderer()->node())
2292 renderer()->node()->setNeedsStyleRecalc(SyntheticStyleChange);
2293 }
2294 #endif
2295 }
2296
paintOverflowControls(GraphicsContext * context,int tx,int ty,const IntRect & damageRect,bool paintingOverlayControls)2297 void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty, const IntRect& damageRect, bool paintingOverlayControls)
2298 {
2299 // Don't do anything if we have no overflow.
2300 if (!renderer()->hasOverflowClip())
2301 return;
2302
2303 // Overlay scrollbars paint in a second pass through the layer tree so that they will paint
2304 // on top of everything else. If this is the normal painting pass, paintingOverlayControls
2305 // will be false, and we should just tell the root layer that there are overlay scrollbars
2306 // that need to be painted. That will cause the second pass through the layer tree to run,
2307 // and we'll paint the scrollbars then. In the meantime, cache tx and ty so that the
2308 // second pass doesn't need to re-enter the RenderTree to get it right.
2309 if (hasOverlayScrollbars() && !paintingOverlayControls) {
2310 RenderView* renderView = renderer()->view();
2311 renderView->layer()->setContainsDirtyOverlayScrollbars(true);
2312 m_cachedOverlayScrollbarOffset = IntPoint(tx, ty);
2313 renderView->frameView()->setContainsScrollableAreaWithOverlayScrollbars(true);
2314 return;
2315 }
2316
2317 int offsetX = tx;
2318 int offsetY = ty;
2319 if (paintingOverlayControls) {
2320 offsetX = m_cachedOverlayScrollbarOffset.x();
2321 offsetY = m_cachedOverlayScrollbarOffset.y();
2322 }
2323
2324 // Move the scrollbar widgets if necessary. We normally move and resize widgets during layout, but sometimes
2325 // widgets can move without layout occurring (most notably when you scroll a document that
2326 // contains fixed positioned elements).
2327 positionOverflowControls(offsetX, offsetY);
2328
2329 // Now that we're sure the scrollbars are in the right place, paint them.
2330 if (m_hBar
2331 #if USE(ACCELERATED_COMPOSITING)
2332 && !layerForHorizontalScrollbar()
2333 #endif
2334 )
2335 m_hBar->paint(context, damageRect);
2336 if (m_vBar
2337 #if USE(ACCELERATED_COMPOSITING)
2338 && !layerForVerticalScrollbar()
2339 #endif
2340 )
2341 m_vBar->paint(context, damageRect);
2342
2343 #if USE(ACCELERATED_COMPOSITING)
2344 if (layerForScrollCorner())
2345 return;
2346 #endif
2347
2348 // We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the
2349 // edge of the box.
2350 paintScrollCorner(context, offsetX, offsetY, damageRect);
2351
2352 // Paint our resizer last, since it sits on top of the scroll corner.
2353 paintResizer(context, offsetX, offsetY, damageRect);
2354 }
2355
paintScrollCorner(GraphicsContext * context,int tx,int ty,const IntRect & damageRect)2356 void RenderLayer::paintScrollCorner(GraphicsContext* context, int tx, int ty, const IntRect& damageRect)
2357 {
2358 RenderBox* box = renderBox();
2359 ASSERT(box);
2360
2361 IntRect cornerRect = scrollCornerRect();
2362 IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height());
2363 if (!absRect.intersects(damageRect))
2364 return;
2365
2366 if (context->updatingControlTints()) {
2367 updateScrollCornerStyle();
2368 return;
2369 }
2370
2371 if (m_scrollCorner) {
2372 m_scrollCorner->paintIntoRect(context, tx, ty, absRect);
2373 return;
2374 }
2375
2376 // We don't want to paint white if we have overlay scrollbars, since we need
2377 // to see what is behind it.
2378 if (!hasOverlayScrollbars())
2379 context->fillRect(absRect, Color::white, box->style()->colorSpace());
2380 }
2381
paintResizer(GraphicsContext * context,int tx,int ty,const IntRect & damageRect)2382 void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const IntRect& damageRect)
2383 {
2384 if (renderer()->style()->resize() == RESIZE_NONE)
2385 return;
2386
2387 RenderBox* box = renderBox();
2388 ASSERT(box);
2389
2390 IntRect cornerRect = resizerCornerRect(this, box->borderBoxRect());
2391 IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height());
2392 if (!absRect.intersects(damageRect))
2393 return;
2394
2395 if (context->updatingControlTints()) {
2396 updateResizerStyle();
2397 return;
2398 }
2399
2400 if (m_resizer) {
2401 m_resizer->paintIntoRect(context, tx, ty, absRect);
2402 return;
2403 }
2404
2405 // Paint the resizer control.
2406 DEFINE_STATIC_LOCAL(RefPtr<Image>, resizeCornerImage, (Image::loadPlatformResource("textAreaResizeCorner")));
2407 IntPoint imagePoint(absRect.maxX() - resizeCornerImage->width(), absRect.maxY() - resizeCornerImage->height());
2408 context->drawImage(resizeCornerImage.get(), box->style()->colorSpace(), imagePoint);
2409
2410 // Draw a frame around the resizer (1px grey line) if there are any scrollbars present.
2411 // Clipping will exclude the right and bottom edges of this frame.
2412 if (!hasOverlayScrollbars() && (m_vBar || m_hBar)) {
2413 context->save();
2414 context->clip(absRect);
2415 IntRect largerCorner = absRect;
2416 largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1));
2417 context->setStrokeColor(Color(makeRGB(217, 217, 217)), ColorSpaceDeviceRGB);
2418 context->setStrokeThickness(1.0f);
2419 context->setFillColor(Color::transparent, ColorSpaceDeviceRGB);
2420 context->drawRect(largerCorner);
2421 context->restore();
2422 }
2423 }
2424
isPointInResizeControl(const IntPoint & absolutePoint) const2425 bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const
2426 {
2427 if (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)
2428 return false;
2429
2430 RenderBox* box = renderBox();
2431 ASSERT(box);
2432
2433 IntPoint localPoint = absoluteToContents(absolutePoint);
2434
2435 IntRect localBounds(0, 0, box->width(), box->height());
2436 return resizerCornerRect(this, localBounds).contains(localPoint);
2437 }
2438
hitTestOverflowControls(HitTestResult & result,const IntPoint & localPoint)2439 bool RenderLayer::hitTestOverflowControls(HitTestResult& result, const IntPoint& localPoint)
2440 {
2441 if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
2442 return false;
2443
2444 RenderBox* box = renderBox();
2445 ASSERT(box);
2446
2447 IntRect resizeControlRect;
2448 if (renderer()->style()->resize() != RESIZE_NONE) {
2449 resizeControlRect = resizerCornerRect(this, box->borderBoxRect());
2450 if (resizeControlRect.contains(localPoint))
2451 return true;
2452 }
2453
2454 int resizeControlSize = max(resizeControlRect.height(), 0);
2455
2456 if (m_vBar) {
2457 IntRect vBarRect(box->width() - box->borderRight() - m_vBar->width(),
2458 box->borderTop(),
2459 m_vBar->width(),
2460 box->height() - (box->borderTop() + box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
2461 if (vBarRect.contains(localPoint)) {
2462 result.setScrollbar(m_vBar.get());
2463 return true;
2464 }
2465 }
2466
2467 resizeControlSize = max(resizeControlRect.width(), 0);
2468 if (m_hBar) {
2469 IntRect hBarRect(box->borderLeft(),
2470 box->height() - box->borderBottom() - m_hBar->height(),
2471 box->width() - (box->borderLeft() + box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize),
2472 m_hBar->height());
2473 if (hBarRect.contains(localPoint)) {
2474 result.setScrollbar(m_hBar.get());
2475 return true;
2476 }
2477 }
2478
2479 return false;
2480 }
2481
scroll(ScrollDirection direction,ScrollGranularity granularity,float multiplier)2482 bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
2483 {
2484 return ScrollableArea::scroll(direction, granularity, multiplier);
2485 }
2486
paint(GraphicsContext * p,const IntRect & damageRect,PaintBehavior paintBehavior,RenderObject * paintingRoot)2487 void RenderLayer::paint(GraphicsContext* p, const IntRect& damageRect, PaintBehavior paintBehavior, RenderObject *paintingRoot)
2488 {
2489 OverlapTestRequestMap overlapTestRequests;
2490 paintLayer(this, p, damageRect, paintBehavior, paintingRoot, &overlapTestRequests);
2491 OverlapTestRequestMap::iterator end = overlapTestRequests.end();
2492 for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it)
2493 it->first->setOverlapTestResult(false);
2494 }
2495
paintOverlayScrollbars(GraphicsContext * p,const IntRect & damageRect,PaintBehavior paintBehavior,RenderObject * paintingRoot)2496 void RenderLayer::paintOverlayScrollbars(GraphicsContext* p, const IntRect& damageRect, PaintBehavior paintBehavior, RenderObject *paintingRoot)
2497 {
2498 if (!m_containsDirtyOverlayScrollbars)
2499 return;
2500 paintLayer(this, p, damageRect, paintBehavior, paintingRoot, 0, PaintLayerHaveTransparency | PaintLayerTemporaryClipRects
2501 | PaintLayerPaintingOverlayScrollbars);
2502 m_containsDirtyOverlayScrollbars = false;
2503 }
2504
setClip(GraphicsContext * p,const IntRect & paintDirtyRect,const IntRect & clipRect)2505 static void setClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect)
2506 {
2507 if (paintDirtyRect == clipRect)
2508 return;
2509 p->save();
2510 p->clip(clipRect);
2511 }
2512
restoreClip(GraphicsContext * p,const IntRect & paintDirtyRect,const IntRect & clipRect)2513 static void restoreClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect)
2514 {
2515 if (paintDirtyRect == clipRect)
2516 return;
2517 p->restore();
2518 }
2519
performOverlapTests(OverlapTestRequestMap & overlapTestRequests,const RenderLayer * rootLayer,const RenderLayer * layer)2520 static void performOverlapTests(OverlapTestRequestMap& overlapTestRequests, const RenderLayer* rootLayer, const RenderLayer* layer)
2521 {
2522 Vector<OverlapTestRequestClient*> overlappedRequestClients;
2523 OverlapTestRequestMap::iterator end = overlapTestRequests.end();
2524 IntRect boundingBox = layer->boundingBox(rootLayer);
2525 for (OverlapTestRequestMap::iterator it = overlapTestRequests.begin(); it != end; ++it) {
2526 if (!boundingBox.intersects(it->second))
2527 continue;
2528
2529 it->first->setOverlapTestResult(true);
2530 overlappedRequestClients.append(it->first);
2531 }
2532 for (size_t i = 0; i < overlappedRequestClients.size(); ++i)
2533 overlapTestRequests.remove(overlappedRequestClients[i]);
2534 }
2535
2536 #if USE(ACCELERATED_COMPOSITING)
shouldDoSoftwarePaint(const RenderLayer * layer,bool paintingReflection)2537 static bool shouldDoSoftwarePaint(const RenderLayer* layer, bool paintingReflection)
2538 {
2539 return paintingReflection && !layer->has3DTransform();
2540 }
2541 #endif
2542
paintLayer(RenderLayer * rootLayer,GraphicsContext * p,const IntRect & paintDirtyRect,PaintBehavior paintBehavior,RenderObject * paintingRoot,OverlapTestRequestMap * overlapTestRequests,PaintLayerFlags paintFlags)2543 void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
2544 const IntRect& paintDirtyRect, PaintBehavior paintBehavior,
2545 RenderObject* paintingRoot, OverlapTestRequestMap* overlapTestRequests,
2546 PaintLayerFlags paintFlags)
2547 {
2548 #if USE(ACCELERATED_COMPOSITING)
2549 if (isComposited()) {
2550 // The updatingControlTints() painting pass goes through compositing layers,
2551 // but we need to ensure that we don't cache clip rects computed with the wrong root in this case.
2552 if (p->updatingControlTints() || (paintBehavior & PaintBehaviorFlattenCompositingLayers))
2553 paintFlags |= PaintLayerTemporaryClipRects;
2554 else if (!backing()->paintingGoesToWindow() && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection)) {
2555 // If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer().
2556 return;
2557 }
2558 }
2559 #endif
2560
2561 // Avoid painting layers when stylesheets haven't loaded. This eliminates FOUC.
2562 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
2563 // will do a full repaint().
2564 if (renderer()->document()->didLayoutWithPendingStylesheets() && !renderer()->isRenderView() && !renderer()->isRoot())
2565 return;
2566
2567 // If this layer is totally invisible then there is nothing to paint.
2568 if (!renderer()->opacity())
2569 return;
2570
2571 if (paintsWithTransparency(paintBehavior))
2572 paintFlags |= PaintLayerHaveTransparency;
2573
2574 // Apply a transform if we have one. A reflection is considered to be a transform, since it is a flip and a translate.
2575 if (paintsWithTransform(paintBehavior) && !(paintFlags & PaintLayerAppliedTransform)) {
2576 TransformationMatrix layerTransform = renderableTransform(paintBehavior);
2577 // If the transform can't be inverted, then don't paint anything.
2578 if (!layerTransform.isInvertible())
2579 return;
2580
2581 // If we have a transparency layer enclosing us and we are the root of a transform, then we need to establish the transparency
2582 // layer from the parent now.
2583 if (paintFlags & PaintLayerHaveTransparency)
2584 parent()->beginTransparencyLayers(p, rootLayer, paintBehavior);
2585
2586 // Make sure the parent's clip rects have been calculated.
2587 IntRect clipRect = paintDirtyRect;
2588 if (parent()) {
2589 clipRect = backgroundClipRect(rootLayer, paintFlags & PaintLayerTemporaryClipRects);
2590 clipRect.intersect(paintDirtyRect);
2591 }
2592
2593 // Push the parent coordinate space's clip.
2594 setClip(p, paintDirtyRect, clipRect);
2595
2596 // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space.
2597 // This involves subtracting out the position of the layer in our current coordinate space.
2598 int x = 0;
2599 int y = 0;
2600 convertToLayerCoords(rootLayer, x, y);
2601 TransformationMatrix transform(layerTransform);
2602 transform.translateRight(x, y);
2603
2604 // Apply the transform.
2605 p->save();
2606 p->concatCTM(transform.toAffineTransform());
2607
2608 // Now do a paint with the root layer shifted to be us.
2609 paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), paintBehavior, paintingRoot, overlapTestRequests, paintFlags | PaintLayerAppliedTransform);
2610
2611 p->restore();
2612
2613 // Restore the clip.
2614 restoreClip(p, paintDirtyRect, clipRect);
2615
2616 return;
2617 }
2618
2619 PaintLayerFlags localPaintFlags = paintFlags & ~PaintLayerAppliedTransform;
2620 bool haveTransparency = localPaintFlags & PaintLayerHaveTransparency;
2621
2622 // Paint the reflection first if we have one.
2623 if (m_reflection && !m_paintingInsideReflection) {
2624 // Mark that we are now inside replica painting.
2625 m_paintingInsideReflection = true;
2626 reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags | PaintLayerPaintingReflection);
2627 m_paintingInsideReflection = false;
2628 }
2629
2630 // Calculate the clip rects we should use.
2631 IntRect layerBounds, damageRect, clipRectToApply, outlineRect;
2632 calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, localPaintFlags & PaintLayerTemporaryClipRects);
2633 int x = layerBounds.x();
2634 int y = layerBounds.y();
2635 int tx = x - renderBoxX();
2636 int ty = y - renderBoxY();
2637
2638 // Ensure our lists are up-to-date.
2639 updateCompositingAndLayerListsIfNeeded();
2640
2641 bool forceBlackText = paintBehavior & PaintBehaviorForceBlackText;
2642 bool selectionOnly = paintBehavior & PaintBehaviorSelectionOnly;
2643
2644 // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which
2645 // is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set).
2646 // Else, our renderer tree may or may not contain the painting root, so we pass that root along
2647 // so it will be tested against as we descend through the renderers.
2648 RenderObject* paintingRootForRenderer = 0;
2649 if (paintingRoot && !renderer()->isDescendantOf(paintingRoot))
2650 paintingRootForRenderer = paintingRoot;
2651
2652 if (overlapTestRequests && isSelfPaintingLayer())
2653 performOverlapTests(*overlapTestRequests, rootLayer, this);
2654
2655 bool paintingOverlayScrollbars = paintFlags & PaintLayerPaintingOverlayScrollbars;
2656
2657 // We want to paint our layer, but only if we intersect the damage rect.
2658 bool shouldPaint = intersectsDamageRect(layerBounds, damageRect, rootLayer) && m_hasVisibleContent && isSelfPaintingLayer();
2659 if (shouldPaint && !selectionOnly && !damageRect.isEmpty() && !paintingOverlayScrollbars) {
2660 // Begin transparency layers lazily now that we know we have to paint something.
2661 if (haveTransparency)
2662 beginTransparencyLayers(p, rootLayer, paintBehavior);
2663
2664 // Paint our background first, before painting any child layers.
2665 // Establish the clip used to paint our background.
2666 setClip(p, paintDirtyRect, damageRect);
2667
2668 // Paint the background.
2669 PaintInfo paintInfo(p, damageRect, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0);
2670 renderer()->paint(paintInfo, tx, ty);
2671
2672 // Restore the clip.
2673 restoreClip(p, paintDirtyRect, damageRect);
2674 }
2675
2676 // Now walk the sorted list of children with negative z-indices.
2677 paintList(m_negZOrderList, rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags);
2678
2679 // Now establish the appropriate clip and paint our child RenderObjects.
2680 if (shouldPaint && !clipRectToApply.isEmpty() && !paintingOverlayScrollbars) {
2681 // Begin transparency layers lazily now that we know we have to paint something.
2682 if (haveTransparency)
2683 beginTransparencyLayers(p, rootLayer, paintBehavior);
2684
2685 // Set up the clip used when painting our children.
2686 setClip(p, paintDirtyRect, clipRectToApply);
2687 PaintInfo paintInfo(p, clipRectToApply,
2688 selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds,
2689 forceBlackText, paintingRootForRenderer, 0);
2690 renderer()->paint(paintInfo, tx, ty);
2691 if (!selectionOnly) {
2692 paintInfo.phase = PaintPhaseFloat;
2693 renderer()->paint(paintInfo, tx, ty);
2694 paintInfo.phase = PaintPhaseForeground;
2695 paintInfo.overlapTestRequests = overlapTestRequests;
2696 renderer()->paint(paintInfo, tx, ty);
2697 paintInfo.phase = PaintPhaseChildOutlines;
2698 renderer()->paint(paintInfo, tx, ty);
2699 }
2700
2701 // Now restore our clip.
2702 restoreClip(p, paintDirtyRect, clipRectToApply);
2703 }
2704
2705 if (!outlineRect.isEmpty() && isSelfPaintingLayer() && !paintingOverlayScrollbars) {
2706 // Paint our own outline
2707 PaintInfo paintInfo(p, outlineRect, PaintPhaseSelfOutline, false, paintingRootForRenderer, 0);
2708 setClip(p, paintDirtyRect, outlineRect);
2709 renderer()->paint(paintInfo, tx, ty);
2710 restoreClip(p, paintDirtyRect, outlineRect);
2711 }
2712
2713 // Paint any child layers that have overflow.
2714 paintList(m_normalFlowList, rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags);
2715
2716 // Now walk the sorted list of children with positive z-indices.
2717 paintList(m_posZOrderList, rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, localPaintFlags);
2718
2719 if (renderer()->hasMask() && shouldPaint && !selectionOnly && !damageRect.isEmpty() && !paintingOverlayScrollbars) {
2720 setClip(p, paintDirtyRect, damageRect);
2721
2722 // Paint the mask.
2723 PaintInfo paintInfo(p, damageRect, PaintPhaseMask, false, paintingRootForRenderer, 0);
2724 renderer()->paint(paintInfo, tx, ty);
2725
2726 // Restore the clip.
2727 restoreClip(p, paintDirtyRect, damageRect);
2728 }
2729
2730 if (paintingOverlayScrollbars) {
2731 setClip(p, paintDirtyRect, damageRect);
2732 paintOverflowControls(p, tx, ty, damageRect, true);
2733 restoreClip(p, paintDirtyRect, damageRect);
2734 }
2735
2736 // End our transparency layer
2737 if (haveTransparency && m_usedTransparency && !m_paintingInsideReflection) {
2738 p->endTransparencyLayer();
2739 p->restore();
2740 m_usedTransparency = false;
2741 }
2742 }
2743
paintList(Vector<RenderLayer * > * list,RenderLayer * rootLayer,GraphicsContext * p,const IntRect & paintDirtyRect,PaintBehavior paintBehavior,RenderObject * paintingRoot,OverlapTestRequestMap * overlapTestRequests,PaintLayerFlags paintFlags)2744 void RenderLayer::paintList(Vector<RenderLayer*>* list, RenderLayer* rootLayer, GraphicsContext* p,
2745 const IntRect& paintDirtyRect, PaintBehavior paintBehavior,
2746 RenderObject* paintingRoot, OverlapTestRequestMap* overlapTestRequests,
2747 PaintLayerFlags paintFlags)
2748 {
2749 if (!list)
2750 return;
2751
2752 for (size_t i = 0; i < list->size(); ++i) {
2753 RenderLayer* childLayer = list->at(i);
2754 if (!childLayer->isPaginated())
2755 childLayer->paintLayer(rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, paintFlags);
2756 else
2757 paintPaginatedChildLayer(childLayer, rootLayer, p, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, paintFlags);
2758 }
2759 }
2760
paintPaginatedChildLayer(RenderLayer * childLayer,RenderLayer * rootLayer,GraphicsContext * context,const IntRect & paintDirtyRect,PaintBehavior paintBehavior,RenderObject * paintingRoot,OverlapTestRequestMap * overlapTestRequests,PaintLayerFlags paintFlags)2761 void RenderLayer::paintPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, GraphicsContext* context,
2762 const IntRect& paintDirtyRect, PaintBehavior paintBehavior,
2763 RenderObject* paintingRoot, OverlapTestRequestMap* overlapTestRequests,
2764 PaintLayerFlags paintFlags)
2765 {
2766 // We need to do multiple passes, breaking up our child layer into strips.
2767 Vector<RenderLayer*> columnLayers;
2768 RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContext();
2769 for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
2770 if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox()))
2771 columnLayers.append(curr);
2772 if (curr == ancestorLayer)
2773 break;
2774 }
2775
2776 ASSERT(columnLayers.size());
2777
2778 paintChildLayerIntoColumns(childLayer, rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, paintFlags, columnLayers, columnLayers.size() - 1);
2779 }
2780
paintChildLayerIntoColumns(RenderLayer * childLayer,RenderLayer * rootLayer,GraphicsContext * context,const IntRect & paintDirtyRect,PaintBehavior paintBehavior,RenderObject * paintingRoot,OverlapTestRequestMap * overlapTestRequests,PaintLayerFlags paintFlags,const Vector<RenderLayer * > & columnLayers,size_t colIndex)2781 void RenderLayer::paintChildLayerIntoColumns(RenderLayer* childLayer, RenderLayer* rootLayer, GraphicsContext* context,
2782 const IntRect& paintDirtyRect, PaintBehavior paintBehavior,
2783 RenderObject* paintingRoot, OverlapTestRequestMap* overlapTestRequests,
2784 PaintLayerFlags paintFlags, const Vector<RenderLayer*>& columnLayers, size_t colIndex)
2785 {
2786 RenderBlock* columnBlock = toRenderBlock(columnLayers[colIndex]->renderer());
2787
2788 ASSERT(columnBlock && columnBlock->hasColumns());
2789 if (!columnBlock || !columnBlock->hasColumns())
2790 return;
2791
2792 int layerX = 0;
2793 int layerY = 0;
2794 columnBlock->layer()->convertToLayerCoords(rootLayer, layerX, layerY);
2795
2796 bool isHorizontal = columnBlock->style()->isHorizontalWritingMode();
2797
2798 ColumnInfo* colInfo = columnBlock->columnInfo();
2799 unsigned colCount = columnBlock->columnCount(colInfo);
2800 int currLogicalTopOffset = 0;
2801 for (unsigned i = 0; i < colCount; i++) {
2802 // For each rect, we clip to the rect, and then we adjust our coords.
2803 IntRect colRect = columnBlock->columnRectAt(colInfo, i);
2804 columnBlock->flipForWritingMode(colRect);
2805 int logicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - columnBlock->logicalLeftOffsetForContent();
2806 IntSize offset = isHorizontal ? IntSize(logicalLeftOffset, currLogicalTopOffset) : IntSize(currLogicalTopOffset, logicalLeftOffset);
2807
2808 colRect.move(layerX, layerY);
2809
2810 IntRect localDirtyRect(paintDirtyRect);
2811 localDirtyRect.intersect(colRect);
2812
2813 if (!localDirtyRect.isEmpty()) {
2814 context->save();
2815
2816 // Each strip pushes a clip, since column boxes are specified as being
2817 // like overflow:hidden.
2818 context->clip(colRect);
2819
2820 if (!colIndex) {
2821 // Apply a translation transform to change where the layer paints.
2822 TransformationMatrix oldTransform;
2823 bool oldHasTransform = childLayer->transform();
2824 if (oldHasTransform)
2825 oldTransform = *childLayer->transform();
2826 TransformationMatrix newTransform(oldTransform);
2827 newTransform.translateRight(offset.width(), offset.height());
2828
2829 childLayer->m_transform.set(new TransformationMatrix(newTransform));
2830 childLayer->paintLayer(rootLayer, context, localDirtyRect, paintBehavior, paintingRoot, overlapTestRequests, paintFlags);
2831 if (oldHasTransform)
2832 childLayer->m_transform.set(new TransformationMatrix(oldTransform));
2833 else
2834 childLayer->m_transform.clear();
2835 } else {
2836 // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space.
2837 // This involves subtracting out the position of the layer in our current coordinate space.
2838 int childX = 0;
2839 int childY = 0;
2840 columnLayers[colIndex - 1]->convertToLayerCoords(rootLayer, childX, childY);
2841 TransformationMatrix transform;
2842 transform.translateRight(childX + offset.width(), childY + offset.height());
2843
2844 // Apply the transform.
2845 context->concatCTM(transform.toAffineTransform());
2846
2847 // Now do a paint with the root layer shifted to be the next multicol block.
2848 paintChildLayerIntoColumns(childLayer, columnLayers[colIndex - 1], context, transform.inverse().mapRect(localDirtyRect), paintBehavior,
2849 paintingRoot, overlapTestRequests, paintFlags,
2850 columnLayers, colIndex - 1);
2851 }
2852
2853 context->restore();
2854 }
2855
2856 // Move to the next position.
2857 int blockDelta = isHorizontal ? colRect.height() : colRect.width();
2858 if (columnBlock->style()->isFlippedBlocksWritingMode())
2859 currLogicalTopOffset += blockDelta;
2860 else
2861 currLogicalTopOffset -= blockDelta;
2862 }
2863 }
2864
frameVisibleRect(RenderObject * renderer)2865 static inline IntRect frameVisibleRect(RenderObject* renderer)
2866 {
2867 FrameView* frameView = renderer->document()->view();
2868 if (!frameView)
2869 return IntRect();
2870
2871 return frameView->visibleContentRect();
2872 }
2873
hitTest(const HitTestRequest & request,HitTestResult & result)2874 bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
2875 {
2876 renderer()->document()->updateLayout();
2877
2878 IntRect hitTestArea = renderer()->view()->documentRect();
2879 if (!request.ignoreClipping())
2880 hitTestArea.intersect(frameVisibleRect(renderer()));
2881
2882 RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, hitTestArea, result.point(), false);
2883 if (!insideLayer) {
2884 // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down,
2885 // return ourselves. We do this so mouse events continue getting delivered after a drag has
2886 // exited the WebView, and so hit testing over a scrollbar hits the content document.
2887 if ((request.active() || request.mouseUp()) && renderer()->isRenderView()) {
2888 renderer()->updateHitTestResult(result, result.point());
2889 insideLayer = this;
2890 }
2891 }
2892
2893 // Now determine if the result is inside an anchor - if the urlElement isn't already set.
2894 Node* node = result.innerNode();
2895 if (node && !result.URLElement())
2896 result.setURLElement(static_cast<Element*>(node->enclosingLinkEventParentOrSelf()));
2897
2898 // Next set up the correct :hover/:active state along the new chain.
2899 updateHoverActiveState(request, result);
2900
2901 // Now return whether we were inside this layer (this will always be true for the root
2902 // layer).
2903 return insideLayer;
2904 }
2905
enclosingElement() const2906 Node* RenderLayer::enclosingElement() const
2907 {
2908 for (RenderObject* r = renderer(); r; r = r->parent()) {
2909 if (Node* e = r->node())
2910 return e;
2911 }
2912 ASSERT_NOT_REACHED();
2913 return 0;
2914 }
2915
2916 // Compute the z-offset of the point in the transformState.
2917 // This is effectively projecting a ray normal to the plane of ancestor, finding where that
2918 // ray intersects target, and computing the z delta between those two points.
computeZOffset(const HitTestingTransformState & transformState)2919 static double computeZOffset(const HitTestingTransformState& transformState)
2920 {
2921 // We got an affine transform, so no z-offset
2922 if (transformState.m_accumulatedTransform.isAffine())
2923 return 0;
2924
2925 // Flatten the point into the target plane
2926 FloatPoint targetPoint = transformState.mappedPoint();
2927
2928 // Now map the point back through the transform, which computes Z.
2929 FloatPoint3D backmappedPoint = transformState.m_accumulatedTransform.mapPoint(FloatPoint3D(targetPoint));
2930 return backmappedPoint.z();
2931 }
2932
createLocalTransformState(RenderLayer * rootLayer,RenderLayer * containerLayer,const IntRect & hitTestRect,const IntPoint & hitTestPoint,const HitTestingTransformState * containerTransformState) const2933 PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer,
2934 const IntRect& hitTestRect, const IntPoint& hitTestPoint,
2935 const HitTestingTransformState* containerTransformState) const
2936 {
2937 RefPtr<HitTestingTransformState> transformState;
2938 int offsetX = 0;
2939 int offsetY = 0;
2940 if (containerTransformState) {
2941 // If we're already computing transform state, then it's relative to the container (which we know is non-null).
2942 transformState = HitTestingTransformState::create(*containerTransformState);
2943 convertToLayerCoords(containerLayer, offsetX, offsetY);
2944 } else {
2945 // If this is the first time we need to make transform state, then base it off of hitTestPoint,
2946 // which is relative to rootLayer.
2947 transformState = HitTestingTransformState::create(hitTestPoint, FloatQuad(hitTestRect));
2948 convertToLayerCoords(rootLayer, offsetX, offsetY);
2949 }
2950
2951 RenderObject* containerRenderer = containerLayer ? containerLayer->renderer() : 0;
2952 if (renderer()->shouldUseTransformFromContainer(containerRenderer)) {
2953 TransformationMatrix containerTransform;
2954 renderer()->getTransformFromContainer(containerRenderer, IntSize(offsetX, offsetY), containerTransform);
2955 transformState->applyTransform(containerTransform, HitTestingTransformState::AccumulateTransform);
2956 } else {
2957 transformState->translate(offsetX, offsetY, HitTestingTransformState::AccumulateTransform);
2958 }
2959
2960 return transformState;
2961 }
2962
2963
isHitCandidate(const RenderLayer * hitLayer,bool canDepthSort,double * zOffset,const HitTestingTransformState * transformState)2964 static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, double* zOffset, const HitTestingTransformState* transformState)
2965 {
2966 if (!hitLayer)
2967 return false;
2968
2969 // The hit layer is depth-sorting with other layers, so just say that it was hit.
2970 if (canDepthSort)
2971 return true;
2972
2973 // We need to look at z-depth to decide if this layer was hit.
2974 if (zOffset) {
2975 ASSERT(transformState);
2976 // This is actually computing our z, but that's OK because the hitLayer is coplanar with us.
2977 double childZOffset = computeZOffset(*transformState);
2978 if (childZOffset > *zOffset) {
2979 *zOffset = childZOffset;
2980 return true;
2981 }
2982 return false;
2983 }
2984
2985 return true;
2986 }
2987
2988 // hitTestPoint and hitTestRect are relative to rootLayer.
2989 // A 'flattening' layer is one preserves3D() == false.
2990 // transformState.m_accumulatedTransform holds the transform from the containing flattening layer.
2991 // transformState.m_lastPlanarPoint is the hitTestPoint in the plane of the containing flattening layer.
2992 // transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of the containing flattening layer.
2993 //
2994 // If zOffset is non-null (which indicates that the caller wants z offset information),
2995 // *zOffset on return is the z offset of the hit point relative to the containing flattening layer.
hitTestLayer(RenderLayer * rootLayer,RenderLayer * containerLayer,const HitTestRequest & request,HitTestResult & result,const IntRect & hitTestRect,const IntPoint & hitTestPoint,bool appliedTransform,const HitTestingTransformState * transformState,double * zOffset)2996 RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result,
2997 const IntRect& hitTestRect, const IntPoint& hitTestPoint, bool appliedTransform,
2998 const HitTestingTransformState* transformState, double* zOffset)
2999 {
3000 // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate.
3001
3002 bool useTemporaryClipRects = false;
3003 #if USE(ACCELERATED_COMPOSITING)
3004 useTemporaryClipRects = compositor()->inCompositingMode();
3005 #endif
3006 useTemporaryClipRects |= renderer()->view()->frameView()->containsScrollableAreaWithOverlayScrollbars();
3007
3008 IntRect hitTestArea = result.rectForPoint(hitTestPoint);
3009
3010 // Apply a transform if we have one.
3011 if (transform() && !appliedTransform) {
3012 // Make sure the parent's clip rects have been calculated.
3013 if (parent()) {
3014 IntRect clipRect = backgroundClipRect(rootLayer, useTemporaryClipRects, IncludeOverlayScrollbarSize);
3015 // Go ahead and test the enclosing clip now.
3016 if (!clipRect.intersects(hitTestArea))
3017 return 0;
3018 }
3019
3020 // Create a transform state to accumulate this transform.
3021 RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestPoint, transformState);
3022
3023 // If the transform can't be inverted, then don't hit test this layer at all.
3024 if (!newTransformState->m_accumulatedTransform.isInvertible())
3025 return 0;
3026
3027 // Compute the point and the hit test rect in the coords of this layer by using the values
3028 // from the transformState, which store the point and quad in the coords of the last flattened
3029 // layer, and the accumulated transform which lets up map through preserve-3d layers.
3030 //
3031 // We can't just map hitTestPoint and hitTestRect because they may have been flattened (losing z)
3032 // by our container.
3033 IntPoint localPoint = roundedIntPoint(newTransformState->mappedPoint());
3034 IntRect localHitTestRect;
3035 #if USE(ACCELERATED_COMPOSITING)
3036 if (isComposited()) {
3037 // It doesn't make sense to project hitTestRect into the plane of this layer, so use the same bounds we use for painting.
3038 localHitTestRect = backing()->compositedBounds();
3039 } else
3040 #endif
3041 localHitTestRect = newTransformState->mappedQuad().enclosingBoundingBox();
3042
3043 // Now do a hit test with the root layer shifted to be us.
3044 return hitTestLayer(this, containerLayer, request, result, localHitTestRect, localPoint, true, newTransformState.get(), zOffset);
3045 }
3046
3047 // Ensure our lists and 3d status are up-to-date.
3048 updateCompositingAndLayerListsIfNeeded();
3049 update3DTransformedDescendantStatus();
3050
3051 RefPtr<HitTestingTransformState> localTransformState;
3052 if (appliedTransform) {
3053 // We computed the correct state in the caller (above code), so just reference it.
3054 ASSERT(transformState);
3055 localTransformState = const_cast<HitTestingTransformState*>(transformState);
3056 } else if (transformState || m_has3DTransformedDescendant || preserves3D()) {
3057 // We need transform state for the first time, or to offset the container state, so create it here.
3058 localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestPoint, transformState);
3059 }
3060
3061 // Check for hit test on backface if backface-visibility is 'hidden'
3062 if (localTransformState && renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) {
3063 TransformationMatrix invertedMatrix = localTransformState->m_accumulatedTransform.inverse();
3064 // If the z-vector of the matrix is negative, the back is facing towards the viewer.
3065 if (invertedMatrix.m33() < 0)
3066 return 0;
3067 }
3068
3069 RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformState;
3070 if (localTransformState && !preserves3D()) {
3071 // Keep a copy of the pre-flattening state, for computing z-offsets for the container
3072 unflattenedTransformState = HitTestingTransformState::create(*localTransformState);
3073 // This layer is flattening, so flatten the state passed to descendants.
3074 localTransformState->flatten();
3075 }
3076
3077 // Calculate the clip rects we should use.
3078 IntRect layerBounds;
3079 IntRect bgRect;
3080 IntRect fgRect;
3081 IntRect outlineRect;
3082 calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect, outlineRect, useTemporaryClipRects, IncludeOverlayScrollbarSize);
3083
3084 // The following are used for keeping track of the z-depth of the hit point of 3d-transformed
3085 // descendants.
3086 double localZOffset = -numeric_limits<double>::infinity();
3087 double* zOffsetForDescendantsPtr = 0;
3088 double* zOffsetForContentsPtr = 0;
3089
3090 bool depthSortDescendants = false;
3091 if (preserves3D()) {
3092 depthSortDescendants = true;
3093 // Our layers can depth-test with our container, so share the z depth pointer with the container, if it passed one down.
3094 zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
3095 zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
3096 } else if (m_has3DTransformedDescendant) {
3097 // Flattening layer with 3d children; use a local zOffset pointer to depth-test children and foreground.
3098 depthSortDescendants = true;
3099 zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
3100 zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
3101 } else if (zOffset) {
3102 zOffsetForDescendantsPtr = 0;
3103 // Container needs us to give back a z offset for the hit layer.
3104 zOffsetForContentsPtr = zOffset;
3105 }
3106
3107 // This variable tracks which layer the mouse ends up being inside.
3108 RenderLayer* candidateLayer = 0;
3109
3110 // Begin by walking our list of positive layers from highest z-index down to the lowest z-index.
3111 RenderLayer* hitLayer = hitTestList(m_posZOrderList, rootLayer, request, result, hitTestRect, hitTestPoint,
3112 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
3113 if (hitLayer) {
3114 if (!depthSortDescendants)
3115 return hitLayer;
3116 candidateLayer = hitLayer;
3117 }
3118
3119 // Now check our overflow objects.
3120 hitLayer = hitTestList(m_normalFlowList, rootLayer, request, result, hitTestRect, hitTestPoint,
3121 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
3122 if (hitLayer) {
3123 if (!depthSortDescendants)
3124 return hitLayer;
3125 candidateLayer = hitLayer;
3126 }
3127
3128 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
3129 if (hasOverflowParent()) {
3130 ClipRects clipRects;
3131 calculateClipRects(rootLayer, clipRects, useTemporaryClipRects);
3132 fgRect.intersect(clipRects.hitTestClip());
3133 bgRect.intersect(clipRects.hitTestClip());
3134 }
3135 #endif
3136 // Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
3137 if (fgRect.intersects(hitTestArea) && isSelfPaintingLayer()) {
3138 // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost.
3139 HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding());
3140 if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestDescendants) &&
3141 isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
3142 if (result.isRectBasedTest())
3143 result.append(tempResult);
3144 else
3145 result = tempResult;
3146 if (!depthSortDescendants)
3147 return this;
3148 // Foreground can depth-sort with descendant layers, so keep this as a candidate.
3149 candidateLayer = this;
3150 } else if (result.isRectBasedTest())
3151 result.append(tempResult);
3152 }
3153
3154 // Now check our negative z-index children.
3155 hitLayer = hitTestList(m_negZOrderList, rootLayer, request, result, hitTestRect, hitTestPoint,
3156 localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants);
3157 if (hitLayer) {
3158 if (!depthSortDescendants)
3159 return hitLayer;
3160 candidateLayer = hitLayer;
3161 }
3162
3163 // If we found a layer, return. Child layers, and foreground always render in front of background.
3164 if (candidateLayer)
3165 return candidateLayer;
3166
3167 if (bgRect.intersects(hitTestArea) && isSelfPaintingLayer()) {
3168 HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding());
3169 if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestSelf) &&
3170 isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
3171 if (result.isRectBasedTest())
3172 result.append(tempResult);
3173 else
3174 result = tempResult;
3175 return this;
3176 } else if (result.isRectBasedTest())
3177 result.append(tempResult);
3178 }
3179
3180 return 0;
3181 }
3182
hitTestContents(const HitTestRequest & request,HitTestResult & result,const IntRect & layerBounds,const IntPoint & hitTestPoint,HitTestFilter hitTestFilter) const3183 bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const IntRect& layerBounds, const IntPoint& hitTestPoint, HitTestFilter hitTestFilter) const
3184 {
3185 if (!renderer()->hitTest(request, result, hitTestPoint,
3186 layerBounds.x() - renderBoxX(),
3187 layerBounds.y() - renderBoxY(),
3188 hitTestFilter)) {
3189 // It's wrong to set innerNode, but then claim that you didn't hit anything, unless it is
3190 // a rect-based test.
3191 ASSERT(!result.innerNode() || (result.isRectBasedTest() && result.rectBasedTestResult().size()));
3192 return false;
3193 }
3194
3195 // For positioned generated content, we might still not have a
3196 // node by the time we get to the layer level, since none of
3197 // the content in the layer has an element. So just walk up
3198 // the tree.
3199 if (!result.innerNode() || !result.innerNonSharedNode()) {
3200 Node* e = enclosingElement();
3201 if (!result.innerNode())
3202 result.setInnerNode(e);
3203 if (!result.innerNonSharedNode())
3204 result.setInnerNonSharedNode(e);
3205 }
3206
3207 return true;
3208 }
3209
hitTestList(Vector<RenderLayer * > * list,RenderLayer * rootLayer,const HitTestRequest & request,HitTestResult & result,const IntRect & hitTestRect,const IntPoint & hitTestPoint,const HitTestingTransformState * transformState,double * zOffsetForDescendants,double * zOffset,const HitTestingTransformState * unflattenedTransformState,bool depthSortDescendants)3210 RenderLayer* RenderLayer::hitTestList(Vector<RenderLayer*>* list, RenderLayer* rootLayer,
3211 const HitTestRequest& request, HitTestResult& result,
3212 const IntRect& hitTestRect, const IntPoint& hitTestPoint,
3213 const HitTestingTransformState* transformState,
3214 double* zOffsetForDescendants, double* zOffset,
3215 const HitTestingTransformState* unflattenedTransformState,
3216 bool depthSortDescendants)
3217 {
3218 if (!list)
3219 return 0;
3220
3221 RenderLayer* resultLayer = 0;
3222 for (int i = list->size() - 1; i >= 0; --i) {
3223 RenderLayer* childLayer = list->at(i);
3224 RenderLayer* hitLayer = 0;
3225 HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding());
3226 if (childLayer->isPaginated())
3227 hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request, tempResult, hitTestRect, hitTestPoint, transformState, zOffsetForDescendants);
3228 else
3229 hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestPoint, false, transformState, zOffsetForDescendants);
3230
3231 // If it a rect-based test, we can safely append the temporary result since it might had hit
3232 // nodes but not necesserily had hitLayer set.
3233 if (result.isRectBasedTest())
3234 result.append(tempResult);
3235
3236 if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState)) {
3237 resultLayer = hitLayer;
3238 if (!result.isRectBasedTest())
3239 result = tempResult;
3240 if (!depthSortDescendants)
3241 break;
3242 }
3243 }
3244
3245 return resultLayer;
3246 }
3247
hitTestPaginatedChildLayer(RenderLayer * childLayer,RenderLayer * rootLayer,const HitTestRequest & request,HitTestResult & result,const IntRect & hitTestRect,const IntPoint & hitTestPoint,const HitTestingTransformState * transformState,double * zOffset)3248 RenderLayer* RenderLayer::hitTestPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result,
3249 const IntRect& hitTestRect, const IntPoint& hitTestPoint, const HitTestingTransformState* transformState, double* zOffset)
3250 {
3251 Vector<RenderLayer*> columnLayers;
3252 RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContext();
3253 for (RenderLayer* curr = childLayer->parent(); curr; curr = curr->parent()) {
3254 if (curr->renderer()->hasColumns() && checkContainingBlockChainForPagination(childLayer->renderer(), curr->renderBox()))
3255 columnLayers.append(curr);
3256 if (curr == ancestorLayer)
3257 break;
3258 }
3259
3260 ASSERT(columnLayers.size());
3261 return hitTestChildLayerColumns(childLayer, rootLayer, request, result, hitTestRect, hitTestPoint, transformState, zOffset,
3262 columnLayers, columnLayers.size() - 1);
3263 }
3264
hitTestChildLayerColumns(RenderLayer * childLayer,RenderLayer * rootLayer,const HitTestRequest & request,HitTestResult & result,const IntRect & hitTestRect,const IntPoint & hitTestPoint,const HitTestingTransformState * transformState,double * zOffset,const Vector<RenderLayer * > & columnLayers,size_t columnIndex)3265 RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result,
3266 const IntRect& hitTestRect, const IntPoint& hitTestPoint, const HitTestingTransformState* transformState, double* zOffset,
3267 const Vector<RenderLayer*>& columnLayers, size_t columnIndex)
3268 {
3269 RenderBlock* columnBlock = toRenderBlock(columnLayers[columnIndex]->renderer());
3270
3271 ASSERT(columnBlock && columnBlock->hasColumns());
3272 if (!columnBlock || !columnBlock->hasColumns())
3273 return 0;
3274
3275 int layerX = 0;
3276 int layerY = 0;
3277 columnBlock->layer()->convertToLayerCoords(rootLayer, layerX, layerY);
3278
3279 ColumnInfo* colInfo = columnBlock->columnInfo();
3280 int colCount = columnBlock->columnCount(colInfo);
3281
3282 // We have to go backwards from the last column to the first.
3283 bool isHorizontal = columnBlock->style()->isHorizontalWritingMode();
3284 int logicalLeft = columnBlock->logicalLeftOffsetForContent();
3285 int currLogicalTopOffset = 0;
3286 int i;
3287 for (i = 0; i < colCount; i++) {
3288 IntRect colRect = columnBlock->columnRectAt(colInfo, i);
3289 int blockDelta = (isHorizontal ? colRect.height() : colRect.width());
3290 if (columnBlock->style()->isFlippedBlocksWritingMode())
3291 currLogicalTopOffset += blockDelta;
3292 else
3293 currLogicalTopOffset -= blockDelta;
3294 }
3295 for (i = colCount - 1; i >= 0; i--) {
3296 // For each rect, we clip to the rect, and then we adjust our coords.
3297 IntRect colRect = columnBlock->columnRectAt(colInfo, i);
3298 columnBlock->flipForWritingMode(colRect);
3299 int currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - logicalLeft;
3300 int blockDelta = (isHorizontal ? colRect.height() : colRect.width());
3301 if (columnBlock->style()->isFlippedBlocksWritingMode())
3302 currLogicalTopOffset -= blockDelta;
3303 else
3304 currLogicalTopOffset += blockDelta;
3305 colRect.move(layerX, layerY);
3306
3307 IntRect localClipRect(hitTestRect);
3308 localClipRect.intersect(colRect);
3309
3310 IntSize offset = isHorizontal ? IntSize(currLogicalLeftOffset, currLogicalTopOffset) : IntSize(currLogicalTopOffset, currLogicalLeftOffset);
3311
3312 if (!localClipRect.isEmpty() && localClipRect.intersects(result.rectForPoint(hitTestPoint))) {
3313 RenderLayer* hitLayer = 0;
3314 if (!columnIndex) {
3315 // Apply a translation transform to change where the layer paints.
3316 TransformationMatrix oldTransform;
3317 bool oldHasTransform = childLayer->transform();
3318 if (oldHasTransform)
3319 oldTransform = *childLayer->transform();
3320 TransformationMatrix newTransform(oldTransform);
3321 newTransform.translateRight(offset.width(), offset.height());
3322
3323 childLayer->m_transform.set(new TransformationMatrix(newTransform));
3324 hitLayer = childLayer->hitTestLayer(rootLayer, columnLayers[0], request, result, localClipRect, hitTestPoint, false, transformState, zOffset);
3325 if (oldHasTransform)
3326 childLayer->m_transform.set(new TransformationMatrix(oldTransform));
3327 else
3328 childLayer->m_transform.clear();
3329 } else {
3330 // Adjust the transform such that the renderer's upper left corner will be at (0,0) in user space.
3331 // This involves subtracting out the position of the layer in our current coordinate space.
3332 RenderLayer* nextLayer = columnLayers[columnIndex - 1];
3333 RefPtr<HitTestingTransformState> newTransformState = nextLayer->createLocalTransformState(rootLayer, nextLayer, localClipRect, hitTestPoint, transformState);
3334 newTransformState->translate(offset.width(), offset.height(), HitTestingTransformState::AccumulateTransform);
3335 IntPoint localPoint = roundedIntPoint(newTransformState->mappedPoint());
3336 IntRect localHitTestRect = newTransformState->mappedQuad().enclosingBoundingBox();
3337 newTransformState->flatten();
3338
3339 hitLayer = hitTestChildLayerColumns(childLayer, columnLayers[columnIndex - 1], request, result, localHitTestRect, localPoint,
3340 newTransformState.get(), zOffset, columnLayers, columnIndex - 1);
3341 }
3342
3343 if (hitLayer)
3344 return hitLayer;
3345 }
3346 }
3347
3348 return 0;
3349 }
3350
updateClipRects(const RenderLayer * rootLayer,OverlayScrollbarSizeRelevancy relevancy)3351 void RenderLayer::updateClipRects(const RenderLayer* rootLayer, OverlayScrollbarSizeRelevancy relevancy)
3352 {
3353 if (m_clipRects) {
3354 ASSERT(rootLayer == m_clipRectsRoot);
3355 return; // We have the correct cached value.
3356 }
3357
3358 // For transformed layers, the root layer was shifted to be us, so there is no need to
3359 // examine the parent. We want to cache clip rects with us as the root.
3360 RenderLayer* parentLayer = rootLayer != this ? parent() : 0;
3361 if (parentLayer)
3362 parentLayer->updateClipRects(rootLayer, relevancy);
3363
3364 ClipRects clipRects;
3365 calculateClipRects(rootLayer, clipRects, true, relevancy);
3366
3367 if (parentLayer && parentLayer->clipRects() && clipRects == *parentLayer->clipRects())
3368 m_clipRects = parentLayer->clipRects();
3369 else
3370 m_clipRects = new (renderer()->renderArena()) ClipRects(clipRects);
3371 m_clipRects->ref();
3372 #ifndef NDEBUG
3373 m_clipRectsRoot = rootLayer;
3374 #endif
3375 }
3376
calculateClipRects(const RenderLayer * rootLayer,ClipRects & clipRects,bool useCached,OverlayScrollbarSizeRelevancy relevancy) const3377 void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool useCached, OverlayScrollbarSizeRelevancy relevancy) const
3378 {
3379 if (!parent()) {
3380 // The root layer's clip rect is always infinite.
3381 clipRects.reset(PaintInfo::infiniteRect());
3382 return;
3383 }
3384
3385 // For transformed layers, the root layer was shifted to be us, so there is no need to
3386 // examine the parent. We want to cache clip rects with us as the root.
3387 RenderLayer* parentLayer = rootLayer != this ? parent() : 0;
3388
3389 // Ensure that our parent's clip has been calculated so that we can examine the values.
3390 if (parentLayer) {
3391 if (useCached && parentLayer->clipRects())
3392 clipRects = *parentLayer->clipRects();
3393 else
3394 parentLayer->calculateClipRects(rootLayer, clipRects);
3395 }
3396 else
3397 clipRects.reset(PaintInfo::infiniteRect());
3398
3399 // A fixed object is essentially the root of its containing block hierarchy, so when
3400 // we encounter such an object, we reset our clip rects to the fixedClipRect.
3401 if (renderer()->style()->position() == FixedPosition) {
3402 clipRects.setPosClipRect(clipRects.fixedClipRect());
3403 clipRects.setOverflowClipRect(clipRects.fixedClipRect());
3404 clipRects.setFixed(true);
3405 }
3406 else if (renderer()->style()->position() == RelativePosition)
3407 clipRects.setPosClipRect(clipRects.overflowClipRect());
3408 else if (renderer()->style()->position() == AbsolutePosition)
3409 clipRects.setOverflowClipRect(clipRects.posClipRect());
3410
3411 // Update the clip rects that will be passed to child layers.
3412 if (renderer()->hasOverflowClip() || renderer()->hasClip()) {
3413 // This layer establishes a clip of some kind.
3414 int x = 0;
3415 int y = 0;
3416 convertToLayerCoords(rootLayer, x, y);
3417 RenderView* view = renderer()->view();
3418 ASSERT(view);
3419 if (view && clipRects.fixed() && rootLayer->renderer() == view) {
3420 x -= view->frameView()->scrollXForFixedPosition();
3421 y -= view->frameView()->scrollYForFixedPosition();
3422 }
3423
3424 if (renderer()->hasOverflowClip()) {
3425 IntRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(x, y, relevancy);
3426 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
3427 clipRects.setHitTestClip(intersection(clipRects.fixed() ? clipRects.fixedClipRect()
3428 : newOverflowClip, clipRects.hitTestClip()));
3429 if (hasOverflowScroll()) {
3430 RenderBox* box = toRenderBox(renderer());
3431 newOverflowClip =
3432 IntRect(x + box->borderLeft(), y + box->borderTop(),
3433 m_scrollWidth, m_scrollHeight);
3434 }
3435 #endif
3436 clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect()));
3437 if (renderer()->isPositioned() || renderer()->isRelPositioned())
3438 clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect()));
3439 }
3440 if (renderer()->hasClip()) {
3441 IntRect newPosClip = toRenderBox(renderer())->clipRect(x, y);
3442 clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect()));
3443 clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect()));
3444 clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect()));
3445 }
3446 }
3447 }
3448
parentClipRects(const RenderLayer * rootLayer,ClipRects & clipRects,bool temporaryClipRects,OverlayScrollbarSizeRelevancy relevancy) const3449 void RenderLayer::parentClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool temporaryClipRects, OverlayScrollbarSizeRelevancy relevancy) const
3450 {
3451 ASSERT(parent());
3452 if (temporaryClipRects) {
3453 parent()->calculateClipRects(rootLayer, clipRects, false, relevancy);
3454 return;
3455 }
3456
3457 parent()->updateClipRects(rootLayer, relevancy);
3458 clipRects = *parent()->clipRects();
3459 }
3460
backgroundClipRect(const RenderLayer * rootLayer,bool temporaryClipRects,OverlayScrollbarSizeRelevancy relevancy) const3461 IntRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, bool temporaryClipRects, OverlayScrollbarSizeRelevancy relevancy) const
3462 {
3463 IntRect backgroundRect;
3464 if (parent()) {
3465 ClipRects parentRects;
3466 parentClipRects(rootLayer, parentRects, temporaryClipRects, relevancy);
3467 backgroundRect = renderer()->style()->position() == FixedPosition ? parentRects.fixedClipRect() :
3468 (renderer()->isPositioned() ? parentRects.posClipRect() :
3469 parentRects.overflowClipRect());
3470 RenderView* view = renderer()->view();
3471 ASSERT(view);
3472 if (view && parentRects.fixed() && rootLayer->renderer() == view)
3473 backgroundRect.move(view->frameView()->scrollXForFixedPosition(), view->frameView()->scrollYForFixedPosition());
3474 }
3475 return backgroundRect;
3476 }
3477
calculateRects(const RenderLayer * rootLayer,const IntRect & paintDirtyRect,IntRect & layerBounds,IntRect & backgroundRect,IntRect & foregroundRect,IntRect & outlineRect,bool temporaryClipRects,OverlayScrollbarSizeRelevancy relevancy) const3478 void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& paintDirtyRect, IntRect& layerBounds,
3479 IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects,
3480 OverlayScrollbarSizeRelevancy relevancy) const
3481 {
3482 if (rootLayer != this && parent()) {
3483 backgroundRect = backgroundClipRect(rootLayer, temporaryClipRects, relevancy);
3484 backgroundRect.intersect(paintDirtyRect);
3485 } else
3486 backgroundRect = paintDirtyRect;
3487
3488 foregroundRect = backgroundRect;
3489 outlineRect = backgroundRect;
3490
3491 int x = 0;
3492 int y = 0;
3493 convertToLayerCoords(rootLayer, x, y);
3494 layerBounds = IntRect(x, y, width(), height());
3495
3496 // Update the clip rects that will be passed to child layers.
3497 if (renderer()->hasOverflowClip() || renderer()->hasClip()) {
3498 // This layer establishes a clip of some kind.
3499 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
3500 if (hasOverflowScroll()) {
3501 // Use the entire foreground rectangle to record the contents.
3502 RenderBox* box = toRenderBox(renderer());
3503 foregroundRect =
3504 IntRect(x + box->borderLeft(), y + box->borderTop(),
3505 m_scrollWidth, m_scrollHeight);
3506 } else
3507 #endif
3508 if (renderer()->hasOverflowClip())
3509 foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(x, y, relevancy));
3510 if (renderer()->hasClip()) {
3511 // Clip applies to *us* as well, so go ahead and update the damageRect.
3512 IntRect newPosClip = toRenderBox(renderer())->clipRect(x, y);
3513 backgroundRect.intersect(newPosClip);
3514 foregroundRect.intersect(newPosClip);
3515 outlineRect.intersect(newPosClip);
3516 }
3517
3518 // If we establish a clip at all, then go ahead and make sure our background
3519 // rect is intersected with our layer's bounds.
3520 // FIXME: This could be changed to just use generic visual overflow.
3521 // See https://bugs.webkit.org/show_bug.cgi?id=37467 for more information.
3522 if (const ShadowData* boxShadow = renderer()->style()->boxShadow()) {
3523 IntRect overflow = layerBounds;
3524 do {
3525 if (boxShadow->style() == Normal) {
3526 IntRect shadowRect = layerBounds;
3527 shadowRect.move(boxShadow->x(), boxShadow->y());
3528 shadowRect.inflate(boxShadow->blur() + boxShadow->spread());
3529 overflow.unite(shadowRect);
3530 }
3531
3532 boxShadow = boxShadow->next();
3533 } while (boxShadow);
3534 backgroundRect.intersect(overflow);
3535 } else
3536 backgroundRect.intersect(layerBounds);
3537 }
3538 }
3539
childrenClipRect() const3540 IntRect RenderLayer::childrenClipRect() const
3541 {
3542 RenderView* renderView = renderer()->view();
3543 RenderLayer* clippingRootLayer = clippingRoot();
3544 IntRect layerBounds, backgroundRect, foregroundRect, outlineRect;
3545 calculateRects(clippingRootLayer, renderView->documentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
3546 return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect)).enclosingBoundingBox();
3547 }
3548
selfClipRect() const3549 IntRect RenderLayer::selfClipRect() const
3550 {
3551 RenderView* renderView = renderer()->view();
3552 RenderLayer* clippingRootLayer = clippingRoot();
3553 IntRect layerBounds, backgroundRect, foregroundRect, outlineRect;
3554 calculateRects(clippingRootLayer, renderView->documentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect);
3555 return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(backgroundRect)).enclosingBoundingBox();
3556 }
3557
addBlockSelectionGapsBounds(const IntRect & bounds)3558 void RenderLayer::addBlockSelectionGapsBounds(const IntRect& bounds)
3559 {
3560 m_blockSelectionGapsBounds.unite(bounds);
3561 }
3562
clearBlockSelectionGapsBounds()3563 void RenderLayer::clearBlockSelectionGapsBounds()
3564 {
3565 m_blockSelectionGapsBounds = IntRect();
3566 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
3567 child->clearBlockSelectionGapsBounds();
3568 }
3569
repaintBlockSelectionGaps()3570 void RenderLayer::repaintBlockSelectionGaps()
3571 {
3572 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
3573 child->repaintBlockSelectionGaps();
3574
3575 if (m_blockSelectionGapsBounds.isEmpty())
3576 return;
3577
3578 IntRect rect = m_blockSelectionGapsBounds;
3579 rect.move(-scrolledContentOffset());
3580 if (renderer()->hasOverflowClip())
3581 rect.intersect(toRenderBox(renderer())->overflowClipRect(0, 0));
3582 if (renderer()->hasClip())
3583 rect.intersect(toRenderBox(renderer())->clipRect(0, 0));
3584 if (!rect.isEmpty())
3585 renderer()->repaintRectangle(rect);
3586 }
3587
intersectsDamageRect(const IntRect & layerBounds,const IntRect & damageRect,const RenderLayer * rootLayer) const3588 bool RenderLayer::intersectsDamageRect(const IntRect& layerBounds, const IntRect& damageRect, const RenderLayer* rootLayer) const
3589 {
3590 // Always examine the canvas and the root.
3591 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
3592 // paints the root's background.
3593 if (renderer()->isRenderView() || renderer()->isRoot())
3594 return true;
3595
3596 // If we aren't an inline flow, and our layer bounds do intersect the damage rect, then we
3597 // can go ahead and return true.
3598 RenderView* view = renderer()->view();
3599 ASSERT(view);
3600 if (view && !renderer()->isRenderInline()) {
3601 IntRect b = layerBounds;
3602 b.inflate(view->maximalOutlineSize());
3603 if (b.intersects(damageRect))
3604 return true;
3605 }
3606
3607 // Otherwise we need to compute the bounding box of this single layer and see if it intersects
3608 // the damage rect.
3609 return boundingBox(rootLayer).intersects(damageRect);
3610 }
3611
localBoundingBox() const3612 IntRect RenderLayer::localBoundingBox() const
3613 {
3614 // There are three special cases we need to consider.
3615 // (1) Inline Flows. For inline flows we will create a bounding box that fully encompasses all of the lines occupied by the
3616 // inline. In other words, if some <span> wraps to three lines, we'll create a bounding box that fully encloses the
3617 // line boxes of all three lines (including overflow on those lines).
3618 // (2) Left/Top Overflow. The width/height of layers already includes right/bottom overflow. However, in the case of left/top
3619 // overflow, we have to create a bounding box that will extend to include this overflow.
3620 // (3) Floats. When a layer has overhanging floats that it paints, we need to make sure to include these overhanging floats
3621 // as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those
3622 // floats.
3623 IntRect result;
3624 if (renderer()->isRenderInline())
3625 result = toRenderInline(renderer())->linesVisualOverflowBoundingBox();
3626 else if (renderer()->isTableRow()) {
3627 // Our bounding box is just the union of all of our cells' border/overflow rects.
3628 for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) {
3629 if (child->isTableCell()) {
3630 IntRect bbox = toRenderBox(child)->borderBoxRect();
3631 result.unite(bbox);
3632 IntRect overflowRect = renderBox()->visualOverflowRect();
3633 if (bbox != overflowRect)
3634 result.unite(overflowRect);
3635 }
3636 }
3637 } else {
3638 RenderBox* box = renderBox();
3639 ASSERT(box);
3640 if (box->hasMask())
3641 result = box->maskClipRect();
3642 else {
3643 IntRect bbox = box->borderBoxRect();
3644 result = bbox;
3645 IntRect overflowRect = box->visualOverflowRect();
3646 if (bbox != overflowRect)
3647 result.unite(overflowRect);
3648 }
3649 }
3650
3651 RenderView* view = renderer()->view();
3652 ASSERT(view);
3653 if (view)
3654 result.inflate(view->maximalOutlineSize()); // Used to apply a fudge factor to dirty-rect checks on blocks/tables.
3655
3656 return result;
3657 }
3658
boundingBox(const RenderLayer * ancestorLayer) const3659 IntRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer) const
3660 {
3661 IntRect result = localBoundingBox();
3662 if (renderer()->isBox())
3663 renderBox()->flipForWritingMode(result);
3664 else
3665 renderer()->containingBlock()->flipForWritingMode(result);
3666 int deltaX = 0, deltaY = 0;
3667 convertToLayerCoords(ancestorLayer, deltaX, deltaY);
3668 result.move(deltaX, deltaY);
3669 return result;
3670 }
3671
absoluteBoundingBox() const3672 IntRect RenderLayer::absoluteBoundingBox() const
3673 {
3674 return boundingBox(root());
3675 }
3676
clearClipRectsIncludingDescendants()3677 void RenderLayer::clearClipRectsIncludingDescendants()
3678 {
3679 if (!m_clipRects)
3680 return;
3681
3682 clearClipRects();
3683
3684 for (RenderLayer* l = firstChild(); l; l = l->nextSibling())
3685 l->clearClipRectsIncludingDescendants();
3686 }
3687
clearClipRects()3688 void RenderLayer::clearClipRects()
3689 {
3690 if (m_clipRects) {
3691 m_clipRects->deref(renderer()->renderArena());
3692 m_clipRects = 0;
3693 #ifndef NDEBUG
3694 m_clipRectsRoot = 0;
3695 #endif
3696 }
3697 }
3698
3699 #if USE(ACCELERATED_COMPOSITING)
ensureBacking()3700 RenderLayerBacking* RenderLayer::ensureBacking()
3701 {
3702 if (!m_backing)
3703 m_backing.set(new RenderLayerBacking(this));
3704 return m_backing.get();
3705 }
3706
clearBacking()3707 void RenderLayer::clearBacking()
3708 {
3709 m_backing.clear();
3710 }
3711
hasCompositedMask() const3712 bool RenderLayer::hasCompositedMask() const
3713 {
3714 return m_backing && m_backing->hasMaskLayer();
3715 }
3716
layerForHorizontalScrollbar() const3717 GraphicsLayer* RenderLayer::layerForHorizontalScrollbar() const
3718 {
3719 return m_backing ? m_backing->layerForHorizontalScrollbar() : 0;
3720 }
3721
layerForVerticalScrollbar() const3722 GraphicsLayer* RenderLayer::layerForVerticalScrollbar() const
3723 {
3724 return m_backing ? m_backing->layerForVerticalScrollbar() : 0;
3725 }
3726
layerForScrollCorner() const3727 GraphicsLayer* RenderLayer::layerForScrollCorner() const
3728 {
3729 return m_backing ? m_backing->layerForScrollCorner() : 0;
3730 }
3731 #endif
3732
paintsWithTransform(PaintBehavior paintBehavior) const3733 bool RenderLayer::paintsWithTransform(PaintBehavior paintBehavior) const
3734 {
3735 #if USE(ACCELERATED_COMPOSITING)
3736 bool paintsToWindow = !isComposited() || backing()->paintingGoesToWindow();
3737 #else
3738 bool paintsToWindow = true;
3739 #endif
3740 return transform() && ((paintBehavior & PaintBehaviorFlattenCompositingLayers) || paintsToWindow);
3741 }
3742
setParent(RenderLayer * parent)3743 void RenderLayer::setParent(RenderLayer* parent)
3744 {
3745 if (parent == m_parent)
3746 return;
3747
3748 #if USE(ACCELERATED_COMPOSITING)
3749 if (m_parent && !renderer()->documentBeingDestroyed())
3750 compositor()->layerWillBeRemoved(m_parent, this);
3751 #endif
3752
3753 m_parent = parent;
3754
3755 #if USE(ACCELERATED_COMPOSITING)
3756 if (m_parent && !renderer()->documentBeingDestroyed())
3757 compositor()->layerWasAdded(m_parent, this);
3758 #endif
3759 }
3760
commonAncestor(RenderObject * obj1,RenderObject * obj2)3761 static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2)
3762 {
3763 if (!obj1 || !obj2)
3764 return 0;
3765
3766 for (RenderObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor())
3767 for (RenderObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor())
3768 if (currObj1 == currObj2)
3769 return currObj1;
3770
3771 return 0;
3772 }
3773
updateHoverActiveState(const HitTestRequest & request,HitTestResult & result)3774 void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestResult& result)
3775 {
3776 // We don't update :hover/:active state when the result is marked as readOnly.
3777 if (request.readOnly())
3778 return;
3779
3780 Document* doc = renderer()->document();
3781
3782 Node* activeNode = doc->activeNode();
3783 if (activeNode && !request.active()) {
3784 // We are clearing the :active chain because the mouse has been released.
3785 for (RenderObject* curr = activeNode->renderer(); curr; curr = curr->parent()) {
3786 if (curr->node() && !curr->isText())
3787 curr->node()->clearInActiveChain();
3788 }
3789 doc->setActiveNode(0);
3790 } else {
3791 Node* newActiveNode = result.innerNode();
3792 if (!activeNode && newActiveNode && request.active()) {
3793 // We are setting the :active chain and freezing it. If future moves happen, they
3794 // will need to reference this chain.
3795 for (RenderObject* curr = newActiveNode->renderer(); curr; curr = curr->parent()) {
3796 if (curr->node() && !curr->isText()) {
3797 curr->node()->setInActiveChain();
3798 }
3799 }
3800 doc->setActiveNode(newActiveNode);
3801 }
3802 }
3803
3804 // If the mouse is down and if this is a mouse move event, we want to restrict changes in
3805 // :hover/:active to only apply to elements that are in the :active chain that we froze
3806 // at the time the mouse went down.
3807 bool mustBeInActiveChain = request.active() && request.mouseMove();
3808
3809 // Check to see if the hovered node has changed. If not, then we don't need to
3810 // do anything.
3811 RefPtr<Node> oldHoverNode = doc->hoverNode();
3812 Node* newHoverNode = result.innerNode();
3813
3814 // Update our current hover node.
3815 doc->setHoverNode(newHoverNode);
3816
3817 // We have two different objects. Fetch their renderers.
3818 RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
3819 RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0;
3820
3821 // Locate the common ancestor render object for the two renderers.
3822 RenderObject* ancestor = commonAncestor(oldHoverObj, newHoverObj);
3823
3824 Vector<RefPtr<Node>, 32> nodesToRemoveFromChain;
3825 Vector<RefPtr<Node>, 32> nodesToAddToChain;
3826
3827 if (oldHoverObj != newHoverObj) {
3828 // The old hover path only needs to be cleared up to (and not including) the common ancestor;
3829 for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) {
3830 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain()))
3831 nodesToRemoveFromChain.append(curr->node());
3832 }
3833 }
3834
3835 // Now set the hover state for our new object up to the root.
3836 for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) {
3837 if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain()))
3838 nodesToAddToChain.append(curr->node());
3839 }
3840
3841 size_t removeCount = nodesToRemoveFromChain.size();
3842 for (size_t i = 0; i < removeCount; ++i) {
3843 nodesToRemoveFromChain[i]->setActive(false);
3844 nodesToRemoveFromChain[i]->setHovered(false);
3845 }
3846
3847 size_t addCount = nodesToAddToChain.size();
3848 for (size_t i = 0; i < addCount; ++i) {
3849 nodesToAddToChain[i]->setActive(request.active());
3850 nodesToAddToChain[i]->setHovered(true);
3851 }
3852 }
3853
3854 // Helper for the sorting of layers by z-index.
compareZIndex(RenderLayer * first,RenderLayer * second)3855 static inline bool compareZIndex(RenderLayer* first, RenderLayer* second)
3856 {
3857 return first->zIndex() < second->zIndex();
3858 }
3859
dirtyZOrderLists()3860 void RenderLayer::dirtyZOrderLists()
3861 {
3862 if (m_posZOrderList)
3863 m_posZOrderList->clear();
3864 if (m_negZOrderList)
3865 m_negZOrderList->clear();
3866 m_zOrderListsDirty = true;
3867
3868 #if USE(ACCELERATED_COMPOSITING)
3869 if (!renderer()->documentBeingDestroyed())
3870 compositor()->setCompositingLayersNeedRebuild();
3871 #endif
3872 }
3873
dirtyStackingContextZOrderLists()3874 void RenderLayer::dirtyStackingContextZOrderLists()
3875 {
3876 RenderLayer* sc = stackingContext();
3877 if (sc)
3878 sc->dirtyZOrderLists();
3879 }
3880
dirtyNormalFlowList()3881 void RenderLayer::dirtyNormalFlowList()
3882 {
3883 if (m_normalFlowList)
3884 m_normalFlowList->clear();
3885 m_normalFlowListDirty = true;
3886
3887 #if USE(ACCELERATED_COMPOSITING)
3888 if (!renderer()->documentBeingDestroyed())
3889 compositor()->setCompositingLayersNeedRebuild();
3890 #endif
3891 }
3892
updateZOrderLists()3893 void RenderLayer::updateZOrderLists()
3894 {
3895 if (!isStackingContext() || !m_zOrderListsDirty)
3896 return;
3897
3898 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
3899 if (!m_reflection || reflectionLayer() != child)
3900 child->collectLayers(m_posZOrderList, m_negZOrderList);
3901
3902 // Sort the two lists.
3903 if (m_posZOrderList)
3904 std::stable_sort(m_posZOrderList->begin(), m_posZOrderList->end(), compareZIndex);
3905
3906 if (m_negZOrderList)
3907 std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(), compareZIndex);
3908
3909 m_zOrderListsDirty = false;
3910 }
3911
updateNormalFlowList()3912 void RenderLayer::updateNormalFlowList()
3913 {
3914 if (!m_normalFlowListDirty)
3915 return;
3916
3917 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
3918 // Ignore non-overflow layers and reflections.
3919 if (child->isNormalFlowOnly() && (!m_reflection || reflectionLayer() != child)) {
3920 if (!m_normalFlowList)
3921 m_normalFlowList = new Vector<RenderLayer*>;
3922 m_normalFlowList->append(child);
3923 }
3924 }
3925
3926 m_normalFlowListDirty = false;
3927 }
3928
collectLayers(Vector<RenderLayer * > * & posBuffer,Vector<RenderLayer * > * & negBuffer)3929 void RenderLayer::collectLayers(Vector<RenderLayer*>*& posBuffer, Vector<RenderLayer*>*& negBuffer)
3930 {
3931 updateVisibilityStatus();
3932
3933 // Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists.
3934 if ((m_hasVisibleContent || (m_hasVisibleDescendant && isStackingContext())) && !isNormalFlowOnly()) {
3935 // Determine which buffer the child should be in.
3936 Vector<RenderLayer*>*& buffer = (zIndex() >= 0) ? posBuffer : negBuffer;
3937
3938 // Create the buffer if it doesn't exist yet.
3939 if (!buffer)
3940 buffer = new Vector<RenderLayer*>;
3941
3942 // Append ourselves at the end of the appropriate buffer.
3943 buffer->append(this);
3944 }
3945
3946 // Recur into our children to collect more layers, but only if we don't establish
3947 // a stacking context.
3948 if (m_hasVisibleDescendant && !isStackingContext()) {
3949 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
3950 // Ignore reflections.
3951 if (!m_reflection || reflectionLayer() != child)
3952 child->collectLayers(posBuffer, negBuffer);
3953 }
3954 }
3955 }
3956
updateLayerListsIfNeeded()3957 void RenderLayer::updateLayerListsIfNeeded()
3958 {
3959 updateZOrderLists();
3960 updateNormalFlowList();
3961 }
3962
updateCompositingAndLayerListsIfNeeded()3963 void RenderLayer::updateCompositingAndLayerListsIfNeeded()
3964 {
3965 #if USE(ACCELERATED_COMPOSITING)
3966 if (compositor()->inCompositingMode()) {
3967 if ((isStackingContext() && m_zOrderListsDirty) || m_normalFlowListDirty)
3968 compositor()->updateCompositingLayers(CompositingUpdateOnPaitingOrHitTest, this);
3969 return;
3970 }
3971 #endif
3972 updateLayerListsIfNeeded();
3973 }
3974
repaintIncludingDescendants()3975 void RenderLayer::repaintIncludingDescendants()
3976 {
3977 renderer()->repaint();
3978 for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling())
3979 curr->repaintIncludingDescendants();
3980 }
3981
3982 #if USE(ACCELERATED_COMPOSITING)
setBackingNeedsRepaint()3983 void RenderLayer::setBackingNeedsRepaint()
3984 {
3985 ASSERT(isComposited());
3986 if (backing()->paintingGoesToWindow()) {
3987 // If we're trying to repaint the placeholder document layer, propagate the
3988 // repaint to the native view system.
3989 RenderView* view = renderer()->view();
3990 if (view)
3991 view->repaintViewRectangle(absoluteBoundingBox());
3992 } else
3993 backing()->setContentsNeedDisplay();
3994 }
3995
setBackingNeedsRepaintInRect(const IntRect & r)3996 void RenderLayer::setBackingNeedsRepaintInRect(const IntRect& r)
3997 {
3998 ASSERT(isComposited());
3999 if (backing()->paintingGoesToWindow()) {
4000 // If we're trying to repaint the placeholder document layer, propagate the
4001 // repaint to the native view system.
4002 IntRect absRect(r);
4003 int x = 0;
4004 int y = 0;
4005 convertToLayerCoords(root(), x, y);
4006 absRect.move(x, y);
4007
4008 RenderView* view = renderer()->view();
4009 if (view)
4010 view->repaintViewRectangle(absRect);
4011 } else
4012 backing()->setContentsNeedDisplayInRect(r);
4013 }
4014
4015 // Since we're only painting non-composited layers, we know that they all share the same repaintContainer.
repaintIncludingNonCompositingDescendants(RenderBoxModelObject * repaintContainer)4016 void RenderLayer::repaintIncludingNonCompositingDescendants(RenderBoxModelObject* repaintContainer)
4017 {
4018 renderer()->repaintUsingContainer(repaintContainer, renderer()->clippedOverflowRectForRepaint(repaintContainer));
4019
4020 for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling()) {
4021 if (!curr->isComposited())
4022 curr->repaintIncludingNonCompositingDescendants(repaintContainer);
4023 }
4024 }
4025 #endif
4026
shouldBeNormalFlowOnly() const4027 bool RenderLayer::shouldBeNormalFlowOnly() const
4028 {
4029 return (renderer()->hasOverflowClip()
4030 || renderer()->hasReflection()
4031 || renderer()->hasMask()
4032 || renderer()->isVideo()
4033 || renderer()->isEmbeddedObject()
4034 || renderer()->isApplet()
4035 || renderer()->isRenderIFrame()
4036 || renderer()->style()->specifiesColumns())
4037 && !renderer()->isPositioned()
4038 && !renderer()->isRelPositioned()
4039 && !renderer()->hasTransform()
4040 && !isTransparent();
4041 }
4042
isSelfPaintingLayer() const4043 bool RenderLayer::isSelfPaintingLayer() const
4044 {
4045 #if ENABLE(ANDROID_OVERFLOW_SCROLL)
4046 if (hasOverflowScroll())
4047 return true;
4048 #endif
4049 return !isNormalFlowOnly()
4050 || renderer()->hasReflection()
4051 || renderer()->hasMask()
4052 || renderer()->isTableRow()
4053 || renderer()->isVideo()
4054 || renderer()->isEmbeddedObject()
4055 || renderer()->isApplet()
4056 || renderer()->isRenderIFrame();
4057 }
4058
styleChanged(StyleDifference diff,const RenderStyle * oldStyle)4059 void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle* oldStyle)
4060 {
4061 bool isNormalFlowOnly = shouldBeNormalFlowOnly();
4062 if (isNormalFlowOnly != m_isNormalFlowOnly) {
4063 m_isNormalFlowOnly = isNormalFlowOnly;
4064 RenderLayer* p = parent();
4065 if (p)
4066 p->dirtyNormalFlowList();
4067 dirtyStackingContextZOrderLists();
4068 }
4069
4070 if (renderer()->style()->overflowX() == OMARQUEE && renderer()->style()->marqueeBehavior() != MNONE && renderer()->isBox()) {
4071 if (!m_marquee)
4072 m_marquee = new RenderMarquee(this);
4073 m_marquee->updateMarqueeStyle();
4074 }
4075 else if (m_marquee) {
4076 delete m_marquee;
4077 m_marquee = 0;
4078 }
4079
4080 if (!hasReflection() && m_reflection)
4081 removeReflection();
4082 else if (hasReflection()) {
4083 if (!m_reflection)
4084 createReflection();
4085 updateReflectionStyle();
4086 }
4087
4088 // FIXME: Need to detect a swap from custom to native scrollbars (and vice versa).
4089 if (m_hBar)
4090 m_hBar->styleChanged();
4091 if (m_vBar)
4092 m_vBar->styleChanged();
4093
4094 updateScrollCornerStyle();
4095 updateResizerStyle();
4096
4097 #if USE(ACCELERATED_COMPOSITING)
4098 updateTransform();
4099
4100 if (compositor()->updateLayerCompositingState(this))
4101 compositor()->setCompositingLayersNeedRebuild();
4102 else if (m_backing)
4103 m_backing->updateGraphicsLayerGeometry();
4104 else if (oldStyle && oldStyle->overflowX() != renderer()->style()->overflowX()) {
4105 if (stackingContext()->hasCompositingDescendant())
4106 compositor()->setCompositingLayersNeedRebuild();
4107 }
4108
4109 if (m_backing && diff >= StyleDifferenceRepaint)
4110 m_backing->setContentsNeedDisplay();
4111 #else
4112 UNUSED_PARAM(diff);
4113 #endif
4114 }
4115
updateScrollCornerStyle()4116 void RenderLayer::updateScrollCornerStyle()
4117 {
4118 RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
4119 RefPtr<RenderStyle> corner = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, actualRenderer->style()) : 0;
4120 if (corner) {
4121 if (!m_scrollCorner) {
4122 m_scrollCorner = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document());
4123 m_scrollCorner->setParent(renderer());
4124 }
4125 m_scrollCorner->setStyle(corner.release());
4126 } else if (m_scrollCorner) {
4127 m_scrollCorner->destroy();
4128 m_scrollCorner = 0;
4129 }
4130 }
4131
updateResizerStyle()4132 void RenderLayer::updateResizerStyle()
4133 {
4134 RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
4135 RefPtr<RenderStyle> resizer = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RESIZER, actualRenderer->style()) : 0;
4136 if (resizer) {
4137 if (!m_resizer) {
4138 m_resizer = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document());
4139 m_resizer->setParent(renderer());
4140 }
4141 m_resizer->setStyle(resizer.release());
4142 } else if (m_resizer) {
4143 m_resizer->destroy();
4144 m_resizer = 0;
4145 }
4146 }
4147
reflectionLayer() const4148 RenderLayer* RenderLayer::reflectionLayer() const
4149 {
4150 return m_reflection ? m_reflection->layer() : 0;
4151 }
4152
createReflection()4153 void RenderLayer::createReflection()
4154 {
4155 ASSERT(!m_reflection);
4156 m_reflection = new (renderer()->renderArena()) RenderReplica(renderer()->document());
4157 m_reflection->setParent(renderer()); // We create a 1-way connection.
4158 }
4159
removeReflection()4160 void RenderLayer::removeReflection()
4161 {
4162 if (!m_reflection->documentBeingDestroyed())
4163 m_reflection->removeLayers(this);
4164
4165 m_reflection->setParent(0);
4166 m_reflection->destroy();
4167 m_reflection = 0;
4168 }
4169
updateReflectionStyle()4170 void RenderLayer::updateReflectionStyle()
4171 {
4172 RefPtr<RenderStyle> newStyle = RenderStyle::create();
4173 newStyle->inheritFrom(renderer()->style());
4174
4175 // Map in our transform.
4176 TransformOperations transform;
4177 switch (renderer()->style()->boxReflect()->direction()) {
4178 case ReflectionBelow:
4179 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::TRANSLATE));
4180 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), renderer()->style()->boxReflect()->offset(), TransformOperation::TRANSLATE));
4181 transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::SCALE));
4182 break;
4183 case ReflectionAbove:
4184 transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::SCALE));
4185 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::TRANSLATE));
4186 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), renderer()->style()->boxReflect()->offset(), TransformOperation::TRANSLATE));
4187 break;
4188 case ReflectionRight:
4189 transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::TRANSLATE));
4190 transform.operations().append(TranslateTransformOperation::create(renderer()->style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::TRANSLATE));
4191 transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::SCALE));
4192 break;
4193 case ReflectionLeft:
4194 transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::SCALE));
4195 transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::TRANSLATE));
4196 transform.operations().append(TranslateTransformOperation::create(renderer()->style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::TRANSLATE));
4197 break;
4198 }
4199 newStyle->setTransform(transform);
4200
4201 // Map in our mask.
4202 newStyle->setMaskBoxImage(renderer()->style()->boxReflect()->mask());
4203
4204 m_reflection->setStyle(newStyle.release());
4205 }
4206
updateContentsScale(float scale)4207 void RenderLayer::updateContentsScale(float scale)
4208 {
4209 #if USE(ACCELERATED_COMPOSITING)
4210 if (m_backing)
4211 m_backing->updateContentsScale(scale);
4212 #endif
4213 }
4214
4215 } // namespace WebCore
4216
4217 #ifndef NDEBUG
showLayerTree(const WebCore::RenderLayer * layer)4218 void showLayerTree(const WebCore::RenderLayer* layer)
4219 {
4220 if (!layer)
4221 return;
4222
4223 if (WebCore::Frame* frame = layer->renderer()->frame()) {
4224 WTF::String output = externalRepresentation(frame, WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers | WebCore::RenderAsTextShowAddresses | WebCore::RenderAsTextShowIDAndClass | WebCore::RenderAsTextDontUpdateLayout | WebCore::RenderAsTextShowLayoutState);
4225 fprintf(stderr, "%s\n", output.utf8().data());
4226 }
4227 }
4228
showLayerTree(const WebCore::RenderObject * renderer)4229 void showLayerTree(const WebCore::RenderObject* renderer)
4230 {
4231 if (!renderer)
4232 return;
4233 showLayerTree(renderer->enclosingLayer());
4234 }
4235 #endif
4236