layers and zindex in Safari

David Hyatt hyatt at apple.com
Mon Sep 1 02:49:39 CEST 2003


Lars:

Inspired by your patch, I have produced a new version of the layer code 
for Safari that avoids the recalculation of the layer list except when 
z-indices of layers change or layers are added/removed.  In this patch, 
a layer now holds onto a sorted list of positive layers and a sorted 
list of negative layers.  Think of this patch as a rough draft.  It 
needs more testing and has not yet landed in the Safari tree.

With the two separate z-order lists, the paint method and nodeAtPoint 
method can be cleanly recursive.  For example, paint just does the 
following:

1. Compute the right clip rects.
2. Paint the element's background/border/scrollbars with the background 
clip.
3. Descend into the negative list, calling paint on each layer.
4. Paint the child content of the element with the foreground/child 
clip.
5. Descend into the positive list, calling paint on each layer.

The one feature that is the most difficult to understand in the layer 
code is clipping.  Clipping is actually incredibly complicated, and the 
current layer code in Safari is actually very close (modulo some bugs 
with fixed positioning) to matching the CSS2.1 specification.  This new 
patch actually fixes the fixed positioning clipping bugs and is 
designed to match the spec completely.

Here are some notes to help understand how clipping works.

There are two completely different clip mechanisms in CSS.  The first 
is the 'clip' property.  It can be specified only on positioned 
elements but then applies to all descendants in the document tree.  The 
'clip' property when applied to an element actually clips the *element 
itself* as well as all descendants.

The second mechanism is overflow.  In CSS3, you can actually specify an 
overflow-clip property that indicates a rectangle to clip, but by 
default this overflow clip rect is the padding-box (minus the scrolling 
mechanism if one is present).  Overflow does not apply to the element 
itself, and the only descendants it applies to are those that are *in 
the containing block hierarchy* of the object.

Clipping is a pain, since painting does not do a clean descent in 
document order through the layer tree because of auto z-index. You 
might have the following layer hierarchy:

(Layer A with z-index 1) -> (Layer B with auto z-index that clips) -> 
(Layer C with negative z-index)

In the above example, B establishes a clip that affects C, and yet when 
you do a paint that recurs through sorted layer lists, C is going to 
paint completely before B.

The clip rect to use when painting also varies based on where you are 
in the containing block hierarchy.  In the above example if B is 
position:absolute and specifies an overflow clip, but C is 
position:fixed, then B should not clip C, but if C is 
position:absolute, B *should* clip C.

Another point of clarification regarding the layer code itself: even 
though layers have x/y member variables, those values are *not 
necessarily relative to the parent layer*.  A layer hierarchy does not 
match containing block order, so you can have layers like so:

(Layer A Non-Positioned) -> (Layer B Abs Pos) -> (Layer C Fixed Pos)

The x/y coords of C are not relative to B, nor are the coords of B 
relative to A in the above example.

This patch (like the old code did) handles most of these bizarre 
combinations correctly.

Another feature of this new patch is that it fixes the remaining 
problems with nodeAtPoint and hover.  The old Safari code could 
mistakenly set hover on two overlapping elements, when only one should 
have gotten the hover state set.  This new code is much more efficient 
in its handling of :hover and fixes this problem.

Here is a diff against the current Safari tree along with the 
render_layer.h/cpp files, since they'll probably be easier to read by 
themselves.

Cheers,
Dave
(hyatt at apple.com)

-------------- next part --------------
Index: khtml/css/cssstyleselector.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/css/cssstyleselector.cpp,v
retrieving revision 1.95
diff -u -p -r1.95 khtml/css/cssstyleselector.cpp
--- khtml/css/cssstyleselector.cpp	2003/08/26 22:19:17	1.95
+++ khtml/css/cssstyleselector.cpp	2003/09/01 08:16:09
@@ -527,6 +527,21 @@ void CSSStyleSelector::adjustRenderStyle
         }
     }
 
+    // Make sure our z-index value is only applied if the object is positioned,
+    // relatively positioned, or transparent.
+    if (style->position() == STATIC && style->opacity() == 1.0f) {
+        if (e && e->getDocument()->documentElement() == e)
+            style->setZIndex(0); // The root has a z-index of 0 if not positioned or transparent.
+        else
+            style->setHasAutoZIndex(); // Everyone else gets an auto z-index.
+    }
+
+    // Auto z-index becomes 0 for transparent objects.  This prevents cases where
+    // objects that should be blended as a single unit end up with a non-transparent object
+    // wedged in between them.
+    if (style->opacity() < 1.0f && style->hasAutoZIndex())
+        style->setZIndex(0);
+    
     // Finally update our text decorations in effect, but don't allow text-decoration to percolate through
     // tables, inline blocks, inline tables, or run-ins.
     if (style->display() == TABLE || style->display() == INLINE_TABLE || style->display() == RUN_IN
Index: khtml/rendering/render_block.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_block.cpp,v
retrieving revision 1.55
diff -u -p -r1.55 khtml/rendering/render_block.cpp
--- khtml/rendering/render_block.cpp	2003/08/28 21:24:07	1.55
+++ khtml/rendering/render_block.cpp	2003/09/01 08:16:13
@@ -1853,13 +1853,14 @@ bool RenderBlock::isPointInScrollbar(int
     return false;    
 }
 
-bool RenderBlock::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, bool inBox)
+bool RenderBlock::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
+                              HitTestAction hitTestAction, bool inBox)
 {
     bool inScrollbar = isPointInScrollbar(_x, _y, _tx+xPos(), _ty+yPos());
-    if (inScrollbar)
+    if (inScrollbar && hitTestAction != HitTestChildrenOnly)
         inBox = true;
     
-    if (m_floatingObjects && !inScrollbar) {
+    if (hitTestAction != HitTestSelfOnly && m_floatingObjects && !inScrollbar) {
         int stx = _tx + xPos();
         int sty = _ty + yPos();
         if (style()->hidesOverflow() && m_layer)
@@ -1877,7 +1878,7 @@ bool RenderBlock::nodeAtPoint(NodeInfo& 
                                               sty+o->startY + o->node->marginTop() - o->node->yPos());
     }
 
-    inBox |= RenderFlow::nodeAtPoint(info, _x, _y, _tx, _ty, inBox);
+    inBox |= RenderFlow::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inBox);
     return inBox;
 }
 
Index: khtml/rendering/render_block.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_block.h,v
retrieving revision 1.21
diff -u -p -r1.21 khtml/rendering/render_block.h
--- khtml/rendering/render_block.h	2003/08/27 01:09:18	1.21
+++ khtml/rendering/render_block.h	2003/09/01 08:16:13
@@ -158,7 +158,8 @@ public:
                       int *heightRemaining = 0) const;
     int leftOffset(int y) const { return leftRelOffset(y, leftOffset(), true); }
 
-    virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, bool inside=false);
+    virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty,
+                             HitTestAction hitTestAction = HitTestAll, bool inside=false);
 
     bool isPointInScrollbar(int x, int y, int tx, int ty);
     
Index: khtml/rendering/render_box.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_box.cpp,v
retrieving revision 1.80
diff -u -p -r1.80 khtml/rendering/render_box.cpp
--- khtml/rendering/render_box.cpp	2003/08/21 18:52:06	1.80
+++ khtml/rendering/render_box.cpp	2003/09/01 08:16:15
@@ -108,32 +108,9 @@ void RenderBox::setStyle(RenderStyle *_s
         m_layer = 0;
     }
 
-    adjustZIndex();
-
     // Set the text color if we're the body.
     if (isBody())
         element()->getDocument()->setTextColor(_style->color());
-}
-
-void RenderBox::adjustZIndex()
-{
-    if (m_layer) {
-        // Make sure our z-index values are only applied if we're positioned or
-        // relpositioned or transparent.
-        if (!isPositioned() && !isRelPositioned() && style()->opacity() == 1.0f) {
-            // Set the auto z-index flag.
-            if (isRoot())
-                style()->setZIndex(0);
-            else
-                style()->setHasAutoZIndex();
-        }
-        
-        // Auto z-index becomes 0 for transparent objects.  This prevents cases where
-        // objects that should be blended as a single unit end up with a non-transparent object
-        // wedged in between them.
-        if (style()->opacity() < 1.0f && style()->hasAutoZIndex())
-            style()->setZIndex(0);
-    }
 }
 
 RenderBox::~RenderBox()
Index: khtml/rendering/render_box.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_box.h,v
retrieving revision 1.26
diff -u -p -r1.26 khtml/rendering/render_box.h
--- khtml/rendering/render_box.h	2003/07/11 17:55:42	1.26
+++ khtml/rendering/render_box.h	2003/09/01 08:16:15
@@ -137,9 +137,6 @@ protected:
     virtual QRect getOverflowClipRect(int tx, int ty);
     virtual QRect getClipRect(int tx, int ty);
 
-    // Called to correct the z-index after the style has been changed.
-    void adjustZIndex();
-    
     // the actual height of the contents + borders + padding
     int m_height;
 
Index: khtml/rendering/render_frames.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_frames.cpp,v
retrieving revision 1.42
diff -u -p -r1.42 khtml/rendering/render_frames.cpp
--- khtml/rendering/render_frames.cpp	2003/08/19 21:49:53	1.42
+++ khtml/rendering/render_frames.cpp	2003/09/01 08:16:16
@@ -84,9 +84,10 @@ RenderFrameSet::~RenderFrameSet()
       delete [] m_vSplitVar;
 }
 
-bool RenderFrameSet::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, bool inside)
+bool RenderFrameSet::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
+                                 HitTestAction hitTestAction, bool inside)
 {
-    RenderBox::nodeAtPoint(info, _x, _y, _tx, _ty, inside);
+    RenderBox::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inside);
 
     inside = m_resizing || canResize(_x, _y);
 
Index: khtml/rendering/render_frames.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_frames.h,v
retrieving revision 1.9
diff -u -p -r1.9 khtml/rendering/render_frames.h
--- khtml/rendering/render_frames.h	2003/05/17 01:40:18	1.9
+++ khtml/rendering/render_frames.h	2003/09/01 08:16:16
@@ -60,7 +60,8 @@ public:
   bool canResize( int _x, int _y);
   void setResizing(bool e);
 
-  bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, bool inside=false);
+  bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty,
+                   HitTestAction hitTestAction = HitTestAll, bool inside=false);
 
     DOM::HTMLFrameSetElementImpl *element() const
     { return static_cast<DOM::HTMLFrameSetElementImpl*>(RenderObject::element()); }
Index: khtml/rendering/render_image.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_image.cpp,v
retrieving revision 1.38
diff -u -p -r1.38 khtml/rendering/render_image.cpp
--- khtml/rendering/render_image.cpp	2003/07/30 21:03:32	1.38
+++ khtml/rendering/render_image.cpp	2003/09/01 08:16:17
@@ -439,9 +439,10 @@ void RenderImage::detach(RenderArena *ar
     RenderReplaced::detach(arena);
 }
 
-bool RenderImage::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, bool inside)
+bool RenderImage::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
+                              HitTestAction hitTestAction, bool inside)
 {
-    inside |= RenderReplaced::nodeAtPoint(info, _x, _y, _tx, _ty, inside);
+    inside |= RenderReplaced::nodeAtPoint(info, _x, _y, _tx, _ty, hitTestAction, inside);
 
     if (inside && element()) {
         int tx = _tx + m_x;
Index: khtml/rendering/render_image.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_image.h,v
retrieving revision 1.11
diff -u -p -r1.11 khtml/rendering/render_image.h
--- khtml/rendering/render_image.h	2003/05/05 17:31:40	1.11
+++ khtml/rendering/render_image.h	2003/09/01 08:16:17
@@ -64,7 +64,8 @@ public:
     virtual void notifyFinished(CachedObject *finishedObj);
     void dispatchLoadEvent();
 
-    virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, bool inside=false);
+    virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty,
+                             HitTestAction hitTestAction = HitTestAll, bool inside=false);
     
     virtual short calcReplacedWidth() const;
     virtual int calcReplacedHeight() const;
Index: khtml/rendering/render_inline.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_inline.cpp,v
retrieving revision 1.16
diff -u -p -r1.16 khtml/rendering/render_inline.cpp
--- khtml/rendering/render_inline.cpp	2003/08/11 23:41:02	1.16
+++ khtml/rendering/render_inline.cpp	2003/09/01 08:16:17
@@ -366,15 +366,18 @@ const char *RenderInline::renderName() c
     return "RenderInline";
 }
 
-bool RenderInline::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, bool inside)
+bool RenderInline::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
+                               HitTestAction hitTestAction, bool inside)
 {
-    // Always check our kids.
-    for (RenderObject* child = lastChild(); child; child = child->previousSibling())
-        if (!child->layer() && !child->isFloating() && child->nodeAtPoint(info, _x, _y, _tx, _ty))
-            inside = true;
-
+    // Check our kids if our HitTestAction says to.
+    if (hitTestAction != HitTestSelfOnly) {
+        for (RenderObject* child = lastChild(); child; child = child->previousSibling())
+            if (!child->layer() && !child->isFloating() && child->nodeAtPoint(info, _x, _y, _tx, _ty))
+                inside = true;
+    }
+    
     // Check our line boxes if we're still not inside.
-    if (!inside && style()->visibility() != HIDDEN) {
+    if (hitTestAction != HitTestChildrenOnly && !inside && style()->visibility() != HIDDEN) {
         // See if we're inside one of our line boxes.
         for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
             if((_y >=_ty + curr->m_y) && (_y < _ty + curr->m_y + curr->m_height) &&
@@ -401,31 +404,8 @@ bool RenderInline::nodeAtPoint(NodeInfo&
 
         if(!info.innerNonSharedNode())
             info.setInnerNonSharedNode(element());
-
-        if (!info.URLElement()) {
-            RenderObject* p = this;
-            while (p) {
-                if (p->element() && p->element()->hasAnchor()) {
-                    info.setURLElement(p->element());
-                    break;
-                }
-                if (!isFloatingOrPositioned()) break;
-                p = p->parent();
-            }
-        }
-        
     }
 
-    if (!info.readonly()) {
-        // lets see if we need a new style
-        bool oldinside = mouseInside();
-        setMouseInside(inside);
-
-        setHoverAndActive(info, oldinside, inside);
-        if (!isInline() && continuation())
-            continuation()->setHoverAndActive(info, oldinside, inside);
-    }
-    
     return inside;
 }
 
Index: khtml/rendering/render_inline.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_inline.h,v
retrieving revision 1.11
diff -u -p -r1.11 khtml/rendering/render_inline.h
--- khtml/rendering/render_inline.h	2003/08/11 23:41:02	1.11
+++ khtml/rendering/render_inline.h	2003/09/01 08:16:18
@@ -58,7 +58,8 @@ public:
     virtual void paintObject(QPainter *, int x, int y, int w, int h,
                              int tx, int ty, PaintAction paintAction);
 
-    virtual bool nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, bool inside);
+    virtual bool nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
+                             HitTestAction hitTestAction = HitTestAll, bool inside=false);
     
     virtual void calcMinMaxWidth();
 
Index: khtml/rendering/render_layer.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_layer.cpp,v
retrieving revision 1.49
diff -u -p -r1.49 khtml/rendering/render_layer.cpp
--- khtml/rendering/render_layer.cpp	2003/07/24 01:51:17	1.49
+++ khtml/rendering/render_layer.cpp	2003/09/01 08:16:19
@@ -49,15 +49,18 @@
 #include "render_arena.h"
 #include "xml/dom_docimpl.h"
 
+#include <qscrollbar.h>
+#include <qptrvector.h>
+
 using namespace DOM;
 using namespace khtml;
 
-QWidget* RenderLayer::gScrollBar = 0;
+#ifdef APPLE_CHANGES
+QScrollBar* RenderLayer::gScrollBar = 0;
+#endif
 
 #ifndef NDEBUG
 static bool inRenderLayerDetach;
-static bool inRenderLayerElementDetach;
-static bool inRenderZTreeNodeDetach;
 #endif
 
 void
@@ -73,17 +76,20 @@ m_previous( 0 ),
 m_next( 0 ),
 m_first( 0 ),
 m_last( 0 ),
-m_height( 0 ),
-m_y( 0 ),
 m_x( 0 ),
+m_y( 0 ),
 m_width( 0 ),
+m_height( 0 ),
 m_scrollX( 0 ),
 m_scrollY( 0 ),
 m_scrollWidth( 0 ),
 m_scrollHeight( 0 ),
 m_hBar( 0 ),
 m_vBar( 0 ),
-m_scrollMediator( 0 )
+m_scrollMediator( 0 ),
+m_posZOrderList( 0 ),
+m_negZOrderList( 0 ),
+m_zOrderListsDirty( true )
 {
 }
 
@@ -95,6 +101,8 @@ RenderLayer::~RenderLayer()
     delete m_hBar;
     delete m_vBar;
     delete m_scrollMediator;
+    delete m_posZOrderList;
+    delete m_negZOrderList;
 }
 
 void RenderLayer::updateLayerPosition()
