fix logic
[personal-kdelibs.git] / khtml / rendering / render_layer.cpp
blobb1353a27a70c08b618828e7ef6894a44e62d73c2
1 /*
2 * Copyright (C) 2003 Apple Computer, Inc.
3 * (C) 2006 Germain Garand <germain@ebooksfrance.org>
4 * (C) 2006 Allan Sandfeld Jense <kde@carewolf.com>
6 * Portions are Copyright (C) 1998 Netscape Communications Corporation.
8 * Other contributors:
9 * Robert O'Callahan <roc+@cs.cmu.edu>
10 * David Baron <dbaron@fas.harvard.edu>
11 * Christian Biesinger <cbiesinger@web.de>
12 * Randall Jesup <rjesup@wgate.com>
13 * Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
14 * Josh Soref <timeless@mac.com>
15 * Boris Zbarsky <bzbarsky@mit.edu>
17 * This library is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public
19 * License as published by the Free Software Foundation; either
20 * version 2.1 of the License, or (at your option) any later version.
22 * This library is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * Lesser General Public License for more details.
27 * You should have received a copy of the GNU Lesser General Public
28 * License along with this library; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
31 * Alternatively, the contents of this file may be used under the terms
32 * of either the Mozilla Public License Version 1.1, found at
33 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
34 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
35 * (the "GPL"), in which case the provisions of the MPL or the GPL are
36 * applicable instead of those above. If you wish to allow use of your
37 * version of this file only under the terms of one of those two
38 * licenses (the MPL or the GPL) and not to allow others to use your
39 * version of this file under the LGPL, indicate your decision by
40 * deletingthe provisions above and replace them with the notice and
41 * other provisions required by the MPL or the GPL, as the case may be.
42 * If you do not delete the provisions above, a recipient may use your
43 * version of this file under any of the LGPL, the MPL or the GPL.
46 //#define BOX_DEBUG
48 #include "render_layer.h"
49 #include <kdebug.h>
50 #include <assert.h>
51 #include "khtmlview.h"
52 #include "render_canvas.h"
53 #include "render_arena.h"
54 #include "render_replaced.h"
55 #include "render_form.h"
56 #include "xml/dom_docimpl.h"
57 #include "xml/dom2_eventsimpl.h"
58 #include "misc/htmltags.h"
59 #include "misc/paintbuffer.h"
60 #include "html/html_blockimpl.h"
61 #include "xml/dom_restyler.h"
63 #include <QtGui/QStyle>
64 #include <QtCore/QStack>
66 using namespace DOM;
67 using namespace khtml;
69 ScrollBarWidget* RenderLayer::gScrollBar = 0;
71 #ifndef NDEBUG
72 static bool inRenderLayerDetach;
73 #endif
75 void
76 RenderScrollMediator::slotValueChanged()
78 m_layer->updateScrollPositionFromScrollbars();
81 RenderLayer::RenderLayer(RenderObject* object)
82 : m_object( object ),
83 m_parent( 0 ),
84 m_previous( 0 ),
85 m_next( 0 ),
86 m_first( 0 ),
87 m_last( 0 ),
88 m_x( 0 ),
89 m_y( 0 ),
90 m_scrollX( 0 ),
91 m_scrollY( 0 ),
92 m_scrollWidth( 0 ),
93 m_scrollHeight( 0 ),
94 m_hBar( 0 ),
95 m_vBar( 0 ),
96 m_scrollMediator( 0 ),
97 m_posZOrderList( 0 ),
98 m_negZOrderList( 0 ),
99 m_overflowList(0),
100 m_zOrderListsDirty( true ),
101 m_overflowListDirty(true),
102 m_isOverflowOnly( shouldBeOverflowOnly() ),
103 m_markedForRepaint( false ),
104 m_hasOverlaidWidgets( false ),
105 m_visibleContentStatusDirty( true ),
106 m_hasVisibleContent( false ),
107 m_visibleDescendantStatusDirty( false ),
108 m_hasVisibleDescendant( false ),
109 m_marquee( 0 )
111 if (!object->firstChild() && object->style()) {
112 m_visibleContentStatusDirty = false;
113 m_hasVisibleContent = object->style()->visibility() == VISIBLE;
115 m_buffer[0] = 0;
116 m_buffer[1] = 0;
119 RenderLayer::~RenderLayer()
121 // Child layers will be deleted by their corresponding render objects, so
122 // our destructor doesn't have to do anything.
123 delete m_hBar;
124 delete m_vBar;
125 delete m_buffer[0];
126 delete m_buffer[1];
127 delete m_scrollMediator;
128 delete m_posZOrderList;
129 delete m_negZOrderList;
130 delete m_overflowList;
131 delete m_marquee;
134 void RenderLayer::updateLayerPosition()
137 // The canvas is sized to the docWidth/Height over in RenderCanvas::layout, so we
138 // don't need to ever update our layer position here.
139 if (renderer()->isCanvas())
140 return;
142 int x = m_object->xPos();
143 int y = m_object->yPos() - m_object->borderTopExtra();
145 if (!m_object->isPositioned()) {
146 // We must adjust our position by walking up the render tree looking for the
147 // nearest enclosing object with a layer.
148 RenderObject* curr = m_object->parent();
149 while (curr && !curr->layer()) {
150 x += curr->xPos();
151 y += curr->yPos();
152 curr = curr->parent();
154 if (curr)
155 y += curr->borderTopExtra();
158 if (m_object->isRelPositioned())
159 static_cast<RenderBox*>(m_object)->relativePositionOffset(x, y);
161 // Subtract our parent's scroll offset.
162 if (m_object->isPositioned() && enclosingPositionedAncestor()) {
163 RenderLayer* positionedParent = enclosingPositionedAncestor();
165 // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
166 positionedParent->subtractScrollOffset(x, y);
167 positionedParent->checkInlineRelOffset(m_object, x, y);
169 else if (parent())
170 parent()->subtractScrollOffset(x, y);
172 setPos(x,y);
175 QRegion RenderLayer::paintedRegion(RenderLayer* rootLayer)
177 updateZOrderLists();
178 QRegion r;
179 const RenderStyle *s= renderer()->style();
180 bool isTrans = (s->opacity() < 1.0);
181 if (isTrans && m_hasVisibleDescendant) {
182 if (!s->opacity())
183 return r;
184 for (RenderLayer* ch = firstChild(); ch ; ch = ch->nextSibling())
185 r += ch->paintedRegion(rootLayer);
186 } else if (m_negZOrderList && m_hasVisibleDescendant) {
187 uint count = m_negZOrderList->count();
188 for (uint i = 0; i < count; i++) {
189 RenderLayer* child = m_negZOrderList->at(i);
190 r += child->paintedRegion(rootLayer);
194 if (m_hasVisibleContent) {
195 int x = 0; int y = 0;
196 convertToLayerCoords(rootLayer,x,y);
197 QRect cr(x,y,width(),height());
198 if (s->visibility() == VISIBLE && (s->backgroundImage() || s->backgroundColor().isValid() || s->hasBorder() ||
199 renderer()->scrollsOverflow() || renderer()->isReplaced()) ) {
200 if (!s->hidesOverflow())
201 r += renderer()->visibleFlowRegion(x, y);
202 r += cr;
203 } else {
204 r += renderer()->visibleFlowRegion(x, y);
208 if (!isTrans && m_posZOrderList && m_hasVisibleDescendant) {
209 uint count = m_posZOrderList->count();
210 for (uint i = 0; i < count; i++) {
211 RenderLayer* child = m_posZOrderList->at(i);
212 r += child->paintedRegion(rootLayer);
215 return r;
218 void RenderLayer::repaint( Priority p, bool markForRepaint )
220 if (markForRepaint && m_markedForRepaint)
221 return;
222 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
223 child->repaint( p, markForRepaint );
224 QRect layerBounds, damageRect, fgrect;
225 calculateRects(renderer()->canvas()->layer(), renderer()->viewRect(), layerBounds, damageRect, fgrect);
226 m_visibleRect = damageRect.intersect( layerBounds );
227 if (m_visibleRect.isValid())
228 renderer()->canvas()->repaintViewRectangle( m_visibleRect.x(), m_visibleRect.y(), m_visibleRect.width(), m_visibleRect.height(), (p > NormalPriority) );
229 if (markForRepaint)
230 m_markedForRepaint = true;
233 void RenderLayer::updateLayerPositions(RenderLayer* rootLayer, bool doFullRepaint, bool checkForRepaint)
235 if (doFullRepaint) {
236 m_object->repaint();
237 checkForRepaint = doFullRepaint = false;
240 updateLayerPosition(); // For relpositioned layers or non-positioned layers,
241 // we need to keep in sync, since we may have shifted relative
242 // to our parent layer.
244 if (m_hBar || m_vBar) {
245 // Need to position the scrollbars.
246 int x = 0;
247 int y = 0;
248 convertToLayerCoords(rootLayer, x, y);
249 QRect layerBounds = QRect(x,y,width(),height());
250 positionScrollbars(layerBounds);
253 updateVisibilityStatus();
255 if (m_hasVisibleContent && checkForRepaint && m_markedForRepaint) {
256 QRect layerBounds, damageRect, fgrect;
257 calculateRects(rootLayer, renderer()->viewRect(), layerBounds, damageRect, fgrect);
258 QRect vr = damageRect.intersect( layerBounds );
259 if (vr != m_visibleRect && vr.isValid()) {
260 renderer()->canvas()->repaintViewRectangle( vr.x(), vr.y(), vr.width(), vr.height() );
261 m_visibleRect = vr;
264 m_markedForRepaint = false;
266 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
267 child->updateLayerPositions(rootLayer, doFullRepaint, checkForRepaint);
269 // With all our children positioned, now update our marquee if we need to.
270 if (m_marquee)
271 m_marquee->updateMarqueePosition();
275 void RenderLayer::setHasVisibleContent(bool b)
277 if (m_hasVisibleContent == b && !m_visibleContentStatusDirty)
278 return;
279 m_visibleContentStatusDirty = false;
280 m_hasVisibleContent = b;
281 if (m_hasVisibleContent) {
282 // ### dirty painted region
283 // m_region = QRegion();
284 if (!isOverflowOnly())
285 if (RenderLayer* sc = stackingContext())
286 sc->dirtyZOrderLists();
288 if (parent())
289 parent()->childVisibilityChanged(m_hasVisibleContent);
292 void RenderLayer::dirtyVisibleContentStatus()
294 m_visibleContentStatusDirty = true;
295 if (parent())
296 parent()->dirtyVisibleDescendantStatus();
299 void RenderLayer::childVisibilityChanged(bool newVisibility)
301 if (m_hasVisibleDescendant == newVisibility || m_visibleDescendantStatusDirty)
302 return;
303 if (newVisibility) {
304 RenderLayer* l = this;
305 while (l && !l->m_visibleDescendantStatusDirty && !l->m_hasVisibleDescendant) {
306 l->m_hasVisibleDescendant = true;
307 l = l->parent();
309 } else
310 dirtyVisibleDescendantStatus();
313 void RenderLayer::dirtyVisibleDescendantStatus()
315 RenderLayer* l = this;
316 while (l && !l->m_visibleDescendantStatusDirty) {
317 l->m_visibleDescendantStatusDirty = true;
318 l = l->parent();
322 void RenderLayer::updateVisibilityStatus()
324 if (m_visibleDescendantStatusDirty) {
325 m_hasVisibleDescendant = false;
326 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
327 child->updateVisibilityStatus();
328 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant) {
329 m_hasVisibleDescendant = true;
330 break;
333 m_visibleDescendantStatusDirty = false;
336 if (m_visibleContentStatusDirty) {
337 if (m_object->style()->visibility() == VISIBLE)
338 m_hasVisibleContent = true;
339 else {
340 // layer may be hidden but still have some visible content, check for this
341 m_hasVisibleContent = false;
342 RenderObject* r = m_object->firstChild();
343 while (r) {
344 if (r->style()->visibility() == VISIBLE && !r->layer()) {
345 m_hasVisibleContent = true;
346 break;
348 if (r->firstChild() && !r->layer())
349 r = r->firstChild();
350 else if (r->nextSibling())
351 r = r->nextSibling();
352 else {
353 do {
354 r = r->parent();
355 if (r==m_object)
356 r = 0;
357 } while (r && !r->nextSibling());
358 if (r)
359 r = r->nextSibling();
363 m_visibleContentStatusDirty = false;
367 void RenderLayer::updateWidgetMasks(RenderLayer* rootLayer)
369 if (hasOverlaidWidgets() && !renderer()->canvas()->pagedMode()) {
370 updateZOrderLists();
371 uint count = m_posZOrderList ? m_posZOrderList->count() : 0;
372 bool needUpdate = false;
373 KHTMLView* sa = 0;
374 if ( count > 0 ) {
375 sa = m_object->document()->view();
376 m_region = QRect(0,0,sa->contentsWidth(),sa->contentsHeight());
377 for (uint i = 0; i < count; i++) {
378 RenderLayer* child = m_posZOrderList->at(i);
379 if (child->zIndex() == 0 && child->renderer()->style()->position() == PSTATIC)
380 continue; // we don't know the widget's exact stacking position within flow
381 m_region -= child->paintedRegion(rootLayer);
383 needUpdate = true;
385 RenderLayer* sc = this;
386 int zx = zIndex();
387 while ((sc = sc->stackingContext())) {
388 sc->updateZOrderLists();
389 bool found = false;
390 if (zx < 0) {
391 count = sc->m_negZOrderList ? sc->m_negZOrderList->count() : 0;
392 needUpdate = needUpdate || count > 0;
393 for (uint i = 0; i < count; i++) {
394 found = found || sc->m_negZOrderList->at(i)->zIndex() > zx;
395 if (found) {
396 if (!sa) {
397 sa = m_object->document()->view();
398 m_region = QRect(0,0,sa->contentsWidth(),sa->contentsHeight());
400 m_region -= sc->m_negZOrderList->at(i)->paintedRegion(rootLayer);
404 count = sc->m_posZOrderList ? sc->m_posZOrderList->count() : 0;
405 if ( count > 0 ) {
406 needUpdate = true;
407 for (uint i = 0; i < count; i++) {
408 found = found || sc->m_posZOrderList->at(i)->zIndex() > zx;
409 if (found) {
410 if (!sa) {
411 sa = m_object->document()->view();
412 m_region = QRect(0,0,sa->contentsWidth(),sa->contentsHeight());
414 m_region -= sc->m_posZOrderList->at(i)->paintedRegion(rootLayer);
418 zx = sc->zIndex();
420 if (!needUpdate) {
421 needUpdate = needUpdate || !m_region.isEmpty();
422 m_region = QRegion();
424 if (needUpdate)
425 renderer()->updateWidgetMasks();
427 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
428 child->updateWidgetMasks(rootLayer);
431 short RenderLayer::width() const
433 int w = m_object->width();
434 if (!m_object->hasOverflowClip())
435 w = qMax(m_object->overflowWidth(), w);
436 return w;
439 int RenderLayer::height() const
441 int h = m_object->height() + m_object->borderTopExtra() + m_object->borderBottomExtra();
442 if (!m_object->hasOverflowClip())
443 h = qMax(m_object->overflowHeight(), h);
444 return h;
448 RenderLayer *RenderLayer::stackingContext() const
450 RenderLayer* curr = parent();
451 for ( ; curr && !curr->m_object->isCanvas() &&
452 curr->m_object->style()->hasAutoZIndex();
453 curr = curr->parent());
454 return curr;
457 RenderLayer* RenderLayer::enclosingPositionedAncestor() const
459 RenderLayer* curr = parent();
460 for ( ; curr && !curr->m_object->isCanvas() &&
461 !curr->m_object->isPositioned() && !curr->m_object->isRelPositioned();
462 curr = curr->parent());
464 return curr;
467 bool RenderLayer::isTransparent() const
469 return m_object->style()->opacity() < 1.0f;
472 RenderLayer* RenderLayer::transparentAncestor() const
474 RenderLayer* curr = parent();
475 for ( ; curr && curr->m_object->style()->opacity() == 1.0f; curr = curr->parent());
476 return curr;
479 void* RenderLayer::operator new(size_t sz, RenderArena* renderArena) throw()
481 return renderArena->allocate(sz);
484 void RenderLayer::operator delete(void* ptr, size_t sz)
486 assert(inRenderLayerDetach);
487 #ifdef KHTML_USE_ARENA_ALLOCATOR
488 // Stash size where detach can find it.
489 *(size_t *)ptr = sz;
490 #endif
493 void RenderLayer::detach(RenderArena* renderArena)
495 #ifndef NDEBUG
496 inRenderLayerDetach = true;
497 #endif
498 delete this;
499 #ifndef NDEBUG
500 inRenderLayerDetach = false;
501 #endif
503 // Recover the size left there for us by operator delete and free the memory.
504 renderArena->free(*(size_t *)this, this);
507 void RenderLayer::addChild(RenderLayer *child, RenderLayer* beforeChild)
509 RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
510 if (prevSibling) {
511 child->setPreviousSibling(prevSibling);
512 prevSibling->setNextSibling(child);
514 else
515 setFirstChild(child);
517 if (beforeChild) {
518 beforeChild->setPreviousSibling(child);
519 child->setNextSibling(beforeChild);
521 else
522 setLastChild(child);
524 child->setParent(this);
526 if (child->isOverflowOnly())
527 dirtyOverflowList();
528 else {
529 // Dirty the z-order list in which we are contained. The stackingContext() can be null in the
530 // case where we're building up generated content layers. This is ok, since the lists will start
531 // off dirty in that case anyway.
532 RenderLayer* stackingContext = child->stackingContext();
533 if (stackingContext)
534 stackingContext->dirtyZOrderLists();
536 child->updateVisibilityStatus();
537 if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
538 childVisibilityChanged(true);
541 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
543 // remove the child
544 if (oldChild->previousSibling())
545 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
546 if (oldChild->nextSibling())
547 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
549 if (m_first == oldChild)
550 m_first = oldChild->nextSibling();
551 if (m_last == oldChild)
552 m_last = oldChild->previousSibling();
554 if (oldChild->isOverflowOnly())
555 dirtyOverflowList();
556 else {
557 // Dirty the z-order list in which we are contained. When called via the
558 // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
559 // from the main layer tree, so we need to null-check the |stackingContext| value.
560 RenderLayer* stackingContext = oldChild->stackingContext();
561 if (stackingContext)
562 stackingContext->dirtyZOrderLists();
565 oldChild->setPreviousSibling(0);
566 oldChild->setNextSibling(0);
567 oldChild->setParent(0);
569 oldChild->updateVisibilityStatus();
570 if (oldChild->m_hasVisibleContent || oldChild->m_hasVisibleDescendant)
571 childVisibilityChanged(false);
573 return oldChild;
576 void RenderLayer::removeOnlyThisLayer()
578 if (!m_parent)
579 return;
581 // Remove us from the parent.
582 RenderLayer* parent = m_parent;
583 RenderLayer* nextSib = nextSibling();
584 parent->removeChild(this);
586 // Now walk our kids and reattach them to our parent.
587 RenderLayer* current = m_first;
588 while (current) {
589 RenderLayer* next = current->nextSibling();
590 removeChild(current);
591 parent->addChild(current, nextSib);
592 current = next;
595 detach(renderer()->renderArena());
598 void RenderLayer::insertOnlyThisLayer()
600 if (!m_parent && renderer()->parent()) {
601 // We need to connect ourselves when our renderer() has a parent.
602 // Find our enclosingLayer and add ourselves.
603 RenderLayer* parentLayer = renderer()->parent()->enclosingLayer();
604 if (parentLayer)
605 parentLayer->addChild(this,
606 renderer()->parent()->findNextLayer(parentLayer, renderer()));
609 // Remove all descendant layers from the hierarchy and add them to the new position.
610 for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
611 curr->moveLayers(m_parent, this);
614 void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const
616 if (ancestorLayer == this)
617 return;
619 if (m_object->style()->position() == PFIXED) {
620 // Add in the offset of the view. We can obtain this by calling
621 // absolutePosition() on the RenderCanvas.
622 int xOff, yOff;
623 m_object->absolutePosition(xOff, yOff, true);
624 x += xOff;
625 y += yOff;
626 return;
629 RenderLayer* parentLayer;
630 if (m_object->style()->position() == PABSOLUTE)
631 parentLayer = enclosingPositionedAncestor();
632 else
633 parentLayer = parent();
635 if (!parentLayer) return;
637 parentLayer->convertToLayerCoords(ancestorLayer, x, y);
639 x += xPos();
640 y += yPos();
643 void RenderLayer::scrollOffset(int& x, int& y)
645 x += scrollXOffset();
646 y += scrollYOffset();
649 void RenderLayer::subtractScrollOffset(int& x, int& y)
651 x -= scrollXOffset();
652 y -= scrollYOffset();
655 void RenderLayer::checkInlineRelOffset(const RenderObject* o, int& x, int& y)
657 if(o->style()->position() != PABSOLUTE || !renderer()->isRelPositioned() || !renderer()->isInlineFlow())
658 return;
660 // Our renderer is an enclosing relpositioned inline, we need to add in the offset of the first line
661 // box from the rest of the content, but only in the cases where we know our descendant is positioned
662 // relative to the inline itself.
663 assert( o->container() == m_object );
665 RenderFlow* flow = static_cast<RenderFlow*>(m_object);
666 int sx = 0, sy = 0;
667 if (flow->firstLineBox()) {
668 if (flow->style()->direction() == LTR)
669 sx = flow->firstLineBox()->xPos();
670 else
671 sx = flow->lastLineBox()->xPos();
672 sy = flow->firstLineBox()->yPos();
673 } else {
674 sx = flow->staticX(); // ###
675 sy = flow->staticY();
677 bool isInlineType = o->style()->isOriginalDisplayInlineType();
679 if (!o->hasStaticX())
680 x += sx;
682 // Despite the positioned child being a block display type inside an inline, we still keep
683 // its x locked to our left. Arguably the correct behavior would be to go flush left to
684 // the block that contains us, but that isn't what other browsers do.
685 if (o->hasStaticX() && !isInlineType)
686 // Avoid adding in the left border/padding of the containing block twice. Subtract it out.
687 x += sx - (o->containingBlock()->borderLeft() + o->containingBlock()->paddingLeft());
689 if (!o->hasStaticY())
690 y += sy;
693 void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint)
695 if (renderer()->style()->overflowX() != OMARQUEE || !renderer()->hasOverflowClip()) {
696 if (x < 0) x = 0;
697 if (y < 0) y = 0;
699 // Call the scrollWidth/Height functions so that the dimensions will be computed if they need
700 // to be (for overflow:hidden blocks).
701 // ### merge the scrollWidth()/scrollHeight() methods
702 int maxX = m_scrollWidth - m_object->clientWidth();
703 int maxY = m_scrollHeight - m_object->clientHeight();
705 if (x > maxX) x = maxX;
706 if (y > maxY) y = maxY;
709 // FIXME: Eventually, we will want to perform a blit. For now never
710 // blit, since the check for blitting is going to be very
711 // complicated (since it will involve testing whether our layer
712 // is either occluded by another layer or clipped by an enclosing
713 // layer or contains fixed backgrounds, etc.).
714 m_scrollX = x;
715 m_scrollY = y;
717 // Update the positions of our child layers.
718 RenderLayer* rootLayer = root();
719 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
720 child->updateLayerPositions(rootLayer);
722 // Just schedule a full repaint of our object.
723 if (repaint)
724 m_object->repaint(RealtimePriority);
726 if (updateScrollbars) {
727 if (m_hBar)
728 m_hBar->setValue(m_scrollX);
729 if (m_vBar)
730 m_vBar->setValue(m_scrollY);
733 // Fire the scroll DOM event. Do this the very last thing, since the handler may kill us.
734 m_object->element()->dispatchHTMLEvent(EventImpl::SCROLL_EVENT, false, false);
737 void RenderLayer::updateScrollPositionFromScrollbars()
739 bool needUpdate = false;
740 int newX = m_scrollX;
741 int newY = m_scrollY;
743 if (m_hBar) {
744 newX = m_hBar->value();
745 if (newX != m_scrollX)
746 needUpdate = true;
749 if (m_vBar) {
750 newY = m_vBar->value();
751 if (newY != m_scrollY)
752 needUpdate = true;
755 if (needUpdate)
756 scrollToOffset(newX, newY, false);
759 void
760 RenderLayer::showScrollbar(Qt::Orientation o, bool show)
762 ScrollBarWidget *sb = (o == Qt::Horizontal) ? m_hBar : m_vBar;
764 if (show && !sb) {
765 KHTMLView* view = m_object->document()->view();
766 sb = new ScrollBarWidget(o, view->widget());
767 sb->move(0, -50000);
768 sb->setAttribute(Qt::WA_NoSystemBackground);
769 sb->show();
770 if (!m_scrollMediator)
771 m_scrollMediator = new RenderScrollMediator(this);
772 m_scrollMediator->connect(sb, SIGNAL(valueChanged(int)), SLOT(slotValueChanged()));
774 else if (!show && sb) {
775 delete sb;
776 sb = 0;
779 if (o == Qt::Horizontal)
780 m_hBar = sb;
781 else
782 m_vBar = sb;
785 int RenderLayer::verticalScrollbarWidth()
787 if (!m_vBar)
788 return 0;
790 #ifdef APPLE_CHANGES
791 return m_vBar->width();
792 #else
793 return m_vBar->style()->pixelMetric(QStyle::PM_ScrollBarExtent);
794 #endif
798 int RenderLayer::horizontalScrollbarHeight()
800 if (!m_hBar)
801 return 0;
803 #ifdef APPLE_CHANGES
804 return m_hBar->height();
805 #else
806 return m_hBar->style()->pixelMetric(QStyle::PM_ScrollBarExtent);
807 #endif
811 void RenderLayer::positionScrollbars(const QRect& absBounds)
813 #ifdef APPLE_CHANGES
814 if (m_vBar) {
815 view->addChild(m_vBar, absBounds.x()+absBounds.width()-m_object->borderRight()-m_vBar->width(),
816 absBounds.y()+m_object->borderTop());
817 m_vBar->resize(m_vBar->width(), absBounds.height() -
818 (m_object->borderTop()+m_object->borderBottom()) -
819 (m_hBar ? m_hBar->height()-1 : 0));
822 if (m_hBar) {
823 view->addChild(m_hBar, absBounds.x()+m_object->borderLeft(),
824 absBounds.y()+absBounds.height()-m_object->borderBottom()-m_hBar->height());
825 m_hBar->resize(absBounds.width() - (m_object->borderLeft()+m_object->borderRight()) -
826 (m_vBar ? m_vBar->width()-1 : 0), m_hBar->height());
828 #else
829 int tx = absBounds.x();
830 int ty = absBounds.y();
831 int bl = m_object->borderLeft();
832 int bt = m_object->borderTop();
833 int w = width() - bl - m_object->borderRight();
834 int h = height() - bt - m_object->borderBottom();
836 if (w <= 0 || h <= 0 || (!m_vBar && !m_hBar))
837 return;
839 tx += bl;
840 ty += bt;
842 ScrollBarWidget *b = m_hBar;
843 if (!m_hBar)
844 b = m_vBar;
845 int sw = b->style()->pixelMetric(QStyle::PM_ScrollBarExtent);
846 bool rtl = b->layoutDirection() == Qt::RightToLeft;
848 if (m_vBar) {
849 QRect vBarRect = QRect(tx + (rtl ? 0 : w-sw), ty, sw, h - (m_hBar ? sw : 0));
850 m_vBar->resize(vBarRect.width(), vBarRect.height());
851 m_vBar->m_kwp->setPos(QPoint(vBarRect.x(), vBarRect.y()));
854 if (m_hBar) {
855 QRect hBarRect = QRect(tx + (rtl && m_vBar ? sw : 0), ty + h - sw, w - (!rtl && m_vBar ? sw : 0), sw);
856 m_hBar->resize(hBarRect.width(), hBarRect.height());
857 m_hBar->m_kwp->setPos(QPoint(hBarRect.x(), hBarRect.y()));
859 #endif
862 #define LINE_STEP 10
863 #define PAGE_KEEP 40
865 void RenderLayer::checkScrollbarsAfterLayout()
867 int rightPos = m_object->rightmostPosition(true);
868 int bottomPos = m_object->lowestPosition(true);
870 /* TODO
871 m_scrollLeft = m_object->leftmostPosition(true);
872 m_scrollTop = m_object->highestPosition(true);
875 int clientWidth = m_object->clientWidth();
876 int clientHeight = m_object->clientHeight();
877 m_scrollWidth = clientWidth;
878 m_scrollHeight = clientHeight;
880 if (rightPos - m_object->borderLeft() > m_scrollWidth)
881 m_scrollWidth = rightPos - m_object->borderLeft();
882 if (bottomPos - m_object->borderTop() > m_scrollHeight)
883 m_scrollHeight = bottomPos - m_object->borderTop();
885 bool needHorizontalBar = rightPos > width();
886 bool needVerticalBar = bottomPos > height();
888 bool haveHorizontalBar = m_hBar && m_hBar->isEnabled();
889 bool haveVerticalBar = m_vBar && m_vBar->isEnabled();
891 bool hasOvf = m_object->hasOverflowClip();
893 // overflow:scroll should just enable/disable.
894 if (hasOvf && m_object->style()->overflowX() == OSCROLL)
895 m_hBar->setEnabled(needHorizontalBar);
896 if (hasOvf && m_object->style()->overflowY() == OSCROLL)
897 m_vBar->setEnabled(needVerticalBar);
899 // overflow:auto may need to lay out again if scrollbars got added/removed.
900 bool scrollbarsChanged = (hasOvf && m_object->style()->overflowX() == OAUTO && haveHorizontalBar != needHorizontalBar)
901 || (hasOvf && m_object->style()->overflowY() == OAUTO && haveVerticalBar != needVerticalBar);
902 if (scrollbarsChanged) {
903 if (m_object->style()->overflowX() == OAUTO) {
904 showScrollbar(Qt::Horizontal, needHorizontalBar);
905 if (m_hBar)
906 m_hBar->setEnabled(true);
908 if (m_object->style()->overflowY() == OAUTO) {
909 showScrollbar(Qt::Vertical, needVerticalBar);
910 if (m_vBar)
911 m_vBar->setEnabled(true);
914 m_object->setNeedsLayout(true);
915 if (m_object->isRenderBlock())
916 static_cast<RenderBlock*>(m_object)->layoutBlock(true);
917 else
918 m_object->layout();
919 return;
922 // Set up the range (and page step/line step).
923 if (m_hBar) {
924 int pageStep = (clientWidth-PAGE_KEEP);
925 if (pageStep < 0) pageStep = clientWidth;
926 m_hBar->setSingleStep(LINE_STEP);
927 m_hBar->setPageStep(pageStep);
928 #ifdef APPLE_CHANGES
929 m_hBar->setKnobProportion(clientWidth, m_scrollWidth);
930 #else
931 m_hBar->setRange(0, needHorizontalBar ? m_scrollWidth-clientWidth : 0);
932 #endif
934 if (m_vBar) {
935 int pageStep = (clientHeight-PAGE_KEEP);
936 if (pageStep < 0) pageStep = clientHeight;
937 m_vBar->setSingleStep(LINE_STEP);
938 m_vBar->setPageStep(pageStep);
939 #ifdef APPLE_CHANGES
940 m_vBar->setKnobProportion(clientHeight, m_scrollHeight);
941 #else
942 m_vBar->setRange(0, needVerticalBar ? m_scrollHeight-clientHeight : 0);
943 #endif
947 void RenderLayer::paintScrollbars(RenderObject::PaintInfo& pI)
949 if (!m_object->element())
950 return;
952 if (m_hBar) {
953 if (!m_buffer[0] || m_buffer[0]->size() != m_hBar->size()) {
954 delete m_buffer[0];
955 m_buffer[0] = new QPixmap( m_hBar->size() );
957 QPoint p = m_hBar->m_kwp->absolutePos();
958 RenderWidget::paintWidget(pI, m_hBar, p.x(), p.y(), m_buffer );
960 if (m_vBar) {
961 if (!m_buffer[1] || m_buffer[1]->size() != m_vBar->size()) {
962 delete m_buffer[1];
963 m_buffer[1] = new QPixmap( m_vBar->size() );
965 QPixmap* tmp[1];
966 tmp[0] = m_buffer[1];
967 QPoint p = m_vBar->m_kwp->absolutePos();
968 RenderWidget::paintWidget(pI, m_vBar, p.x(), p.y(), tmp);
972 void RenderLayer::paint(QPainter *p, const QRect& damageRect, bool selectionOnly)
974 paintLayer(this, p, damageRect, selectionOnly);
977 void RenderLayer::setClip(QPainter* p, const QRect& paintDirtyRect, const QRect& clipRect, bool /*setup*/)
979 if (paintDirtyRect == clipRect)
980 return;
981 KHTMLView* v = m_object->canvas()->view();
982 QRegion r = clipRect;
983 if (p->hasClipping()) {
984 if (!v->clipHolder())
985 v->setClipHolder(new QStack<QRegion>);
986 v->clipHolder()->push( p->clipRegion() );
987 r &= v->clipHolder()->top();
989 p->setClipRegion( r );
992 void RenderLayer::restoreClip(QPainter* p, const QRect& paintDirtyRect, const QRect& clipRect, bool /*cleanup*/)
994 if (paintDirtyRect == clipRect)
995 return;
996 KHTMLView* v = m_object->document()->view();
997 if (v->clipHolder() && !v->clipHolder()->isEmpty())
998 p->setClipRegion( v->clipHolder()->pop() );
999 else
1000 p->setClipRegion( QRegion(), Qt::NoClip );
1003 void RenderLayer::paintLayer(RenderLayer* rootLayer, QPainter *p,
1004 const QRect& paintDirtyRect, bool selectionOnly)
1006 assert( rootLayer != this || !m_object->canvas()->view()->clipHolder() );
1008 if (!m_object->style()->opacity())
1009 return;
1011 // Calculate the clip rects we should use.
1012 QRect layerBounds, damageRect, clipRectToApply;
1013 calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply);
1014 int x = layerBounds.x();
1015 int y = layerBounds.y();
1017 // Ensure our lists are up-to-date.
1018 updateZOrderLists();
1019 updateOverflowList();
1021 // Set our transparency if we need to.
1022 khtml::BufferedPainter *bPainter = 0;
1023 if (isTransparent()) {
1024 //### cache paintedRegion
1025 QRegion rr = paintedRegion( rootLayer ) & damageRect;
1026 if (p->hasClipping())
1027 rr &= p->clipRegion();
1028 bPainter = khtml::BufferedPainter::start(p, rr);
1030 // We want to paint our layer, but only if we intersect the damage rect.
1031 bool shouldPaint = intersectsDamageRect(layerBounds, damageRect) && m_hasVisibleContent;
1032 if (shouldPaint && !selectionOnly) {
1033 // Paint our background first, before painting any child layers.
1034 if (!damageRect.isEmpty()) {
1035 // Establish the clip used to paint our background.
1036 setClip(p, paintDirtyRect, damageRect);
1038 // Paint the background.
1039 RenderObject::PaintInfo paintInfo(p, damageRect, PaintActionElementBackground);
1040 renderer()->paint(paintInfo,
1041 x - renderer()->xPos(), y - renderer()->yPos() + renderer()->borderTopExtra());
1043 // Position our scrollbars.
1044 positionScrollbars(layerBounds);
1046 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
1047 // z-index. We paint after we painted the background/border, so that the scrollbars will
1048 // sit above the background/border.
1049 paintScrollbars(paintInfo);
1051 // Restore the clip.
1052 restoreClip(p, paintDirtyRect, damageRect);
1056 // Now walk the sorted list of children with negative z-indices.
1057 if (m_negZOrderList) {
1058 for (int i = 0; i < m_negZOrderList->count() ; i++) {
1059 RenderLayer* child = m_negZOrderList->at(i);
1060 child->paintLayer(rootLayer, p, paintDirtyRect, selectionOnly);
1064 // Now establish the appropriate clip and paint our child RenderObjects.
1065 if (shouldPaint && !clipRectToApply.isEmpty()) {
1066 // Set up the clip used when painting our children.
1067 setClip(p, paintDirtyRect, clipRectToApply);
1069 RenderObject::PaintInfo paintInfo(p, clipRectToApply, PaintActionSelection);
1071 int tx = x - renderer()->xPos();
1072 int ty = y - renderer()->yPos() + renderer()->borderTopExtra();
1074 if (selectionOnly)
1075 renderer()->paint(paintInfo, tx, ty);
1076 else {
1077 paintInfo.phase = PaintActionChildBackgrounds;
1078 renderer()->paint(paintInfo, tx, ty);
1079 paintInfo.phase = PaintActionFloat;
1080 renderer()->paint(paintInfo, tx, ty);
1081 paintInfo.phase = PaintActionForeground;
1082 renderer()->paint(paintInfo, tx, ty);
1083 RenderCanvas *rc = static_cast<RenderCanvas*>(renderer()->document()->renderer());
1084 if (rc->maximalOutlineSize()) {
1085 paintInfo.phase = PaintActionOutline;
1086 renderer()->paint(paintInfo, tx, ty);
1088 if (renderer()->canvas()->hasSelection()) {
1089 paintInfo.phase = PaintActionSelection;
1090 renderer()->paint(paintInfo, tx, ty);
1094 // Now restore our clip.
1095 restoreClip(p, paintDirtyRect, clipRectToApply);
1098 // Paint any child layers that have overflow.
1099 if (m_overflowList)
1100 foreach (RenderLayer* layer, *m_overflowList)
1101 layer->paintLayer(rootLayer, p, paintDirtyRect, selectionOnly);
1103 // Now walk the sorted list of children with positive z-indices.
1104 if (m_posZOrderList) {
1105 for (int i = 0; i < m_posZOrderList->count() ; i++) {
1106 RenderLayer* child = m_posZOrderList->at(i);
1107 child->paintLayer(rootLayer, p, paintDirtyRect, selectionOnly);
1111 #ifdef BOX_DEBUG
1113 int ax=0;
1114 int ay=0;
1115 renderer()->absolutePosition( ax, ay );
1116 p->setPen(QPen(QColor("yellow"), 1, Qt::DotLine));
1117 p->setBrush( Qt::NoBrush );
1118 p->drawRect(ax, ay, width(), height());
1120 #endif
1122 // End our transparency layer
1123 if (bPainter) {
1124 khtml::BufferedPainter::end( p, bPainter , m_object->style()->opacity() );
1127 if (rootLayer == this && m_object->canvas()->view()->clipHolder()) {
1128 KHTMLView* const v = m_object->canvas()->view();
1129 assert(v->clipHolder()->isEmpty());
1130 delete v->clipHolder();
1131 v->setClipHolder(0);
1135 bool RenderLayer::nodeAtPoint(RenderObject::NodeInfo& info, int x, int y)
1137 // Clear our our scrollbar variable
1138 RenderLayer::gScrollBar = 0;
1140 int stx = m_x;
1141 int sty = m_y;
1143 if (renderer()->isCanvas()) {
1144 static_cast<RenderCanvas*>(renderer())->view()->revertTransforms(stx, sty);
1147 QRect damageRect(stx,sty, width(), height());
1148 RenderLayer* insideLayer = nodeAtPointForLayer(this, info, x, y, damageRect);
1150 // Now determine if the result is inside an anchor.
1151 DOM::NodeImpl* node = info.innerNode();
1152 while (node) {
1153 if (node->hasAnchor() && !info.URLElement())
1154 info.setURLElement(node);
1155 node = node->parentNode();
1158 // Next set up the correct :hover/:active state along the new chain.
1159 updateHoverActiveState(info);
1161 // Now return whether we were inside this layer (this will always be true for the root
1162 // layer).
1163 return insideLayer;
1166 RenderLayer* RenderLayer::nodeAtPointForLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info,
1167 int xMousePos, int yMousePos, const QRect& hitTestRect)
1169 // Calculate the clip rects we should use.
1170 QRect layerBounds, bgRect, fgRect;
1171 calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect);
1173 // Ensure our lists are up-to-date.
1174 updateZOrderLists();
1175 updateOverflowList();
1177 // This variable tracks which layer the mouse ends up being inside. The minute we find an insideLayer,
1178 // we are done and can return it.
1179 RenderLayer* insideLayer = 0;
1181 // Begin by walking our list of positive layers from highest z-index down to the lowest
1182 // z-index.
1183 if (m_posZOrderList) {
1184 uint count = m_posZOrderList->count();
1185 for (int i = count-1; i >= 0; i--) {
1186 RenderLayer* child = m_posZOrderList->at(i);
1187 insideLayer = child->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
1188 if (insideLayer)
1189 return insideLayer;
1193 // Now check our overflow objects.
1194 if (m_overflowList) {
1195 QVector<RenderLayer*>::iterator it = m_overflowList->end();
1196 while (it != m_overflowList->begin()) {
1197 --it;
1198 insideLayer = (*it)->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
1199 if (insideLayer)
1200 return insideLayer;
1204 // Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
1205 if (containsPoint(xMousePos, yMousePos, fgRect) &&
1206 renderer()->nodeAtPoint(info, xMousePos, yMousePos,
1207 layerBounds.x() - renderer()->xPos(),
1208 layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(),
1209 HitTestChildrenOnly)) {
1210 if (info.innerNode() != m_object->element())
1211 return this;
1214 // Now check our negative z-index children.
1215 if (m_negZOrderList) {
1216 uint count = m_negZOrderList->count();
1217 for (int i = count-1; i >= 0; i--) {
1218 RenderLayer* child = m_negZOrderList->at(i);
1219 insideLayer = child->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
1220 if (insideLayer)
1221 return insideLayer;
1225 // Next we want to see if the mouse pos is inside this layer but not any of its children.
1226 if (containsPoint(xMousePos, yMousePos, bgRect) &&
1227 renderer()->nodeAtPoint(info, xMousePos, yMousePos,
1228 layerBounds.x() - renderer()->xPos(),
1229 layerBounds.y() - renderer()->yPos() + m_object->borderTopExtra(),
1230 HitTestSelfOnly))
1231 return this;
1233 // No luck.
1234 return 0;
1237 void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, QRect& overflowClipRect,
1238 QRect& posClipRect, QRect& fixedClipRect)
1240 if (parent())
1241 parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
1243 switch (m_object->style()->position()) {
1244 // A fixed object is essentially the root of its containing block hierarchy, so when
1245 // we encounter such an object, we reset our clip rects to the fixedClipRect.
1246 case PFIXED:
1247 posClipRect = fixedClipRect;
1248 overflowClipRect = fixedClipRect;
1249 break;
1250 case PABSOLUTE:
1251 overflowClipRect = posClipRect;
1252 break;
1253 case PRELATIVE:
1254 posClipRect = overflowClipRect;
1255 break;
1256 default:
1257 break;
1260 // Update the clip rects that will be passed to child layers.
1261 if (m_object->hasOverflowClip() || m_object->hasClip()) {
1262 // This layer establishes a clip of some kind.
1263 int x = 0;
1264 int y = 0;
1265 convertToLayerCoords(rootLayer, x, y);
1267 if (m_object->hasOverflowClip()) {
1268 QRect newOverflowClip = m_object->overflowClipRect(x,y);
1269 overflowClipRect = newOverflowClip.intersect(overflowClipRect);
1270 if (m_object->isPositioned() || m_object->isRelPositioned())
1271 posClipRect = newOverflowClip.intersect(posClipRect);
1273 if (m_object->hasClip()) {
1274 QRect newPosClip = m_object->clipRect(x,y);
1275 posClipRect = posClipRect.intersect(newPosClip);
1276 overflowClipRect = overflowClipRect.intersect(newPosClip);
1277 fixedClipRect = fixedClipRect.intersect(newPosClip);
1282 void RenderLayer::calculateRects(const RenderLayer* rootLayer, const QRect& paintDirtyRect, QRect& layerBounds,
1283 QRect& backgroundRect, QRect& foregroundRect)
1285 QRect overflowClipRect = paintDirtyRect;
1286 QRect posClipRect = paintDirtyRect;
1287 QRect fixedClipRect = paintDirtyRect;
1288 if (parent())
1289 parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
1291 int x = 0;
1292 int y = 0;
1293 convertToLayerCoords(rootLayer, x, y);
1294 layerBounds = QRect(x,y,width(),height());
1296 backgroundRect = m_object->style()->position() == PFIXED ? fixedClipRect :
1297 (m_object->isPositioned() ? posClipRect : overflowClipRect);
1298 foregroundRect = backgroundRect;
1300 // Update the clip rects that will be passed to child layers.
1301 if (m_object->hasOverflowClip() || m_object->hasClip()) {
1302 // This layer establishes a clip of some kind.
1303 if (m_object->hasOverflowClip())
1304 foregroundRect = foregroundRect.intersect(m_object->overflowClipRect(x,y));
1306 if (m_object->hasClip()) {
1307 // Clip applies to *us* as well, so go ahead and update the damageRect.
1308 QRect newPosClip = m_object->clipRect(x,y);
1309 backgroundRect = backgroundRect.intersect(newPosClip);
1310 foregroundRect = foregroundRect.intersect(newPosClip);
1313 // If we establish a clip at all, then go ahead and make sure our background
1314 // rect is intersected with our layer's bounds.
1315 backgroundRect = backgroundRect.intersect(layerBounds);
1319 bool RenderLayer::intersectsDamageRect(const QRect& layerBounds, const QRect& damageRect) const
1321 return (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isBody() ||
1322 (renderer()->hasOverhangingFloats() && !renderer()->hasOverflowClip()) ||
1323 (renderer()->isInline() && !renderer()->isReplaced()) ||
1324 layerBounds.intersects(damageRect));
1327 bool RenderLayer::containsPoint(int x, int y, const QRect& damageRect) const
1329 return (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isInlineFlow() ||
1330 damageRect.contains(x, y));
1333 // This code has been written to anticipate the addition of CSS3-::outside and ::inside generated
1334 // content (and perhaps XBL). That's why it uses the render tree and not the DOM tree.
1335 static RenderObject* hoverAncestor(RenderObject* obj)
1337 return (!obj->isInline() && obj->continuation()) ? obj->continuation() : obj->parent();
1340 static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2)
1342 if (!obj1 || !obj2)
1343 return 0;
1345 for (RenderObject* currObj1 = obj1; currObj1; currObj1 = hoverAncestor(currObj1))
1346 for (RenderObject* currObj2 = obj2; currObj2; currObj2 = hoverAncestor(currObj2))
1347 if (currObj1 == currObj2)
1348 return currObj1;
1350 return 0;
1354 void RenderLayer::updateHoverActiveState(RenderObject::NodeInfo& info)
1356 // We don't update :hover/:active state when the info is marked as readonly.
1357 if (info.readonly())
1358 return;
1360 DOM::NodeImpl *e = m_object->element();
1361 DOM::DocumentImpl *doc = e ? e->document() : 0;
1362 if (!doc) return;
1364 // Check to see if the hovered node has changed. If not, then we don't need to
1365 // do anything.
1366 DOM::NodeImpl* oldHoverNode = doc->hoverNode();
1367 DOM::NodeImpl* newHoverNode = info.innerNode();
1369 if (oldHoverNode == newHoverNode && (!oldHoverNode || oldHoverNode->active() == info.active()))
1370 return;
1372 // Update our current hover node.
1373 doc->setHoverNode(newHoverNode);
1374 if (info.active())
1375 doc->setActiveNode(newHoverNode);
1376 else
1377 doc->setActiveNode(0);
1379 // We have two different objects. Fetch their renderers.
1380 RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
1381 RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0;
1383 // Locate the common ancestor render object for the two renderers.
1384 RenderObject* ancestor = commonAncestor(oldHoverObj, newHoverObj);
1386 // The old hover path only needs to be cleared up to (and not including) the common ancestor;
1387 for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = hoverAncestor(curr)) {
1388 curr->setMouseInside(false);
1389 if (curr->element()) {
1390 curr->element()->setActive(false);
1391 curr->element()->setHovered(false);
1395 // Now set the hover state for our new object up to the root.
1396 for (RenderObject* curr = newHoverObj; curr; curr = hoverAncestor(curr)) {
1397 curr->setMouseInside(true);
1398 if (curr->element()) {
1399 curr->element()->setActive(info.active());
1400 curr->element()->setHovered(true);
1405 // Sort the buffer from lowest z-index to highest. The common scenario will have
1406 // most z-indices equal, so we optimize for that case (i.e., the list will be mostly
1407 // sorted already).
1408 static void sortByZOrder(QVector<RenderLayer*>* buffer,
1409 QVector<RenderLayer*>* mergeBuffer,
1410 uint start, uint end)
1412 if (start >= end)
1413 return; // Sanity check.
1415 if (end - start <= 6) {
1416 // Apply a bubble sort for smaller lists.
1417 for (uint i = end-1; i > start; i--) {
1418 bool sorted = true;
1419 for (uint j = start; j < i; j++) {
1420 RenderLayer* elt = buffer->at(j);
1421 RenderLayer* elt2 = buffer->at(j+1);
1422 if (elt->zIndex() > elt2->zIndex()) {
1423 sorted = false;
1424 buffer->replace(j, elt2);
1425 buffer->replace(j+1, elt);
1428 if (sorted)
1429 return;
1432 else {
1433 // Peform a merge sort for larger lists.
1434 uint mid = (start+end)/2;
1435 sortByZOrder(buffer, mergeBuffer, start, mid);
1436 sortByZOrder(buffer, mergeBuffer, mid, end);
1438 RenderLayer* elt = buffer->at(mid-1);
1439 RenderLayer* elt2 = buffer->at(mid);
1441 // Handle the fast common case (of equal z-indices). The list may already
1442 // be completely sorted.
1443 if (elt->zIndex() <= elt2->zIndex())
1444 return;
1446 // We have to merge sort.
1447 uint i1 = start;
1448 uint i2 = mid;
1450 elt = buffer->at(i1);
1451 elt2 = buffer->at(i2);
1453 while (i1 < mid || i2 < end) {
1454 if (i1 < mid && (i2 == end || elt->zIndex() <= elt2->zIndex())) {
1455 mergeBuffer->append(elt);
1456 i1++;
1457 if (i1 < mid)
1458 elt = buffer->at(i1);
1460 else {
1461 mergeBuffer->append(elt2);
1462 i2++;
1463 if (i2 < end)
1464 elt2 = buffer->at(i2);
1468 for (uint i = start; i < end; i++)
1469 buffer->replace(i, mergeBuffer->at(i-start));
1471 mergeBuffer->clear();
1475 void RenderLayer::dirtyZOrderLists()
1477 if (m_posZOrderList)
1478 m_posZOrderList->clear();
1479 if (m_negZOrderList)
1480 m_negZOrderList->clear();
1481 m_zOrderListsDirty = true;
1484 void RenderLayer::dirtyOverflowList()
1486 if (m_overflowList)
1487 m_overflowList->clear();
1488 m_overflowListDirty = true;
1491 void RenderLayer::updateZOrderLists()
1493 if (!isStackingContext() || !m_zOrderListsDirty)
1494 return;
1496 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
1497 child->collectLayers(m_posZOrderList, m_negZOrderList);
1499 // Sort the two lists.
1500 if (m_posZOrderList) {
1501 QVector<RenderLayer*> mergeBuffer;
1502 sortByZOrder(m_posZOrderList, &mergeBuffer, 0, m_posZOrderList->count());
1504 if (m_negZOrderList) {
1505 QVector<RenderLayer*> mergeBuffer;
1506 sortByZOrder(m_negZOrderList, &mergeBuffer, 0, m_negZOrderList->count());
1509 m_zOrderListsDirty = false;
1512 void RenderLayer::updateOverflowList()
1514 if (!m_overflowListDirty)
1515 return;
1517 for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
1518 if (child->isOverflowOnly()) {
1519 if (!m_overflowList)
1520 m_overflowList = new QVector<RenderLayer*>;
1521 m_overflowList->append(child);
1525 m_overflowListDirty = false;
1528 void RenderLayer::collectLayers(QVector<RenderLayer*>*& posBuffer, QVector<RenderLayer*>*& negBuffer)
1530 updateVisibilityStatus();
1532 // Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists.
1533 if ((m_hasVisibleContent || (m_hasVisibleDescendant && isStackingContext())) && !isOverflowOnly()) {
1534 // Determine which buffer the child should be in.
1535 QVector<RenderLayer*>*& buffer = (zIndex() >= 0) ? posBuffer : negBuffer;
1537 // Create the buffer if it doesn't exist yet.
1538 if (!buffer)
1539 buffer = new QVector<RenderLayer*>();
1541 // Append ourselves at the end of the appropriate buffer.
1542 buffer->append(this);
1545 // Recur into our children to collect more layers, but only if we don't establish
1546 // a stacking context.
1547 if (m_hasVisibleDescendant && !isStackingContext()) {
1548 for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
1549 child->collectLayers(posBuffer, negBuffer);
1553 #ifdef ENABLE_DUMP
1554 #ifndef KDE_USE_FINAL
1555 static QTextStream &operator<<(QTextStream &ts, const QRect &r)
1557 return ts << "at (" << r.x() << "," << r.y() << ") size " << r.width() << "x" << r.height();
1559 #endif
1561 static void write(QTextStream &ts, RenderObject& o, const QString& indent )
1563 o.dump(ts, indent);
1565 for (RenderObject *child = o.firstChild(); child; child = child->nextSibling()) {
1566 if (child->layer()) continue;
1567 write( ts, *child, indent + " " );
1571 static void write(QTextStream &ts, const RenderLayer &l,
1572 const QRect& layerBounds, const QRect& backgroundClipRect, const QRect& clipRect,
1573 int layerType = 0, const QString& indent = QString())
1576 ts << indent << "layer";
1578 ts << " at (" << l.xPos() << "," << l.yPos() << ") size " << l.width() << "x" << l.height();
1580 if (layerBounds != layerBounds.intersect(backgroundClipRect)) {
1581 ts << " backgroundClip " << backgroundClipRect;
1583 if (layerBounds != layerBounds.intersect(clipRect)) {
1584 ts << " clip " << clipRect;
1587 if (layerType == -1)
1588 ts << " layerType: background only";
1589 else if (layerType == 1)
1590 ts << " layerType: foreground only";
1592 ts << "\n";
1594 if (layerType != -1)
1595 write( ts, *l.renderer(), indent + " " );
1597 ts << "\n";
1600 static void writeLayers(QTextStream &ts, const RenderLayer* rootLayer, RenderLayer* l,
1601 const QRect& paintDirtyRect, const QString& indent)
1603 // Calculate the clip rects we should use.
1604 QRect layerBounds, damageRect, clipRectToApply;
1605 l->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply);
1607 // Ensure our lists are up-to-date.
1608 l->updateZOrderLists();
1609 l->updateOverflowList();
1611 bool shouldPaint = l->intersectsDamageRect(layerBounds, damageRect);
1612 QVector<RenderLayer*>* negList = l->negZOrderList();
1613 QVector<RenderLayer*>* ovfList = l->overflowList();
1614 if (shouldPaint && negList && negList->count() > 0)
1615 write(ts, *l, layerBounds, damageRect, clipRectToApply, -1, indent);
1617 if (negList) {
1618 for (int i = 0; i != negList->count(); ++i)
1619 writeLayers(ts, rootLayer, negList->at(i), paintDirtyRect, indent );
1622 if (shouldPaint)
1623 write(ts, *l, layerBounds, damageRect, clipRectToApply, negList && negList->count() > 0, indent);
1625 if (ovfList) {
1626 for (QVector<RenderLayer*>::iterator it = ovfList->begin(); it != ovfList->end(); ++it)
1627 writeLayers(ts, rootLayer, *it, paintDirtyRect, indent);
1630 QVector<RenderLayer*>* posList = l->posZOrderList();
1631 if (posList) {
1632 for (int i = 0; i != posList->count(); ++i)
1633 writeLayers(ts, rootLayer, posList->at(i), paintDirtyRect, indent);
1638 void RenderLayer::dump(QTextStream &ts, const QString &ind)
1640 assert( renderer()->isCanvas() );
1642 writeLayers(ts, this, this, QRect(xPos(), yPos(), width(), height()), ind);
1646 #endif
1648 bool RenderLayer::shouldBeOverflowOnly() const
1650 return renderer()->style() && renderer()->hasOverflowClip() &&
1651 !renderer()->isPositioned() && !renderer()->isRelPositioned() && !isTransparent();
1654 void RenderLayer::styleChanged()
1656 bool isOverflowOnly = shouldBeOverflowOnly();
1657 if (isOverflowOnly != m_isOverflowOnly) {
1658 m_isOverflowOnly = isOverflowOnly;
1659 RenderLayer* p = parent();
1660 RenderLayer* sc = stackingContext();
1661 if (p)
1662 p->dirtyOverflowList();
1663 if (sc)
1664 sc->dirtyZOrderLists();
1667 if (m_object->hasOverflowClip() &&
1668 m_object->style()->overflowX() == OMARQUEE && m_object->style()->marqueeBehavior() != MNONE) {
1669 if (!m_marquee)
1670 m_marquee = new Marquee(this);
1671 m_marquee->updateMarqueeStyle();
1673 else if (m_marquee) {
1674 delete m_marquee;
1675 m_marquee = 0;
1679 void RenderLayer::suspendMarquees()
1681 if (m_marquee)
1682 m_marquee->suspend();
1684 for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling())
1685 curr->suspendMarquees();
1688 // --------------------------------------------------------------------------
1689 // Marquee implementation
1691 Marquee::Marquee(RenderLayer* l)
1692 :m_layer(l), m_currentLoop(0), m_totalLoops(0), m_timerId(0), m_start(0), m_end(0), m_speed(0), m_unfurlPos(0), m_reset(false),
1693 m_suspended(false), m_stopped(false), m_whiteSpace(NORMAL), m_direction(MAUTO)
1697 int Marquee::marqueeSpeed() const
1699 int result = m_layer->renderer()->style()->marqueeSpeed();
1700 DOM::NodeImpl* elt = m_layer->renderer()->element();
1701 if (elt && elt->id() == ID_MARQUEE) {
1702 HTMLMarqueeElementImpl* marqueeElt = static_cast<HTMLMarqueeElementImpl*>(elt);
1703 result = qMax(result, marqueeElt->minimumDelay());
1705 return result;
1708 EMarqueeDirection Marquee::direction() const
1710 // FIXME: Support the CSS3 "auto" value for determining the direction of the marquee.
1711 // For now just map MAUTO to MBACKWARD
1712 EMarqueeDirection result = m_layer->renderer()->style()->marqueeDirection();
1713 EDirection dir = m_layer->renderer()->style()->direction();
1714 if (result == MAUTO)
1715 result = MBACKWARD;
1716 if (result == MFORWARD)
1717 result = (dir == LTR) ? MRIGHT : MLEFT;
1718 if (result == MBACKWARD)
1719 result = (dir == LTR) ? MLEFT : MRIGHT;
1721 // Now we have the real direction. Next we check to see if the increment is negative.
1722 // If so, then we reverse the direction.
1723 Length increment = m_layer->renderer()->style()->marqueeIncrement();
1724 if (increment.value() < 0)
1725 result = static_cast<EMarqueeDirection>(-result);
1727 return result;
1730 bool Marquee::isHorizontal() const
1732 return direction() == MLEFT || direction() == MRIGHT;
1735 bool Marquee::isUnfurlMarquee() const
1737 EMarqueeBehavior behavior = m_layer->renderer()->style()->marqueeBehavior();
1738 return (behavior == MUNFURL);
1741 int Marquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge)
1743 RenderObject* o = m_layer->renderer();
1744 RenderStyle* s = o->style();
1745 if (isHorizontal()) {
1746 bool ltr = s->direction() == LTR;
1747 int clientWidth = o->clientWidth();
1748 int contentWidth = ltr ? o->rightmostPosition(true, false) : o->leftmostPosition(true, false);
1749 if (ltr)
1750 contentWidth += (o->paddingRight() - o->borderLeft());
1751 else {
1752 contentWidth = o->width() - contentWidth;
1753 contentWidth += (o->paddingLeft() - o->borderRight());
1755 if (dir == MRIGHT) {
1756 if (stopAtContentEdge)
1757 return qMax(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth));
1758 else
1759 return ltr ? contentWidth : clientWidth;
1761 else {
1762 if (stopAtContentEdge)
1763 return qMin(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth));
1764 else
1765 return ltr ? -clientWidth : -contentWidth;
1768 else {
1769 int contentHeight = m_layer->renderer()->lowestPosition(true, false) -
1770 m_layer->renderer()->borderTop() + m_layer->renderer()->paddingBottom();
1771 int clientHeight = m_layer->renderer()->clientHeight();
1772 if (dir == MUP) {
1773 if (stopAtContentEdge)
1774 return qMin(contentHeight - clientHeight, 0);
1775 else
1776 return -clientHeight;
1778 else {
1779 if (stopAtContentEdge)
1780 return qMax(contentHeight - clientHeight, 0);
1781 else
1782 return contentHeight;
1787 void Marquee::start()
1789 if (m_timerId || m_layer->renderer()->style()->marqueeIncrement().value() == 0)
1790 return;
1792 if (!m_suspended && !m_stopped) {
1793 if (isUnfurlMarquee()) {
1794 bool forward = direction() == MDOWN || direction() == MRIGHT;
1795 bool isReversed = (forward && m_currentLoop % 2) || (!forward && !(m_currentLoop % 2));
1796 m_unfurlPos = isReversed ? m_end : m_start;
1797 m_layer->renderer()->setChildNeedsLayout(true);
1799 else {
1800 if (isHorizontal())
1801 m_layer->scrollToOffset(m_start, 0, false, false);
1802 else
1803 m_layer->scrollToOffset(0, m_start, false, false);
1806 else
1807 m_suspended = false;
1809 m_stopped = false;
1810 m_timerId = startTimer(speed());
1813 void Marquee::suspend()
1815 if (m_timerId) {
1816 killTimer(m_timerId);
1817 m_timerId = 0;
1820 m_suspended = true;
1823 void Marquee::stop()
1825 if (m_timerId) {
1826 killTimer(m_timerId);
1827 m_timerId = 0;
1830 m_stopped = true;
1833 void Marquee::updateMarqueePosition()
1835 bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops);
1836 if (activate) {
1837 if (isUnfurlMarquee()) {
1838 if (m_unfurlPos < m_start) {
1839 m_unfurlPos = m_start;
1840 m_layer->renderer()->setChildNeedsLayout(true);
1842 else if (m_unfurlPos > m_end) {
1843 m_unfurlPos = m_end;
1844 m_layer->renderer()->setChildNeedsLayout(true);
1847 else {
1848 EMarqueeBehavior behavior = m_layer->renderer()->style()->marqueeBehavior();
1849 m_start = computePosition(direction(), behavior == MALTERNATE);
1850 m_end = computePosition(reverseDirection(), behavior == MALTERNATE || behavior == MSLIDE);
1852 if (!m_stopped) start();
1856 void Marquee::updateMarqueeStyle()
1858 RenderStyle* s = m_layer->renderer()->style();
1860 if (m_direction != s->marqueeDirection() || (m_totalLoops != s->marqueeLoopCount() && m_currentLoop >= m_totalLoops))
1861 m_currentLoop = 0; // When direction changes or our loopCount is a smaller number than our current loop, reset our loop.
1863 m_totalLoops = s->marqueeLoopCount();
1864 m_direction = s->marqueeDirection();
1865 m_whiteSpace = s->whiteSpace();
1867 if (m_layer->renderer()->isHTMLMarquee()) {
1868 // Hack for WinIE. In WinIE, a value of 0 or lower for the loop count for SLIDE means to only do
1869 // one loop.
1870 if (m_totalLoops <= 0 && (s->marqueeBehavior() == MSLIDE || s->marqueeBehavior() == MUNFURL))
1871 m_totalLoops = 1;
1873 // Hack alert: Set the white-space value to nowrap for horizontal marquees with inline children, thus ensuring
1874 // all the text ends up on one line by default. Limit this hack to the <marquee> element to emulate
1875 // WinIE's behavior. Someone using CSS3 can use white-space: nowrap on their own to get this effect.
1876 // Second hack alert: Set the text-align back to auto. WinIE completely ignores text-align on the
1877 // marquee element.
1878 // FIXME: Bring these up with the CSS WG.
1879 if (isHorizontal() && m_layer->renderer()->childrenInline()) {
1880 s->setWhiteSpace(NOWRAP);
1881 s->setTextAlign(TAAUTO);
1885 if (speed() != marqueeSpeed()) {
1886 m_speed = marqueeSpeed();
1887 if (m_timerId) {
1888 killTimer(m_timerId);
1889 m_timerId = startTimer(speed());
1893 // Check the loop count to see if we should now stop.
1894 bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops);
1895 if (activate && !m_timerId)
1896 m_layer->renderer()->setNeedsLayout(true);
1897 else if (!activate && m_timerId) {
1898 // Destroy the timer.
1899 killTimer(m_timerId);
1900 m_timerId = 0;
1904 void Marquee::timerEvent(QTimerEvent* /*evt*/)
1906 if (m_layer->renderer()->needsLayout())
1907 return;
1909 if (m_reset) {
1910 m_reset = false;
1911 if (isHorizontal())
1912 m_layer->scrollToXOffset(m_start);
1913 else
1914 m_layer->scrollToYOffset(m_start);
1915 return;
1918 RenderStyle* s = m_layer->renderer()->style();
1920 int endPoint = m_end;
1921 int range = m_end - m_start;
1922 int newPos;
1923 if (range == 0)
1924 newPos = m_end;
1925 else {
1926 bool addIncrement = direction() == MUP || direction() == MLEFT;
1927 bool isReversed = s->marqueeBehavior() == MALTERNATE && m_currentLoop % 2;
1928 if (isUnfurlMarquee()) {
1929 isReversed = (!addIncrement && m_currentLoop % 2) || (addIncrement && !(m_currentLoop % 2));
1930 addIncrement = !isReversed;
1932 if (isReversed) {
1933 // We're going in the reverse direction.
1934 endPoint = m_start;
1935 range = -range;
1936 if (!isUnfurlMarquee())
1937 addIncrement = !addIncrement;
1939 bool positive = range > 0;
1940 int clientSize = isUnfurlMarquee() ? abs(range) :
1941 (isHorizontal() ? m_layer->renderer()->clientWidth() : m_layer->renderer()->clientHeight());
1942 int increment = qMax(1, abs(m_layer->renderer()->style()->marqueeIncrement().width(clientSize)));
1943 int currentPos = isUnfurlMarquee() ? m_unfurlPos :
1944 (isHorizontal() ? m_layer->scrollXOffset() : m_layer->scrollYOffset());
1945 newPos = currentPos + (addIncrement ? increment : -increment);
1946 if (positive)
1947 newPos = qMin(newPos, endPoint);
1948 else
1949 newPos = qMax(newPos, endPoint);
1952 if (newPos == endPoint) {
1953 m_currentLoop++;
1954 if (m_totalLoops > 0 && m_currentLoop >= m_totalLoops) {
1955 killTimer(m_timerId);
1956 m_timerId = 0;
1958 else if (s->marqueeBehavior() != MALTERNATE && s->marqueeBehavior() != MUNFURL)
1959 m_reset = true;
1962 if (isUnfurlMarquee()) {
1963 m_unfurlPos = newPos;
1964 m_layer->renderer()->setChildNeedsLayout(true);
1966 else {
1967 if (isHorizontal())
1968 m_layer->scrollToXOffset(newPos);
1969 else
1970 m_layer->scrollToYOffset(newPos);
1974 #include "render_layer.moc"