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 "CSSPropertyNames.h"
48 #include "Document.h"
49 #include "EventHandler.h"
50 #include "EventNames.h"
51 #include "FloatRect.h"
52 #include "FocusController.h"
53 #include "Frame.h"
54 #include "FrameTree.h"
55 #include "FrameView.h"
56 #include "Gradient.h"
57 #include "GraphicsContext.h"
58 #include "HTMLNames.h"
59 #include "HitTestRequest.h"
60 #include "HitTestResult.h"
61 #include "OverflowEvent.h"
62 #include "Page.h"
63 #include "PlatformMouseEvent.h"
64 #include "RenderArena.h"
65 #include "RenderInline.h"
66 #include "RenderMarquee.h"
67 #include "RenderReplica.h"
68 #include "RenderScrollbar.h"
69 #include "RenderScrollbarPart.h"
70 #include "RenderTheme.h"
71 #include "RenderView.h"
72 #include "ScaleTransformOperation.h"
73 #include "Scrollbar.h"
74 #include "ScrollbarTheme.h"
75 #include "SelectionController.h"
76 #include "TranslateTransformOperation.h"
77 #include <wtf/StdLibExtras.h>
78
79 #if ENABLE(SVG)
80 #include "SVGNames.h"
81 #endif
82
83 #define MIN_INTERSECT_FOR_REVEAL 32
84
85 using namespace std;
86
87 namespace WebCore {
88
89 using namespace HTMLNames;
90
91 const RenderLayer::ScrollAlignment RenderLayer::gAlignCenterIfNeeded = { RenderLayer::noScroll, RenderLayer::alignCenter, RenderLayer::alignToClosestEdge };
92 const RenderLayer::ScrollAlignment RenderLayer::gAlignToEdgeIfNeeded = { RenderLayer::noScroll, RenderLayer::alignToClosestEdge, RenderLayer::alignToClosestEdge };
93 const RenderLayer::ScrollAlignment RenderLayer::gAlignCenterAlways = { RenderLayer::alignCenter, RenderLayer::alignCenter, RenderLayer::alignCenter };
94 const RenderLayer::ScrollAlignment RenderLayer::gAlignTopAlways = { RenderLayer::alignTop, RenderLayer::alignTop, RenderLayer::alignTop };
95 const RenderLayer::ScrollAlignment RenderLayer::gAlignBottomAlways = { RenderLayer::alignBottom, RenderLayer::alignBottom, RenderLayer::alignBottom };
96
97 const int MinimumWidthWhileResizing = 100;
98 const int MinimumHeightWhileResizing = 40;
99
operator new(size_t sz,RenderArena * renderArena)100 void* ClipRects::operator new(size_t sz, RenderArena* renderArena) throw()
101 {
102 return renderArena->allocate(sz);
103 }
104
operator delete(void * ptr,size_t sz)105 void ClipRects::operator delete(void* ptr, size_t sz)
106 {
107 // Stash size where destroy can find it.
108 *(size_t *)ptr = sz;
109 }
110
destroy(RenderArena * renderArena)111 void ClipRects::destroy(RenderArena* renderArena)
112 {
113 delete this;
114
115 // Recover the size left there for us by operator delete and free the memory.
116 renderArena->free(*(size_t *)this, this);
117 }
118
RenderLayer(RenderBox * renderer)119 RenderLayer::RenderLayer(RenderBox* renderer)
120 : m_renderer(renderer)
121 , m_parent(0)
122 , m_previous(0)
123 , m_next(0)
124 , m_first(0)
125 , m_last(0)
126 , m_relX(0)
127 , m_relY(0)
128 , m_x(0)
129 , m_y(0)
130 , m_width(0)
131 , m_height(0)
132 , m_scrollX(0)
133 , m_scrollY(0)
134 , m_scrollOriginX(0)
135 , m_scrollLeftOverflow(0)
136 , m_scrollWidth(0)
137 , m_scrollHeight(0)
138 , m_inResizeMode(false)
139 , m_posZOrderList(0)
140 , m_negZOrderList(0)
141 , m_overflowList(0)
142 , m_clipRects(0)
143 #ifndef NDEBUG
144 , m_clipRectsRoot(0)
145 #endif
146 , m_scrollDimensionsDirty(true)
147 , m_zOrderListsDirty(true)
148 , m_overflowListDirty(true)
149 , m_isOverflowOnly(shouldBeOverflowOnly())
150 , m_usedTransparency(false)
151 , m_paintingInsideReflection(false)
152 , m_inOverflowRelayout(false)
153 , m_needsFullRepaint(false)
154 , m_overflowStatusDirty(true)
155 , m_visibleContentStatusDirty(true)
156 , m_hasVisibleContent(false)
157 , m_visibleDescendantStatusDirty(false)
158 , m_hasVisibleDescendant(false)
159 , m_marquee(0)
160 , m_staticX(0)
161 , m_staticY(0)
162 , m_transform(0)
163 , m_reflection(0)
164 , m_scrollCorner(0)
165 , m_resizer(0)
166 {
167 if (!renderer->firstChild() && renderer->style()) {
168 m_visibleContentStatusDirty = false;
169 m_hasVisibleContent = renderer->style()->visibility() == VISIBLE;
170 }
171 }
172
~RenderLayer()173 RenderLayer::~RenderLayer()
174 {
175 if (inResizeMode() && !renderer()->documentBeingDestroyed()) {
176 if (Frame* frame = renderer()->document()->frame())
177 frame->eventHandler()->resizeLayerDestroyed();
178 }
179
180 destroyScrollbar(HorizontalScrollbar);
181 destroyScrollbar(VerticalScrollbar);
182
183 // Child layers will be deleted by their corresponding render objects, so
184 // we don't need to delete them ourselves.
185
186 delete m_posZOrderList;
187 delete m_negZOrderList;
188 delete m_overflowList;
189 delete m_marquee;
190
191 // Make sure we have no lingering clip rects.
192 ASSERT(!m_clipRects);
193
194 if (m_reflection) {
195 if (!m_reflection->documentBeingDestroyed())
196 m_reflection->removeLayers(this);
197 m_reflection->setParent(0);
198 m_reflection->destroy();
199 }
200
201 if (m_scrollCorner)
202 m_scrollCorner->destroy();
203 if (m_resizer)
204 m_resizer->destroy();
205 }
206
updateLayerPositions(bool doFullRepaint,bool checkForRepaint)207 void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint)
208 {
209 if (doFullRepaint) {
210 renderer()->repaint();
211 checkForRepaint = doFullRepaint = false;
212 }
213
214 updateLayerPosition(); // For relpositioned layers or non-positioned layers,
215 // we need to keep in sync, since we may have shifted relative
216 // to our parent layer.
217
218 int x = 0;
219 int y = 0;
220 convertToLayerCoords(root(), x, y);
221 positionOverflowControls(x, y);
222
223 updateVisibilityStatus();
224
225 updateTransform();
226
227 if (m_hasVisibleContent) {
228 RenderView* view = renderer()->view();
229 ASSERT(view);
230 // FIXME: Optimize using LayoutState and remove the disableLayoutState() call
231 // from updateScrollInfoAfterLayout().
232 ASSERT(!view->layoutStateEnabled());
233
234 IntRect newRect = renderer()->absoluteClippedOverflowRect();
235 IntRect newOutlineBox = renderer()->absoluteOutlineBounds();
236 if (checkForRepaint) {
237 if (view && !view->printing()) {
238 if (m_needsFullRepaint) {
239 view->repaintViewRectangle(m_repaintRect);
240 if (newRect != m_repaintRect)
241 view->repaintViewRectangle(newRect);
242 } else
243 renderer()->repaintAfterLayoutIfNeeded(m_repaintRect, m_outlineBox);
244 }
245 }
246 m_repaintRect = newRect;
247 m_outlineBox = newOutlineBox;
248 } else {
249 m_repaintRect = IntRect();
250 m_outlineBox = IntRect();
251 }
252
253 m_needsFullRepaint = false;
254
255 // Go ahead and update the reflection's position and size.
256 if (m_reflection)
257 m_reflection->layout();
258
259 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
260 child->updateLayerPositions(doFullRepaint, checkForRepaint);
261
262 // With all our children positioned, now update our marquee if we need to.
263 if (m_marquee)
264 m_marquee->updateMarqueePosition();
265 }
266
updateTransform()267 void RenderLayer::updateTransform()
268 {
269 bool hasTransform = renderer()->hasTransform();
270 bool hadTransform = m_transform;
271 if (hasTransform != hadTransform) {
272 if (hasTransform)
273 m_transform.set(new TransformationMatrix);
274 else
275 m_transform.clear();
276 }
277
278 if (hasTransform) {
279 m_transform->reset();
280 renderer()->style()->applyTransform(*m_transform, renderer()->borderBoxRect().size());
281 }
282 }
283
setHasVisibleContent(bool b)284 void RenderLayer::setHasVisibleContent(bool b)
285 {
286 if (m_hasVisibleContent == b && !m_visibleContentStatusDirty)
287 return;
288 m_visibleContentStatusDirty = false;
289 m_hasVisibleContent = b;
290 if (m_hasVisibleContent) {
291 m_repaintRect = renderer()->absoluteClippedOverflowRect();
292 m_outlineBox = renderer()->absoluteOutlineBounds();
293 if (!isOverflowOnly())
294 dirtyStackingContextZOrderLists();
295 }
296 if (parent())
297 parent()->childVisibilityChanged(m_hasVisibleContent);
298 }
299
dirtyVisibleContentStatus()300 void RenderLayer::dirtyVisibleContentStatus()
301 {
302 m_visibleContentStatusDirty = true;
303 if (parent())
304 parent()->dirtyVisibleDescendantStatus();
305 }
306
childVisibilityChanged(bool newVisibility)307 void RenderLayer::childVisibilityChanged(bool newVisibility)
308 {
309 if (m_hasVisibleDescendant == newVisibility || m_visibleDescendantStatusDirty)
310 return;
311 if (newVisibility) {
312 RenderLayer* l = this;
313 while (l && !l->m_visibleDescendantStatusDirty && !l->m_hasVisibleDescendant) {
314 l->m_hasVisibleDescendant = true;
315 l = l->parent();
316 }
317 } else
318 dirtyVisibleDescendantStatus();
319 }
320
dirtyVisibleDescendantStatus()321 void RenderLayer::dirtyVisibleDescendantStatus()
322 {
323 RenderLayer* l = this;
324 while (l && !l->m_visibleDescendantStatusDirty) {
325 l->m_visibleDescendantStatusDirty = true;
326 l = l->parent();
327 }
328 }
329
updateVisibilityStatus()330 void RenderLayer::updateVisibilityStatus()
331 {
332 if (m_visibleDescendantStatusDirty) {
333 m_hasVisibleDescendant = false;
334 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
335 child->updateVisibilityStatus();
336 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) {
337 m_hasVisibleDescendant = true;
338 break;
339 }
340 }
341 m_visibleDescendantStatusDirty = false;
342 }
343
344 if (m_visibleContentStatusDirty) {
345 if (renderer()->style()->visibility() == VISIBLE)
346 m_hasVisibleContent = true;
347 else {
348 // layer may be hidden but still have some visible content, check for this
349 m_hasVisibleContent = false;
350 RenderObject* r = renderer()->firstChild();
351 while (r) {
352 if (r->style()->visibility() == VISIBLE && !r->hasLayer()) {
353 m_hasVisibleContent = true;
354 break;
355 }
356 if (r->firstChild() && !r->hasLayer())
357 r = r->firstChild();
358 else if (r->nextSibling())
359 r = r->nextSibling();
360 else {
361 do {
362 r = r->parent();
363 if (r==renderer())
364 r = 0;
365 } while (r && !r->nextSibling());
366 if (r)
367 r = r->nextSibling();
368 }
369 }
370 }
371 m_visibleContentStatusDirty = false;
372 }
373 }
374
updateLayerPosition()375 void RenderLayer::updateLayerPosition()
376 {
377 // Clear our cached clip rect information.
378 clearClipRects();
379
380 int x = renderer()->x();
381 int y = renderer()->y();
382
383 if (!renderer()->isPositioned() && renderer()->parent()) {
384 // We must adjust our position by walking up the render tree looking for the
385 // nearest enclosing object with a layer.
386 RenderBox* curr = renderer()->parentBox();
387 while (curr && !curr->hasLayer()) {
388 if (!curr->isTableRow()) {
389 // Rows and cells share the same coordinate space (that of the section).
390 // Omit them when computing our xpos/ypos.
391 x += curr->x();
392 y += curr->y();
393 }
394 curr = curr->parentBox();
395 }
396 if (curr->isTableRow()) {
397 // Put ourselves into the row coordinate space.
398 x -= curr->x();
399 y -= curr->y();
400 }
401 }
402
403 m_relX = m_relY = 0;
404 if (renderer()->isRelPositioned()) {
405 m_relX = toRenderBox(renderer())->relativePositionOffsetX();
406 m_relY = toRenderBox(renderer())->relativePositionOffsetY();
407 x += m_relX; y += m_relY;
408 }
409
410 // Subtract our parent's scroll offset.
411 if (renderer()->isPositioned() && enclosingPositionedAncestor()) {
412 RenderLayer* positionedParent = enclosingPositionedAncestor();
413
414 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
415 positionedParent->subtractScrolledContentOffset(x, y);
416
417 if (renderer()->isPositioned()) {
418 IntSize offset = toRenderBox(renderer())->offsetForPositionedInContainer(positionedParent->renderer());
419 x += offset.width();
420 y += offset.height();
421 }
422 } else if (parent())
423 parent()->subtractScrolledContentOffset(x, y);
424
425 // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
426
427 setPos(x, y);
428
429 if (renderer()->isRenderInline()) {
430 RenderInline* inlineFlow = static_cast<RenderInline*>(renderer());
431 IntRect lineBox = inlineFlow->linesBoundingBox();
432 setWidth(lineBox.width());
433 setHeight(lineBox.height());
434 } else {
435 setWidth(renderer()->width());
436 setHeight(renderer()->height());
437
438 if (!renderer()->hasOverflowClip()) {
439 if (renderer()->overflowWidth() > renderer()->width())
440 setWidth(renderer()->overflowWidth());
441 if (renderer()->overflowHeight() > renderer()->height())
442 setHeight(renderer()->overflowHeight());
443 }
444 }
445 }
446
stackingContext() const447 RenderLayer *RenderLayer::stackingContext() const
448 {
449 RenderLayer* curr = parent();
450 for ( ; curr && !curr->renderer()->isRenderView() && !curr->renderer()->isRoot() &&
451 curr->renderer()->style()->hasAutoZIndex();
452 curr = curr->parent()) { }
453 return curr;
454 }
455
enclosingPositionedAncestor() const456 RenderLayer* RenderLayer::enclosingPositionedAncestor() const
457 {
458 RenderLayer* curr = parent();
459 for ( ; curr && !curr->renderer()->isRenderView() && !curr->renderer()->isPositioned() && !curr->renderer()->isRelPositioned() && !curr->hasTransform();
460 curr = curr->parent()) { }
461 return curr;
462 }
463
enclosingTransformedAncestor() const464 RenderLayer* RenderLayer::enclosingTransformedAncestor() const
465 {
466 RenderLayer* curr = parent();
467 for ( ; curr && !curr->renderer()->isRenderView() && !curr->transform(); curr = curr->parent())
468 { }
469 return curr;
470 }
471
absoluteToContents(const IntPoint & absolutePoint) const472 IntPoint RenderLayer::absoluteToContents(const IntPoint& absolutePoint) const
473 {
474 // We don't use convertToLayerCoords because it doesn't know about transforms
475 return roundedIntPoint(renderer()->absoluteToLocal(absolutePoint, false, true));
476 }
477
requiresSlowRepaints() const478 bool RenderLayer::requiresSlowRepaints() const
479 {
480 if (isTransparent() || hasReflection() || hasTransform())
481 return true;
482 if (!parent())
483 return false;
484 return parent()->requiresSlowRepaints();
485 }
486
isTransparent() const487 bool RenderLayer::isTransparent() const
488 {
489 #if ENABLE(SVG)
490 if (renderer()->node()->namespaceURI() == SVGNames::svgNamespaceURI)
491 return false;
492 #endif
493 return renderer()->isTransparent() || renderer()->hasMask();
494 }
495
496 RenderLayer*
transparentAncestor()497 RenderLayer::transparentAncestor()
498 {
499 RenderLayer* curr = parent();
500 for ( ; curr && !curr->isTransparent(); curr = curr->parent()) { }
501 return curr;
502 }
503
transparencyClipBox(const TransformationMatrix & enclosingTransform,const RenderLayer * l,const RenderLayer * rootLayer)504 static IntRect transparencyClipBox(const TransformationMatrix& enclosingTransform, const RenderLayer* l, const RenderLayer* rootLayer)
505 {
506 // FIXME: Although this function completely ignores CSS-imposed clipping, we did already intersect with the
507 // paintDirtyRect, and that should cut down on the amount we have to paint. Still it
508 // would be better to respect clips.
509
510 TransformationMatrix* t = l->transform();
511 if (t && rootLayer != l) {
512 // The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
513 // the transformed layer and all of its children.
514 int x = 0;
515 int y = 0;
516 l->convertToLayerCoords(rootLayer, x, y);
517 TransformationMatrix transform;
518 transform.translate(x, y);
519 transform = *t * transform;
520 transform = transform * enclosingTransform;
521
522 // We now have a transform that will produce a rectangle in our view's space.
523 IntRect clipRect = transform.mapRect(l->boundingBox(l));
524
525 // Now shift the root layer to be us and pass down the new enclosing transform.
526 for (RenderLayer* curr = l->firstChild(); curr; curr = curr->nextSibling()) {
527 if (!l->reflection() || l->reflectionLayer() != curr)
528 clipRect.unite(transparencyClipBox(transform, curr, l));
529 }
530
531 return clipRect;
532 }
533
534 // Note: we don't have to walk z-order lists since transparent elements always establish
535 // a stacking context. This means we can just walk the layer tree directly.
536 IntRect clipRect = l->boundingBox(rootLayer);
537
538 // If we have a mask, then the clip is limited to the border box area (and there is
539 // no need to examine child layers).
540 if (!l->renderer()->hasMask()) {
541 for (RenderLayer* curr = l->firstChild(); curr; curr = curr->nextSibling()) {
542 if (!l->reflection() || l->reflectionLayer() != curr)
543 clipRect.unite(transparencyClipBox(enclosingTransform, curr, rootLayer));
544 }
545 }
546
547 // Now map the clipRect via the enclosing transform
548 return enclosingTransform.mapRect(clipRect);
549 }
550
beginTransparencyLayers(GraphicsContext * p,const RenderLayer * rootLayer)551 void RenderLayer::beginTransparencyLayers(GraphicsContext* p, const RenderLayer* rootLayer)
552 {
553 if (p->paintingDisabled() || (isTransparent() && m_usedTransparency))
554 return;
555
556 RenderLayer* ancestor = transparentAncestor();
557 if (ancestor)
558 ancestor->beginTransparencyLayers(p, rootLayer);
559
560 if (isTransparent()) {
561 m_usedTransparency = true;
562 p->save();
563 p->clip(transparencyClipBox(TransformationMatrix(), this, rootLayer));
564 p->beginTransparencyLayer(renderer()->opacity());
565 }
566 }
567
operator new(size_t sz,RenderArena * renderArena)568 void* RenderLayer::operator new(size_t sz, RenderArena* renderArena) throw()
569 {
570 return renderArena->allocate(sz);
571 }
572
operator delete(void * ptr,size_t sz)573 void RenderLayer::operator delete(void* ptr, size_t sz)
574 {
575 // Stash size where destroy can find it.
576 *(size_t *)ptr = sz;
577 }
578
destroy(RenderArena * renderArena)579 void RenderLayer::destroy(RenderArena* renderArena)
580 {
581 delete this;
582
583 // Recover the size left there for us by operator delete and free the memory.
584 renderArena->free(*(size_t *)this, this);
585 }
586
addChild(RenderLayer * child,RenderLayer * beforeChild)587 void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
588 {
589 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
590 if (prevSibling) {
591 child->setPreviousSibling(prevSibling);
592 prevSibling->setNextSibling(child);
593 } else
594 setFirstChild(child);
595
596 if (beforeChild) {
597 beforeChild->setPreviousSibling(child);
598 child->setNextSibling(beforeChild);
599 } else
600 setLastChild(child);
601
602 child->setParent(this);
603
604 if (child->isOverflowOnly())
605 dirtyOverflowList();
606
607 if (!child->isOverflowOnly() || child->firstChild()) {
608 // Dirty the z-order list in which we are contained. The stackingContext() can be null in the
609 // case where we're building up generated content layers. This is ok, since the lists will start
610 // off dirty in that case anyway.
611 child->dirtyStackingContextZOrderLists();
612 }
613
614 child->updateVisibilityStatus();
615 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
616 childVisibilityChanged(true);
617 }
618
removeChild(RenderLayer * oldChild)619 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
620 {
621 // remove the child
622 if (oldChild->previousSibling())
623 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
624 if (oldChild->nextSibling())
625 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
626
627 if (m_first == oldChild)
628 m_first = oldChild->nextSibling();
629 if (m_last == oldChild)
630 m_last = oldChild->previousSibling();
631
632 if (oldChild->isOverflowOnly())
633 dirtyOverflowList();
634 if (!oldChild->isOverflowOnly() || oldChild->firstChild()) {
635 // Dirty the z-order list in which we are contained. When called via the
636 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
637 // from the main layer tree, so we need to null-check the |stackingContext| value.
638 oldChild->dirtyStackingContextZOrderLists();
639 }
640
641 oldChild->setPreviousSibling(0);
642 oldChild->setNextSibling(0);
643 oldChild->setParent(0);
644
645 oldChild->updateVisibilityStatus();
646 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
647 childVisibilityChanged(false);
648
649 return oldChild;
650 }
651
removeOnlyThisLayer()652 void RenderLayer::removeOnlyThisLayer()
653 {
654 if (!m_parent)
655 return;
656
657 // Dirty the clip rects.
658 clearClipRectsIncludingDescendants();
659
660 // Remove us from the parent.
661 RenderLayer* parent = m_parent;
662 RenderLayer* nextSib = nextSibling();
663 parent->removeChild(this);
664
665 if (reflection())
666 removeChild(reflectionLayer());
667
668 // Now walk our kids and reattach them to our parent.
669 RenderLayer* current = m_first;
670 while (current) {
671 RenderLayer* next = current->nextSibling();
672 removeChild(current);
673 parent->addChild(current, nextSib);
674 current->updateLayerPositions();
675 current = next;
676 }
677
678 destroy(renderer()->renderArena());
679 }
680
insertOnlyThisLayer()681 void RenderLayer::insertOnlyThisLayer()
682 {
683 if (!m_parent && renderer()->parent()) {
684 // We need to connect ourselves when our renderer() has a parent.
685 // Find our enclosingLayer and add ourselves.
686 RenderLayer* parentLayer = renderer()->parent()->enclosingLayer();
687 RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer()->parent()->findNextLayer(parentLayer, renderer()) : 0;
688 if (parentLayer)
689 parentLayer->addChild(this, beforeChild);
690 }
691
692 // Remove all descendant layers from the hierarchy and add them to the new position.
693 for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
694 curr->moveLayers(m_parent, this);
695
696 // Clear out all the clip rects.
697 clearClipRectsIncludingDescendants();
698 }
699
700 void
convertToLayerCoords(const RenderLayer * ancestorLayer,int & x,int & y) const701 RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const
702 {
703 if (ancestorLayer == this)
704 return;
705
706 if (renderer()->style()->position() == FixedPosition) {
707 // Add in the offset of the view. We can obtain this by calling
708 // localToAbsolute() on the RenderView.
709 FloatPoint absPos = renderer()->localToAbsolute(FloatPoint(), true);
710 x += absPos.x();
711 y += absPos.y();
712 return;
713 }
714
715 RenderLayer* parentLayer;
716 if (renderer()->style()->position() == AbsolutePosition)
717 parentLayer = enclosingPositionedAncestor();
718 else
719 parentLayer = parent();
720
721 if (!parentLayer) return;
722
723 parentLayer->convertToLayerCoords(ancestorLayer, x, y);
724
725 x += xPos();
726 y += yPos();
727 }
728
panScrollFromPoint(const IntPoint & sourcePoint)729 void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint)
730 {
731 // We want to reduce the speed if we're close from the original point to improve the handleability of the scroll
732 const int shortDistanceLimit = 100; // We delimit a 200 pixels long square enclosing the original point
733 const int speedReducer = 2; // Within this square we divide the scrolling speed by 2
734
735 const int iconRadius = 10;
736 Frame* frame = renderer()->document()->frame();
737 if (!frame)
738 return;
739
740 IntPoint currentMousePosition = frame->eventHandler()->currentMousePosition();
741
742 // 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
743 static IntPoint previousMousePosition;
744 if (currentMousePosition.x() < 0 || currentMousePosition.y() < 0)
745 currentMousePosition = previousMousePosition;
746 else
747 previousMousePosition = currentMousePosition;
748
749 int xDelta = currentMousePosition.x() - sourcePoint.x();
750 int yDelta = currentMousePosition.y() - sourcePoint.y();
751
752 if (abs(xDelta) < iconRadius) // at the center we let the space for the icon
753 xDelta = 0;
754 if (abs(yDelta) < iconRadius)
755 yDelta = 0;
756
757 // Let's attenuate the speed for the short distances
758 if (abs(xDelta) < shortDistanceLimit)
759 xDelta /= speedReducer;
760 if (abs(yDelta) < shortDistanceLimit)
761 yDelta /= speedReducer;
762
763 scrollByRecursively(xDelta, yDelta);
764 }
765
scrollByRecursively(int xDelta,int yDelta)766 void RenderLayer::scrollByRecursively(int xDelta, int yDelta)
767 {
768 bool restrictedByLineClamp = false;
769 if (renderer()->parent())
770 restrictedByLineClamp = renderer()->parent()->style()->lineClamp() >= 0;
771
772 if (renderer()->hasOverflowClip() && !restrictedByLineClamp) {
773 int newOffsetX = scrollXOffset() + xDelta;
774 int newOffsetY = scrollYOffset() + yDelta;
775 scrollToOffset(newOffsetX, newOffsetY);
776
777 // If this layer can't do the scroll we ask its parent
778 int leftToScrollX = newOffsetX - scrollXOffset();
779 int leftToScrollY = newOffsetY - scrollYOffset();
780 if ((leftToScrollX || leftToScrollY) && renderer()->parent()) {
781 renderer()->parent()->enclosingLayer()->scrollByRecursively(leftToScrollX, leftToScrollY);
782 Frame* frame = renderer()->document()->frame();
783 if (frame)
784 frame->eventHandler()->updateAutoscrollRenderer();
785 }
786 } else if (renderer()->view()->frameView())
787 renderer()->view()->frameView()->scrollBy(IntSize(xDelta, yDelta));
788 }
789
790
791 void
addScrolledContentOffset(int & x,int & y) const792 RenderLayer::addScrolledContentOffset(int& x, int& y) const
793 {
794 x += scrollXOffset() + m_scrollLeftOverflow;
795 y += scrollYOffset();
796 }
797
798 void
subtractScrolledContentOffset(int & x,int & y) const799 RenderLayer::subtractScrolledContentOffset(int& x, int& y) const
800 {
801 x -= scrollXOffset() + m_scrollLeftOverflow;
802 y -= scrollYOffset();
803 }
804
scrollToOffset(int x,int y,bool updateScrollbars,bool repaint)805 void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint)
806 {
807 if (renderer()->style()->overflowX() != OMARQUEE) {
808 if (x < 0) x = 0;
809 if (y < 0) y = 0;
810
811 // Call the scrollWidth/Height functions so that the dimensions will be computed if they need
812 // to be (for overflow:hidden blocks).
813 int maxX = scrollWidth() - renderer()->clientWidth();
814 int maxY = scrollHeight() - renderer()->clientHeight();
815
816 if (x > maxX) x = maxX;
817 if (y > maxY) y = maxY;
818 }
819
820 // FIXME: Eventually, we will want to perform a blit. For now never
821 // blit, since the check for blitting is going to be very
822 // complicated (since it will involve testing whether our layer
823 // is either occluded by another layer or clipped by an enclosing
824 // layer or contains fixed backgrounds, etc.).
825 int newScrollX = x - m_scrollOriginX;
826 if (m_scrollY == y && m_scrollX == newScrollX)
827 return;
828 m_scrollX = newScrollX;
829 m_scrollY = y;
830
831 // Update the positions of our child layers.
832 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
833 child->updateLayerPositions(false, false);
834
835 RenderView* view = renderer()->view();
836
837 // We should have a RenderView if we're trying to scroll.
838 ASSERT(view);
839 if (view) {
840 #if ENABLE(DASHBOARD_SUPPORT)
841 // Update dashboard regions, scrolling may change the clip of a
842 // particular region.
843 view->frameView()->updateDashboardRegions();
844 #endif
845
846 view->updateWidgetPositions();
847 }
848
849 // The caret rect needs to be invalidated after scrolling
850 Frame* frame = renderer()->document()->frame();
851 if (frame)
852 frame->invalidateSelection();
853
854 // Just schedule a full repaint of our object.
855 if (repaint)
856 renderer()->repaint();
857
858 if (updateScrollbars) {
859 if (m_hBar)
860 m_hBar->setValue(scrollXOffset());
861 if (m_vBar)
862 m_vBar->setValue(m_scrollY);
863 }
864
865 // Schedule the scroll DOM event.
866 if (view) {
867 if (FrameView* frameView = view->frameView())
868 frameView->scheduleEvent(Event::create(eventNames().scrollEvent, false, false), EventTargetNodeCast(renderer()->element()));
869 }
870 }
871
scrollRectToVisible(const IntRect & rect,bool scrollToAnchor,const ScrollAlignment & alignX,const ScrollAlignment & alignY)872 void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
873 {
874 RenderLayer* parentLayer = 0;
875 IntRect newRect = rect;
876 int xOffset = 0, yOffset = 0;
877
878 // We may end up propagating a scroll event. It is important that we suspend events until
879 // the end of the function since they could delete the layer or the layer's renderer().
880 FrameView* frameView = renderer()->document()->view();
881 if (frameView)
882 frameView->pauseScheduledEvents();
883
884 bool restrictedByLineClamp = false;
885 if (renderer()->parent()) {
886 parentLayer = renderer()->parent()->enclosingLayer();
887 restrictedByLineClamp = renderer()->parent()->style()->lineClamp() >= 0;
888 }
889
890 if (renderer()->hasOverflowClip() && !restrictedByLineClamp) {
891 // Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
892 // This will prevent us from revealing text hidden by the slider in Safari RSS.
893 FloatPoint absPos = renderer()->localToAbsolute();
894 absPos.move(renderer()->borderLeft(), renderer()->borderTop());
895
896 IntRect layerBounds = IntRect(absPos.x() + scrollXOffset(), absPos.y() + scrollYOffset(), renderer()->clientWidth(), renderer()->clientHeight());
897 IntRect exposeRect = IntRect(rect.x() + scrollXOffset(), rect.y() + scrollYOffset(), rect.width(), rect.height());
898 IntRect r = getRectToExpose(layerBounds, exposeRect, alignX, alignY);
899
900 xOffset = r.x() - absPos.x();
901 yOffset = r.y() - absPos.y();
902 // Adjust offsets if they're outside of the allowable range.
903 xOffset = max(0, min(scrollWidth() - layerBounds.width(), xOffset));
904 yOffset = max(0, min(scrollHeight() - layerBounds.height(), yOffset));
905
906 if (xOffset != scrollXOffset() || yOffset != scrollYOffset()) {
907 int diffX = scrollXOffset();
908 int diffY = scrollYOffset();
909 scrollToOffset(xOffset, yOffset);
910 diffX = scrollXOffset() - diffX;
911 diffY = scrollYOffset() - diffY;
912 newRect.setX(rect.x() - diffX);
913 newRect.setY(rect.y() - diffY);
914 }
915 } else if (!parentLayer && renderer()->canBeProgramaticallyScrolled(scrollToAnchor)) {
916 if (frameView) {
917 if (renderer()->document() && renderer()->document()->ownerElement() && renderer()->document()->ownerElement()->renderer()) {
918 IntRect viewRect = frameView->visibleContentRect();
919 IntRect r = getRectToExpose(viewRect, rect, alignX, alignY);
920
921 xOffset = r.x();
922 yOffset = r.y();
923 // Adjust offsets if they're outside of the allowable range.
924 xOffset = max(0, min(frameView->contentsWidth(), xOffset));
925 yOffset = max(0, min(frameView->contentsHeight(), yOffset));
926
927 frameView->setScrollPosition(IntPoint(xOffset, yOffset));
928 parentLayer = renderer()->document()->ownerElement()->renderer()->enclosingLayer();
929 newRect.setX(rect.x() - frameView->scrollX() + frameView->x());
930 newRect.setY(rect.y() - frameView->scrollY() + frameView->y());
931 } else {
932 IntRect viewRect = frameView->visibleContentRect(true);
933 IntRect r = getRectToExpose(viewRect, rect, alignX, alignY);
934
935 // If this is the outermost view that RenderLayer needs to scroll, then we should scroll the view recursively
936 // Other apps, like Mail, rely on this feature.
937 frameView->scrollRectIntoViewRecursively(r);
938 }
939 }
940 }
941
942 if (parentLayer)
943 parentLayer->scrollRectToVisible(newRect, scrollToAnchor, alignX, alignY);
944
945 if (frameView)
946 frameView->resumeScheduledEvents();
947 }
948
getRectToExpose(const IntRect & visibleRect,const IntRect & exposeRect,const ScrollAlignment & alignX,const ScrollAlignment & alignY)949 IntRect RenderLayer::getRectToExpose(const IntRect &visibleRect, const IntRect &exposeRect, const ScrollAlignment& alignX, const ScrollAlignment& alignY)
950 {
951 // Determine the appropriate X behavior.
952 ScrollBehavior scrollX;
953 IntRect exposeRectX(exposeRect.x(), visibleRect.y(), exposeRect.width(), visibleRect.height());
954 int intersectWidth = intersection(visibleRect, exposeRectX).width();
955 if (intersectWidth == exposeRect.width() || intersectWidth >= MIN_INTERSECT_FOR_REVEAL)
956 // If the rectangle is fully visible, use the specified visible behavior.
957 // If the rectangle is partially visible, but over a certain threshold,
958 // then treat it as fully visible to avoid unnecessary horizontal scrolling
959 scrollX = getVisibleBehavior(alignX);
960 else if (intersectWidth == visibleRect.width()) {
961 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
962 scrollX = getVisibleBehavior(alignX);
963 if (scrollX == alignCenter)
964 scrollX = noScroll;
965 } else if (intersectWidth > 0)
966 // If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
967 scrollX = getPartialBehavior(alignX);
968 else
969 scrollX = getHiddenBehavior(alignX);
970 // If we're trying to align to the closest edge, and the exposeRect is further right
971 // than the visibleRect, and not bigger than the visible area, then align with the right.
972 if (scrollX == alignToClosestEdge && exposeRect.right() > visibleRect.right() && exposeRect.width() < visibleRect.width())
973 scrollX = alignRight;
974
975 // Given the X behavior, compute the X coordinate.
976 int x;
977 if (scrollX == noScroll)
978 x = visibleRect.x();
979 else if (scrollX == alignRight)
980 x = exposeRect.right() - visibleRect.width();
981 else if (scrollX == alignCenter)
982 x = exposeRect.x() + (exposeRect.width() - visibleRect.width()) / 2;
983 else
984 x = exposeRect.x();
985
986 // Determine the appropriate Y behavior.
987 ScrollBehavior scrollY;
988 IntRect exposeRectY(visibleRect.x(), exposeRect.y(), visibleRect.width(), exposeRect.height());
989 int intersectHeight = intersection(visibleRect, exposeRectY).height();
990 if (intersectHeight == exposeRect.height())
991 // If the rectangle is fully visible, use the specified visible behavior.
992 scrollY = getVisibleBehavior(alignY);
993 else if (intersectHeight == visibleRect.height()) {
994 // If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
995 scrollY = getVisibleBehavior(alignY);
996 if (scrollY == alignCenter)
997 scrollY = noScroll;
998 } else if (intersectHeight > 0)
999 // If the rectangle is partially visible, use the specified partial behavior
1000 scrollY = getPartialBehavior(alignY);
1001 else
1002 scrollY = getHiddenBehavior(alignY);
1003 // If we're trying to align to the closest edge, and the exposeRect is further down
1004 // than the visibleRect, and not bigger than the visible area, then align with the bottom.
1005 if (scrollY == alignToClosestEdge && exposeRect.bottom() > visibleRect.bottom() && exposeRect.height() < visibleRect.height())
1006 scrollY = alignBottom;
1007
1008 // Given the Y behavior, compute the Y coordinate.
1009 int y;
1010 if (scrollY == noScroll)
1011 y = visibleRect.y();
1012 else if (scrollY == alignBottom)
1013 y = exposeRect.bottom() - visibleRect.height();
1014 else if (scrollY == alignCenter)
1015 y = exposeRect.y() + (exposeRect.height() - visibleRect.height()) / 2;
1016 else
1017 y = exposeRect.y();
1018
1019 return IntRect(IntPoint(x, y), visibleRect.size());
1020 }
1021
autoscroll()1022 void RenderLayer::autoscroll()
1023 {
1024 Frame* frame = renderer()->document()->frame();
1025 if (!frame)
1026 return;
1027
1028 FrameView* frameView = frame->view();
1029 if (!frameView)
1030 return;
1031
1032 frame->eventHandler()->updateSelectionForMouseDrag();
1033
1034 IntPoint currentDocumentPosition = frameView->windowToContents(frame->eventHandler()->currentMousePosition());
1035 scrollRectToVisible(IntRect(currentDocumentPosition, IntSize(1, 1)), false, gAlignToEdgeIfNeeded, gAlignToEdgeIfNeeded);
1036 }
1037
resize(const PlatformMouseEvent & evt,const IntSize & oldOffset)1038 void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset)
1039 {
1040 if (!inResizeMode() || !renderer()->hasOverflowClip())
1041 return;
1042
1043 // Set the width and height of the shadow ancestor node if there is one.
1044 // This is necessary for textarea elements since the resizable layer is in the shadow content.
1045 Element* element = static_cast<Element*>(renderer()->node()->shadowAncestorNode());
1046 RenderBox* renderer = toRenderBox(element->renderer());
1047
1048 EResize resize = renderer->style()->resize();
1049 if (resize == RESIZE_NONE)
1050 return;
1051
1052 Document* document = element->document();
1053 if (!document->frame()->eventHandler()->mousePressed())
1054 return;
1055
1056 float zoomFactor = renderer->style()->effectiveZoom();
1057
1058 IntSize newOffset = offsetFromResizeCorner(document->view()->windowToContents(evt.pos()));
1059 newOffset.setWidth(newOffset.width() / zoomFactor);
1060 newOffset.setHeight(newOffset.height() / zoomFactor);
1061
1062 IntSize currentSize = IntSize(renderer->width() / zoomFactor, renderer->height() / zoomFactor);
1063 IntSize minimumSize = element->minimumSizeForResizing().shrunkTo(currentSize);
1064 element->setMinimumSizeForResizing(minimumSize);
1065
1066 IntSize adjustedOldOffset = IntSize(oldOffset.width() / zoomFactor, oldOffset.height() / zoomFactor);
1067
1068 IntSize difference = (currentSize + newOffset - adjustedOldOffset).expandedTo(minimumSize) - currentSize;
1069
1070 CSSStyleDeclaration* style = element->style();
1071 bool isBoxSizingBorder = renderer->style()->boxSizing() == BORDER_BOX;
1072
1073 ExceptionCode ec;
1074
1075 if (difference.width()) {
1076 if (element && element->isControl()) {
1077 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
1078 style->setProperty(CSSPropertyMarginLeft, String::number(renderer->marginLeft() / zoomFactor) + "px", false, ec);
1079 style->setProperty(CSSPropertyMarginRight, String::number(renderer->marginRight() / zoomFactor) + "px", false, ec);
1080 }
1081 int baseWidth = renderer->width() - (isBoxSizingBorder ? 0
1082 : renderer->borderLeft() + renderer->paddingLeft() + renderer->borderRight() + renderer->paddingRight());
1083 baseWidth = baseWidth / zoomFactor;
1084 style->setProperty(CSSPropertyWidth, String::number(baseWidth + difference.width()) + "px", false, ec);
1085 }
1086
1087 if (difference.height()) {
1088 if (element && element->isControl()) {
1089 // Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
1090 style->setProperty(CSSPropertyMarginTop, String::number(renderer->marginTop() / zoomFactor) + "px", false, ec);
1091 style->setProperty(CSSPropertyMarginBottom, String::number(renderer->marginBottom() / zoomFactor) + "px", false, ec);
1092 }
1093 int baseHeight = renderer->height() - (isBoxSizingBorder ? 0
1094 : renderer->borderTop() + renderer->paddingTop() + renderer->borderBottom() + renderer->paddingBottom());
1095 baseHeight = baseHeight / zoomFactor;
1096 style->setProperty(CSSPropertyHeight, String::number(baseHeight + difference.height()) + "px", false, ec);
1097 }
1098
1099 document->updateLayout();
1100
1101 // FIXME (Radar 4118564): We should also autoscroll the window as necessary to keep the point under the cursor in view.
1102 }
1103
valueChanged(Scrollbar *)1104 void RenderLayer::valueChanged(Scrollbar*)
1105 {
1106 // Update scroll position from scrollbars.
1107
1108 bool needUpdate = false;
1109 int newX = scrollXOffset();
1110 int newY = m_scrollY;
1111
1112 if (m_hBar) {
1113 newX = m_hBar->value();
1114 if (newX != scrollXOffset())
1115 needUpdate = true;
1116 }
1117
1118 if (m_vBar) {
1119 newY = m_vBar->value();
1120 if (newY != m_scrollY)
1121 needUpdate = true;
1122 }
1123
1124 if (needUpdate)
1125 scrollToOffset(newX, newY, false);
1126 }
1127
isActive() const1128 bool RenderLayer::isActive() const
1129 {
1130 Page* page = renderer()->document()->frame()->page();
1131 return page && page->focusController()->isActive();
1132 }
1133
1134
cornerRect(const RenderLayer * layer,const IntRect & bounds)1135 static IntRect cornerRect(const RenderLayer* layer, const IntRect& bounds)
1136 {
1137 int horizontalThickness;
1138 int verticalThickness;
1139 if (!layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
1140 // FIXME: This isn't right. We need to know the thickness of custom scrollbars
1141 // even when they don't exist in order to set the resizer square size properly.
1142 horizontalThickness = ScrollbarTheme::nativeTheme()->scrollbarThickness();
1143 verticalThickness = horizontalThickness;
1144 } else if (layer->verticalScrollbar() && !layer->horizontalScrollbar()) {
1145 horizontalThickness = layer->verticalScrollbar()->width();
1146 verticalThickness = horizontalThickness;
1147 } else if (layer->horizontalScrollbar() && !layer->verticalScrollbar()) {
1148 verticalThickness = layer->horizontalScrollbar()->height();
1149 horizontalThickness = verticalThickness;
1150 } else {
1151 horizontalThickness = layer->verticalScrollbar()->width();
1152 verticalThickness = layer->horizontalScrollbar()->height();
1153 }
1154 return IntRect(bounds.right() - horizontalThickness - layer->renderer()->style()->borderRightWidth(),
1155 bounds.bottom() - verticalThickness - layer->renderer()->style()->borderBottomWidth(),
1156 horizontalThickness, verticalThickness);
1157 }
1158
scrollCornerRect(const RenderLayer * layer,const IntRect & bounds)1159 static IntRect scrollCornerRect(const RenderLayer* layer, const IntRect& bounds)
1160 {
1161 // We have a scrollbar corner when a scrollbar is visible and not filling the entire length of the box.
1162 // This happens when:
1163 // (a) A resizer is present and at least one scrollbar is present
1164 // (b) Both scrollbars are present.
1165 bool hasHorizontalBar = layer->horizontalScrollbar();
1166 bool hasVerticalBar = layer->verticalScrollbar();
1167 bool hasResizer = layer->renderer()->style()->resize() != RESIZE_NONE;
1168 if ((hasHorizontalBar && hasVerticalBar) || (hasResizer && (hasHorizontalBar || hasVerticalBar)))
1169 return cornerRect(layer, bounds);
1170 return IntRect();
1171 }
1172
resizerCornerRect(const RenderLayer * layer,const IntRect & bounds)1173 static IntRect resizerCornerRect(const RenderLayer* layer, const IntRect& bounds)
1174 {
1175 if (layer->renderer()->style()->resize() == RESIZE_NONE)
1176 return IntRect();
1177 return cornerRect(layer, bounds);
1178 }
1179
scrollbarCornerPresent() const1180 bool RenderLayer::scrollbarCornerPresent() const
1181 {
1182 return !scrollCornerRect(this, renderer()->borderBoxRect()).isEmpty();
1183 }
1184
invalidateScrollbarRect(Scrollbar * scrollbar,const IntRect & rect)1185 void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
1186 {
1187 IntRect scrollRect = rect;
1188 if (scrollbar == m_vBar.get())
1189 scrollRect.move(renderer()->width() - renderer()->borderRight() - scrollbar->width(), renderer()->borderTop());
1190 else
1191 scrollRect.move(renderer()->borderLeft(), renderer()->height() - renderer()->borderBottom() - scrollbar->height());
1192 renderer()->repaintRectangle(scrollRect);
1193 }
1194
createScrollbar(ScrollbarOrientation orientation)1195 PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
1196 {
1197 RefPtr<Scrollbar> widget;
1198 bool hasCustomScrollbarStyle = renderer()->node()->shadowAncestorNode()->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR);
1199 if (hasCustomScrollbarStyle)
1200 widget = RenderScrollbar::createCustomScrollbar(this, orientation, renderer()->node()->shadowAncestorNode()->renderBox());
1201 else
1202 widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
1203 renderer()->document()->view()->addChild(widget.get());
1204 return widget.release();
1205 }
1206
destroyScrollbar(ScrollbarOrientation orientation)1207 void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation)
1208 {
1209 RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar;
1210 if (scrollbar) {
1211 scrollbar->removeFromParent();
1212 scrollbar->setClient(0);
1213 scrollbar = 0;
1214 }
1215 }
1216
setHasHorizontalScrollbar(bool hasScrollbar)1217 void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
1218 {
1219 if (hasScrollbar == (m_hBar != 0))
1220 return;
1221
1222 if (hasScrollbar)
1223 m_hBar = createScrollbar(HorizontalScrollbar);
1224 else
1225 destroyScrollbar(HorizontalScrollbar);
1226
1227 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
1228 if (m_hBar)
1229 m_hBar->styleChanged();
1230 if (m_vBar)
1231 m_vBar->styleChanged();
1232
1233 #if ENABLE(DASHBOARD_SUPPORT)
1234 // Force an update since we know the scrollbars have changed things.
1235 if (renderer()->document()->hasDashboardRegions())
1236 renderer()->document()->setDashboardRegionsDirty(true);
1237 #endif
1238 }
1239
setHasVerticalScrollbar(bool hasScrollbar)1240 void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
1241 {
1242 if (hasScrollbar == (m_vBar != 0))
1243 return;
1244
1245 if (hasScrollbar)
1246 m_vBar = createScrollbar(VerticalScrollbar);
1247 else
1248 destroyScrollbar(VerticalScrollbar);
1249
1250 // Destroying or creating one bar can cause our scrollbar corner to come and go. We need to update the opposite scrollbar's style.
1251 if (m_hBar)
1252 m_hBar->styleChanged();
1253 if (m_vBar)
1254 m_vBar->styleChanged();
1255
1256 #if ENABLE(DASHBOARD_SUPPORT)
1257 // Force an update since we know the scrollbars have changed things.
1258 if (renderer()->document()->hasDashboardRegions())
1259 renderer()->document()->setDashboardRegionsDirty(true);
1260 #endif
1261 }
1262
verticalScrollbarWidth() const1263 int RenderLayer::verticalScrollbarWidth() const
1264 {
1265 if (!m_vBar)
1266 return 0;
1267 return m_vBar->width();
1268 }
1269
horizontalScrollbarHeight() const1270 int RenderLayer::horizontalScrollbarHeight() const
1271 {
1272 if (!m_hBar)
1273 return 0;
1274 return m_hBar->height();
1275 }
1276
offsetFromResizeCorner(const IntPoint & absolutePoint) const1277 IntSize RenderLayer::offsetFromResizeCorner(const IntPoint& absolutePoint) const
1278 {
1279 // Currently the resize corner is always the bottom right corner
1280 IntPoint bottomRight(width(), height());
1281 IntPoint localPoint = absoluteToContents(absolutePoint);
1282 return localPoint - bottomRight;
1283 }
1284
positionOverflowControls(int tx,int ty)1285 void RenderLayer::positionOverflowControls(int tx, int ty)
1286 {
1287 if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
1288 return;
1289
1290 IntRect borderBox = renderer()->borderBoxRect();
1291 IntRect scrollCorner(scrollCornerRect(this, borderBox));
1292 IntRect absBounds(borderBox.x() + tx, borderBox.y() + ty, borderBox.width(), borderBox.height());
1293 if (m_vBar)
1294 m_vBar->setFrameRect(IntRect(absBounds.right() - renderer()->borderRight() - m_vBar->width(),
1295 absBounds.y() + renderer()->borderTop(),
1296 m_vBar->width(),
1297 absBounds.height() - (renderer()->borderTop() + renderer()->borderBottom()) - scrollCorner.height()));
1298
1299 if (m_hBar)
1300 m_hBar->setFrameRect(IntRect(absBounds.x() + renderer()->borderLeft(),
1301 absBounds.bottom() - renderer()->borderBottom() - m_hBar->height(),
1302 absBounds.width() - (renderer()->borderLeft() + renderer()->borderRight()) - scrollCorner.width(),
1303 m_hBar->height()));
1304
1305 if (m_scrollCorner)
1306 m_scrollCorner->setFrameRect(scrollCorner);
1307 if (m_resizer)
1308 m_resizer->setFrameRect(resizerCornerRect(this, borderBox));
1309 }
1310
scrollWidth()1311 int RenderLayer::scrollWidth()
1312 {
1313 if (m_scrollDimensionsDirty)
1314 computeScrollDimensions();
1315 return m_scrollWidth;
1316 }
1317
scrollHeight()1318 int RenderLayer::scrollHeight()
1319 {
1320 if (m_scrollDimensionsDirty)
1321 computeScrollDimensions();
1322 return m_scrollHeight;
1323 }
1324
computeScrollDimensions(bool * needHBar,bool * needVBar)1325 void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar)
1326 {
1327 m_scrollDimensionsDirty = false;
1328
1329 bool ltr = renderer()->style()->direction() == LTR;
1330
1331 int clientWidth = renderer()->clientWidth();
1332 int clientHeight = renderer()->clientHeight();
1333
1334 m_scrollLeftOverflow = ltr ? 0 : min(0, renderer()->leftmostPosition(true, false) - renderer()->borderLeft());
1335
1336 int rightPos = ltr ?
1337 renderer()->rightmostPosition(true, false) - renderer()->borderLeft() :
1338 clientWidth - m_scrollLeftOverflow;
1339 int bottomPos = renderer()->lowestPosition(true, false) - renderer()->borderTop();
1340
1341 m_scrollWidth = max(rightPos, clientWidth);
1342 m_scrollHeight = max(bottomPos, clientHeight);
1343
1344 m_scrollOriginX = ltr ? 0 : m_scrollWidth - clientWidth;
1345
1346 if (needHBar)
1347 *needHBar = rightPos > clientWidth;
1348 if (needVBar)
1349 *needVBar = bottomPos > clientHeight;
1350 }
1351
updateOverflowStatus(bool horizontalOverflow,bool verticalOverflow)1352 void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
1353 {
1354 if (m_overflowStatusDirty) {
1355 m_horizontalOverflow = horizontalOverflow;
1356 m_verticalOverflow = verticalOverflow;
1357 m_overflowStatusDirty = false;
1358
1359 return;
1360 }
1361
1362 bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
1363 bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
1364
1365 if (horizontalOverflowChanged || verticalOverflowChanged) {
1366 m_horizontalOverflow = horizontalOverflow;
1367 m_verticalOverflow = verticalOverflow;
1368
1369 if (FrameView* frameView = renderer()->document()->view()) {
1370 frameView->scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow),
1371 EventTargetNodeCast(renderer()->element()));
1372 }
1373 }
1374 }
1375
1376 void
updateScrollInfoAfterLayout()1377 RenderLayer::updateScrollInfoAfterLayout()
1378 {
1379 m_scrollDimensionsDirty = true;
1380
1381 bool horizontalOverflow, verticalOverflow;
1382 computeScrollDimensions(&horizontalOverflow, &verticalOverflow);
1383
1384 if (renderer()->style()->overflowX() != OMARQUEE) {
1385 // Layout may cause us to be in an invalid scroll position. In this case we need
1386 // to pull our scroll offsets back to the max (or push them up to the min).
1387 int newX = max(0, min(scrollXOffset(), scrollWidth() - renderer()->clientWidth()));
1388 int newY = max(0, min(m_scrollY, scrollHeight() - renderer()->clientHeight()));
1389 if (newX != scrollXOffset() || newY != m_scrollY) {
1390 RenderView* view = renderer()->view();
1391 ASSERT(view);
1392 // scrollToOffset() may call updateLayerPositions(), which doesn't work
1393 // with LayoutState.
1394 // FIXME: Remove the disableLayoutState/enableLayoutState if the above changes.
1395 if (view)
1396 view->disableLayoutState();
1397 scrollToOffset(newX, newY);
1398 if (view)
1399 view->enableLayoutState();
1400 }
1401 }
1402
1403 bool haveHorizontalBar = m_hBar;
1404 bool haveVerticalBar = m_vBar;
1405
1406 // overflow:scroll should just enable/disable.
1407 if (renderer()->style()->overflowX() == OSCROLL)
1408 m_hBar->setEnabled(horizontalOverflow);
1409 if (renderer()->style()->overflowY() == OSCROLL)
1410 m_vBar->setEnabled(verticalOverflow);
1411
1412 // A dynamic change from a scrolling overflow to overflow:hidden means we need to get rid of any
1413 // scrollbars that may be present.
1414 if (renderer()->style()->overflowX() == OHIDDEN && haveHorizontalBar)
1415 setHasHorizontalScrollbar(false);
1416 if (renderer()->style()->overflowY() == OHIDDEN && haveVerticalBar)
1417 setHasVerticalScrollbar(false);
1418
1419 // overflow:auto may need to lay out again if scrollbars got added/removed.
1420 bool scrollbarsChanged = (renderer()->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) ||
1421 (renderer()->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow);
1422 if (scrollbarsChanged) {
1423 if (renderer()->hasAutoHorizontalScrollbar())
1424 setHasHorizontalScrollbar(horizontalOverflow);
1425 if (renderer()->hasAutoVerticalScrollbar())
1426 setHasVerticalScrollbar(verticalOverflow);
1427
1428 #if ENABLE(DASHBOARD_SUPPORT)
1429 // Force an update since we know the scrollbars have changed things.
1430 if (renderer()->document()->hasDashboardRegions())
1431 renderer()->document()->setDashboardRegionsDirty(true);
1432 #endif
1433
1434 renderer()->repaint();
1435
1436 if (renderer()->style()->overflowX() == OAUTO || renderer()->style()->overflowY() == OAUTO) {
1437 if (!m_inOverflowRelayout) {
1438 // Our proprietary overflow: overlay value doesn't trigger a layout.
1439 m_inOverflowRelayout = true;
1440 renderer()->setNeedsLayout(true, false);
1441 if (renderer()->isRenderBlock())
1442 static_cast<RenderBlock*>(renderer())->layoutBlock(true);
1443 else
1444 renderer()->layout();
1445 m_inOverflowRelayout = false;
1446 }
1447 }
1448 }
1449
1450 // If overflow:scroll is turned into overflow:auto a bar might still be disabled (Bug 11985).
1451 if (m_hBar && renderer()->hasAutoHorizontalScrollbar())
1452 m_hBar->setEnabled(true);
1453 if (m_vBar && renderer()->hasAutoVerticalScrollbar())
1454 m_vBar->setEnabled(true);
1455
1456 // Set up the range (and page step/line step).
1457 if (m_hBar) {
1458 int clientWidth = renderer()->clientWidth();
1459 int pageStep = (clientWidth - cAmountToKeepWhenPaging);
1460 if (pageStep < 0) pageStep = clientWidth;
1461 m_hBar->setSteps(cScrollbarPixelsPerLineStep, pageStep);
1462 m_hBar->setProportion(clientWidth, m_scrollWidth);
1463 m_hBar->setValue(scrollXOffset());
1464 }
1465 if (m_vBar) {
1466 int clientHeight = renderer()->clientHeight();
1467 int pageStep = (clientHeight - cAmountToKeepWhenPaging);
1468 if (pageStep < 0) pageStep = clientHeight;
1469 m_vBar->setSteps(cScrollbarPixelsPerLineStep, pageStep);
1470 m_vBar->setProportion(clientHeight, m_scrollHeight);
1471 }
1472
1473 if (renderer()->element() && renderer()->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
1474 updateOverflowStatus(horizontalOverflow, verticalOverflow);
1475 }
1476
paintOverflowControls(GraphicsContext * context,int tx,int ty,const IntRect & damageRect)1477 void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty, const IntRect& damageRect)
1478 {
1479 // Don't do anything if we have no overflow.
1480 if (!renderer()->hasOverflowClip())
1481 return;
1482
1483 // Move the scrollbar widgets if necessary. We normally move and resize widgets during layout, but sometimes
1484 // widgets can move without layout occurring (most notably when you scroll a document that
1485 // contains fixed positioned elements).
1486 positionOverflowControls(tx, ty);
1487
1488 // Now that we're sure the scrollbars are in the right place, paint them.
1489 if (m_hBar)
1490 m_hBar->paint(context, damageRect);
1491 if (m_vBar)
1492 m_vBar->paint(context, damageRect);
1493
1494 // We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the
1495 // edge of the box.
1496 paintScrollCorner(context, tx, ty, damageRect);
1497
1498 // Paint our resizer last, since it sits on top of the scroll corner.
1499 paintResizer(context, tx, ty, damageRect);
1500 }
1501
paintScrollCorner(GraphicsContext * context,int tx,int ty,const IntRect & damageRect)1502 void RenderLayer::paintScrollCorner(GraphicsContext* context, int tx, int ty, const IntRect& damageRect)
1503 {
1504 IntRect cornerRect = scrollCornerRect(this, renderer()->borderBoxRect());
1505 IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height());
1506 if (!absRect.intersects(damageRect))
1507 return;
1508
1509 if (context->updatingControlTints()) {
1510 updateScrollCornerStyle();
1511 return;
1512 }
1513
1514 if (m_scrollCorner) {
1515 m_scrollCorner->paintIntoRect(context, tx, ty, absRect);
1516 return;
1517 }
1518
1519 context->fillRect(absRect, Color::white);
1520 }
1521
paintResizer(GraphicsContext * context,int tx,int ty,const IntRect & damageRect)1522 void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const IntRect& damageRect)
1523 {
1524 if (renderer()->style()->resize() == RESIZE_NONE)
1525 return;
1526
1527 IntRect cornerRect = resizerCornerRect(this, renderer()->borderBoxRect());
1528 IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height());
1529 if (!absRect.intersects(damageRect))
1530 return;
1531
1532 if (context->updatingControlTints()) {
1533 updateResizerStyle();
1534 return;
1535 }
1536
1537 if (m_resizer) {
1538 m_resizer->paintIntoRect(context, tx, ty, absRect);
1539 return;
1540 }
1541
1542 // Paint the resizer control.
1543 DEFINE_STATIC_LOCAL(RefPtr<Image>, resizeCornerImage, (Image::loadPlatformResource("textAreaResizeCorner")));
1544 IntPoint imagePoint(absRect.right() - resizeCornerImage->width(), absRect.bottom() - resizeCornerImage->height());
1545 context->drawImage(resizeCornerImage.get(), imagePoint);
1546
1547 // Draw a frame around the resizer (1px grey line) if there are any scrollbars present.
1548 // Clipping will exclude the right and bottom edges of this frame.
1549 if (m_hBar || m_vBar) {
1550 context->save();
1551 IntRect largerCorner = absRect;
1552 largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1));
1553 context->setStrokeColor(Color(makeRGB(217, 217, 217)));
1554 context->setStrokeThickness(1.0f);
1555 context->setFillColor(Color::transparent);
1556 context->drawRect(largerCorner);
1557 context->restore();
1558 }
1559 }
1560
isPointInResizeControl(const IntPoint & absolutePoint) const1561 bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const
1562 {
1563 if (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)
1564 return false;
1565
1566 IntPoint localPoint = absoluteToContents(absolutePoint);
1567
1568 IntRect localBounds(0, 0, renderer()->width(), renderer()->height());
1569 return resizerCornerRect(this, localBounds).contains(localPoint);
1570 }
1571
hitTestOverflowControls(HitTestResult & result)1572 bool RenderLayer::hitTestOverflowControls(HitTestResult& result)
1573 {
1574 if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
1575 return false;
1576
1577 int x = 0;
1578 int y = 0;
1579 convertToLayerCoords(root(), x, y);
1580 IntRect absBounds(x, y, renderer()->width(), renderer()->height());
1581
1582 IntRect resizeControlRect;
1583 if (renderer()->style()->resize() != RESIZE_NONE) {
1584 resizeControlRect = resizerCornerRect(this, absBounds);
1585 if (resizeControlRect.contains(result.point()))
1586 return true;
1587 }
1588
1589 int resizeControlSize = max(resizeControlRect.height(), 0);
1590
1591 if (m_vBar) {
1592 IntRect vBarRect(absBounds.right() - renderer()->borderRight() - m_vBar->width(), absBounds.y() + renderer()->borderTop(), m_vBar->width(), absBounds.height() - (renderer()->borderTop() + renderer()->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
1593 if (vBarRect.contains(result.point())) {
1594 result.setScrollbar(m_vBar.get());
1595 return true;
1596 }
1597 }
1598
1599 resizeControlSize = max(resizeControlRect.width(), 0);
1600 if (m_hBar) {
1601 IntRect hBarRect(absBounds.x() + renderer()->borderLeft(), absBounds.bottom() - renderer()->borderBottom() - m_hBar->height(), absBounds.width() - (renderer()->borderLeft() + renderer()->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize), m_hBar->height());
1602 if (hBarRect.contains(result.point())) {
1603 result.setScrollbar(m_hBar.get());
1604 return true;
1605 }
1606 }
1607
1608 return false;
1609 }
1610
scroll(ScrollDirection direction,ScrollGranularity granularity,float multiplier)1611 bool RenderLayer::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
1612 {
1613 bool didHorizontalScroll = false;
1614 bool didVerticalScroll = false;
1615
1616 if (m_hBar) {
1617 if (granularity == ScrollByDocument) {
1618 // Special-case for the ScrollByDocument granularity. A document scroll can only be up
1619 // or down and in both cases the horizontal bar goes all the way to the left.
1620 didHorizontalScroll = m_hBar->scroll(ScrollLeft, ScrollByDocument, multiplier);
1621 } else
1622 didHorizontalScroll = m_hBar->scroll(direction, granularity, multiplier);
1623 }
1624
1625 if (m_vBar)
1626 didVerticalScroll = m_vBar->scroll(direction, granularity, multiplier);
1627
1628 return (didHorizontalScroll || didVerticalScroll);
1629 }
1630
1631 void
paint(GraphicsContext * p,const IntRect & damageRect,PaintRestriction paintRestriction,RenderObject * paintingRoot)1632 RenderLayer::paint(GraphicsContext* p, const IntRect& damageRect, PaintRestriction paintRestriction, RenderObject *paintingRoot)
1633 {
1634 paintLayer(this, p, damageRect, false, paintRestriction, paintingRoot);
1635 }
1636
setClip(GraphicsContext * p,const IntRect & paintDirtyRect,const IntRect & clipRect)1637 static void setClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect)
1638 {
1639 if (paintDirtyRect == clipRect)
1640 return;
1641 p->save();
1642 p->clip(clipRect);
1643 }
1644
restoreClip(GraphicsContext * p,const IntRect & paintDirtyRect,const IntRect & clipRect)1645 static void restoreClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect)
1646 {
1647 if (paintDirtyRect == clipRect)
1648 return;
1649 p->restore();
1650 }
1651
1652 void
paintLayer(RenderLayer * rootLayer,GraphicsContext * p,const IntRect & paintDirtyRect,bool haveTransparency,PaintRestriction paintRestriction,RenderObject * paintingRoot,bool appliedTransform,bool temporaryClipRects)1653 RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
1654 const IntRect& paintDirtyRect, bool haveTransparency, PaintRestriction paintRestriction,
1655 RenderObject* paintingRoot, bool appliedTransform, bool temporaryClipRects)
1656 {
1657 // Avoid painting layers when stylesheets haven't loaded. This eliminates FOUC.
1658 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
1659 // will do a full repaint().
1660 if (renderer()->document()->didLayoutWithPendingStylesheets() && !renderer()->isRenderView() && !renderer()->isRoot())
1661 return;
1662
1663 // If this layer is totally invisible then there is nothing to paint.
1664 if (!renderer()->opacity())
1665 return;
1666
1667 if (isTransparent())
1668 haveTransparency = true;
1669
1670 // Apply a transform if we have one. A reflection is considered to be a transform, since it is a flip and a translate.
1671 if (m_transform && !appliedTransform) {
1672 // If the transform can't be inverted, then don't paint anything.
1673 if (!m_transform->isInvertible())
1674 return;
1675
1676 // If we have a transparency layer enclosing us and we are the root of a transform, then we need to establish the transparency
1677 // layer from the parent now.
1678 if (haveTransparency)
1679 parent()->beginTransparencyLayers(p, rootLayer);
1680
1681 // Make sure the parent's clip rects have been calculated.
1682 IntRect clipRect = paintDirtyRect;
1683 if (parent()) {
1684 if (temporaryClipRects) {
1685 ClipRects parentClipRects;
1686 parent()->calculateClipRects(rootLayer, parentClipRects);
1687 clipRect = parentClipRects.overflowClipRect();
1688 } else {
1689 parent()->updateClipRects(rootLayer);
1690 clipRect = parent()->clipRects()->overflowClipRect();
1691 }
1692 clipRect.intersect(paintDirtyRect);
1693 }
1694
1695 // Push the parent coordinate space's clip.
1696 setClip(p, paintDirtyRect, clipRect);
1697
1698 // Adjust the transform such that the renderer's upper left corner will paint at (0,0) in user space.
1699 // This involves subtracting out the position of the layer in our current coordinate space.
1700 int x = 0;
1701 int y = 0;
1702 convertToLayerCoords(rootLayer, x, y);
1703 TransformationMatrix transform;
1704 transform.translate(x, y);
1705 transform = *m_transform * transform;
1706
1707 // Apply the transform.
1708 p->save();
1709 p->concatCTM(transform);
1710
1711 // Now do a paint with the root layer shifted to be us.
1712 paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), haveTransparency, paintRestriction, paintingRoot, true, temporaryClipRects);
1713
1714 p->restore();
1715
1716 // Restore the clip.
1717 restoreClip(p, paintDirtyRect, clipRect);
1718
1719 return;
1720 }
1721
1722 // Paint the reflection first if we have one.
1723 if (m_reflection && !m_paintingInsideReflection && (!m_transform || appliedTransform)) {
1724 // Mark that we are now inside replica painting.
1725 m_paintingInsideReflection = true;
1726 reflectionLayer()->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects);
1727 m_paintingInsideReflection = false;
1728 }
1729
1730 // Calculate the clip rects we should use.
1731 IntRect layerBounds, damageRect, clipRectToApply, outlineRect;
1732 calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, temporaryClipRects);
1733 int x = layerBounds.x();
1734 int y = layerBounds.y();
1735 int tx = x - renderer()->x();
1736 int ty = y - renderer()->y();
1737
1738 // Ensure our lists are up-to-date.
1739 updateZOrderLists();
1740 updateOverflowList();
1741
1742 bool selectionOnly = paintRestriction == PaintRestrictionSelectionOnly || paintRestriction == PaintRestrictionSelectionOnlyBlackText;
1743 bool forceBlackText = paintRestriction == PaintRestrictionSelectionOnlyBlackText;
1744
1745 // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which
1746 // is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set).
1747 // Else, our renderer tree may or may not contain the painting root, so we pass that root along
1748 // so it will be tested against as we decend through the renderers.
1749 RenderObject* paintingRootForRenderer = 0;
1750 if (paintingRoot && !renderer()->isDescendantOf(paintingRoot))
1751 paintingRootForRenderer = paintingRoot;
1752
1753 // We want to paint our layer, but only if we intersect the damage rect.
1754 bool shouldPaint = intersectsDamageRect(layerBounds, damageRect, rootLayer) && m_hasVisibleContent;
1755 if (shouldPaint && !selectionOnly && !damageRect.isEmpty()) {
1756 // Begin transparency layers lazily now that we know we have to paint something.
1757 if (haveTransparency)
1758 beginTransparencyLayers(p, rootLayer);
1759
1760 // Paint our background first, before painting any child layers.
1761 // Establish the clip used to paint our background.
1762 setClip(p, paintDirtyRect, damageRect);
1763
1764 // Paint the background.
1765 RenderObject::PaintInfo paintInfo(p, damageRect, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0);
1766 renderer()->paint(paintInfo, tx, ty);
1767
1768 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
1769 // z-index. We paint after we painted the background/border, so that the scrollbars will
1770 // sit above the background/border.
1771 paintOverflowControls(p, x, y, damageRect);
1772
1773 // Restore the clip.
1774 restoreClip(p, paintDirtyRect, damageRect);
1775 }
1776
1777 // Now walk the sorted list of children with negative z-indices.
1778 if (m_negZOrderList)
1779 for (Vector<RenderLayer*>::iterator it = m_negZOrderList->begin(); it != m_negZOrderList->end(); ++it)
1780 it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects);
1781
1782 // Now establish the appropriate clip and paint our child RenderObjects.
1783 if (shouldPaint && !clipRectToApply.isEmpty()) {
1784 // Begin transparency layers lazily now that we know we have to paint something.
1785 if (haveTransparency)
1786 beginTransparencyLayers(p, rootLayer);
1787
1788 // Set up the clip used when painting our children.
1789 setClip(p, paintDirtyRect, clipRectToApply);
1790 RenderObject::PaintInfo paintInfo(p, clipRectToApply,
1791 selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds,
1792 forceBlackText, paintingRootForRenderer, 0);
1793 renderer()->paint(paintInfo, tx, ty);
1794 if (!selectionOnly) {
1795 paintInfo.phase = PaintPhaseFloat;
1796 renderer()->paint(paintInfo, tx, ty);
1797 paintInfo.phase = PaintPhaseForeground;
1798 renderer()->paint(paintInfo, tx, ty);
1799 paintInfo.phase = PaintPhaseChildOutlines;
1800 renderer()->paint(paintInfo, tx, ty);
1801 }
1802
1803 // Now restore our clip.
1804 restoreClip(p, paintDirtyRect, clipRectToApply);
1805 }
1806
1807 if (!outlineRect.isEmpty()) {
1808 // Paint our own outline
1809 RenderObject::PaintInfo paintInfo(p, outlineRect, PaintPhaseSelfOutline, false, paintingRootForRenderer, 0);
1810 setClip(p, paintDirtyRect, outlineRect);
1811 renderer()->paint(paintInfo, tx, ty);
1812 restoreClip(p, paintDirtyRect, outlineRect);
1813 }
1814
1815 // Paint any child layers that have overflow.
1816 if (m_overflowList)
1817 for (Vector<RenderLayer*>::iterator it = m_overflowList->begin(); it != m_overflowList->end(); ++it)
1818 it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects);
1819
1820 // Now walk the sorted list of children with positive z-indices.
1821 if (m_posZOrderList)
1822 for (Vector<RenderLayer*>::iterator it = m_posZOrderList->begin(); it != m_posZOrderList->end(); ++it)
1823 it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects);
1824
1825 if (renderer()->hasMask() && shouldPaint && !selectionOnly && !damageRect.isEmpty()) {
1826 setClip(p, paintDirtyRect, damageRect);
1827
1828 // Paint the mask.
1829 RenderObject::PaintInfo paintInfo(p, damageRect, PaintPhaseMask, false, paintingRootForRenderer, 0);
1830 renderer()->paint(paintInfo, tx, ty);
1831
1832 // Restore the clip.
1833 restoreClip(p, paintDirtyRect, damageRect);
1834 }
1835
1836 // End our transparency layer
1837 if (isTransparent() && m_usedTransparency) {
1838 p->endTransparencyLayer();
1839 p->restore();
1840 m_usedTransparency = false;
1841 }
1842 }
1843
frameVisibleRect(RenderObject * renderer)1844 static inline IntRect frameVisibleRect(RenderObject* renderer)
1845 {
1846 FrameView* frameView = renderer->document()->view();
1847 if (!frameView)
1848 return IntRect();
1849
1850 return frameView->visibleContentRect();
1851 }
1852
hitTest(const HitTestRequest & request,HitTestResult & result)1853 bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
1854 {
1855 renderer()->document()->updateLayout();
1856
1857 IntRect boundsRect(m_x, m_y, width(), height());
1858 boundsRect.intersect(frameVisibleRect(renderer()));
1859
1860 RenderLayer* insideLayer = hitTestLayer(this, request, result, boundsRect, result.point());
1861
1862 // Now determine if the result is inside an anchor; make sure an image map wins if
1863 // it already set URLElement and only use the innermost.
1864 Node* node = result.innerNode();
1865 while (node) {
1866 // for imagemaps, URLElement is the associated area element not the image itself
1867 if (node->isLink() && !result.URLElement() && !node->hasTagName(imgTag))
1868 result.setURLElement(static_cast<Element*>(node));
1869 node = node->eventParentNode();
1870 }
1871
1872 // Next set up the correct :hover/:active state along the new chain.
1873 updateHoverActiveState(request, result);
1874
1875 // Now return whether we were inside this layer (this will always be true for the root
1876 // layer).
1877 return insideLayer;
1878 }
1879
enclosingElement() const1880 Node* RenderLayer::enclosingElement() const
1881 {
1882 for (RenderObject* r = renderer(); r; r = r->parent()) {
1883 if (Node* e = r->element())
1884 return e;
1885 }
1886 ASSERT_NOT_REACHED();
1887 return 0;
1888 }
1889
hitTestLayer(RenderLayer * rootLayer,const HitTestRequest & request,HitTestResult & result,const IntRect & hitTestRect,const IntPoint & hitTestPoint,bool appliedTransform)1890 RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result,
1891 const IntRect& hitTestRect, const IntPoint& hitTestPoint, bool appliedTransform)
1892 {
1893 // Apply a transform if we have one.
1894 if (m_transform && !appliedTransform) {
1895 // If the transform can't be inverted, then don't hit test this layer at all.
1896 if (!m_transform->isInvertible())
1897 return 0;
1898
1899 // Make sure the parent's clip rects have been calculated.
1900 if (parent()) {
1901 parent()->updateClipRects(rootLayer);
1902
1903 // Go ahead and test the enclosing clip now.
1904 IntRect clipRect = parent()->clipRects()->overflowClipRect();
1905 if (!clipRect.contains(hitTestPoint))
1906 return 0;
1907 }
1908
1909 // Adjust the transform such that the renderer's upper left corner is at (0,0) in user space.
1910 // This involves subtracting out the position of the layer in our current coordinate space.
1911 int x = 0;
1912 int y = 0;
1913 convertToLayerCoords(rootLayer, x, y);
1914 TransformationMatrix transform;
1915 transform.translate(x, y);
1916 transform = *m_transform * transform;
1917
1918 // Map the hit test point into the transformed space and then do a hit test with the root layer shifted to be us.
1919 return hitTestLayer(this, request, result, transform.inverse().mapRect(hitTestRect), transform.inverse().mapPoint(hitTestPoint), true);
1920 }
1921
1922 // Calculate the clip rects we should use.
1923 IntRect layerBounds;
1924 IntRect bgRect;
1925 IntRect fgRect;
1926 IntRect outlineRect;
1927 calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect, outlineRect);
1928
1929 // Ensure our lists are up-to-date.
1930 updateZOrderLists();
1931 updateOverflowList();
1932
1933 // This variable tracks which layer the mouse ends up being inside. The minute we find an insideLayer,
1934 // we are done and can return it.
1935 RenderLayer* insideLayer = 0;
1936
1937 // Begin by walking our list of positive layers from highest z-index down to the lowest
1938 // z-index.
1939 if (m_posZOrderList) {
1940 for (int i = m_posZOrderList->size() - 1; i >= 0; --i) {
1941 insideLayer = m_posZOrderList->at(i)->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint);
1942 if (insideLayer)
1943 return insideLayer;
1944 }
1945 }
1946
1947 // Now check our overflow objects.
1948 if (m_overflowList) {
1949 for (int i = m_overflowList->size() - 1; i >= 0; --i) {
1950 insideLayer = m_overflowList->at(i)->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint);
1951 if (insideLayer)
1952 return insideLayer;
1953 }
1954 }
1955
1956 // Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
1957 if (fgRect.contains(hitTestPoint) &&
1958 renderer()->hitTest(request, result, hitTestPoint,
1959 layerBounds.x() - renderer()->x(),
1960 layerBounds.y() - renderer()->y(),
1961 HitTestDescendants)) {
1962 // For positioned generated content, we might still not have a
1963 // node by the time we get to the layer level, since none of
1964 // the content in the layer has an element. So just walk up
1965 // the tree.
1966 if (!result.innerNode() || !result.innerNonSharedNode()) {
1967 Node* e = enclosingElement();
1968 if (!result.innerNode())
1969 result.setInnerNode(e);
1970 if (!result.innerNonSharedNode())
1971 result.setInnerNonSharedNode(e);
1972 }
1973
1974 return this;
1975 }
1976
1977 // Now check our negative z-index children.
1978 if (m_negZOrderList) {
1979 for (int i = m_negZOrderList->size() - 1; i >= 0; --i) {
1980 insideLayer = m_negZOrderList->at(i)->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint);
1981 if (insideLayer)
1982 return insideLayer;
1983 }
1984 }
1985
1986 // Next we want to see if the mouse is inside this layer but not any of its children.
1987 if (bgRect.contains(hitTestPoint) &&
1988 renderer()->hitTest(request, result, hitTestPoint,
1989 layerBounds.x() - renderer()->x(),
1990 layerBounds.y() - renderer()->y(),
1991 HitTestSelf)) {
1992 if (!result.innerNode() || !result.innerNonSharedNode()) {
1993 Node* e = enclosingElement();
1994 if (!result.innerNode())
1995 result.setInnerNode(e);
1996 if (!result.innerNonSharedNode())
1997 result.setInnerNonSharedNode(e);
1998 }
1999
2000 return this;
2001 }
2002
2003 // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down,
2004 // return ourselves. We do this so mouse events continue getting delivered after a drag has
2005 // exited the WebView, and so hit testing over a scrollbar hits the content document.
2006 if ((request.active || request.mouseUp) && renderer()->isRenderView()) {
2007 renderer()->updateHitTestResult(result, hitTestPoint);
2008 return this;
2009 }
2010
2011 return 0;
2012 }
2013
updateClipRects(const RenderLayer * rootLayer)2014 void RenderLayer::updateClipRects(const RenderLayer* rootLayer)
2015 {
2016 if (m_clipRects) {
2017 ASSERT(rootLayer == m_clipRectsRoot);
2018 return; // We have the correct cached value.
2019 }
2020
2021 // For transformed layers, the root layer was shifted to be us, so there is no need to
2022 // examine the parent. We want to cache clip rects with us as the root.
2023 RenderLayer* parentLayer = rootLayer != this ? parent() : 0;
2024 if (parentLayer)
2025 parentLayer->updateClipRects(rootLayer);
2026
2027 ClipRects clipRects;
2028 calculateClipRects(rootLayer, clipRects, true);
2029
2030 if (parentLayer && parentLayer->clipRects() && clipRects == *parentLayer->clipRects())
2031 m_clipRects = parentLayer->clipRects();
2032 else
2033 m_clipRects = new (renderer()->renderArena()) ClipRects(clipRects);
2034 m_clipRects->ref();
2035 #ifndef NDEBUG
2036 m_clipRectsRoot = rootLayer;
2037 #endif
2038 }
2039
calculateClipRects(const RenderLayer * rootLayer,ClipRects & clipRects,bool useCached) const2040 void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool useCached) const
2041 {
2042 IntRect infiniteRect(INT_MIN/2, INT_MIN/2, INT_MAX, INT_MAX);
2043 if (!parent()) {
2044 // The root layer's clip rect is always infinite.
2045 clipRects.reset(infiniteRect);
2046 return;
2047 }
2048
2049 // For transformed layers, the root layer was shifted to be us, so there is no need to
2050 // examine the parent. We want to cache clip rects with us as the root.
2051 RenderLayer* parentLayer = rootLayer != this ? parent() : 0;
2052
2053 // Ensure that our parent's clip has been calculated so that we can examine the values.
2054 if (parentLayer) {
2055 if (useCached && parentLayer->clipRects())
2056 clipRects = *parentLayer->clipRects();
2057 else
2058 parentLayer->calculateClipRects(rootLayer, clipRects);
2059 }
2060 else
2061 clipRects.reset(infiniteRect);
2062
2063 // A fixed object is essentially the root of its containing block hierarchy, so when
2064 // we encounter such an object, we reset our clip rects to the fixedClipRect.
2065 if (renderer()->style()->position() == FixedPosition) {
2066 clipRects.setPosClipRect(clipRects.fixedClipRect());
2067 clipRects.setOverflowClipRect(clipRects.fixedClipRect());
2068 clipRects.setFixed(true);
2069 }
2070 else if (renderer()->style()->position() == RelativePosition)
2071 clipRects.setPosClipRect(clipRects.overflowClipRect());
2072 else if (renderer()->style()->position() == AbsolutePosition)
2073 clipRects.setOverflowClipRect(clipRects.posClipRect());
2074
2075 // Update the clip rects that will be passed to child layers.
2076 if (renderer()->hasOverflowClip() || renderer()->hasClip()) {
2077 // This layer establishes a clip of some kind.
2078 int x = 0;
2079 int y = 0;
2080 convertToLayerCoords(rootLayer, x, y);
2081 RenderView* view = renderer()->view();
2082 ASSERT(view);
2083 if (view && clipRects.fixed() && rootLayer->renderer() == view) {
2084 x -= view->frameView()->scrollX();
2085 y -= view->frameView()->scrollY();
2086 }
2087
2088 if (renderer()->hasOverflowClip()) {
2089 IntRect newOverflowClip = renderer()->getOverflowClipRect(x,y);
2090 clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect()));
2091 if (renderer()->isPositioned() || renderer()->isRelPositioned())
2092 clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect()));
2093 }
2094 if (renderer()->hasClip()) {
2095 IntRect newPosClip = renderer()->getClipRect(x,y);
2096 clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect()));
2097 clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect()));
2098 clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect()));
2099 }
2100 }
2101 }
2102
calculateRects(const RenderLayer * rootLayer,const IntRect & paintDirtyRect,IntRect & layerBounds,IntRect & backgroundRect,IntRect & foregroundRect,IntRect & outlineRect,bool temporaryClipRects) const2103 void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& paintDirtyRect, IntRect& layerBounds,
2104 IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects) const
2105 {
2106 if (rootLayer != this && parent()) {
2107 ClipRects parentClipRects;
2108 if (temporaryClipRects)
2109 parent()->calculateClipRects(rootLayer, parentClipRects);
2110 else {
2111 parent()->updateClipRects(rootLayer);
2112 parentClipRects = *parent()->clipRects();
2113 }
2114
2115 backgroundRect = renderer()->style()->position() == FixedPosition ? parentClipRects.fixedClipRect() :
2116 (renderer()->isPositioned() ? parentClipRects.posClipRect() :
2117 parentClipRects.overflowClipRect());
2118 RenderView* view = renderer()->view();
2119 ASSERT(view);
2120 if (view && parentClipRects.fixed() && rootLayer->renderer() == view)
2121 backgroundRect.move(view->frameView()->scrollX(), view->frameView()->scrollY());
2122
2123 backgroundRect.intersect(paintDirtyRect);
2124 } else
2125 backgroundRect = paintDirtyRect;
2126
2127 foregroundRect = backgroundRect;
2128 outlineRect = backgroundRect;
2129
2130 int x = 0;
2131 int y = 0;
2132 convertToLayerCoords(rootLayer, x, y);
2133 layerBounds = IntRect(x, y, width(), height());
2134
2135 // Update the clip rects that will be passed to child layers.
2136 if (renderer()->hasOverflowClip() || renderer()->hasClip()) {
2137 // This layer establishes a clip of some kind.
2138 if (renderer()->hasOverflowClip())
2139 foregroundRect.intersect(renderer()->getOverflowClipRect(x,y));
2140 if (renderer()->hasClip()) {
2141 // Clip applies to *us* as well, so go ahead and update the damageRect.
2142 IntRect newPosClip = renderer()->getClipRect(x,y);
2143 backgroundRect.intersect(newPosClip);
2144 foregroundRect.intersect(newPosClip);
2145 outlineRect.intersect(newPosClip);
2146 }
2147
2148 // If we establish a clip at all, then go ahead and make sure our background
2149 // rect is intersected with our layer's bounds.
2150 if (ShadowData* boxShadow = renderer()->style()->boxShadow()) {
2151 IntRect overflow = layerBounds;
2152 do {
2153 IntRect shadowRect = layerBounds;
2154 shadowRect.move(boxShadow->x, boxShadow->y);
2155 shadowRect.inflate(boxShadow->blur);
2156 overflow.unite(shadowRect);
2157 boxShadow = boxShadow->next;
2158 } while (boxShadow);
2159 backgroundRect.intersect(overflow);
2160 } else
2161 backgroundRect.intersect(layerBounds);
2162 }
2163 }
2164
childrenClipRect() const2165 IntRect RenderLayer::childrenClipRect() const
2166 {
2167 RenderLayer* rootLayer = renderer()->view()->layer();
2168 IntRect layerBounds, backgroundRect, foregroundRect, outlineRect;
2169 calculateRects(rootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect);
2170 return foregroundRect;
2171 }
2172
selfClipRect() const2173 IntRect RenderLayer::selfClipRect() const
2174 {
2175 RenderLayer* rootLayer = renderer()->view()->layer();
2176 IntRect layerBounds, backgroundRect, foregroundRect, outlineRect;
2177 calculateRects(rootLayer, rootLayer->boundingBox(rootLayer), layerBounds, backgroundRect, foregroundRect, outlineRect);
2178 return backgroundRect;
2179 }
2180
intersectsDamageRect(const IntRect & layerBounds,const IntRect & damageRect,const RenderLayer * rootLayer) const2181 bool RenderLayer::intersectsDamageRect(const IntRect& layerBounds, const IntRect& damageRect, const RenderLayer* rootLayer) const
2182 {
2183 // Always examine the canvas and the root.
2184 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
2185 // paints the root's background.
2186 if (renderer()->isRenderView() || renderer()->isRoot())
2187 return true;
2188
2189 // If we aren't an inline flow, and our layer bounds do intersect the damage rect, then we
2190 // can go ahead and return true.
2191 RenderView* view = renderer()->view();
2192 ASSERT(view);
2193 if (view && !renderer()->isRenderInline()) {
2194 IntRect b = layerBounds;
2195 b.inflate(view->maximalOutlineSize());
2196 if (b.intersects(damageRect))
2197 return true;
2198 }
2199
2200 // Otherwise we need to compute the bounding box of this single layer and see if it intersects
2201 // the damage rect.
2202 return boundingBox(rootLayer).intersects(damageRect);
2203 }
2204
boundingBox(const RenderLayer * rootLayer) const2205 IntRect RenderLayer::boundingBox(const RenderLayer* rootLayer) const
2206 {
2207 // There are three special cases we need to consider.
2208 // (1) Inline Flows. For inline flows we will create a bounding box that fully encompasses all of the lines occupied by the
2209 // inline. In other words, if some <span> wraps to three lines, we'll create a bounding box that fully encloses the root
2210 // line boxes of all three lines (including overflow on those lines).
2211 // (2) Left/Top Overflow. The width/height of layers already includes right/bottom overflow. However, in the case of left/top
2212 // overflow, we have to create a bounding box that will extend to include this overflow.
2213 // (3) Floats. When a layer has overhanging floats that it paints, we need to make sure to include these overhanging floats
2214 // as part of our bounding box. We do this because we are the responsible layer for both hit testing and painting those
2215 // floats.
2216 IntRect result;
2217 if (renderer()->isRenderInline()) {
2218 // Go from our first line box to our last line box.
2219 RenderInline* inlineFlow = static_cast<RenderInline*>(renderer());
2220 InlineFlowBox* firstBox = inlineFlow->firstLineBox();
2221 if (!firstBox)
2222 return result;
2223 int top = firstBox->root()->topOverflow();
2224 int bottom = inlineFlow->lastLineBox()->root()->bottomOverflow();
2225 int left = firstBox->xPos();
2226 for (InlineRunBox* curr = firstBox->nextLineBox(); curr; curr = curr->nextLineBox())
2227 left = min(left, curr->xPos());
2228 result = IntRect(m_x + left, m_y + (top - renderer()->y()), width(), bottom - top);
2229 } else if (renderer()->isTableRow()) {
2230 // Our bounding box is just the union of all of our cells' border/overflow rects.
2231 for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) {
2232 if (child->isTableCell()) {
2233 IntRect bbox = toRenderBox(child)->borderBoxRect();
2234 result.unite(bbox);
2235 IntRect overflowRect = renderer()->overflowRect(false);
2236 if (bbox != overflowRect)
2237 result.unite(overflowRect);
2238 }
2239 }
2240 result.move(m_x, m_y);
2241 } else {
2242 if (renderer()->hasMask())
2243 result = renderer()->maskClipRect();
2244 else {
2245 IntRect bbox = renderer()->borderBoxRect();
2246 result = bbox;
2247 IntRect overflowRect = renderer()->overflowRect(false);
2248 if (bbox != overflowRect)
2249 result.unite(overflowRect);
2250 }
2251
2252 // We have to adjust the x/y of this result so that it is in the coordinate space of the layer.
2253 result.move(m_x, m_y);
2254 }
2255
2256 // Convert the bounding box to an absolute position. We can do this easily by looking at the delta
2257 // between the bounding box's xpos and our layer's xpos and then applying that to the absolute layerBounds
2258 // passed in.
2259 int absX = 0, absY = 0;
2260 convertToLayerCoords(rootLayer, absX, absY);
2261 result.move(absX - m_x, absY - m_y);
2262 RenderView* view = renderer()->view();
2263 ASSERT(view);
2264 if (view)
2265 result.inflate(view->maximalOutlineSize());
2266 return result;
2267 }
2268
clearClipRectsIncludingDescendants()2269 void RenderLayer::clearClipRectsIncludingDescendants()
2270 {
2271 if (!m_clipRects)
2272 return;
2273
2274 clearClipRects();
2275
2276 for (RenderLayer* l = firstChild(); l; l = l->nextSibling())
2277 l->clearClipRectsIncludingDescendants();
2278 }
2279
clearClipRects()2280 void RenderLayer::clearClipRects()
2281 {
2282 if (m_clipRects) {
2283 m_clipRects->deref(renderer()->renderArena());
2284 m_clipRects = 0;
2285 #ifndef NDEBUG
2286 m_clipRectsRoot = 0;
2287 #endif
2288 }
2289 }
2290
commonAncestor(RenderObject * obj1,RenderObject * obj2)2291 static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2)
2292 {
2293 if (!obj1 || !obj2)
2294 return 0;
2295
2296 for (RenderObject* currObj1 = obj1; currObj1; currObj1 = currObj1->hoverAncestor())
2297 for (RenderObject* currObj2 = obj2; currObj2; currObj2 = currObj2->hoverAncestor())
2298 if (currObj1 == currObj2)
2299 return currObj1;
2300
2301 return 0;
2302 }
2303
updateHoverActiveState(const HitTestRequest & request,HitTestResult & result)2304 void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestResult& result)
2305 {
2306 // We don't update :hover/:active state when the result is marked as readonly.
2307 if (request.readonly)
2308 return;
2309
2310 Document* doc = renderer()->document();
2311
2312 Node* activeNode = doc->activeNode();
2313 if (activeNode && !request.active) {
2314 // We are clearing the :active chain because the mouse has been released.
2315 for (RenderObject* curr = activeNode->renderer(); curr; curr = curr->parent()) {
2316 if (curr->element() && !curr->isText())
2317 curr->element()->setInActiveChain(false);
2318 }
2319 doc->setActiveNode(0);
2320 } else {
2321 Node* newActiveNode = result.innerNode();
2322 if (!activeNode && newActiveNode && request.active) {
2323 // We are setting the :active chain and freezing it. If future moves happen, they
2324 // will need to reference this chain.
2325 for (RenderObject* curr = newActiveNode->renderer(); curr; curr = curr->parent()) {
2326 if (curr->element() && !curr->isText()) {
2327 curr->element()->setInActiveChain(true);
2328 }
2329 }
2330 doc->setActiveNode(newActiveNode);
2331 }
2332 }
2333
2334 // If the mouse is down and if this is a mouse move event, we want to restrict changes in
2335 // :hover/:active to only apply to elements that are in the :active chain that we froze
2336 // at the time the mouse went down.
2337 bool mustBeInActiveChain = request.active && request.mouseMove;
2338
2339 // Check to see if the hovered node has changed. If not, then we don't need to
2340 // do anything.
2341 RefPtr<Node> oldHoverNode = doc->hoverNode();
2342 Node* newHoverNode = result.innerNode();
2343
2344 // Update our current hover node.
2345 doc->setHoverNode(newHoverNode);
2346
2347 // We have two different objects. Fetch their renderers.
2348 RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
2349 RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0;
2350
2351 // Locate the common ancestor render object for the two renderers.
2352 RenderObject* ancestor = commonAncestor(oldHoverObj, newHoverObj);
2353
2354 if (oldHoverObj != newHoverObj) {
2355 // The old hover path only needs to be cleared up to (and not including) the common ancestor;
2356 for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) {
2357 if (curr->element() && !curr->isText() && (!mustBeInActiveChain || curr->element()->inActiveChain())) {
2358 curr->element()->setActive(false);
2359 curr->element()->setHovered(false);
2360 }
2361 }
2362 }
2363
2364 // Now set the hover state for our new object up to the root.
2365 for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) {
2366 if (curr->element() && !curr->isText() && (!mustBeInActiveChain || curr->element()->inActiveChain())) {
2367 curr->element()->setActive(request.active);
2368 curr->element()->setHovered(true);
2369 }
2370 }
2371 }
2372
2373 // Helper for the sorting of layers by z-index.
compareZIndex(RenderLayer * first,RenderLayer * second)2374 static inline bool compareZIndex(RenderLayer* first, RenderLayer* second)
2375 {
2376 return first->zIndex() < second->zIndex();
2377 }
2378
dirtyZOrderLists()2379 void RenderLayer::dirtyZOrderLists()
2380 {
2381 if (m_posZOrderList)
2382 m_posZOrderList->clear();
2383 if (m_negZOrderList)
2384 m_negZOrderList->clear();
2385 m_zOrderListsDirty = true;
2386 }
2387
dirtyStackingContextZOrderLists()2388 void RenderLayer::dirtyStackingContextZOrderLists()
2389 {
2390 RenderLayer* sc = stackingContext();
2391 if (sc)
2392 sc->dirtyZOrderLists();
2393 }
2394
dirtyOverflowList()2395 void RenderLayer::dirtyOverflowList()
2396 {
2397 if (m_overflowList)
2398 m_overflowList->clear();
2399 m_overflowListDirty = true;
2400 }
2401
updateZOrderLists()2402 void RenderLayer::updateZOrderLists()
2403 {
2404 if (!isStackingContext() || !m_zOrderListsDirty)
2405 return;
2406
2407 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
2408 if (!m_reflection || reflectionLayer() != child)
2409 child->collectLayers(m_posZOrderList, m_negZOrderList);
2410
2411 // Sort the two lists.
2412 if (m_posZOrderList)
2413 std::stable_sort(m_posZOrderList->begin(), m_posZOrderList->end(), compareZIndex);
2414 if (m_negZOrderList)
2415 std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(), compareZIndex);
2416
2417 m_zOrderListsDirty = false;
2418 }
2419
updateOverflowList()2420 void RenderLayer::updateOverflowList()
2421 {
2422 if (!m_overflowListDirty)
2423 return;
2424
2425 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
2426 // Ignore non-overflow layers and reflections.
2427 if (child->isOverflowOnly() && (!m_reflection || reflectionLayer() != child)) {
2428 if (!m_overflowList)
2429 m_overflowList = new Vector<RenderLayer*>;
2430 m_overflowList->append(child);
2431 }
2432 }
2433
2434 m_overflowListDirty = false;
2435 }
2436
collectLayers(Vector<RenderLayer * > * & posBuffer,Vector<RenderLayer * > * & negBuffer)2437 void RenderLayer::collectLayers(Vector<RenderLayer*>*& posBuffer, Vector<RenderLayer*>*& negBuffer)
2438 {
2439 updateVisibilityStatus();
2440
2441 // Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists.
2442 if ((m_hasVisibleContent || (m_hasVisibleDescendant && isStackingContext())) && !isOverflowOnly()) {
2443 // Determine which buffer the child should be in.
2444 Vector<RenderLayer*>*& buffer = (zIndex() >= 0) ? posBuffer : negBuffer;
2445
2446 // Create the buffer if it doesn't exist yet.
2447 if (!buffer)
2448 buffer = new Vector<RenderLayer*>;
2449
2450 // Append ourselves at the end of the appropriate buffer.
2451 buffer->append(this);
2452 }
2453
2454 // Recur into our children to collect more layers, but only if we don't establish
2455 // a stacking context.
2456 if (m_hasVisibleDescendant && !isStackingContext()) {
2457 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
2458 // Ignore reflections.
2459 if (!m_reflection || reflectionLayer() != child)
2460 child->collectLayers(posBuffer, negBuffer);
2461 }
2462 }
2463 }
2464
repaintIncludingDescendants()2465 void RenderLayer::repaintIncludingDescendants()
2466 {
2467 renderer()->repaint();
2468 for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling())
2469 curr->repaintIncludingDescendants();
2470 }
2471
shouldBeOverflowOnly() const2472 bool RenderLayer::shouldBeOverflowOnly() const
2473 {
2474 return (renderer()->hasOverflowClip() || renderer()->hasReflection()) &&
2475 !renderer()->isPositioned() &&
2476 !renderer()->isRelPositioned() &&
2477 !renderer()->hasTransform() &&
2478 !isTransparent();
2479 }
2480
styleChanged(RenderStyle::Diff,const RenderStyle *)2481 void RenderLayer::styleChanged(RenderStyle::Diff, const RenderStyle*)
2482 {
2483 bool isOverflowOnly = shouldBeOverflowOnly();
2484 if (isOverflowOnly != m_isOverflowOnly) {
2485 m_isOverflowOnly = isOverflowOnly;
2486 RenderLayer* p = parent();
2487 if (p)
2488 p->dirtyOverflowList();
2489 dirtyStackingContextZOrderLists();
2490 }
2491
2492 if (renderer()->style()->overflowX() == OMARQUEE && renderer()->style()->marqueeBehavior() != MNONE) {
2493 if (!m_marquee)
2494 m_marquee = new RenderMarquee(this);
2495 m_marquee->updateMarqueeStyle();
2496 }
2497 else if (m_marquee) {
2498 delete m_marquee;
2499 m_marquee = 0;
2500 }
2501
2502 if (!hasReflection() && m_reflection) {
2503 m_reflection->destroy();
2504 m_reflection = 0;
2505 } else if (hasReflection()) {
2506 if (!m_reflection)
2507 createReflection();
2508 updateReflectionStyle();
2509 }
2510
2511 // FIXME: Need to detect a swap from custom to native scrollbars (and vice versa).
2512 if (m_hBar)
2513 m_hBar->styleChanged();
2514 if (m_vBar)
2515 m_vBar->styleChanged();
2516
2517 updateScrollCornerStyle();
2518 updateResizerStyle();
2519 }
2520
updateScrollCornerStyle()2521 void RenderLayer::updateScrollCornerStyle()
2522 {
2523 RenderObject* actualRenderer = renderer()->node()->isElementNode() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
2524 RefPtr<RenderStyle> corner = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RenderStyle::SCROLLBAR_CORNER, actualRenderer->style()) : 0;
2525 if (corner) {
2526 if (!m_scrollCorner) {
2527 m_scrollCorner = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document());
2528 m_scrollCorner->setParent(renderer());
2529 }
2530 m_scrollCorner->setStyle(corner.release());
2531 } else if (m_scrollCorner) {
2532 m_scrollCorner->destroy();
2533 m_scrollCorner = 0;
2534 }
2535 }
2536
updateResizerStyle()2537 void RenderLayer::updateResizerStyle()
2538 {
2539 RenderObject* actualRenderer = renderer()->node()->isElementNode() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
2540 RefPtr<RenderStyle> resizer = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RenderStyle::RESIZER, actualRenderer->style()) : 0;
2541 if (resizer) {
2542 if (!m_resizer) {
2543 m_resizer = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document());
2544 m_resizer->setParent(renderer());
2545 }
2546 m_resizer->setStyle(resizer.release());
2547 } else if (m_resizer) {
2548 m_resizer->destroy();
2549 m_resizer = 0;
2550 }
2551 }
2552
reflectionLayer() const2553 RenderLayer* RenderLayer::reflectionLayer() const
2554 {
2555 return m_reflection ? m_reflection->layer() : 0;
2556 }
2557
createReflection()2558 void RenderLayer::createReflection()
2559 {
2560 ASSERT(!m_reflection);
2561 m_reflection = new (renderer()->renderArena()) RenderReplica(renderer()->document());
2562 m_reflection->setParent(renderer()); // We create a 1-way connection.
2563 }
2564
updateReflectionStyle()2565 void RenderLayer::updateReflectionStyle()
2566 {
2567 RefPtr<RenderStyle> newStyle = RenderStyle::create();
2568 newStyle->inheritFrom(renderer()->style());
2569
2570 // Map in our transform.
2571 TransformOperations transform;
2572 switch (renderer()->style()->boxReflect()->direction()) {
2573 case ReflectionBelow:
2574 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::TRANSLATE));
2575 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), renderer()->style()->boxReflect()->offset(), TransformOperation::TRANSLATE));
2576 transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::SCALE));
2577 break;
2578 case ReflectionAbove:
2579 transform.operations().append(ScaleTransformOperation::create(1.0, -1.0, ScaleTransformOperation::SCALE));
2580 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), Length(100., Percent), TransformOperation::TRANSLATE));
2581 transform.operations().append(TranslateTransformOperation::create(Length(0, Fixed), renderer()->style()->boxReflect()->offset(), TransformOperation::TRANSLATE));
2582 break;
2583 case ReflectionRight:
2584 transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::TRANSLATE));
2585 transform.operations().append(TranslateTransformOperation::create(renderer()->style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::TRANSLATE));
2586 transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::SCALE));
2587 break;
2588 case ReflectionLeft:
2589 transform.operations().append(ScaleTransformOperation::create(-1.0, 1.0, ScaleTransformOperation::SCALE));
2590 transform.operations().append(TranslateTransformOperation::create(Length(100., Percent), Length(0, Fixed), TransformOperation::TRANSLATE));
2591 transform.operations().append(TranslateTransformOperation::create(renderer()->style()->boxReflect()->offset(), Length(0, Fixed), TransformOperation::TRANSLATE));
2592 break;
2593 }
2594 newStyle->setTransform(transform);
2595
2596 // Map in our mask.
2597 newStyle->setMaskBoxImage(renderer()->style()->boxReflect()->mask());
2598
2599 m_reflection->setStyle(newStyle.release());
2600 }
2601
suspendMarquees()2602 void RenderLayer::suspendMarquees()
2603 {
2604 if (m_marquee)
2605 m_marquee->suspend();
2606
2607 for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling())
2608 curr->suspendMarquees();
2609 }
2610
2611 } // namespace WebCore
2612