@@ -135,94 +143,44 @@ void RenderLayer::updateLayerPosition()
             setWidth(m_object->overflowWidth());
         if (m_object->overflowHeight() > m_object->height())
             setHeight(m_object->overflowHeight());
-    }
+    }    
 }
 
-RenderLayer*
-RenderLayer::enclosingPositionedAncestor()
+RenderLayer *RenderLayer::stackingContext() const
 {
     RenderLayer* curr = parent();
     for ( ; curr && !curr->m_object->isCanvas() && !curr->m_object->isRoot() &&
-         !curr->m_object->isPositioned() && !curr->m_object->isRelPositioned();
-         curr = curr->parent());
-         
+          curr->m_object->style()->hasAutoZIndex();
+          curr = curr->parent());
     return curr;
 }
 
 RenderLayer*
-RenderLayer::transparentAncestor()
+RenderLayer::enclosingPositionedAncestor() const
 {
     RenderLayer* curr = parent();
-    for ( ; curr && curr->m_object->style()->opacity() == 1.0f; curr = curr->parent());
+    for ( ; curr && !curr->m_object->isCanvas() && !curr->m_object->isRoot() &&
+         !curr->m_object->isPositioned() && !curr->m_object->isRelPositioned();
+         curr = curr->parent());
+         
     return curr;
 }
 
+#if APPLE_CHANGES
 bool
 RenderLayer::isTransparent()
 {
     return m_object->style()->opacity() < 1.0f;
 }
 
-static RenderLayer* commonTransparentAncestor(RenderLayer* layer1, RenderLayer* layer2)
-{
-    if (!layer1 || !layer2)
-        return 0;
-    
-    for (RenderLayer* currLayer1 = layer1; currLayer1; currLayer1 = currLayer1->transparentAncestor())
-        for (RenderLayer* currLayer2 = layer2; currLayer2; currLayer2 = currLayer2->transparentAncestor())
-            if (currLayer1 == currLayer2)
-                return currLayer1;
-    
-    return 0;
-}
-
-void RenderLayer::updateTransparentState(QPainter* painter, RenderLayer* newLayer, RenderLayer*& currLayer)
-{
-    RenderLayer* transparentLayer = (!newLayer || newLayer->isTransparent()) ? newLayer :
-                                    newLayer->transparentAncestor();
-    if (transparentLayer == currLayer)
-        return;
-    
-    RenderLayer* commonAncestor = commonTransparentAncestor(currLayer, transparentLayer);
-    endTransparencyLayers(painter, currLayer, commonAncestor);
-    beginTransparencyLayers(painter, transparentLayer, commonAncestor);
-    
-    // Update our current layer.
-    currLayer = transparentLayer;
-}
-
-void RenderLayer::beginTransparencyLayers(QPainter* painter, RenderLayer* newLayer, RenderLayer* ancestorLayer)
+RenderLayer*
+RenderLayer::transparentAncestor()
 {
-    if (!newLayer || newLayer == ancestorLayer)
-        return;
-    
-    // We need to open from the outside in, so begin ancestor layers first.
-    beginTransparencyLayers(painter, newLayer->transparentAncestor(), ancestorLayer);
-    
-    // Konqueror should add its own code for setting up the opacity layer here.
-    // Safari uses a custom extension to QPainter to communicate with CoreGraphics.
-#ifdef APPLE_CHANGES
-    // Begin the layer
-    painter->beginTransparencyLayer(newLayer->renderer()->style()->opacity());
-#endif
+    RenderLayer* curr = parent();
+    for ( ; curr && curr->m_object->style()->opacity() == 1.0f; curr = curr->parent());
+    return curr;
 }
