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