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