-
-void RenderLayer::endTransparencyLayers(QPainter* painter, RenderLayer* newLayer, RenderLayer* ancestorLayer)
-{
-    if (!newLayer || newLayer == ancestorLayer)
-        return;
-    
-    // We need to close from the inside out.
-    
-    // Konqueror should add its own code for popping opacity layers here.
-    // Safari uses a custom extension to QPainter to communicate with CoreGraphics.
-#ifdef APPLE_CHANGES
-    // End the layer
-    painter->endTransparencyLayer();
 #endif
-    
-    endTransparencyLayers(painter, newLayer->transparentAncestor(), ancestorLayer);
-}
 
 void* RenderLayer::operator new(size_t sz, RenderArena* renderArena) throw()
 {
@@ -269,6 +227,9 @@ void RenderLayer::addChild(RenderLayer *
         setLastChild(child);
    
     child->setParent(this);
+
+    // Dirty the z-order list in which we are contained.
+    child->stackingContext()->dirtyZOrderLists();
 }
 
 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
@@ -284,6 +245,9 @@ RenderLayer* RenderLayer::removeChild(Re
     if (m_last == oldChild)
         m_last = oldChild->previousSibling();
 
+    // Dirty the z-order list in which we are contained.
+    oldChild->stackingContext()->dirtyZOrderLists();
+    
     oldChild->setPreviousSibling(0);
     oldChild->setNextSibling(0);
     oldChild->setParent(0);
@@ -330,7 +294,7 @@ void RenderLayer::insertOnlyThisLayer()
 }
 
 void 
-RenderLayer::convertToLayerCoords(RenderLayer* ancestorLayer, int& x, int& y)
+RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const
 {
     if (ancestorLayer == this)
         return;
@@ -533,8 +497,8 @@ RenderLayer::checkScrollbarsAfterLayout(
     if (bottomPos - m_object->borderTop() > m_scrollHeight)
         m_scrollHeight = bottomPos - m_object->borderTop();
     
-    bool needHorizontalBar = rightPos > m_width;
-    bool needVerticalBar = bottomPos > m_height;
+    bool needHorizontalBar = rightPos > width();
+    bool needVerticalBar = bottomPos > height();
 
     bool haveHorizontalBar = m_hBar;
     bool haveVerticalBar = m_vBar;
@@ -583,324 +547,254 @@ RenderLayer::checkScrollbarsAfterLayout(
     }
 }
 
+#if APPLE_CHANGES
 void
-RenderLayer::paintScrollbars(QPainter* p, int x, int y, int w, int h)
+RenderLayer::paintScrollbars(QPainter* p, const QRect& damageRect)
 {
-#if APPLE_CHANGES
     if (m_hBar)
-        m_hBar->paint(p, QRect(x, y, w, h));
+        m_hBar->paint(p, damageRect);
     if (m_vBar)
-        m_vBar->paint(p, QRect(x, y, w, h));
-#endif
+        m_vBar->paint(p, damageRect);
 }
+#endif
 
 void
-RenderLayer::paint(QPainter *p, int x, int y, int w, int h, bool selectionOnly)
+RenderLayer::paint(QPainter *p, const QRect& damageRect, bool selectionOnly)
 {
-    // Create the z-tree of layers that should be displayed.
-    QRect damageRect(x,y,w,h);
-    RenderZTreeNode* node = constructZTree(damageRect, damageRect, this);
-    if (!node)
-        return;
-
-    // Flatten the tree into a back-to-front list for painting.
-    QPtrVector<RenderLayerElement> layerList;
-    constructLayerList(node, &layerList);
-
-    // Walk the list and paint each layer, adding in the appropriate offset.
-    QRect paintRect(x, y, w, h);
-    QRect currRect(paintRect);
-    RenderLayer* currentTransparentLayer = 0;
-    
-    uint count = layerList.count();
-    for (uint i = 0; i < count; i++) {
-        RenderLayerElement* elt = layerList.at(i);
-
-        // Elements add in their own positions as a translation factor.  This forces
-        // us to subtract that out, so that when it's added back in, we get the right
-        // bounds.  This is really disgusting (that paint only sets up the right paint
-        // position after you call into it). -dwh
-        //printf("Painting layer at %d %d\n", elt->absBounds.x(), elt->absBounds.y());
-
-        bool updatedTransparentState = false;
-        if (elt->clipOriginator) {
-            // We originated a clip (we're either positioned or an element with
-            // overflow: hidden).  We need to paint our background and border, subject
-            // to clip regions established by our parent layers.
-            if (elt->backgroundClipRect != currRect) {
-                if (currRect != paintRect)
-                    p->restore(); // Pop the clip.
-
-                // This is called to update our transparency state.
-                updateTransparentState(p, elt->layer, currentTransparentLayer);
-                updatedTransparentState = true;
-                
-                currRect = elt->backgroundClipRect;
-                
-                // Now apply the clip rect.
-                QRect clippedRect = p->xForm(currRect);
-#if APPLE_CHANGES
-                p->save();
-                p->addClip(clippedRect);
-#else
-                QRegion creg(cr);
-                QRegion old = p->clipRegion();
-                if (!old.isNull())
-                    creg = old.intersect(creg);
-            
-                p->save();
-                p->setClipRegion(creg);
-#endif
-            }
-            
-            // A clip is in effect.  The clip is never allowed to clip our render object's
-            // background, borders or scrollbars.  Go ahead and draw those now without our clip (that will
-            // be used for our children) in effect.
-            elt->layer->renderer()->paintBoxDecorations(p, x, y, w, h,
-                                elt->absBounds.x(),
-                                elt->absBounds.y());
+    paintLayer(this, p, damageRect, selectionOnly);
+}
 
-            // Position our scrollbars prior to painting.
-            elt->layer->positionScrollbars(elt->absBounds);
+static void setClip(QPainter* p, const QRect& paintDirtyRect, const QRect& clipRect)
+{
+    if (paintDirtyRect == clipRect)
+        return;
 
-#if APPLE_CHANGES
-            // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
-            // z-index.
-            elt->layer->paintScrollbars(p, x, y, w, h);
-#endif
-        }
-        
-        if (elt->clipRect != currRect) {
-            if (currRect != paintRect)
-                p->restore(); // Pop the clip.
-
-            if (!updatedTransparentState) {
-                // This is called to update our transparency state.
-                updateTransparentState(p, elt->layer, currentTransparentLayer);
-                updatedTransparentState = true;
-            }
-            
-            currRect = elt->clipRect;
-            if (currRect != paintRect) {
-                                
-                // Now apply the clip rect.
-                QRect clippedRect = p->xForm(currRect);
+    p->save();
+    
 #if APPLE_CHANGES
-                p->save();
-                p->addClip(clippedRect);
+    p->addClip(clipRect);
 #else
-                QRegion creg(cr);
-                QRegion old = p->clipRegion();
-                if (!old.isNull())
-                    creg = old.intersect(creg);
-            
-                p->save();
-                p->setClipRegion(creg);
+    QRect clippedRect = p->xForm(clipRect);
+    QRegion creg(clippedRect);
+    QRegion old = p->clipRegion();
+    if (!old.isNull())
+        creg = old.intersect(creg);
+    p->setClipRegion(creg);
 #endif
-            }
-        }
-
-        if (!updatedTransparentState) {
-            // This is called to update our transparency state.
-            updateTransparentState(p, elt->layer, currentTransparentLayer);
-            updatedTransparentState = true;
-        }
-        
-        if (currRect.isEmpty())
-            continue;
-        
-        if (selectionOnly) {
-            if (elt->layerElementType == RenderLayerElement::Normal ||
-                elt->layerElementType == RenderLayerElement::Foreground)
-                elt->layer->renderer()->paint(p, x, y, w, h,
-                                            elt->absBounds.x() - elt->layer->renderer()->xPos(),
-                                            elt->absBounds.y() - elt->layer->renderer()->yPos(),
-                                            PaintActionSelection);
-        } else {
-            if (elt->layerElementType == RenderLayerElement::Normal ||
-                elt->layerElementType == RenderLayerElement::Background)
-                elt->layer->renderer()->paint(p, x, y, w, h,
-                                            elt->absBounds.x() - elt->layer->renderer()->xPos(),
-                                            elt->absBounds.y() - elt->layer->renderer()->yPos(),
-                                            PaintActionElementBackground);
-
-            if (elt->layerElementType == RenderLayerElement::Normal ||
-                elt->layerElementType == RenderLayerElement::Foreground) {
-                elt->layer->renderer()->paint(p, x, y, w, h,
-                                              elt->absBounds.x() - elt->layer->renderer()->xPos(),
-                                              elt->absBounds.y() - elt->layer->renderer()->yPos(),
-                                              PaintActionChildBackgrounds);
-                elt->layer->renderer()->paint(p, x, y, w, h,
-                                            elt->absBounds.x() - elt->layer->renderer()->xPos(),
-                                            elt->absBounds.y() - elt->layer->renderer()->yPos(),
-                                            PaintActionFloat);
-                elt->layer->renderer()->paint(p, x, y, w, h,
-                                            elt->absBounds.x() - elt->layer->renderer()->xPos(),
-                                            elt->absBounds.y() - elt->layer->renderer()->yPos(),
-                                            PaintActionForeground);
-            }
-        }
-    }
     
-    if (currRect != paintRect)
-        p->restore(); // Pop the clip.
-        
-    updateTransparentState(p, 0, currentTransparentLayer); // End any open transparency layers.
-    
-    node->detach(renderer()->renderArena());
 }
 
-void
-RenderLayer::clearOtherLayersHoverActiveState()
+static void restoreClip(QPainter* p, const QRect& paintDirtyRect, const QRect& clipRect)
 {
-    if (!m_parent)
+    if (paintDirtyRect == clipRect)
         return;
-        
-    for (RenderLayer* curr = m_parent->firstChild(); curr; curr = curr->nextSibling()) {
-        if (curr == this)
-            continue;
-        curr->clearHoverAndActiveState(curr->renderer());
-    }
-    
-    m_parent->clearOtherLayersHoverActiveState();
+    p->restore();
 }
 
 void
-RenderLayer::clearHoverAndActiveState(RenderObject* obj)
+RenderLayer::paintLayer(RenderLayer* rootLayer, QPainter *p,
+                        const QRect& paintDirtyRect, bool selectionOnly)
 {
-    if (!obj->mouseInside())
-        return;
+    // Calculate the clip rects we should use.
+    QRect layerBounds, damageRect, clipRectToApply;
+    calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply);
+    int x = layerBounds.x();
+    int y = layerBounds.y();
+                             
+    // Ensure our z-order lists are up-to-date.
+    updateZOrderLists();
+
+#if APPLE_CHANGES
+    // Set our transparency if we need to.
+    if (isTransparent())
+        p->beginTransparencyLayer(renderer()->style()->opacity());
+#endif
+    
+    // We want to paint our layer, but only if we intersect the damage rect.
+    bool shouldPaint = intersectsDamageRect(layerBounds, damageRect);
+    if (shouldPaint && !selectionOnly) {
+        // Paint our background first, before painting any child layers.
+        if (!damageRect.isEmpty()) {
+            // Establish the clip used to paint our background.
+            setClip(p, paintDirtyRect, damageRect);
+
+            // Paint the background.
+            renderer()->paint(p, damageRect.x(), damageRect.y(),
+                              damageRect.width(), damageRect.height(),
+                              x - renderer()->xPos(), y - renderer()->yPos(),
+                              PaintActionElementBackground);
+
+            // Position our scrollbars.
+            positionScrollbars(layerBounds);
+
+#if APPLE_CHANGES
+            // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
+            // z-index.  We paint after we painted the background/border, so that the scrollbars will
+            // sit above the background/border.
+            paintScrollbars(p, damageRect);
+#endif
+            // Restore the clip.
+            restoreClip(p, paintDirtyRect, damageRect);
+        }
+    }
+
+    // Now walk the sorted list of children with negative z-indices.
+    if (m_negZOrderList) {
+        uint count = m_negZOrderList->count();
+        for (uint i = 0; i < count; i++) {
+            RenderLayer* child = m_negZOrderList->at(i);
+            child->paintLayer(rootLayer, p, paintDirtyRect, selectionOnly);
+        }
+    }
     
-    obj->setMouseInside(false);
-    if (obj->element()) {
-        obj->element()->setActive(false);
-        if (obj->style()->affectedByHoverRules() || obj->style()->affectedByActiveRules())
-            obj->element()->setChanged(true);
+    // Now establish the appropriate clip and paint our child RenderObjects.
+    if (shouldPaint && !clipRectToApply.isEmpty()) {
+        // Set up the clip used when painting our children.
+        setClip(p, paintDirtyRect, clipRectToApply);
+
+        if (selectionOnly)
+            renderer()->paint(p, clipRectToApply.x(), clipRectToApply.y(),
+                              clipRectToApply.width(), clipRectToApply.height(),
+                              x - renderer()->xPos(), y - renderer()->yPos(), PaintActionSelection);
+        else {
+            renderer()->paint(p, clipRectToApply.x(), clipRectToApply.y(),
+                              clipRectToApply.width(), clipRectToApply.height(),
+                              x - renderer()->xPos(), y - renderer()->yPos(), PaintActionChildBackgrounds);
+            renderer()->paint(p, clipRectToApply.x(), clipRectToApply.y(),
+                              clipRectToApply.width(), clipRectToApply.height(),
+                              x - renderer()->xPos(), y - renderer()->yPos(), PaintActionFloat);
+            renderer()->paint(p, clipRectToApply.x(), clipRectToApply.y(),
+                              clipRectToApply.width(), clipRectToApply.height(),
+                              x - renderer()->xPos(), y - renderer()->yPos(), PaintActionForeground);
+        }
+
+        // Now restore our clip.
+        restoreClip(p, paintDirtyRect, clipRectToApply);
+    }
+    
+    // Now walk the sorted list of children with positive z-indices.
+    if (m_posZOrderList) {
+        uint count = m_posZOrderList->count();
+        for (uint i = 0; i < count; i++) {
+            RenderLayer* child = m_posZOrderList->at(i);
+            child->paintLayer(rootLayer, p, paintDirtyRect, selectionOnly);
+        }
     }
     
-    for (RenderObject* child = obj->firstChild(); child; child = child->nextSibling())
-        if (child->mouseInside())
-            clearHoverAndActiveState(child);
+#if APPLE_CHANGES
+    // End our transparency layer
+    if (isTransparent())
+        p->endTransparencyLayer();
+#endif
 }
 
 bool
 RenderLayer::nodeAtPoint(RenderObject::NodeInfo& info, int x, int y)
 {
-    // Clear out our global scrollbar tracking variable.
-    gScrollBar = 0;
+    QRect damageRect(m_x, m_y, width(), height());
+    RenderLayer* insideLayer = nodeAtPointForLayer(this, info, x, y, damageRect);
+
+    // Now determine if the result is inside an anchor.
+    DOM::NodeImpl* node = info.innerNode();
+    while (node) {
+        if (node->hasAnchor())
+            info.setURLElement(node);
+        node = node->parentNode();
+    }
+
+    // Next set up the correct :hover/:active state along the new chain.
+    updateHoverActiveState(info);
+
+    // Now return whether we were inside this layer (this will always be true for the root
+    // layer).
+    return insideLayer;
+}
+
+RenderLayer*
+RenderLayer::nodeAtPointForLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info,
+                                 int xMousePos, int yMousePos, const QRect& hitTestRect)
+{
+    // Calculate the clip rects we should use.
+    QRect layerBounds, bgRect, fgRect;
+    calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect);
     
-    bool inside = false;
+    // Ensure our z-order lists are up-to-date.
+    updateZOrderLists();
+
+    // This variable tracks which layer the mouse ends up being inside.  The minute we find an insideLayer,
+    // we are done and can return it.
     RenderLayer* insideLayer = 0;
-    QRect damageRect(m_x, m_y, m_width, m_height);
-    RenderZTreeNode* node = constructZTree(damageRect, damageRect, this, true, x, y);
-    if (!node)
-        return false;
-
-    // Flatten the tree into a back-to-front list for painting.
-    QPtrVector<RenderLayerElement> layerList;
-    constructLayerList(node, &layerList);
-
-    // Walk the list and test each layer, adding in the appropriate offset.
-    uint count = layerList.count();
-    for (int i = count-1; i >= 0; i--) {
-        RenderLayerElement* elt = layerList.at(i);
-        
-        // Elements add in their own positions as a translation factor.  This forces
-        // us to subtract that out, so that when it's added back in, we get the right
-        // bounds.  This is really disgusting (that paint only sets up the right paint
-        // position after you call into it). -dwh
-        //printf("Painting layer at %d %d\n", elt->absBounds.x(), elt->absBounds.y());
-
-        inside = elt->layer->renderer()->nodeAtPoint(info, x, y,
-                                      elt->absBounds.x() - elt->layer->renderer()->xPos(),
-                                      elt->absBounds.y() - elt->layer->renderer()->yPos());
-        if (inside) {
-            // For foreground layer elements where the layer has been split into two, we
-            // are only considered to be inside the foreground layer if we hit content other
-            // than ourselves.
-            if (elt->layerElementType == RenderLayerElement::Foreground &&
-                info.innerNode() == elt->layer->renderer()->element()) {
-                inside = false;
-                info.setInnerNode(0);
-                info.setInnerNonSharedNode(0);
-                info.setURLElement(0);
-                continue;
-            }
-            // Otherwise the mouse is inside this layer, and we can stop looking.
-            insideLayer = elt->layer;
-            break;
+    
+    // Begin by walking our list of positive layers from highest z-index down to the lowest
+    // z-index.
+    if (m_posZOrderList) {
+        uint count = m_posZOrderList->count();
+        for (int i = count-1; i >= 0; i--) {
+            RenderLayer* child = m_posZOrderList->at(i);
+            insideLayer = child->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
+            if (insideLayer)
+                return insideLayer;
         }
     }
-    node->detach(renderer()->renderArena());
 
-    if (insideLayer) {
-        // Clear out the other layers' hover/active state
-        insideLayer->clearOtherLayersHoverActiveState();
-    
-        // Now clear out our descendant layers
-        for (RenderLayer* child = insideLayer->firstChild();
-             child; child = child->nextSibling())
-            child->clearHoverAndActiveState(child->renderer());
+    // Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
+    if (containsPoint(xMousePos, yMousePos, fgRect) &&
+        renderer()->nodeAtPoint(info, xMousePos, yMousePos,
+                                layerBounds.x() - renderer()->xPos(),
+                                layerBounds.y() - renderer()->yPos(),
+                                HitTestChildrenOnly))
+        return this;
+        
+    // Now check our negative z-index children.
+    if (m_negZOrderList) {
+        uint count = m_negZOrderList->count();
+        for (int i = count-1; i >= 0; i--) {
+            RenderLayer* child = m_negZOrderList->at(i);
+            insideLayer = child->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
+            if (insideLayer)
+                return insideLayer;
+        }
     }
-    
-    return inside;
+
+    // Next we want to see if the mouse pos is inside this layer but not any of its children.
+    if (containsPoint(xMousePos, yMousePos, bgRect) &&
+        renderer()->nodeAtPoint(info, xMousePos, yMousePos,
+                                layerBounds.x() - renderer()->xPos(),
+                                layerBounds.y() - renderer()->yPos(),
+                                HitTestSelfOnly))
+        return this;
+
+    // No luck.
+    return 0;
 }
 
-RenderLayer::RenderZTreeNode*
-RenderLayer::constructZTree(QRect overflowClipRect, QRect posClipRect,
-                            RenderLayer* rootLayer,
-                            bool eventProcessing, int xMousePos, int yMousePos)
+void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, QRect& overflowClipRect,
+                                     QRect& posClipRect, QRect& fixedClipRect)
 {
-    // The arena we use for allocating our temporary ztree elements.
-    RenderArena* renderArena = renderer()->renderArena();
-    
-    // This variable stores the result we will hand back.
-    RenderZTreeNode* returnNode = 0;
-
-    // FIXME: A child render object or layer could override visibility.  Don't remove this
-    // optimization though until nodeAtPoint is patched as well.
-    //
-    // If a layer isn't visible, then none of its child layers are visible either.
-    // Don't build this branch of the z-tree, since these layers should not be painted.
-    if (renderer()->style()->visibility() != VISIBLE)
-        return 0;
-    
-    // Compute this layer's absolute position, so that we can compare it with our
-    // damage rect and avoid repainting the layer if it falls outside that rect.
-    // An exception to this rule is the root layer, which always paints (hence the
-    // m_parent null check below).
-    updateLayerPosition(); // For relpositioned layers or non-positioned layers,
-                            // we need to keep in sync, since we may have shifted relative
-                            // to our parent layer.
-                               
-    int x = 0;
-    int y = 0;
-    convertToLayerCoords(rootLayer, x, y);
-    QRect layerBounds(x, y, width(), height());
-     
-    returnNode = new (renderArena) RenderZTreeNode(this);
-
-    // Positioned elements are clipped according to the posClipRect.  All other
-    // layers are clipped according to the overflowClipRect.
-    QRect clipRectToApply = m_object->isPositioned() ? posClipRect : overflowClipRect;
-    QRect damageRect = clipRectToApply.intersect(layerBounds);
-    
-    // Clip applies to *us* as well, so go ahead and update the damageRect.
-    if (m_object->hasClip())
-        damageRect = damageRect.intersect(m_object->getClipRect(x,y));
+    if (parent())
+        parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
         
-    // If we establish a clip rect, then we want to intersect that rect
-    // with the damage rect to form a new damage rect.
-    bool clipOriginator = false;
+    updateLayerPosition(); // For relpositioned layers or non-positioned layers,
+                           // we need to keep in sync, since we may have shifted relative
+                           // to our parent layer.
+
+    // A fixed object is essentially the root of its containing block hierarchy, so when
+    // we encounter such an object, we reset our clip rects to the fixedClipRect.
+    if (m_object->style()->position() == FIXED) {
+        posClipRect = fixedClipRect;
+        overflowClipRect = fixedClipRect;
+    }
     
-    // Update the clip rects that will be passed to children layers.
+    // Update the clip rects that will be passed to child layers.
     if (m_object->hasOverflowClip() || m_object->hasClip()) {
         // This layer establishes a clip of some kind.
-        clipOriginator = true;
+        int x = 0;
+        int y = 0;
+        convertToLayerCoords(rootLayer, x, y);
+        
         if (m_object->hasOverflowClip()) {
             QRect newOverflowClip = m_object->getOverflowClipRect(x,y);
             overflowClipRect  = newOverflowClip.intersect(overflowClipRect);
-            clipRectToApply = clipRectToApply.intersect(newOverflowClip);
             if (m_object->isPositioned() || m_object->isRelPositioned())
                 posClipRect = newOverflowClip.intersect(posClipRect);
         }
@@ -908,100 +802,142 @@ RenderLayer::constructZTree(QRect overfl
             QRect newPosClip = m_object->getClipRect(x,y);
             posClipRect = newPosClip.intersect(posClipRect);
             overflowClipRect = overflowClipRect.intersect(posClipRect);
-            clipRectToApply = clipRectToApply.intersect(newPosClip);
+            fixedClipRect = fixedClipRect.intersect(posClipRect);
         }
     }
+}
+
+void RenderLayer::calculateRects(const RenderLayer* rootLayer, const QRect& paintDirtyRect, QRect& layerBounds,
+                                 QRect& backgroundRect, QRect& foregroundRect)
+{
+    QRect overflowClipRect = paintDirtyRect;
+    QRect posClipRect = paintDirtyRect;
+    QRect fixedClipRect = paintDirtyRect;
+    if (parent())
+        parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
+
+    updateLayerPosition();
     
-    // Walk our list of child layers looking only for those layers that have a 
-    // non-negative z-index (a z-index >= 0).
-    RenderZTreeNode* lastChildNode = 0;
-    for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
-        if (child->zIndex() < 0)
-            continue; // Ignore negative z-indices in this first pass.
-
-        RenderZTreeNode* childNode = child->constructZTree(overflowClipRect, posClipRect, 
-                                                           rootLayer, eventProcessing, 
-                                                           xMousePos, yMousePos);
-        if (childNode) {
-            // Put the new node into the tree at the front of the parent's list.
-            if (lastChildNode)
-                lastChildNode->next = childNode;
-            else
-                returnNode->child = childNode;
-            lastChildNode = childNode;
-        }
-    }
+    int x = 0;
+    int y = 0;
+    convertToLayerCoords(rootLayer, x, y);
+    layerBounds = QRect(x,y,width(),height());
 
-    // Now add a leaf node for ourselves, but only if we intersect the damage
-    // rect.  This intersection test is valid only for replaced elements or
-    // block elements, since inline non-replaced elements have a width of 0 (and
-    // thus the layer does too).  We also exclude the root from this test, since
-    // the HTML can be much taller than the root (because of scrolling).
-    if (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isBody() ||
-        renderer()->hasOverhangingFloats() || 
-        (renderer()->isInline() && !renderer()->isReplaced()) ||
-        (eventProcessing && damageRect.contains(xMousePos,yMousePos)) ||
-        (!eventProcessing && layerBounds.intersects(damageRect))) {
-        RenderLayerElement* layerElt = new (renderArena) RenderLayerElement(this, layerBounds, 
-                                                              damageRect, clipRectToApply,
-                                                              clipOriginator, x, y);
-        if (returnNode->child) {
-            RenderZTreeNode* leaf = new (renderArena) RenderZTreeNode(layerElt);
-            leaf->next = returnNode->child;
-            returnNode->child = leaf;
-            
-            // We are an interior node and have other child layers.  Our layer
-            // will need to be sorted with the other layers as though it has
-            // a z-index of 0.
-            if (!layerElt->zauto)
-                layerElt->zindex = 0;
-        }
-        else
-            returnNode->layerElement = layerElt;
-    } 
+    backgroundRect = m_object->style()->position() == FIXED ? fixedClipRect :
+        (m_object->isPositioned() ? posClipRect : overflowClipRect);
+    foregroundRect = backgroundRect;
     
-    // Now look for children that have a negative z-index.
-    for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
-        if (child->zIndex() >= 0)
-            continue; // Ignore non-negative z-indices in this second pass.
-
-        RenderZTreeNode* childNode = child->constructZTree(overflowClipRect, posClipRect,
-                                                           rootLayer, eventProcessing,
-                                                           xMousePos, yMousePos);
-        if (childNode) {
-            // Deal with the case where all our children views had negative z-indices.
-            // Demote our leaf node and make a new interior node that can hold these
-            // children.
-            if (returnNode->layerElement) {
-                RenderZTreeNode* leaf = returnNode;
-                returnNode = new (renderArena) RenderZTreeNode(this);
-                returnNode->child = leaf;
-            }
-            
-            // Put the new node into the tree at the front of the parent's list.
-            childNode->next = returnNode->child;
-            returnNode->child = childNode;
+    // Update the clip rects that will be passed to child layers.
+    if (m_object->hasOverflowClip() || m_object->hasClip()) {
+        // This layer establishes a clip of some kind.
+        if (m_object->hasOverflowClip())
+            foregroundRect = foregroundRect.intersect(m_object->getOverflowClipRect(x,y));
+        if (m_object->hasClip()) {
+            // Clip applies to *us* as well, so go ahead and update the damageRect.
+            QRect newPosClip = m_object->getClipRect(x,y);
+            backgroundRect = backgroundRect.intersect(newPosClip);
+            foregroundRect = foregroundRect.intersect(newPosClip);
         }
+
+        // If we establish a clip at all, then go ahead and make sure our background
+        // rect is intersected with our layer's bounds.
+        backgroundRect = backgroundRect.intersect(layerBounds);
     }
-    
-    return returnNode;
 }
 
-void
-RenderLayer::constructLayerList(RenderZTreeNode* ztree, QPtrVector<RenderLayerElement>* result)
+bool RenderLayer::intersectsDamageRect(const QRect& layerBounds, const QRect& damageRect) const
 {
-    // This merge buffer is just a temporary used during computation as we do merge sorting.
-    QPtrVector<RenderLayerElement> mergeBuffer;
-    ztree->constructLayerList(&mergeBuffer, result);
+    return (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isBody() ||
+            renderer()->hasOverhangingFloats() ||
+            (renderer()->isInline() && !renderer()->isReplaced()) ||
+            layerBounds.intersects(damageRect));
 }
 
+bool RenderLayer::containsPoint(int x, int y, const QRect& damageRect) const
+{
+    return (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isBody() ||
+            renderer()->hasOverhangingFloats() ||
+            (renderer()->isInline() && !renderer()->isReplaced()) ||
+            damageRect.contains(x, y));
+}
+
+// This code has been written to anticipate the addition of CSS3-::outside and ::inside generated
+// content (and perhaps XBL).  That's why it uses the render tree and not the DOM tree.
+static RenderObject* hoverAncestor(RenderObject* obj)
+{
+    return (!obj->isInline() && obj->continuation()) ? obj->continuation() : obj->parent();
+}
+
+static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2)
+{
+    if (!obj1 || !obj2)
+        return 0;
+
+    for (RenderObject* currObj1 = obj1; currObj1; currObj1 = hoverAncestor(currObj1))
+        for (RenderObject* currObj2 = obj2; currObj2; currObj2 = hoverAncestor(currObj2))
+            if (currObj1 == currObj2)
+                return currObj1;
+
+    return 0;
+}
+
+void RenderLayer::updateHoverActiveState(RenderObject::NodeInfo& info)
+{
+    // We don't update :hover/:active state when the info is marked as readonly.
+    if (info.readonly())
+        return;
+    
+    // Check to see if the hovered node has changed.  If not, then we don't need to
+    // do anything.  An exception is if we just went from :hover into :hover:active,
+    // in which case we need to update to get the new :active state.
+    DOM::NodeImpl* oldHoverNode = info.innerNode()->getDocument()->hoverNode();
+    DOM::NodeImpl* newHoverNode = info.innerNode();
+        
+    if (oldHoverNode == newHoverNode && oldHoverNode->active() == info.active())
+        return;
+
+    // Update our current hover node.
+    info.innerNode()->getDocument()->setHoverNode(newHoverNode);
+    
+    // We have two different objects.  Fetch their renderers.
+    RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
+    RenderObject* newHoverObj = info.innerNode() ? info.innerNode()->renderer() : 0;
+    
+    // Locate the common ancestor render object for the two renderers.
+    RenderObject* ancestor = commonAncestor(oldHoverObj, newHoverObj);
+    
+    // The old hover path only needs to be cleared up to (and not including) the common ancestor;
+    for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = hoverAncestor(curr)) {
+        curr->setMouseInside(false);
+        if (curr->element() && !curr->isText()) {
+            bool oldActive = curr->element()->active();
+            curr->element()->setActive(false);
+            if (curr->style()->affectedByHoverRules() ||
+                (curr->style()->affectedByActiveRules() && oldActive))
+                curr->element()->setChanged();
+        }
+    }
+
+    // Now set the hover state for our new object up to the root.
+    for (RenderObject* curr = newHoverObj; curr; curr = hoverAncestor(curr)) {
+        bool oldInside = curr->mouseInside();
+        curr->setMouseInside(true);
+        if (curr->element() && !curr->isText()) {
+            bool oldActive = curr->element()->active();
+            curr->element()->setActive(info.active());
+            if ((curr->style()->affectedByHoverRules() && !oldInside) ||
+                (curr->style()->affectedByActiveRules() && oldActive != info.active()))
+                curr->element()->setChanged();
+        }
+    }
+}
+
 // Sort the buffer from lowest z-index to highest.  The common scenario will have
 // most z-indices equal, so we optimize for that case (i.e., the list will be mostly
 // sorted already).
