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.
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.
48 #include "render_layer.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>
67 using namespace khtml
;
69 ScrollBarWidget
* RenderLayer::gScrollBar
= 0;
72 static bool inRenderLayerDetach
;
76 RenderScrollMediator::slotValueChanged()
78 m_layer
->updateScrollPositionFromScrollbars();
81 RenderLayer::RenderLayer(RenderObject
* object
)
96 m_scrollMediator( 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 ),
111 if (!object
->firstChild() && object
->style()) {
112 m_visibleContentStatusDirty
= false;
113 m_hasVisibleContent
= object
->style()->visibility() == VISIBLE
;
119 RenderLayer::~RenderLayer()
121 // Child layers will be deleted by their corresponding render objects, so
122 // our destructor doesn't have to do anything.
127 delete m_scrollMediator
;
128 delete m_posZOrderList
;
129 delete m_negZOrderList
;
130 delete m_overflowList
;
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())
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()) {
152 curr
= curr
->parent();
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
);
170 parent()->subtractScrollOffset(x
, y
);
175 QRegion
RenderLayer::paintedRegion(RenderLayer
* rootLayer
)
179 const RenderStyle
*s
= renderer()->style();
180 bool isTrans
= (s
->opacity() < 1.0);
181 if (isTrans
&& m_hasVisibleDescendant
) {
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
);
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
);
218 void RenderLayer::repaint( Priority p
, bool markForRepaint
)
220 if (markForRepaint
&& m_markedForRepaint
)
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
) );
230 m_markedForRepaint
= true;
233 void RenderLayer::updateLayerPositions(RenderLayer
* rootLayer
, bool doFullRepaint
, bool checkForRepaint
)
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.
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() );
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.
271 m_marquee
->updateMarqueePosition();
275 void RenderLayer::setHasVisibleContent(bool b
)
277 if (m_hasVisibleContent
== b
&& !m_visibleContentStatusDirty
)
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();
289 parent()->childVisibilityChanged(m_hasVisibleContent
);
292 void RenderLayer::dirtyVisibleContentStatus()
294 m_visibleContentStatusDirty
= true;
296 parent()->dirtyVisibleDescendantStatus();
299 void RenderLayer::childVisibilityChanged(bool newVisibility
)
301 if (m_hasVisibleDescendant
== newVisibility
|| m_visibleDescendantStatusDirty
)
304 RenderLayer
* l
= this;
305 while (l
&& !l
->m_visibleDescendantStatusDirty
&& !l
->m_hasVisibleDescendant
) {
306 l
->m_hasVisibleDescendant
= true;
310 dirtyVisibleDescendantStatus();
313 void RenderLayer::dirtyVisibleDescendantStatus()
315 RenderLayer
* l
= this;
316 while (l
&& !l
->m_visibleDescendantStatusDirty
) {
317 l
->m_visibleDescendantStatusDirty
= true;
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;
333 m_visibleDescendantStatusDirty
= false;
336 if (m_visibleContentStatusDirty
) {
337 if (m_object
->style()->visibility() == VISIBLE
)
338 m_hasVisibleContent
= true;
340 // layer may be hidden but still have some visible content, check for this
341 m_hasVisibleContent
= false;
342 RenderObject
* r
= m_object
->firstChild();
344 if (r
->style()->visibility() == VISIBLE
&& !r
->layer()) {
345 m_hasVisibleContent
= true;
348 if (r
->firstChild() && !r
->layer())
350 else if (r
->nextSibling())
351 r
= r
->nextSibling();
357 } while (r
&& !r
->nextSibling());
359 r
= r
->nextSibling();
363 m_visibleContentStatusDirty
= false;
367 void RenderLayer::updateWidgetMasks(RenderLayer
* rootLayer
)
369 if (hasOverlaidWidgets() && !renderer()->canvas()->pagedMode()) {
371 uint count
= m_posZOrderList
? m_posZOrderList
->count() : 0;
372 bool needUpdate
= false;
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
);
385 RenderLayer
* sc
= this;
387 while ((sc
= sc
->stackingContext())) {
388 sc
->updateZOrderLists();
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
;
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;
407 for (uint i
= 0; i
< count
; i
++) {
408 found
= found
|| sc
->m_posZOrderList
->at(i
)->zIndex() > zx
;
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
);
421 needUpdate
= needUpdate
|| !m_region
.isEmpty();
422 m_region
= QRegion();
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
);
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
);
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());
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());
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());
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.
493 void RenderLayer::detach(RenderArena
* renderArena
)
496 inRenderLayerDetach
= true;
500 inRenderLayerDetach
= false;
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();
511 child
->setPreviousSibling(prevSibling
);
512 prevSibling
->setNextSibling(child
);
515 setFirstChild(child
);
518 beforeChild
->setPreviousSibling(child
);
519 child
->setNextSibling(beforeChild
);
524 child
->setParent(this);
526 if (child
->isOverflowOnly())
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();
534 stackingContext
->dirtyZOrderLists();
536 child
->updateVisibilityStatus();
537 if (child
->m_hasVisibleContent
|| child
->m_hasVisibleDescendant
)
538 childVisibilityChanged(true);
541 RenderLayer
* RenderLayer::removeChild(RenderLayer
* oldChild
)
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())
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();
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);
576 void RenderLayer::removeOnlyThisLayer()
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
;
589 RenderLayer
* next
= current
->nextSibling();
590 removeChild(current
);
591 parent
->addChild(current
, nextSib
);
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();
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)
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.
623 m_object
->absolutePosition(xOff
, yOff
, true);
629 RenderLayer
* parentLayer
;
630 if (m_object
->style()->position() == PABSOLUTE
)
631 parentLayer
= enclosingPositionedAncestor();
633 parentLayer
= parent();
635 if (!parentLayer
) return;
637 parentLayer
->convertToLayerCoords(ancestorLayer
, x
, y
);
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())
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
);
667 if (flow
->firstLineBox()) {
668 if (flow
->style()->direction() == LTR
)
669 sx
= flow
->firstLineBox()->xPos();
671 sx
= flow
->lastLineBox()->xPos();
672 sy
= flow
->firstLineBox()->yPos();
674 sx
= flow
->staticX(); // ###
675 sy
= flow
->staticY();
677 bool isInlineType
= o
->style()->isOriginalDisplayInlineType();
679 if (!o
->hasStaticX())
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())
693 void RenderLayer::scrollToOffset(int x
, int y
, bool updateScrollbars
, bool repaint
)
695 if (renderer()->style()->overflowX() != OMARQUEE
|| !renderer()->hasOverflowClip()) {
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.).
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.
724 m_object
->repaint(RealtimePriority
);
726 if (updateScrollbars
) {
728 m_hBar
->setValue(m_scrollX
);
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
;
744 newX
= m_hBar
->value();
745 if (newX
!= m_scrollX
)
750 newY
= m_vBar
->value();
751 if (newY
!= m_scrollY
)
756 scrollToOffset(newX
, newY
, false);
760 RenderLayer::showScrollbar(Qt::Orientation o
, bool show
)
762 ScrollBarWidget
*sb
= (o
== Qt::Horizontal
) ? m_hBar
: m_vBar
;
765 KHTMLView
* view
= m_object
->document()->view();
766 sb
= new ScrollBarWidget(o
, view
->widget());
768 sb
->setAttribute(Qt::WA_NoSystemBackground
);
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
) {
779 if (o
== Qt::Horizontal
)
785 int RenderLayer::verticalScrollbarWidth()
791 return m_vBar
->width();
793 return m_vBar
->style()->pixelMetric(QStyle::PM_ScrollBarExtent
);
798 int RenderLayer::horizontalScrollbarHeight()
804 return m_hBar
->height();
806 return m_hBar
->style()->pixelMetric(QStyle::PM_ScrollBarExtent
);
811 void RenderLayer::positionScrollbars(const QRect
& absBounds
)
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));
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());
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
))
842 ScrollBarWidget
*b
= m_hBar
;
845 int sw
= b
->style()->pixelMetric(QStyle::PM_ScrollBarExtent
);
846 bool rtl
= b
->layoutDirection() == Qt::RightToLeft
;
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()));
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()));
865 void RenderLayer::checkScrollbarsAfterLayout()
867 int rightPos
= m_object
->rightmostPosition(true);
868 int bottomPos
= m_object
->lowestPosition(true);
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
);
906 m_hBar
->setEnabled(true);
908 if (m_object
->style()->overflowY() == OAUTO
) {
909 showScrollbar(Qt::Vertical
, needVerticalBar
);
911 m_vBar
->setEnabled(true);
914 m_object
->setNeedsLayout(true);
915 if (m_object
->isRenderBlock())
916 static_cast<RenderBlock
*>(m_object
)->layoutBlock(true);
922 // Set up the range (and page step/line step).
924 int pageStep
= (clientWidth
-PAGE_KEEP
);
925 if (pageStep
< 0) pageStep
= clientWidth
;
926 m_hBar
->setSingleStep(LINE_STEP
);
927 m_hBar
->setPageStep(pageStep
);
929 m_hBar
->setKnobProportion(clientWidth
, m_scrollWidth
);
931 m_hBar
->setRange(0, needHorizontalBar
? m_scrollWidth
-clientWidth
: 0);
935 int pageStep
= (clientHeight
-PAGE_KEEP
);
936 if (pageStep
< 0) pageStep
= clientHeight
;
937 m_vBar
->setSingleStep(LINE_STEP
);
938 m_vBar
->setPageStep(pageStep
);
940 m_vBar
->setKnobProportion(clientHeight
, m_scrollHeight
);
942 m_vBar
->setRange(0, needVerticalBar
? m_scrollHeight
-clientHeight
: 0);
947 void RenderLayer::paintScrollbars(RenderObject::PaintInfo
& pI
)
949 if (!m_object
->element())
953 if (!m_buffer
[0] || m_buffer
[0]->size() != m_hBar
->size()) {
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
);
961 if (!m_buffer
[1] || m_buffer
[1]->size() != m_vBar
->size()) {
963 m_buffer
[1] = new QPixmap( m_vBar
->size() );
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
)
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
)
996 KHTMLView
* v
= m_object
->document()->view();
997 if (v
->clipHolder() && !v
->clipHolder()->isEmpty())
998 p
->setClipRegion( v
->clipHolder()->pop() );
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())
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();
1075 renderer()->paint(paintInfo
, tx
, ty
);
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.
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
);
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());
1122 // End our transparency layer
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;
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();
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
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
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
);
1193 // Now check our overflow objects.
1194 if (m_overflowList
) {
1195 QVector
<RenderLayer
*>::iterator it
= m_overflowList
->end();
1196 while (it
!= m_overflowList
->begin()) {
1198 insideLayer
= (*it
)->nodeAtPointForLayer(rootLayer
, info
, xMousePos
, yMousePos
, hitTestRect
);
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())
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
);
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(),
1237 void RenderLayer::calculateClipRects(const RenderLayer
* rootLayer
, QRect
& overflowClipRect
,
1238 QRect
& posClipRect
, QRect
& fixedClipRect
)
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.
1247 posClipRect
= fixedClipRect
;
1248 overflowClipRect
= fixedClipRect
;
1251 overflowClipRect
= posClipRect
;
1254 posClipRect
= overflowClipRect
;
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.
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
;
1289 parent()->calculateClipRects(rootLayer
, overflowClipRect
, posClipRect
, fixedClipRect
);
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
)
1345 for (RenderObject
* currObj1
= obj1
; currObj1
; currObj1
= hoverAncestor(currObj1
))
1346 for (RenderObject
* currObj2
= obj2
; currObj2
; currObj2
= hoverAncestor(currObj2
))
1347 if (currObj1
== currObj2
)
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())
1360 DOM::NodeImpl
*e
= m_object
->element();
1361 DOM::DocumentImpl
*doc
= e
? e
->document() : 0;
1364 // Check to see if the hovered node has changed. If not, then we don't need to
1366 DOM::NodeImpl
* oldHoverNode
= doc
->hoverNode();
1367 DOM::NodeImpl
* newHoverNode
= info
.innerNode();
1369 if (oldHoverNode
== newHoverNode
&& (!oldHoverNode
|| oldHoverNode
->active() == info
.active()))
1372 // Update our current hover node.
1373 doc
->setHoverNode(newHoverNode
);
1375 doc
->setActiveNode(newHoverNode
);
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
1408 static void sortByZOrder(QVector
<RenderLayer
*>* buffer
,
1409 QVector
<RenderLayer
*>* mergeBuffer
,
1410 uint start
, uint 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
--) {
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()) {
1424 buffer
->replace(j
, elt2
);
1425 buffer
->replace(j
+1, elt
);
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())
1446 // We have to merge sort.
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
);
1458 elt
= buffer
->at(i1
);
1461 mergeBuffer
->append(elt2
);
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()
1487 m_overflowList
->clear();
1488 m_overflowListDirty
= true;
1491 void RenderLayer::updateZOrderLists()
1493 if (!isStackingContext() || !m_zOrderListsDirty
)
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
)
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.
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
);
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();
1561 static void write(QTextStream
&ts
, RenderObject
& o
, const QString
& 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";
1594 if (layerType
!= -1)
1595 write( ts
, *l
.renderer(), indent
+ " " );
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
);
1618 for (int i
= 0; i
!= negList
->count(); ++i
)
1619 writeLayers(ts
, rootLayer
, negList
->at(i
), paintDirtyRect
, indent
);
1623 write(ts
, *l
, layerBounds
, damageRect
, clipRectToApply
, negList
&& negList
->count() > 0, indent
);
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();
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
);
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();
1662 p
->dirtyOverflowList();
1664 sc
->dirtyZOrderLists();
1667 if (m_object
->hasOverflowClip() &&
1668 m_object
->style()->overflowX() == OMARQUEE
&& m_object
->style()->marqueeBehavior() != MNONE
) {
1670 m_marquee
= new Marquee(this);
1671 m_marquee
->updateMarqueeStyle();
1673 else if (m_marquee
) {
1679 void RenderLayer::suspendMarquees()
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());
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
)
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
);
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);
1750 contentWidth
+= (o
->paddingRight() - o
->borderLeft());
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
));
1759 return ltr
? contentWidth
: clientWidth
;
1762 if (stopAtContentEdge
)
1763 return qMin(0, ltr
? (contentWidth
- clientWidth
) : (clientWidth
- contentWidth
));
1765 return ltr
? -clientWidth
: -contentWidth
;
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();
1773 if (stopAtContentEdge
)
1774 return qMin(contentHeight
- clientHeight
, 0);
1776 return -clientHeight
;
1779 if (stopAtContentEdge
)
1780 return qMax(contentHeight
- clientHeight
, 0);
1782 return contentHeight
;
1787 void Marquee::start()
1789 if (m_timerId
|| m_layer
->renderer()->style()->marqueeIncrement().value() == 0)
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);
1801 m_layer
->scrollToOffset(m_start
, 0, false, false);
1803 m_layer
->scrollToOffset(0, m_start
, false, false);
1807 m_suspended
= false;
1810 m_timerId
= startTimer(speed());
1813 void Marquee::suspend()
1816 killTimer(m_timerId
);
1823 void Marquee::stop()
1826 killTimer(m_timerId
);
1833 void Marquee::updateMarqueePosition()
1835 bool activate
= (m_totalLoops
<= 0 || m_currentLoop
< m_totalLoops
);
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);
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
1870 if (m_totalLoops
<= 0 && (s
->marqueeBehavior() == MSLIDE
|| s
->marqueeBehavior() == MUNFURL
))
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
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();
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
);
1904 void Marquee::timerEvent(QTimerEvent
* /*evt*/)
1906 if (m_layer
->renderer()->needsLayout())
1912 m_layer
->scrollToXOffset(m_start
);
1914 m_layer
->scrollToYOffset(m_start
);
1918 RenderStyle
* s
= m_layer
->renderer()->style();
1920 int endPoint
= m_end
;
1921 int range
= m_end
- m_start
;
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
;
1933 // We're going in the reverse direction.
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
);
1947 newPos
= qMin(newPos
, endPoint
);
1949 newPos
= qMax(newPos
, endPoint
);
1952 if (newPos
== endPoint
) {
1954 if (m_totalLoops
> 0 && m_currentLoop
>= m_totalLoops
) {
1955 killTimer(m_timerId
);
1958 else if (s
->marqueeBehavior() != MALTERNATE
&& s
->marqueeBehavior() != MUNFURL
)
1962 if (isUnfurlMarquee()) {
1963 m_unfurlPos
= newPos
;
1964 m_layer
->renderer()->setChildNeedsLayout(true);
1968 m_layer
->scrollToXOffset(newPos
);
1970 m_layer
->scrollToYOffset(newPos
);
1974 #include "render_layer.moc"