-static void sortByZOrder(QPtrVector<RenderLayer::RenderLayerElement>* buffer,
-                         QPtrVector<RenderLayer::RenderLayerElement>* mergeBuffer,
-                         uint start,
-                         uint end)
+static void sortByZOrder(QPtrVector<RenderLayer::RenderLayer>* buffer,
+                         QPtrVector<RenderLayer::RenderLayer>* mergeBuffer,
+                         uint start, uint end)
 {
     if (start >= end)
         return; // Sanity check.
@@ -1011,9 +947,9 @@ static void sortByZOrder(QPtrVector<Rend
         for (uint i = end-1; i > start; i--) {
             bool sorted = true;
             for (uint j = start; j < i; j++) {
-                RenderLayer::RenderLayerElement* elt = buffer->at(j);
-                RenderLayer::RenderLayerElement* elt2 = buffer->at(j+1);
-                if (elt->zindex > elt2->zindex) {
+                RenderLayer* elt = buffer->at(j);
+                RenderLayer* elt2 = buffer->at(j+1);
+                if (elt->zIndex() > elt2->zIndex()) {
                     sorted = false;
                     buffer->insert(j, elt2);
                     buffer->insert(j+1, elt);
@@ -1029,12 +965,12 @@ static void sortByZOrder(QPtrVector<Rend
         sortByZOrder(buffer, mergeBuffer, start, mid);
         sortByZOrder(buffer, mergeBuffer, mid, end);
 
-        RenderLayer::RenderLayerElement* elt = buffer->at(mid-1);
-        RenderLayer::RenderLayerElement* elt2 = buffer->at(mid);
+        RenderLayer* elt = buffer->at(mid-1);
+        RenderLayer* elt2 = buffer->at(mid);
 
         // Handle the fast common case (of equal z-indices).  The list may already
         // be completely sorted.
-        if (elt->zindex <= elt2->zindex)
+        if (elt->zIndex() <= elt2->zIndex())
             return;
 
         // We have to merge sort.  Ensure our merge buffer is big enough to hold
@@ -1047,7 +983,7 @@ static void sortByZOrder(QPtrVector<Rend
         elt2 = buffer->at(i2);
 
         while (i1 < mid || i2 < end) {
-            if (i1 < mid && (i2 == end || elt->zindex <= elt2->zindex)) {
+            if (i1 < mid && (i2 == end || elt->zIndex() <= elt2->zIndex())) {
                 mergeBuffer->insert(mergeBuffer->count(), elt);
                 i1++;
                 if (i1 < mid)
@@ -1068,160 +1004,62 @@ static void sortByZOrder(QPtrVector<Rend
     }
 }
 
-void RenderLayer::RenderZTreeNode::constructLayerList(QPtrVector<RenderLayerElement>* mergeTmpBuffer,
-                                                      QPtrVector<RenderLayerElement>* buffer)
+void RenderLayer::dirtyZOrderLists()
 {
-    // The root always establishes a stacking context.  We could add a rule for this
-    // to the UA sheet, but this code guarantees that nobody can do anything wacky
-    // in CSS to prevent the root from establishing a stacking context.
-    bool autoZIndex = layer->parent() ? layer->hasAutoZIndex() : false;
-    int explicitZIndex = layer->zIndex();
-
-    if (layerElement) {
-        // We are a leaf node of the ztree, and so we just place our layer element into
-        // the buffer.
-        if (buffer->count() == buffer->size())
-            // Resize by a power of 2.
-            buffer->resize(2*(buffer->size()+1));
-        
-        buffer->insert(buffer->count(), layerElement);
-        return;
-    }
-
-    uint startIndex = buffer->count();
-    for (RenderZTreeNode* current = child; current; current = current->next)
-        current->constructLayerList(mergeTmpBuffer, buffer);
-    uint endIndex = buffer->count();
-
-    if (autoZIndex || !(endIndex-startIndex))
-        return; // We just had to collect the kids.  We don't apply a sort to them, since
-                // they will actually be layered in some ancestor layer's stacking context.
-    
-    sortByZOrder(buffer, mergeTmpBuffer, startIndex, endIndex);
-
-    // Find out if we have any elements with negative z-indices in this stacking context.
-    // If so, then we need to split our layer in two (a background layer and a foreground
-    // layer).  We then put the background layer before the negative z-index objects, and
-    // leave the foreground layer in the position previously occupied by the unsplit original.
-    RenderLayerElement* elt = buffer->at(startIndex);
-    if (elt->zindex < 0) {
-        // Locate our layer in the layer list.
-        for (uint i = startIndex; i < endIndex; i++) {
-            elt = buffer->at(i);
-            if (elt->layer == layer) {
-                // Clone the layer element.
-                RenderLayerElement* bgLayer =
-                  new (layer->renderer()->renderArena()) RenderLayerElement(*elt);
-
-                // Set the layer types (foreground and background) on the two layer elements.
-                elt->layerElementType = RenderLayerElement::Foreground;
-                bgLayer->layerElementType = RenderLayerElement::Background;
-
-                // Ensure our buffer is big enough to hold a new layer element.
-                if (buffer->count() == buffer->size())
-                    // Resize by a power of 2.
-                    buffer->resize(2*(buffer->size()+1));
-
-                // Insert the background layer element at the front of our sorted list.
-                for (uint j = buffer->count(); j > startIndex; j--)
-                    buffer->insert(j, buffer->at(j-1));
-                buffer->insert(startIndex, bgLayer);
-
-                // Augment endIndex since we added a layer element.
-                endIndex++;
-                break;
-            }
-        }
-    }
-    
-    // Now set all of the elements' z-indices to match the parent's explicit z-index, so that
-    // they will be layered properly in the ancestor layer's stacking context.
-    for (uint i = startIndex; i < endIndex; i++) {
-        elt = buffer->at(i);
-        elt->zindex = explicitZIndex;
-    }
+    if (m_posZOrderList)
+        m_posZOrderList->clear();
+    if (m_negZOrderList)
+        m_negZOrderList->clear();
+    m_zOrderListsDirty = true;
 }
-
-void* RenderLayer::RenderLayerElement::operator new(size_t sz, RenderArena* renderArena) throw()
-{
-    void* result = renderArena->allocate(sz);
-    if (result)
-        memset(result, 0, sz);
-    return result;
-}
-
-void RenderLayer::RenderLayerElement::operator delete(void* ptr, size_t sz)
-{
-    assert(inRenderLayerElementDetach);
-    
-    // Stash size where detach can find it.
-    *(size_t *)ptr = sz;
-}
-
-void RenderLayer::RenderLayerElement::detach(RenderArena* renderArena)
-{
-#ifndef NDEBUG
-    inRenderLayerElementDetach = true;
-#endif
-    delete this;
-#ifndef NDEBUG
-    inRenderLayerElementDetach = false;
-#endif
     
-    // Recover the size left there for us by operator delete and free the memory.
-    renderArena->free(*(size_t *)this, this);
-}
-
-void* RenderLayer::RenderZTreeNode::operator new(size_t sz, RenderArena* renderArena) throw()
+void RenderLayer::updateZOrderLists()
 {
-    void* result = renderArena->allocate(sz);
-    if (result)
-        memset(result, 0, sz);
-    return result;
-}
-
-void RenderLayer::RenderZTreeNode::operator delete(void* ptr, size_t sz)
-{
-    assert(inRenderZTreeNodeDetach);
+    if (!isStackingContext() || !m_zOrderListsDirty)
+        return;
     
-    // Stash size where detach can find it.
-    *(size_t *)ptr = sz;
-}
+    for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
+        child->collectLayers(m_posZOrderList, m_negZOrderList);
 
-void RenderLayer::RenderZTreeNode::detach(RenderArena* renderArena)
-{
-    assert(!next);
-    
-    RenderZTreeNode *n;
-    for (RenderZTreeNode *c = child; c; c = n) {
-        n = c->next;
-        c->next = 0;
-        c->detach(renderArena);
+    // Sort the two lists.
+    if (m_posZOrderList) {
+        QPtrVector<RenderLayer> mergeBuffer;
+        sortByZOrder(m_posZOrderList, &mergeBuffer, 0, m_posZOrderList->count());
     }
-    if (layerElement)
-        layerElement->detach(renderArena);
+    if (m_negZOrderList) {
+        QPtrVector<RenderLayer> mergeBuffer;
+        sortByZOrder(m_negZOrderList, &mergeBuffer, 0, m_negZOrderList->count());
+    }
 
-#ifndef NDEBUG
-    inRenderZTreeNodeDetach = true;
-#endif
-    delete this;
-#ifndef NDEBUG
-    inRenderZTreeNodeDetach = false;
-#endif
-    
-    // Recover the size left there for us by operator delete and free the memory.
-    renderArena->free(*(size_t *)this, this);
+    m_zOrderListsDirty = false;
 }
 
-QPtrVector<RenderLayer::RenderLayerElement> RenderLayer::elementList(RenderZTreeNode *&node)
+void RenderLayer::collectLayers(QPtrVector<RenderLayer>*& posBuffer, QPtrVector<RenderLayer>*& negBuffer)
 {
-    QPtrVector<RenderLayerElement> list;
+    // FIXME: A child render object or layer could override visibility.  Don't remove this
+    // optimization though until RenderObject's nodeAtPoint is patched to understand what to do
+    // when visibility is overridden by a child.
+    if (renderer()->style()->visibility() != VISIBLE)
+        return;
     
-    QRect damageRect(m_x, m_y, m_width, m_height);
-    node = constructZTree(damageRect, damageRect, this);
-    if (node) {
-        constructLayerList(node, &list);
+    // Determine which buffer the child should be in.
+    QPtrVector<RenderLayer>*& buffer = (zIndex() >= 0) ? posBuffer : negBuffer;
+
+    // Create the buffer if it doesn't exist yet.
+    if (!buffer)
+        buffer = new QPtrVector<RenderLayer>();
+    
+    // Resize by a power of 2 when our buffer fills up.
+    if (buffer->count() == buffer->size())
+        buffer->resize(2*(buffer->size()+1));
+
+    // Append ourselves at the end of the appropriate buffer.
+    buffer->insert(buffer->count(), this);
+
+    // Recur into our children to collect more layers, but only if we don't establish
+    // a stacking context.
+    if (!isStackingContext()) {
+        for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
+            child->collectLayers(posBuffer, negBuffer);
     }
-    
-    return list;
 }
Index: khtml/rendering/render_layer.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_layer.h,v
retrieving revision 1.27
diff -u -p -r1.27 khtml/rendering/render_layer.h
--- khtml/rendering/render_layer.h	2003/07/11 17:55:42	1.27
+++ khtml/rendering/render_layer.h	2003/09/01 08:16:19
@@ -49,9 +49,10 @@
 #include <assert.h>
 
 #include "render_object.h"
-#include <qvector.h>
-#include <qscrollbar.h>
 
+class QScrollBar;
+template <class T> class QPtrVector;
+
 namespace khtml {
     class RenderStyle;
     class RenderTable;
@@ -60,7 +61,8 @@ namespace khtml {
     class RenderText;
     class RenderFrameSet;
     class RenderObject;
-
+    class RenderScrollMediator;
+    
 class RenderScrollMediator: public QObject
 {
 public:
@@ -76,6 +78,10 @@ private:
 class RenderLayer
 {
 public:
+#ifdef APPLE_CHANGES
+    static QScrollBar* gScrollBar;
+#endif
+    
     RenderLayer(RenderObject* object);
     ~RenderLayer();
     
@@ -90,14 +96,13 @@ public:
     void addChild(RenderLayer *newChild, RenderLayer* beforeChild = 0);
     RenderLayer* removeChild(RenderLayer *oldChild);
 
-    RenderLayer* transparentAncestor();
-    bool isTransparent();
-    void updateTransparentState(QPainter* painter, RenderLayer* newLayer, RenderLayer*& currLayer);
-    void beginTransparencyLayers(QPainter* painter, RenderLayer* newLayer, RenderLayer* ancestorLayer);
-    void endTransparencyLayers(QPainter* painter, RenderLayer* newLayer, RenderLayer* ancestorLayer);
-    
     void removeOnlyThisLayer();
     void insertOnlyThisLayer();
+
+#if APPLE_CHANGES
+    bool isTransparent();
+    RenderLayer* transparentAncestor();
+#endif
     
     RenderLayer* root() {
         RenderLayer* curr = this;
@@ -109,15 +114,13 @@ public:
     int yPos() const { return m_y; }
     short width() const { return m_width; }
     int height() const { return m_height; }
+
+    void setWidth(short w) { m_width = w; }
+    void setHeight(int h) { m_height = h; }
+    
     short scrollWidth() const { return m_scrollWidth; }
     int scrollHeight() const { return m_scrollHeight; }
     
-    void setWidth( int width ) {
-        m_width = width;
-    }
-    void setHeight( int height ) {
-        m_height = height;
-    }
     void setPos( int xPos, int yPos ) {
         m_x = xPos;
         m_y = yPos;
@@ -133,40 +136,62 @@ public:
     void scrollToYOffset(int y) { scrollToOffset(m_scrollX, y); }
     void setHasHorizontalScrollbar(bool hasScrollbar);
     void setHasVerticalScrollbar(bool hasScrollbar);
-    QWidget* horizontalScrollbar() { return m_hBar; }
-    QWidget* verticalScrollbar() { return m_vBar; }
+    QScrollBar* horizontalScrollbar() { return m_hBar; }
+    QScrollBar* verticalScrollbar() { return m_vBar; }
     int verticalScrollbarWidth();
     int horizontalScrollbarHeight();
     void moveScrollbarsAside();
     void positionScrollbars(const QRect& absBounds);
-    void paintScrollbars(QPainter* p, int x, int y, int w, int h);
+#ifdef APPLE_CHANGES
+    void paintScrollbars(QPainter* p, const QRect& damageRect);
+#endif
     void checkScrollbarsAfterLayout();
     void slotValueChanged(int);
     void updateScrollPositionFromScrollbars();
-    
+
     void updateLayerPosition();
+
+    // Get the enclosing stacking context for this layer.  A stacking context is a layer
+    // that has a non-auto z-index.
+    RenderLayer* stackingContext() const;
+    bool isStackingContext() const { return !hasAutoZIndex() || renderer()->isCanvas(); }
+
+    void dirtyZOrderLists();
+    void updateZOrderLists();
+    QPtrVector<RenderLayer>* posZOrderList() const { return m_posZOrderList; }
+    QPtrVector<RenderLayer>* negZOrderList() const { return m_negZOrderList; }
     
     // Gets the nearest enclosing positioned ancestor layer (also includes
     // the <html> layer and the root layer).
-    RenderLayer* enclosingPositionedAncestor();
+    RenderLayer* enclosingPositionedAncestor() const;
     
-    void convertToLayerCoords(RenderLayer* ancestorLayer, int& x, int& y);
+    void convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const;
     
-    bool hasAutoZIndex() { return renderer()->style()->hasAutoZIndex(); }
-    int zIndex() { return renderer()->style()->zIndex(); }
+    bool hasAutoZIndex() const { return renderer()->style()->hasAutoZIndex(); }
+    int zIndex() const { return renderer()->style()->zIndex(); }
 
     // The two main functions that use the layer system.  The paint method
     // paints the layers that intersect the damage rect from back to
     // front.  The nodeAtPoint method looks for mouse events by walking
     // layers that intersect the point from front to back.
-    void paint(QPainter *p, int x, int y, int w, int h, bool selectionOnly=false);
+    void paint(QPainter *p, const QRect& damageRect, bool selectionOnly=false);
     bool nodeAtPoint(RenderObject::NodeInfo& info, int x, int y);
+
+    // This method figures out our layerBounds in coordinates relative to
+    // |rootLayer}.  It also computes our background and foreground clip rects
+    // for painting/event handling.
+    void calculateRects(const RenderLayer* rootLayer, const QRect& paintDirtyRect, QRect& layerBounds,
+                        QRect& backgroundRect, QRect& foregroundRect);
+    void calculateClipRects(const RenderLayer* rootLayer, QRect& overflowClipRect,
+                            QRect& posClipRect, QRect& fixedClipRect);
+
+    bool intersectsDamageRect(const QRect& layerBounds, const QRect& damageRect) const;
+    bool containsPoint(int x, int y, const QRect& damageRect) const;
     
-    void clearOtherLayersHoverActiveState();
-    void clearHoverAndActiveState(RenderObject* obj);
+    void updateHoverActiveState(RenderObject::NodeInfo& info);
     
     void detach(RenderArena* renderArena);
-    
+
      // Overloaded new operator.  Derived classes must override operator new
     // in order to allocate out of the RenderArena.
     void* operator new(size_t sz, RenderArena* renderArena) throw();    
@@ -178,179 +203,6 @@ private:
     // The normal operator new is disallowed on all render objects.
     void* operator new(size_t sz) throw();
 
-public:
-    // Z-Index Implementation Notes
-    //
-    // In order to properly handle mouse events as well as painting,
-    // we must compute a correct list of layers that should be painted
-    // from back to front (and for mouse events walked from front to
-    // back).
-    //
-    // Positioned elements in the render tree (e.g., relative positioned
-    // divs and absolute positioned divs) have a corresponding layer
-    // that holds them and all children that reside in the same layer.
-    //
-    // When painting is performed on a layer, all render objects in that
-    // layer are painted.  If the render object has descendants in another
-    // layer, those will be dealt with separately.
-    //
-    // A RenderLayerElement represents a single entry in our list of
-    // layers that should be painted.  We perform computations as we
-    // build up this list so that we have the correct translation factor
-    // for painting.  We also use a temporary z-index variable for storage
-    // (more on this below).
-    // 
-    struct RenderLayerElement {
-      enum LayerElementType { Normal, Background, Foreground };
-        
-      RenderLayer* layer;
-      QRect absBounds; // Our bounds in absolute coordinates relative to the root.
-      QRect backgroundClipRect; // Clip rect used for our background/borders. 
-      QRect clipRect; // Clip rect used for our children.
-      int zindex; // Temporary z-index used for processing and sorting.
-      bool zauto : 1; // Whether or not we are using auto z-indexing.
-      bool clipOriginator : 1; // Whether or not we established a clip.
-      int x; // The coords relative to the layer that will be using this list
-             // to paint.
-      int y;
-      LayerElementType layerElementType; // For negative z-indices, we have to split a single layer into two
-                           // RenderLayerElements, one that sits beneath the negative content, and
-                           // another that sits above (denoted with values of Background and Foreground,
-                           // respectively).  A normal layer that fully paints is denoted with the value Normal.
-      
-      RenderLayerElement(RenderLayer* l, const QRect& rect, const QRect& bgclip, 
-                         const QRect& clip, bool clipOrig, int xpos, int ypos,
-                         LayerElementType lType = Normal)
-          :layer(l), absBounds(rect), backgroundClipRect(bgclip), clipRect(clip), 
-           zindex(l->zIndex()), zauto(l->hasAutoZIndex()), clipOriginator(clipOrig),
-           x(xpos), y(ypos), layerElementType(lType) {}
-          
-      void detach(RenderArena* renderArena);
-    
-      // Overloaded new operator.  Derived classes must override operator new
-      // in order to allocate out of the RenderArena.
-      void* operator new(size_t sz, RenderArena* renderArena) throw();    
-
-      // Overridden to prevent the normal delete from being called.
-      void operator delete(void* ptr, size_t sz);
-        
-      // The normal operator new is disallowed.
-      void* operator new(size_t sz) throw();
-    };
-
-    // The list of layer elements is built through a recursive examination
-    // of a tree of z nodes. This tree structure mimics the layer 
-    // hierarchy itself, but only leaf nodes represent items that will
-    // end up in the layer list for painting.
-    //
-    // Every leaf layer in the layer hierarchy will have a corresponding
-    // leaf node in the z-tree.  Layers with children have an
-    // interior z-tree node that contains the tree nodes for the child
-    // layers as well as a leaf node that represents the containing layer.
-    //
-    // Sibling z-tree nodes match the same order as the layers in the
-    // layer hierarchy, which will have been arranged in document order
-    // when the render tree was constructed (since the render tree
-    // constructed the layers).  An exception is if a negative z-index
-    // is specified on a child (see below).
-    
-    struct RenderZTreeNode {
-      RenderLayer* layer;
-      RenderZTreeNode* next;
-
-      // Only one of these will ever be defined.
-      RenderZTreeNode* child; // Defined for interior nodes.
-      RenderLayerElement* layerElement; // Defined for leaf nodes.
-
-      RenderZTreeNode(RenderLayer* l)
-          :layer(l), next(0), child(0), layerElement(0) {}
-
-      RenderZTreeNode(RenderLayerElement* layerElt)
-          :layer(layerElt->layer), next(0), child(0), layerElement(layerElt) {}
-      
-      ~RenderZTreeNode() {}
-
-      void constructLayerList(QPtrVector<RenderLayerElement>* mergeTmpBuffer,
-                              QPtrVector<RenderLayerElement>* finalBuffer);
-      
-      void detach(RenderArena* renderArena);
-          
-      // Overloaded new operator.  Derived classes must override operator new
-      // in order to allocate out of the RenderArena.
-      void* operator new(size_t sz, RenderArena* renderArena) throw();    
-
-      // Overridden to prevent the normal delete from being called.
-      void operator delete(void* ptr, size_t sz);
-        
-      // The normal operator new is disallowed.
-      void* operator new(size_t sz) throw();
-    };
-
-    static QWidget* gScrollBar;
-
-    // For debugging.
-    QPtrVector<RenderLayerElement> elementList(RenderZTreeNode *&node);
-      
-private:
-    // The constructZTree function creates a z-tree for a given layer hierarchy
-    // rooted on this layer.  It will ensure that immediate child
-    // elements of a given z-tree node are at least initially sorted
-    // into <negative z-index children>, <this layer>, <non-negative z-index
-    // children>.
-    //
-    // Here is a concrete example (lifted from Gecko's view system,
-    // which is analogous to our layer system and works the same way):
-    // z-index values as specified by CSS are shown in parentheses.
-    //
-    // L0(auto) --> L1(0) --> L2(auto) --> L3(0)
-    // |        |    +------> L4(2)
-    // |        +-----------> L5(1)
-    // +--------------------> L6(1)
-    //
-    // The corresponding z-tree for this layer hierarchy will be
-    // the following, where |I| represents an interior node, and |L|
-    // represents a leaf RenderLayerElement.
-    //
-    // I(L0) --> L(L0)
-    // +-------> I(L1) --------> L(L1)
-    // |           |   +-------> I(L2) ------> L(L2)
-    // |           |               +---------> L(L3)
-    // |           +-----------> L(L4)
-    // +-------> L(L5)
-    // +-------> L(L6)
-    //
-    RenderZTreeNode* constructZTree(QRect overflowClipRect,
-                                    QRect clipRect,
-                                    RenderLayer* rootLayer,
-                                    bool eventProcessing = false, int x=0, int y=0);
-
-    // Once the z-tree has been constructed, we call constructLayerList
-    // to produce a flattened layer list for rendering/event handling.
-    // This function recursively computes a layer list for each z-tree
-    // node by computing lists for each child node.  It then concatenates
-    // them and sorts them by z-index.
-    //
-    // Z-indices are updated during this computation.  After a list is
-    // computed for one z-tree node, the elements of the layer list are
-    // all changed so that their z-indices match the specified z-index
-    // of the tree node's layer (unless that layer doesn't establish
-    // a z-index, e.g., it just has z-index: auto).
-    //
-    // Continuing the above example, the computation of the list for
-    // L0 would be as follows:
-    //
-    // I(L2) has a list [ L(L2)(0), L(L3)(0), L(L4)(2) ]
-    // I(L2) is auto so the z-indices of the child layer elements remain
-    // unaltered.
-    // I(L1) has a list [ L(L1)(0), L(L2)(0), L(L3)(0), L(L4)(2), L(L5)(1) ]
-    // The nodes are sorted and then reassigned a z-index of 0, so this
-    // list becomes:
-    // [ L(L1)(0), L(L2)(0), L(L3)(0), L(L5)(0), L(L4)(0) ]
-    // Finally we end up with the list for L0, which sorted becomes:
-    // [ L(L0)(0), L(L1)(0), L(L2)(0), L(L3)(0), L(L5)(0), L(L4)(0), L(L6)(1) ]
-    void constructLayerList(RenderZTreeNode* ztree,
-                            QPtrVector<RenderLayerElement>* result);
-
 private:
     void setNextSibling(RenderLayer* next) { m_next = next; }
     void setPreviousSibling(RenderLayer* prev) { m_previous = prev; }
@@ -358,34 +210,50 @@ private:
     void setFirstChild(RenderLayer* first) { m_first = first; }
     void setLastChild(RenderLayer* last) { m_last = last; }
 
+    void collectLayers(QPtrVector<RenderLayer>*&, QPtrVector<RenderLayer>*&);
+
+    void paintLayer(RenderLayer* rootLayer, QPainter *p, const QRect& paintDirtyRect, bool selectionOnly=false);
+    RenderLayer* nodeAtPointForLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info,
+                                     int x, int y, const QRect& hitTestRect);
+
 protected:   
     RenderObject* m_object;
     
-    RenderLayer *m_parent;
-    RenderLayer *m_previous;
-    RenderLayer *m_next;
+    RenderLayer* m_parent;
+    RenderLayer* m_previous;
+    RenderLayer* m_next;
 
-    RenderLayer *m_first;
-    RenderLayer *m_last;
+    RenderLayer* m_first;
+    RenderLayer* m_last;
     
     // Our (x,y) coordinates are in our parent layer's coordinate space.
-    int m_height;
-    int m_y;
     short m_x;
-    short m_width;
+    int m_y;
 
+    // The layer's width/height
+    short m_width;
+    int m_height;
+    
     // Our scroll offsets if the view is scrolled.
     short m_scrollX;
     int m_scrollY;
-
+    
     // The width/height of our scrolled area.
     short m_scrollWidth;
-    short m_scrollHeight;
+    int m_scrollHeight;
     
     // For layers with overflow, we have a pair of scrollbars.
     QScrollBar* m_hBar;
     QScrollBar* m_vBar;
     RenderScrollMediator* m_scrollMediator;
+
+    // For layers that establish stacking contexts, m_posZOrderList holds a sorted list of all the
+    // descendant layers within the stacking context that have z-indices of 0 or greater
+    // (auto will count as 0).  m_negZOrderList holds descendants within our stacking context with negative
+    // z-indices.
+    QPtrVector<RenderLayer>* m_posZOrderList;
+    QPtrVector<RenderLayer>* m_negZOrderList;
+    bool m_zOrderListsDirty;
 };
 
 }; // namespace
Index: khtml/rendering/render_object.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_object.cpp,v
retrieving revision 1.97
diff -u -p -r1.97 khtml/rendering/render_object.cpp
--- khtml/rendering/render_object.cpp	2003/08/20 22:03:24	1.97
+++ khtml/rendering/render_object.cpp	2003/09/01 08:16:21
@@ -983,6 +983,20 @@ void RenderObject::setStyle(RenderStyle 
     if (m_style == style)
         return;
 
+    // If our z-index changes value or our visibility changes,
+    // we need to dirty our stacking context's z-order list.
+    if (m_style && style) {
+        if ((m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
+             m_style->zIndex() != style->zIndex() ||
+             m_style->visibility() != style->visibility()) && layer()) {
+            layer()->stackingContext()->dirtyZOrderLists();
+            if (m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
+                m_style->visibility() != style->visibility())
+                layer()->dirtyZOrderLists();
+        }
+    }
+
+    // If z-index goes from auto to numbered or vice versa, we dirty our own z
     RenderStyle::Diff d = m_style ? m_style->diff( style ) : RenderStyle::Layout;
 
     if (m_style && m_parent && d == RenderStyle::Visible && !isText())
@@ -1335,21 +1349,9 @@ bool RenderObject::mouseInside() const
         return continuation()->mouseInside();
     return m_mouseInside; 
 }
-
-void RenderObject::setHoverAndActive(NodeInfo& info, bool oldinside, bool inside)
-{
-    DOM::NodeImpl* elt = element();
-    if (elt) {
-        bool oldactive = elt->active();
-        if (oldactive != (inside && info.active()))
-            elt->setActive(inside && info.active());
-        if ((oldinside != mouseInside() && style()->affectedByHoverRules()) ||
-            (oldactive != elt->active() && style()->affectedByActiveRules()))
-            elt->setChanged();
-    }
-}
 
-bool RenderObject::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, bool inside)
+bool RenderObject::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
+                               HitTestAction hitTestAction, bool inside)
 {
     int tx = _tx + xPos();
     int ty = _ty + yPos();
@@ -1363,11 +1365,14 @@ bool RenderObject::nodeAtPoint(NodeInfo&
     }
     
     // ### table should have its own, more performant method
-    if ((!isRenderBlock() ||
+    if (hitTestAction != HitTestSelfOnly &&
+        ((!isRenderBlock() ||
          !static_cast<RenderBlock*>(this)->isPointInScrollbar(_x, _y, _tx, _ty)) &&
         (overhangingContents() || inOverflowRect || isInline() || isCanvas() ||
          isTableRow() || isTableSection() || inside || mouseInside() ||
-         (childrenInline() && firstChild() && firstChild()->isCompact()))) {
+         (childrenInline() && firstChild() && firstChild()->isCompact())))) {
+        if (hitTestAction == HitTestChildrenOnly)
+            inside = false;
         int stx = _tx + xPos();
         int sty = _ty + yPos();
         if (style()->hidesOverflow() && layer())
@@ -1394,28 +1399,6 @@ bool RenderObject::nodeAtPoint(NodeInfo&
 
         if(!info.innerNonSharedNode() && element())
             info.setInnerNonSharedNode(element());
-        
-        if (!info.URLElement()) {
-            RenderObject* p = (!isInline() && continuation()) ? continuation() : this;
-            while (p) {
-                if (p->element() && p->element()->hasAnchor()) {
-                    info.setURLElement(p->element());
-                    break;
-                }
-                if (!isFloatingOrPositioned()) break;
-                p = p->parent();
-            }
-        }
-    }
-
-    if (!info.readonly()) {
-        // lets see if we need a new style
-        bool oldinside = mouseInside();
-        setMouseInside(inside);
-        
-        setHoverAndActive(info, oldinside, inside);
-        if (!isInline() && continuation())
-            continuation()->setHoverAndActive(info, oldinside, inside);
     }
 
     return inside;
Index: khtml/rendering/render_object.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_object.h,v
retrieving revision 1.79
diff -u -p -r1.79 khtml/rendering/render_object.h
--- khtml/rendering/render_object.h	2003/08/11 23:41:02	1.79
+++ khtml/rendering/render_object.h	2003/09/01 08:16:22
@@ -70,6 +70,12 @@ typedef enum {
     PaintActionSelection
 } PaintAction;
 
+typedef enum {
+    HitTestAll = 0,
+    HitTestSelfOnly = 1,
+    HitTestChildrenOnly = 2
+} HitTestAction;
+
 namespace DOM {
     class HTMLAreaElementImpl;
     class DOMString;
@@ -405,8 +411,8 @@ public:
 
     FindSelectionResult checkSelectionPoint(int x, int y, int tx, int ty, DOM::NodeImpl*&, int& offset);
     virtual FindSelectionResult checkSelectionPointIgnoringContinuations(int x, int y, int tx, int ty, DOM::NodeImpl*&, int& offset);
-    virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, bool inside=false);
-    void setHoverAndActive(NodeInfo& info, bool oldinside, bool inside);
+    virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty,
+                             HitTestAction hitTestAction = HitTestAll, bool inside=false);
     
     // set the style of the object.
     virtual void setStyle(RenderStyle *style);
Index: khtml/rendering/render_text.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_text.cpp,v
retrieving revision 1.78
diff -u -p -r1.78 khtml/rendering/render_text.cpp
--- khtml/rendering/render_text.cpp	2003/08/27 22:57:14	1.78
+++ khtml/rendering/render_text.cpp	2003/09/01 08:16:24
@@ -377,7 +377,8 @@ TextRun * RenderText::findTextRun( int o
     return s;
 }
 
-bool RenderText::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty, bool inside)
+bool RenderText::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
+                             HitTestAction hitTestAction, bool inside)
 {
     assert(parent());
 
@@ -393,8 +394,6 @@ bool RenderText::nodeAtPoint(NodeInfo& i
         s = si < (int) m_lines.count()-1 ? m_lines[++si] : 0;
     }
 
-    setMouseInside(inside);
-
     if (inside && element()) {
         if (info.innerNode() && info.innerNode()->renderer() && 
             !info.innerNode()->renderer()->isInline()) {
@@ -409,7 +408,7 @@ bool RenderText::nodeAtPoint(NodeInfo& i
         if (!info.innerNode())
             info.setInnerNode(element());
 
-        if(!info.innerNonSharedNode())
+        if (!info.innerNonSharedNode())
             info.setInnerNonSharedNode(element());
     }
 
Index: khtml/rendering/render_text.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/rendering/render_text.h,v
retrieving revision 1.34
diff -u -p -r1.34 khtml/rendering/render_text.h
--- khtml/rendering/render_text.h	2003/07/25 20:22:34	1.34
+++ khtml/rendering/render_text.h	2003/09/01 08:16:24
@@ -141,7 +141,8 @@ public:
     
     virtual void layout() {assert(false);}
 
-    virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty, bool inside = false);
+    virtual bool nodeAtPoint(NodeInfo& info, int x, int y, int tx, int ty,
+                             HitTestAction hitTestAction = HitTestAll, bool inside=false);
 
     // Return before, after (offset set to max), or inside the text, at @p offset
     virtual FindSelectionResult checkSelectionPointIgnoringContinuations
Index: khtml/xml/dom_docimpl.cpp
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/xml/dom_docimpl.cpp,v
retrieving revision 1.75
diff -u -p -r1.75 khtml/xml/dom_docimpl.cpp
--- khtml/xml/dom_docimpl.cpp	2003/07/30 00:39:43	1.75
+++ khtml/xml/dom_docimpl.cpp	2003/09/01 08:16:27
@@ -284,6 +284,7 @@ DocumentImpl::DocumentImpl(DOMImplementa
     m_namespaceURIs[0] = new DOMStringImpl(xhtml.unicode(), xhtml.length());
     m_namespaceURIs[0]->ref();
     m_focusNode = 0;
+    m_hoverNode = 0;
     m_defaultView = new AbstractViewImpl(this);
     m_defaultView->ref();
     m_listenerTypes = 0;
@@ -336,9 +337,12 @@ DocumentImpl::~DocumentImpl()
     delete [] m_namespaceURIs;
     m_defaultView->deref();
     m_styleSheets->deref();
+
     if (m_focusNode)
         m_focusNode->deref();
-        
+    if (m_hoverNode)
+        m_hoverNode->deref();
+    
     if (m_renderArena){
         delete m_renderArena;
         m_renderArena = 0;
@@ -2014,6 +2018,17 @@ void DocumentImpl::recalcStyleSelector()
                                             !inCompatMode() );
 
     m_styleSelectorDirty = false;
+}
+
+void DocumentImpl::setHoverNode(NodeImpl* newHoverNode)
+{
+    if (m_hoverNode != newHoverNode) {
+        if (m_hoverNode)
+            m_hoverNode->deref();
+        m_hoverNode = newHoverNode;
+        if (m_hoverNode)
+            m_hoverNode->ref();
+    }    
 }
 
 void DocumentImpl::setFocusNode(NodeImpl *newFocusNode)
Index: khtml/xml/dom_docimpl.h
===================================================================
RCS file: /local/home/cvs/Labyrinth/WebCore/khtml/xml/dom_docimpl.h,v
retrieving revision 1.38
diff -u -p -r1.38 khtml/xml/dom_docimpl.h
--- khtml/xml/dom_docimpl.h	2003/07/30 00:39:43	1.38
+++ khtml/xml/dom_docimpl.h	2003/09/01 08:16:27
@@ -344,9 +344,13 @@ public:
     void setSelectedStylesheetSet(const DOMString& aString);
 
     QStringList availableStyleSheets() const;
+
     NodeImpl *focusNode() const { return m_focusNode; }
     void setFocusNode(NodeImpl *newFocusNode);
 
+    NodeImpl *hoverNode() const { return m_hoverNode; }
+    void setHoverNode(NodeImpl *newHoverNode);
+    
     // Updates for :target (CSS3 selector).
     void setCSSTarget(NodeImpl* n);
     NodeImpl* getCSSTarget();
@@ -478,8 +482,10 @@ protected:
     HTMLMode hMode;
 
     QColor m_textColor;
-    NodeImpl *m_focusNode;
 
+    NodeImpl *m_focusNode;
+    NodeImpl *m_hoverNode;
+    
     // ### replace me with something more efficient
     // in lookup and insertion.
     DOMStringImpl **m_elementNames;
-------------- next part --------------
/*
 * Copyright (C) 2003 Apple Computer, Inc.
 *
 * Portions are Copyright (C) 1998 Netscape Communications Corporation.
 *
 * Other contributors:
 *   Robert O'Callahan <roc+ at cs.cmu.edu>
 *   David Baron <dbaron at fas.harvard.edu>
 *   Christian Biesinger <cbiesinger at web.de>
 *   Randall Jesup <rjesup at wgate.com>
 *   Roland Mainz <roland.mainz at informatik.med.uni-giessen.de>
 *   Josh Soref <timeless at mac.com>
 *   Boris Zbarsky <bzbarsky at mit.edu>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Alternatively, the contents of this file may be used under the terms
 * of either the Mozilla Public License Version 1.1, found at
 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
 * (the "GPL"), in which case the provisions of the MPL or the GPL are
 * applicable instead of those above.  If you wish to allow use of your
 * version of this file only under the terms of one of those two
 * licenses (the MPL or the GPL) and not to allow others to use your
 * version of this file under the LGPL, indicate your decision by
 * deletingthe provisions above and replace them with the notice and
 * other provisions required by the MPL or the GPL, as the case may be.
 * If you do not delete the provisions above, a recipient may use your
 * version of this file under any of the LGPL, the MPL or the GPL.
 */

#include "render_layer.h"
#include <kdebug.h>
#include <assert.h>
#include "khtmlview.h"
#include "render_block.h"
#include "render_arena.h"
#include "xml/dom_docimpl.h"

#include <qscrollbar.h>
#include <qptrvector.h>

using namespace DOM;
using namespace khtml;

#ifdef APPLE_CHANGES
QScrollBar* RenderLayer::gScrollBar = 0;
#endif

#ifndef NDEBUG
static bool inRenderLayerDetach;
#endif

void
RenderScrollMediator::slotValueChanged(int val)
{
    m_layer->updateScrollPositionFromScrollbars();
}

RenderLayer::RenderLayer(RenderObject* object)
: m_object( object ),
m_parent( 0 ),
m_previous( 0 ),
m_next( 0 ),
m_first( 0 ),
m_last( 0 ),
m_x( 0 ),
m_y( 0 ),
m_width( 0 ),
m_height( 0 ),
m_scrollX( 0 ),
m_scrollY( 0 ),
m_scrollWidth( 0 ),
m_scrollHeight( 0 ),
m_hBar( 0 ),
m_vBar( 0 ),
m_scrollMediator( 0 ),
m_posZOrderList( 0 ),
m_negZOrderList( 0 ),
m_zOrderListsDirty( true )
{
}

RenderLayer::~RenderLayer()
{
    // Child layers will be deleted by their corresponding render objects, so
    // our destructor doesn't have to do anything.
    m_parent = m_previous = m_next = m_first = m_last = 0;
    delete m_hBar;
    delete m_vBar;
    delete m_scrollMediator;
    delete m_posZOrderList;
    delete m_negZOrderList;
}

void RenderLayer::updateLayerPosition()
{
    // The canvas is sized to the docWidth/Height over in RenderCanvas::layout, so we
    // don't need to ever update our layer position here.
    if (renderer()->isCanvas())
        return;
    
    int x = m_object->xPos();
    int y = m_object->yPos();

    if (!m_object->isPositioned()) {
        // We must adjust our position by walking up the render tree looking for the
        // nearest enclosing object with a layer.
        RenderObject* curr = m_object->parent();
        while (curr && !curr->layer()) {
            x += curr->xPos();
            y += curr->yPos();
            curr = curr->parent();
        }
    }

    if (m_object->isRelPositioned())
        static_cast<RenderBox*>(m_object)->relativePositionOffset(x, y);

    // Subtract our parent's scroll offset.
    if (parent())
        parent()->subtractScrollOffset(x, y);
    
    setPos(x,y);

    setWidth(m_object->width());
    setHeight(m_object->height());

    if (!m_object->style()->hidesOverflow()) {
        if (m_object->overflowWidth() > m_object->width())
            setWidth(m_object->overflowWidth());
        if (m_object->overflowHeight() > m_object->height())
            setHeight(m_object->overflowHeight());
    }    
}

RenderLayer *RenderLayer::stackingContext() const
{
    RenderLayer* curr = parent();
    for ( ; curr && !curr->m_object->isCanvas() && !curr->m_object->isRoot() &&
          curr->m_object->style()->hasAutoZIndex();
          curr = curr->parent());
    return curr;
}

RenderLayer*
RenderLayer::enclosingPositionedAncestor() const
{
    RenderLayer* curr = parent();
    for ( ; curr && !curr->m_object->isCanvas() && !curr->m_object->isRoot() &&
         !curr->m_object->isPositioned() && !curr->m_object->isRelPositioned();
         curr = curr->parent());
         
    return curr;
}

#if APPLE_CHANGES
bool
RenderLayer::isTransparent()
{
    return m_object->style()->opacity() < 1.0f;
}

RenderLayer*
RenderLayer::transparentAncestor()
{
    RenderLayer* curr = parent();
    for ( ; curr && curr->m_object->style()->opacity() == 1.0f; curr = curr->parent());
    return curr;
}
#endif

void* RenderLayer::operator new(size_t sz, RenderArena* renderArena) throw()
{
    return renderArena->allocate(sz);
}

void RenderLayer::operator delete(void* ptr, size_t sz)
{
    assert(inRenderLayerDetach);
    
    // Stash size where detach can find it.
    *(size_t *)ptr = sz;
}

void RenderLayer::detach(RenderArena* renderArena)
{
#ifndef NDEBUG
    inRenderLayerDetach = true;
#endif
    delete this;
#ifndef NDEBUG
    inRenderLayerDetach = false;
#endif
    
    // Recover the size left there for us by operator delete and free the memory.
    renderArena->free(*(size_t *)this, this);
}

void RenderLayer::addChild(RenderLayer *child, RenderLayer* beforeChild)
{
    RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
    if (prevSibling) {
        child->setPreviousSibling(prevSibling);
        prevSibling->setNextSibling(child);
    }
    else
        setFirstChild(child);

    if (beforeChild) {
        beforeChild->setPreviousSibling(child);
        child->setNextSibling(beforeChild);
    }
    else
        setLastChild(child);
   
    child->setParent(this);

    // Dirty the z-order list in which we are contained.
    child->stackingContext()->dirtyZOrderLists();
}

RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
{
    // remove the child
    if (oldChild->previousSibling())
        oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
    if (oldChild->nextSibling())
        oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());

    if (m_first == oldChild)
        m_first = oldChild->nextSibling();
    if (m_last == oldChild)
        m_last = oldChild->previousSibling();

    // Dirty the z-order list in which we are contained.
    oldChild->stackingContext()->dirtyZOrderLists();
    
    oldChild->setPreviousSibling(0);
    oldChild->setNextSibling(0);
    oldChild->setParent(0);
    
    return oldChild;
}

void RenderLayer::removeOnlyThisLayer()
{
    if (!m_parent)
        return;
    
    // Remove us from the parent.
    RenderLayer* parent = m_parent;
    RenderLayer* nextSib = nextSibling();
    parent->removeChild(this);
    
    // Now walk our kids and reattach them to our parent.
    RenderLayer* current = m_first;
    while (current) {
        RenderLayer* next = current->nextSibling();
        removeChild(current);
        parent->addChild(current, nextSib);
        current = next;
    }
    
    detach(renderer()->renderArena());
}

void RenderLayer::insertOnlyThisLayer()
{
    if (!m_parent && renderer()->parent()) {
        // We need to connect ourselves when our renderer() has a parent.
        // Find our enclosingLayer and add ourselves.
        RenderLayer* parentLayer = renderer()->parent()->enclosingLayer();
        if (parentLayer)
            parentLayer->addChild(this, 
                                  renderer()->parent()->findNextLayer(parentLayer, renderer()));
    }
    
    // Remove all descendant layers from the hierarchy and add them to the new position.
    for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
        curr->moveLayers(m_parent, this);
}

void 
RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const
{
    if (ancestorLayer == this)
        return;
        
    if (m_object->style()->position() == FIXED) {
        // Add in the offset of the view.  We can obtain this by calling
        // absolutePosition() on the RenderCanvas.
        int xOff, yOff;
        m_object->absolutePosition(xOff, yOff, true);
        x += xOff;
        y += yOff;
        return;
    }
 
    RenderLayer* parentLayer;
    if (m_object->style()->position() == ABSOLUTE)
        parentLayer = enclosingPositionedAncestor();
    else
        parentLayer = parent();
    
    if (!parentLayer) return;
    
    parentLayer->convertToLayerCoords(ancestorLayer, x, y);

    x += xPos();
    y += yPos();
}

void
RenderLayer::scrollOffset(int& x, int& y)
{
    x += scrollXOffset();
    y += scrollYOffset();
}

void
RenderLayer::subtractScrollOffset(int& x, int& y)
{
    x -= scrollXOffset();
    y -= scrollYOffset();
}

void
RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars)
{
    if (x < 0) x = 0;
    if (y < 0) y = 0;
    int maxX = m_scrollWidth - m_object->clientWidth();
    int maxY = m_scrollHeight - m_object->clientHeight();
    if (x > maxX) x = maxX;
    if (y > maxY) y = maxY;

    // FIXME: Eventually, we will want to perform a blit.  For now never
    // blit, since the check for blitting is going to be very
    // complicated (since it will involve testing whether our layer
    // is either occluded by another layer or clipped by an enclosing
    // layer or contains fixed backgrounds, etc.).
    m_scrollX = x;
    m_scrollY = y;

    // FIXME: Fire the onscroll DOM event.
    
    // Just schedule a full repaint of our object.
    m_object->repaint(true);
    
    if (updateScrollbars) {
        if (m_hBar)
            m_hBar->setValue(m_scrollX);
        if (m_vBar)
            m_vBar->setValue(m_scrollY);
    }
}

void
RenderLayer::updateScrollPositionFromScrollbars()
{
    bool needUpdate = false;
    int newX = m_scrollX;
    int newY = m_scrollY;
    
    if (m_hBar) {
        newX = m_hBar->value();
        if (newX != m_scrollX)
           needUpdate = true;
    }

    if (m_vBar) {
        newY = m_vBar->value();
        if (newY != m_scrollY)
           needUpdate = true;
    }

    if (needUpdate)
        scrollToOffset(newX, newY, false);
}

void
RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
{
    if (hasScrollbar && !m_hBar) {
        QScrollView* scrollView = m_object->element()->getDocument()->view();
        m_hBar = new QScrollBar(Qt::Horizontal, scrollView);
        scrollView->addChild(m_hBar, 0, -50000);
        if (!m_scrollMediator)
            m_scrollMediator = new RenderScrollMediator(this);
        m_scrollMediator->connect(m_hBar, SIGNAL(valueChanged(int)), SLOT(slotValueChanged(int)));
    }
    else if (!hasScrollbar && m_hBar) {
        m_scrollMediator->disconnect(m_hBar, SIGNAL(valueChanged(int)),
                                     m_scrollMediator, SLOT(slotValueChanged(int)));
        delete m_hBar;
        m_hBar = 0;
    }
}

void
RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
{
    if (hasScrollbar && !m_vBar) {
        QScrollView* scrollView = m_object->element()->getDocument()->view();
        m_vBar = new QScrollBar(Qt::Vertical, scrollView);
        scrollView->addChild(m_vBar, 0, -50000);
        if (!m_scrollMediator)
            m_scrollMediator = new RenderScrollMediator(this);
        m_scrollMediator->connect(m_vBar, SIGNAL(valueChanged(int)), SLOT(slotValueChanged(int)));
    }
    else if (!hasScrollbar && m_vBar) {
        m_scrollMediator->disconnect(m_vBar, SIGNAL(valueChanged(int)),
                                     m_scrollMediator, SLOT(slotValueChanged(int)));
        delete m_vBar;
        m_vBar = 0;
    }
}

int
RenderLayer::verticalScrollbarWidth()
{
    if (!m_vBar)
        return 0;

    return m_vBar->width();
}

int
RenderLayer::horizontalScrollbarHeight()
{
    if (!m_hBar)
        return 0;

    return m_hBar->height();
}

void
RenderLayer::moveScrollbarsAside()
{
    if (m_hBar)
        m_hBar->move(0, -50000);
    if (m_vBar)
        m_vBar->move(0, -50000);
}

void
RenderLayer::positionScrollbars(const QRect& absBounds)
{
    if (m_vBar) {
        m_vBar->move(absBounds.x()+absBounds.width()-m_object->borderRight()-m_vBar->width(),
                     absBounds.y()+m_object->borderTop());
        m_vBar->resize(m_vBar->width(), absBounds.height() -
                       (m_object->borderTop()+m_object->borderBottom()) -
                       (m_hBar ? m_hBar->height()-1 : 0));
    }

    if (m_hBar) {
        m_hBar->move(absBounds.x()+m_object->borderLeft(),
                     absBounds.y()+absBounds.height()-m_object->borderBottom()-m_hBar->height());
        m_hBar->resize(absBounds.width() - (m_object->borderLeft()+m_object->borderRight()) -
                       (m_vBar ? m_vBar->width()-1 : 0),
                       m_hBar->height());
    }
}

#define LINE_STEP   10
#define PAGE_KEEP   40

void
RenderLayer::checkScrollbarsAfterLayout()
{
    updateLayerPosition();
    
    int rightPos = m_object->rightmostPosition();
    int bottomPos = m_object->lowestPosition();

    int clientWidth = m_object->clientWidth();
    int clientHeight = m_object->clientHeight();
    m_scrollWidth = clientWidth;
    m_scrollHeight = clientHeight;
    
    if (rightPos - m_object->borderLeft() > m_scrollWidth)
        m_scrollWidth = rightPos - m_object->borderLeft();
    if (bottomPos - m_object->borderTop() > m_scrollHeight)
        m_scrollHeight = bottomPos - m_object->borderTop();
    
    bool needHorizontalBar = rightPos > width();
    bool needVerticalBar = bottomPos > height();

    bool haveHorizontalBar = m_hBar;
    bool haveVerticalBar = m_vBar;

    // overflow:scroll should just enable/disable.
    if (m_object->style()->overflow() == OSCROLL) {
        m_hBar->setEnabled(needHorizontalBar);
        m_vBar->setEnabled(needVerticalBar);
    }

    // overflow:auto may need to lay out again if scrollbars got added/removed.
    bool scrollbarsChanged = (m_object->style()->overflow() == OAUTO) &&
        (haveHorizontalBar != needHorizontalBar || haveVerticalBar != needVerticalBar);    
    if (scrollbarsChanged) {
        setHasHorizontalScrollbar(needHorizontalBar);
        setHasVerticalScrollbar(needVerticalBar);
       
        m_object->setNeedsLayout(true);
	if (m_object->isRenderBlock())
            static_cast<RenderBlock*>(m_object)->layoutBlock(true);
        else
            m_object->layout();
	return;
    }

    // Set up the range (and page step/line step).
    if (m_hBar) {
        int pageStep = (clientWidth-PAGE_KEEP);
        if (pageStep < 0) pageStep = clientWidth;
        m_hBar->setSteps(LINE_STEP, pageStep);
#ifdef APPLE_CHANGES
        m_hBar->setKnobProportion(clientWidth, m_scrollWidth);
#else
        m_hBar->setRange(0, m_scrollWidth-clientWidth);
#endif
    }
    if (m_vBar) {
        int pageStep = (clientHeight-PAGE_KEEP);
        if (pageStep < 0) pageStep = clientHeight;
        m_vBar->setSteps(LINE_STEP, pageStep);
#ifdef APPLE_CHANGES
        m_vBar->setKnobProportion(clientHeight, m_scrollHeight);
#else
        m_vBar->setRange(0, m_scrollHeight-clientHeight);
#endif
    }
}

#if APPLE_CHANGES
void
RenderLayer::paintScrollbars(QPainter* p, const QRect& damageRect)
{
    if (m_hBar)
        m_hBar->paint(p, damageRect);
    if (m_vBar)
        m_vBar->paint(p, damageRect);
}
#endif

void
RenderLayer::paint(QPainter *p, const QRect& damageRect, bool selectionOnly)
{
    paintLayer(this, p, damageRect, selectionOnly);
}

static void setClip(QPainter* p, const QRect& paintDirtyRect, const QRect& clipRect)
{
    if (paintDirtyRect == clipRect)
        return;

    p->save();
    
#if APPLE_CHANGES
    p->addClip(clipRect);
#else
    QRect clippedRect = p->xForm(clipRect);
    QRegion creg(clippedRect);
    QRegion old = p->clipRegion();
    if (!old.isNull())
        creg = old.intersect(creg);
    p->setClipRegion(creg);
#endif
    
}

static void restoreClip(QPainter* p, const QRect& paintDirtyRect, const QRect& clipRect)
{
    if (paintDirtyRect == clipRect)
        return;
    p->restore();
}

void
RenderLayer::paintLayer(RenderLayer* rootLayer, QPainter *p,
                        const QRect& paintDirtyRect, bool selectionOnly)
{
    // Calculate the clip rects we should use.
    QRect layerBounds, damageRect, clipRectToApply;
    calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply);
    int x = layerBounds.x();
    int y = layerBounds.y();
                             
    // Ensure our z-order lists are up-to-date.
    updateZOrderLists();

#if APPLE_CHANGES
    // Set our transparency if we need to.
    if (isTransparent())
        p->beginTransparencyLayer(renderer()->style()->opacity());
#endif
    
    // We want to paint our layer, but only if we intersect the damage rect.
    bool shouldPaint = intersectsDamageRect(layerBounds, damageRect);
    if (shouldPaint && !selectionOnly) {
        // Paint our background first, before painting any child layers.
        if (!damageRect.isEmpty()) {
            // Establish the clip used to paint our background.
            setClip(p, paintDirtyRect, damageRect);

            // Paint the background.
            renderer()->paint(p, damageRect.x(), damageRect.y(),
                              damageRect.width(), damageRect.height(),
                              x - renderer()->xPos(), y - renderer()->yPos(),
                              PaintActionElementBackground);

            // Position our scrollbars.
            positionScrollbars(layerBounds);

#if APPLE_CHANGES
            // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
            // z-index.  We paint after we painted the background/border, so that the scrollbars will
            // sit above the background/border.
            paintScrollbars(p, damageRect);
#endif
            // Restore the clip.
            restoreClip(p, paintDirtyRect, damageRect);
        }
    }

    // Now walk the sorted list of children with negative z-indices.
    if (m_negZOrderList) {
        uint count = m_negZOrderList->count();
        for (uint i = 0; i < count; i++) {
            RenderLayer* child = m_negZOrderList->at(i);
            child->paintLayer(rootLayer, p, paintDirtyRect, selectionOnly);
        }
    }
    
    // Now establish the appropriate clip and paint our child RenderObjects.
    if (shouldPaint && !clipRectToApply.isEmpty()) {
        // Set up the clip used when painting our children.
        setClip(p, paintDirtyRect, clipRectToApply);

        if (selectionOnly)
            renderer()->paint(p, clipRectToApply.x(), clipRectToApply.y(),
                              clipRectToApply.width(), clipRectToApply.height(),
                              x - renderer()->xPos(), y - renderer()->yPos(), PaintActionSelection);
        else {
            renderer()->paint(p, clipRectToApply.x(), clipRectToApply.y(),
                              clipRectToApply.width(), clipRectToApply.height(),
                              x - renderer()->xPos(), y - renderer()->yPos(), PaintActionChildBackgrounds);
            renderer()->paint(p, clipRectToApply.x(), clipRectToApply.y(),
                              clipRectToApply.width(), clipRectToApply.height(),
                              x - renderer()->xPos(), y - renderer()->yPos(), PaintActionFloat);
            renderer()->paint(p, clipRectToApply.x(), clipRectToApply.y(),
                              clipRectToApply.width(), clipRectToApply.height(),
                              x - renderer()->xPos(), y - renderer()->yPos(), PaintActionForeground);
        }

        // Now restore our clip.
        restoreClip(p, paintDirtyRect, clipRectToApply);
    }
    
    // Now walk the sorted list of children with positive z-indices.
    if (m_posZOrderList) {
        uint count = m_posZOrderList->count();
        for (uint i = 0; i < count; i++) {
            RenderLayer* child = m_posZOrderList->at(i);
            child->paintLayer(rootLayer, p, paintDirtyRect, selectionOnly);
        }
    }
    
#if APPLE_CHANGES
    // End our transparency layer
    if (isTransparent())
        p->endTransparencyLayer();
#endif
}

bool
RenderLayer::nodeAtPoint(RenderObject::NodeInfo& info, int x, int y)
{
    QRect damageRect(m_x, m_y, width(), height());
    RenderLayer* insideLayer = nodeAtPointForLayer(this, info, x, y, damageRect);

    // Now determine if the result is inside an anchor.
    DOM::NodeImpl* node = info.innerNode();
    while (node) {
        if (node->hasAnchor())
            info.setURLElement(node);
        node = node->parentNode();
    }

    // Next set up the correct :hover/:active state along the new chain.
    updateHoverActiveState(info);

    // Now return whether we were inside this layer (this will always be true for the root
    // layer).
    return insideLayer;
}

RenderLayer*
RenderLayer::nodeAtPointForLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info,
                                 int xMousePos, int yMousePos, const QRect& hitTestRect)
{
    // Calculate the clip rects we should use.
    QRect layerBounds, bgRect, fgRect;
    calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect);
    
    // Ensure our z-order lists are up-to-date.
    updateZOrderLists();

    // This variable tracks which layer the mouse ends up being inside.  The minute we find an insideLayer,
    // we are done and can return it.
    RenderLayer* insideLayer = 0;
    
    // Begin by walking our list of positive layers from highest z-index down to the lowest
    // z-index.
    if (m_posZOrderList) {
        uint count = m_posZOrderList->count();
        for (int i = count-1; i >= 0; i--) {
            RenderLayer* child = m_posZOrderList->at(i);
            insideLayer = child->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
            if (insideLayer)
                return insideLayer;
        }
    }

    // Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
    if (containsPoint(xMousePos, yMousePos, fgRect) &&
        renderer()->nodeAtPoint(info, xMousePos, yMousePos,
                                layerBounds.x() - renderer()->xPos(),
                                layerBounds.y() - renderer()->yPos(),
                                HitTestChildrenOnly))
        return this;
        
    // Now check our negative z-index children.
    if (m_negZOrderList) {
        uint count = m_negZOrderList->count();
        for (int i = count-1; i >= 0; i--) {
            RenderLayer* child = m_negZOrderList->at(i);
            insideLayer = child->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
            if (insideLayer)
                return insideLayer;
        }
    }

    // Next we want to see if the mouse pos is inside this layer but not any of its children.
    if (containsPoint(xMousePos, yMousePos, bgRect) &&
        renderer()->nodeAtPoint(info, xMousePos, yMousePos,
                                layerBounds.x() - renderer()->xPos(),
                                layerBounds.y() - renderer()->yPos(),
                                HitTestSelfOnly))
        return this;

    // No luck.
    return 0;
}

void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, QRect& overflowClipRect,
                                     QRect& posClipRect, QRect& fixedClipRect)
{
    if (parent())
        parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
        
    updateLayerPosition(); // For relpositioned layers or non-positioned layers,
                           // we need to keep in sync, since we may have shifted relative
                           // to our parent layer.

    // A fixed object is essentially the root of its containing block hierarchy, so when
    // we encounter such an object, we reset our clip rects to the fixedClipRect.
    if (m_object->style()->position() == FIXED) {
        posClipRect = fixedClipRect;
        overflowClipRect = fixedClipRect;
    }
    
    // Update the clip rects that will be passed to child layers.
    if (m_object->hasOverflowClip() || m_object->hasClip()) {
        // This layer establishes a clip of some kind.
        int x = 0;
        int y = 0;
        convertToLayerCoords(rootLayer, x, y);
        
        if (m_object->hasOverflowClip()) {
            QRect newOverflowClip = m_object->getOverflowClipRect(x,y);
            overflowClipRect  = newOverflowClip.intersect(overflowClipRect);
            if (m_object->isPositioned() || m_object->isRelPositioned())
                posClipRect = newOverflowClip.intersect(posClipRect);
        }
        if (m_object->hasClip()) {
            QRect newPosClip = m_object->getClipRect(x,y);
            posClipRect = newPosClip.intersect(posClipRect);
            overflowClipRect = overflowClipRect.intersect(posClipRect);
            fixedClipRect = fixedClipRect.intersect(posClipRect);
        }
    }
}

void RenderLayer::calculateRects(const RenderLayer* rootLayer, const QRect& paintDirtyRect, QRect& layerBounds,
                                 QRect& backgroundRect, QRect& foregroundRect)
{
    QRect overflowClipRect = paintDirtyRect;
    QRect posClipRect = paintDirtyRect;
    QRect fixedClipRect = paintDirtyRect;
    if (parent())
        parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);

    updateLayerPosition();
    
    int x = 0;
    int y = 0;
    convertToLayerCoords(rootLayer, x, y);
    layerBounds = QRect(x,y,width(),height());

    backgroundRect = m_object->style()->position() == FIXED ? fixedClipRect :
        (m_object->isPositioned() ? posClipRect : overflowClipRect);
    foregroundRect = backgroundRect;
    
    // Update the clip rects that will be passed to child layers.
    if (m_object->hasOverflowClip() || m_object->hasClip()) {
        // This layer establishes a clip of some kind.
        if (m_object->hasOverflowClip())
            foregroundRect = foregroundRect.intersect(m_object->getOverflowClipRect(x,y));
        if (m_object->hasClip()) {
            // Clip applies to *us* as well, so go ahead and update the damageRect.
            QRect newPosClip = m_object->getClipRect(x,y);
            backgroundRect = backgroundRect.intersect(newPosClip);
            foregroundRect = foregroundRect.intersect(newPosClip);
        }

        // If we establish a clip at all, then go ahead and make sure our background
        // rect is intersected with our layer's bounds.
        backgroundRect = backgroundRect.intersect(layerBounds);
    }
}

bool RenderLayer::intersectsDamageRect(const QRect& layerBounds, const QRect& damageRect) const
{
    return (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isBody() ||
            renderer()->hasOverhangingFloats() ||
            (renderer()->isInline() && !renderer()->isReplaced()) ||
            layerBounds.intersects(damageRect));
}

bool RenderLayer::containsPoint(int x, int y, const QRect& damageRect) const
{
    return (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isBody() ||
            renderer()->hasOverhangingFloats() ||
            (renderer()->isInline() && !renderer()->isReplaced()) ||
            damageRect.contains(x, y));
}

// This code has been written to anticipate the addition of CSS3-::outside and ::inside generated
// content (and perhaps XBL).  That's why it uses the render tree and not the DOM tree.
static RenderObject* hoverAncestor(RenderObject* obj)
{
    return (!obj->isInline() && obj->continuation()) ? obj->continuation() : obj->parent();
}

static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2)
{
    if (!obj1 || !obj2)
        return 0;

    for (RenderObject* currObj1 = obj1; currObj1; currObj1 = hoverAncestor(currObj1))
        for (RenderObject* currObj2 = obj2; currObj2; currObj2 = hoverAncestor(currObj2))
            if (currObj1 == currObj2)
                return currObj1;

    return 0;
}

void RenderLayer::updateHoverActiveState(RenderObject::NodeInfo& info)
{
    // We don't update :hover/:active state when the info is marked as readonly.
    if (info.readonly())
        return;
    
    // Check to see if the hovered node has changed.  If not, then we don't need to
    // do anything.  An exception is if we just went from :hover into :hover:active,
    // in which case we need to update to get the new :active state.
    DOM::NodeImpl* oldHoverNode = info.innerNode()->getDocument()->hoverNode();
    DOM::NodeImpl* newHoverNode = info.innerNode();
        
    if (oldHoverNode == newHoverNode && oldHoverNode->active() == info.active())
        return;

    // Update our current hover node.
    info.innerNode()->getDocument()->setHoverNode(newHoverNode);
    
    // We have two different objects.  Fetch their renderers.
    RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
    RenderObject* newHoverObj = info.innerNode() ? info.innerNode()->renderer() : 0;
    
    // Locate the common ancestor render object for the two renderers.
    RenderObject* ancestor = commonAncestor(oldHoverObj, newHoverObj);
    
    // The old hover path only needs to be cleared up to (and not including) the common ancestor;
    for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = hoverAncestor(curr)) {
        curr->setMouseInside(false);
        if (curr->element() && !curr->isText()) {
            bool oldActive = curr->element()->active();
            curr->element()->setActive(false);
            if (curr->style()->affectedByHoverRules() ||
                (curr->style()->affectedByActiveRules() && oldActive))
                curr->element()->setChanged();
        }
    }

    // Now set the hover state for our new object up to the root.
    for (RenderObject* curr = newHoverObj; curr; curr = hoverAncestor(curr)) {
        bool oldInside = curr->mouseInside();
        curr->setMouseInside(true);
        if (curr->element() && !curr->isText()) {
            bool oldActive = curr->element()->active();
            curr->element()->setActive(info.active());
            if ((curr->style()->affectedByHoverRules() && !oldInside) ||
                (curr->style()->affectedByActiveRules() && oldActive != info.active()))
                curr->element()->setChanged();
        }
    }
}

// Sort the buffer from lowest z-index to highest.  The common scenario will have
// most z-indices equal, so we optimize for that case (i.e., the list will be mostly
// sorted already).
static void sortByZOrder(QPtrVector<RenderLayer::RenderLayer>* buffer,
                         QPtrVector<RenderLayer::RenderLayer>* mergeBuffer,
                         uint start, uint end)
{
    if (start >= end)
        return; // Sanity check.

    if (end - start <= 6) {
        // Apply a bubble sort for smaller lists.
        for (uint i = end-1; i > start; i--) {
            bool sorted = true;
            for (uint j = start; j < i; j++) {
                RenderLayer* elt = buffer->at(j);
                RenderLayer* elt2 = buffer->at(j+1);
                if (elt->zIndex() > elt2->zIndex()) {
                    sorted = false;
                    buffer->insert(j, elt2);
                    buffer->insert(j+1, elt);
                }
            }
            if (sorted)
                return;
        }
    }
    else {
        // Peform a merge sort for larger lists.
        uint mid = (start+end)/2;
        sortByZOrder(buffer, mergeBuffer, start, mid);
        sortByZOrder(buffer, mergeBuffer, mid, end);

        RenderLayer* elt = buffer->at(mid-1);
        RenderLayer* elt2 = buffer->at(mid);

        // Handle the fast common case (of equal z-indices).  The list may already
        // be completely sorted.
        if (elt->zIndex() <= elt2->zIndex())
            return;

        // We have to merge sort.  Ensure our merge buffer is big enough to hold
        // all the items.
        mergeBuffer->resize(end - start);
        uint i1 = start;
        uint i2 = mid;

        elt = buffer->at(i1);
        elt2 = buffer->at(i2);

        while (i1 < mid || i2 < end) {
            if (i1 < mid && (i2 == end || elt->zIndex() <= elt2->zIndex())) {
                mergeBuffer->insert(mergeBuffer->count(), elt);
                i1++;
                if (i1 < mid)
                    elt = buffer->at(i1);
            }
            else {
                mergeBuffer->insert(mergeBuffer->count(), elt2);
                i2++;
                if (i2 < end)
                    elt2 = buffer->at(i2);
            }
        }

        for (uint i = start; i < end; i++)
            buffer->insert(i, mergeBuffer->at(i-start));

        mergeBuffer->clear();
    }
}

void RenderLayer::dirtyZOrderLists()
{
    if (m_posZOrderList)
        m_posZOrderList->clear();
    if (m_negZOrderList)
        m_negZOrderList->clear();
    m_zOrderListsDirty = true;
}
    
void RenderLayer::updateZOrderLists()
{
    if (!isStackingContext() || !m_zOrderListsDirty)
        return;
    
    for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
        child->collectLayers(m_posZOrderList, m_negZOrderList);

    // Sort the two lists.
    if (m_posZOrderList) {
        QPtrVector<RenderLayer> mergeBuffer;
        sortByZOrder(m_posZOrderList, &mergeBuffer, 0, m_posZOrderList->count());
    }
    if (m_negZOrderList) {
        QPtrVector<RenderLayer> mergeBuffer;
        sortByZOrder(m_negZOrderList, &mergeBuffer, 0, m_negZOrderList->count());
    }

    m_zOrderListsDirty = false;
}

void RenderLayer::collectLayers(QPtrVector<RenderLayer>*& posBuffer, QPtrVector<RenderLayer>*& negBuffer)
{
    // FIXME: A child render object or layer could override visibility.  Don't remove this
    // optimization though until RenderObject's nodeAtPoint is patched to understand what to do
    // when visibility is overridden by a child.
    if (renderer()->style()->visibility() != VISIBLE)
        return;
    
    // Determine which buffer the child should be in.
    QPtrVector<RenderLayer>*& buffer = (zIndex() >= 0) ? posBuffer : negBuffer;

    // Create the buffer if it doesn't exist yet.
    if (!buffer)
        buffer = new QPtrVector<RenderLayer>();
    
    // Resize by a power of 2 when our buffer fills up.
    if (buffer->count() == buffer->size())
        buffer->resize(2*(buffer->size()+1));

    // Append ourselves at the end of the appropriate buffer.
    buffer->insert(buffer->count(), this);

    // Recur into our children to collect more layers, but only if we don't establish
    // a stacking context.
    if (!isStackingContext()) {
        for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
            child->collectLayers(posBuffer, negBuffer);
    }
}
-------------- next part --------------
/*
 * Copyright (C) 2003 Apple Computer, Inc.
 *
 * Portions are Copyright (C) 1998 Netscape Communications Corporation.
 *
 * Other contributors:
 *   Robert O'Callahan <roc+ at cs.cmu.edu>
 *   David Baron <dbaron at fas.harvard.edu>
 *   Christian Biesinger <cbiesinger at web.de>
 *   Randall Jesup <rjesup at wgate.com>
 *   Roland Mainz <roland.mainz at informatik.med.uni-giessen.de>
 *   Josh Soref <timeless at mac.com>
 *   Boris Zbarsky <bzbarsky at mit.edu>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Alternatively, the contents of this file may be used under the terms
 * of either the Mozilla Public License Version 1.1, found at
 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
 * (the "GPL"), in which case the provisions of the MPL or the GPL are
 * applicable instead of those above.  If you wish to allow use of your
 * version of this file only under the terms of one of those two
 * licenses (the MPL or the GPL) and not to allow others to use your
 * version of this file under the LGPL, indicate your decision by
 * deletingthe provisions above and replace them with the notice and
 * other provisions required by the MPL or the GPL, as the case may be.
 * If you do not delete the provisions above, a recipient may use your
 * version of this file under any of the LGPL, the MPL or the GPL.
 */

#ifndef render_layer_h
#define render_layer_h

#include <qcolor.h>
#include <qrect.h>
#include <assert.h>

#include "render_object.h"

class QScrollBar;
template <class T> class QPtrVector;

namespace khtml {
    class RenderStyle;
    class RenderTable;
    class CachedObject;
    class RenderCanvas;
    class RenderText;
    class RenderFrameSet;
    class RenderObject;
    class RenderScrollMediator;
    
class RenderScrollMediator: public QObject
{
public:
    RenderScrollMediator(RenderLayer* layer)
    :m_layer(layer) {}

    void slotValueChanged(int);
    
private:
    RenderLayer* m_layer;
};
    
class RenderLayer
{
public:
#ifdef APPLE_CHANGES
    static QScrollBar* gScrollBar;
#endif
    
    RenderLayer(RenderObject* object);
    ~RenderLayer();
    
    RenderObject* renderer() const { return m_object; }
    RenderLayer *parent() const { return m_parent; }
    RenderLayer *previousSibling() const { return m_previous; }
    RenderLayer *nextSibling() const { return m_next; }

    RenderLayer *firstChild() const { return m_first; }
    RenderLayer *lastChild() const { return m_last; }

    void addChild(RenderLayer *newChild, RenderLayer* beforeChild = 0);
    RenderLayer* removeChild(RenderLayer *oldChild);

    void removeOnlyThisLayer();
    void insertOnlyThisLayer();

#if APPLE_CHANGES
    bool isTransparent();
    RenderLayer* transparentAncestor();
#endif
    
    RenderLayer* root() {
        RenderLayer* curr = this;
        while (curr->parent()) curr = curr->parent();
        return curr;
    }
    
    int xPos() const { return m_x; }
    int yPos() const { return m_y; }
    short width() const { return m_width; }
    int height() const { return m_height; }

    void setWidth(short w) { m_width = w; }
    void setHeight(int h) { m_height = h; }
    
    short scrollWidth() const { return m_scrollWidth; }
    int scrollHeight() const { return m_scrollHeight; }
    
    void setPos( int xPos, int yPos ) {
        m_x = xPos;
        m_y = yPos;
    }

    // Scrolling methods for layers that can scroll their overflow.
    void scrollOffset(int& x, int& y);
    void subtractScrollOffset(int& x, int& y);
    short scrollXOffset() { return m_scrollX; }
    int scrollYOffset() { return m_scrollY; }
    void scrollToOffset(int x, int y, bool updateScrollbars = true);
    void scrollToXOffset(int x) { scrollToOffset(x, m_scrollY); }
    void scrollToYOffset(int y) { scrollToOffset(m_scrollX, y); }
    void setHasHorizontalScrollbar(bool hasScrollbar);
    void setHasVerticalScrollbar(bool hasScrollbar);
    QScrollBar* horizontalScrollbar() { return m_hBar; }
    QScrollBar* verticalScrollbar() { return m_vBar; }
    int verticalScrollbarWidth();
    int horizontalScrollbarHeight();
    void moveScrollbarsAside();
    void positionScrollbars(const QRect& absBounds);
#ifdef APPLE_CHANGES
    void paintScrollbars(QPainter* p, const QRect& damageRect);
#endif
    void checkScrollbarsAfterLayout();
    void slotValueChanged(int);
    void updateScrollPositionFromScrollbars();

    void updateLayerPosition();

    // Get the enclosing stacking context for this layer.  A stacking context is a layer
    // that has a non-auto z-index.
    RenderLayer* stackingContext() const;
    bool isStackingContext() const { return !hasAutoZIndex() || renderer()->isCanvas(); }

    void dirtyZOrderLists();
    void updateZOrderLists();
    QPtrVector<RenderLayer>* posZOrderList() const { return m_posZOrderList; }
    QPtrVector<RenderLayer>* negZOrderList() const { return m_negZOrderList; }
    
    // Gets the nearest enclosing positioned ancestor layer (also includes
    // the <html> layer and the root layer).
    RenderLayer* enclosingPositionedAncestor() const;
    
    void convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const;
    
    bool hasAutoZIndex() const { return renderer()->style()->hasAutoZIndex(); }
    int zIndex() const { return renderer()->style()->zIndex(); }

    // The two main functions that use the layer system.  The paint method
    // paints the layers that intersect the damage rect from back to
    // front.  The nodeAtPoint method looks for mouse events by walking
    // layers that intersect the point from front to back.
    void paint(QPainter *p, const QRect& damageRect, bool selectionOnly=false);
    bool nodeAtPoint(RenderObject::NodeInfo& info, int x, int y);

    // This method figures out our layerBounds in coordinates relative to
    // |rootLayer}.  It also computes our background and foreground clip rects
    // for painting/event handling.
    void calculateRects(const RenderLayer* rootLayer, const QRect& paintDirtyRect, QRect& layerBounds,
                        QRect& backgroundRect, QRect& foregroundRect);
    void calculateClipRects(const RenderLayer* rootLayer, QRect& overflowClipRect,
                            QRect& posClipRect, QRect& fixedClipRect);

    bool intersectsDamageRect(const QRect& layerBounds, const QRect& damageRect) const;
    bool containsPoint(int x, int y, const QRect& damageRect) const;
    
    void updateHoverActiveState(RenderObject::NodeInfo& info);
    
    void detach(RenderArena* renderArena);

     // Overloaded new operator.  Derived classes must override operator new
    // in order to allocate out of the RenderArena.
    void* operator new(size_t sz, RenderArena* renderArena) throw();    

    // Overridden to prevent the normal delete from being called.
    void operator delete(void* ptr, size_t sz);
        
private:
    // The normal operator new is disallowed on all render objects.
    void* operator new(size_t sz) throw();

private:
    void setNextSibling(RenderLayer* next) { m_next = next; }
    void setPreviousSibling(RenderLayer* prev) { m_previous = prev; }
    void setParent(RenderLayer* parent) { m_parent = parent; }
    void setFirstChild(RenderLayer* first) { m_first = first; }
    void setLastChild(RenderLayer* last) { m_last = last; }

    void collectLayers(QPtrVector<RenderLayer>*&, QPtrVector<RenderLayer>*&);

    void paintLayer(RenderLayer* rootLayer, QPainter *p, const QRect& paintDirtyRect, bool selectionOnly=false);
    RenderLayer* nodeAtPointForLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info,
                                     int x, int y, const QRect& hitTestRect);

protected:   
    RenderObject* m_object;
    
    RenderLayer* m_parent;
    RenderLayer* m_previous;
    RenderLayer* m_next;

    RenderLayer* m_first;
    RenderLayer* m_last;
    
    // Our (x,y) coordinates are in our parent layer's coordinate space.
    short m_x;
    int m_y;

    // The layer's width/height
    short m_width;
    int m_height;
    
    // Our scroll offsets if the view is scrolled.
    short m_scrollX;
    int m_scrollY;
    
    // The width/height of our scrolled area.
    short m_scrollWidth;
    int m_scrollHeight;
    
    // For layers with overflow, we have a pair of scrollbars.
    QScrollBar* m_hBar;
    QScrollBar* m_vBar;
    RenderScrollMediator* m_scrollMediator;

    // For layers that establish stacking contexts, m_posZOrderList holds a sorted list of all the
    // descendant layers within the stacking context that have z-indices of 0 or greater
    // (auto will count as 0).  m_negZOrderList holds descendants within our stacking context with negative
    // z-indices.
    QPtrVector<RenderLayer>* m_posZOrderList;
    QPtrVector<RenderLayer>* m_negZOrderList;
    bool m_zOrderListsDirty;
};

}; // namespace
#endif
-------------- next part --------------



More information about the Khtml-devel mailing list