7e27d5870b8675fe3f68405ef8f17a62f874ed4b
[WebKit-https.git] / WebCore / khtml / rendering / render_layer.cpp
1 /*
2  * Copyright (C) 2003 Apple Computer, Inc.
3  *
4  * Portions are Copyright (C) 1998 Netscape Communications Corporation.
5  *
6  * Other contributors:
7  *   Robert O'Callahan <roc+@cs.cmu.edu>
8  *   David Baron <dbaron@fas.harvard.edu>
9  *   Christian Biesinger <cbiesinger@web.de>
10  *   Randall Jesup <rjesup@wgate.com>
11  *   Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
12  *   Josh Soref <timeless@mac.com>
13  *   Boris Zbarsky <bzbarsky@mit.edu>
14  *
15  * This library is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU Lesser General Public
17  * License as published by the Free Software Foundation; either
18  * version 2.1 of the License, or (at your option) any later version.
19  *
20  * This library is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * Lesser General Public License for more details.
24  *
25  * You should have received a copy of the GNU Lesser General Public
26  * License along with this library; if not, write to the Free Software
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28  *
29  * Alternatively, the contents of this file may be used under the terms
30  * of either the Mozilla Public License Version 1.1, found at
31  * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
32  * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
33  * (the "GPL"), in which case the provisions of the MPL or the GPL are
34  * applicable instead of those above.  If you wish to allow use of your
35  * version of this file only under the terms of one of those two
36  * licenses (the MPL or the GPL) and not to allow others to use your
37  * version of this file under the LGPL, indicate your decision by
38  * deletingthe provisions above and replace them with the notice and
39  * other provisions required by the MPL or the GPL, as the case may be.
40  * If you do not delete the provisions above, a recipient may use your
41  * version of this file under any of the LGPL, the MPL or the GPL.
42  */
43
44 #include "render_layer.h"
45 #include <kdebug.h>
46 #include <assert.h>
47 #include "khtmlview.h"
48 #include "render_canvas.h"
49 #include "render_arena.h"
50 #include "xml/dom_docimpl.h"
51 #include "xml/dom2_eventsimpl.h"
52 #include "misc/htmltags.h"
53 #include "html/html_blockimpl.h"
54
55 #include <qscrollbar.h>
56 #include <qptrvector.h>
57
58 using namespace DOM;
59 using namespace khtml;
60
61 #ifdef APPLE_CHANGES
62 QScrollBar* RenderLayer::gScrollBar = 0;
63 #endif
64
65 #ifndef NDEBUG
66 static bool inRenderLayerDetach;
67 #endif
68
69 void
70 RenderScrollMediator::slotValueChanged(int val)
71 {
72     m_layer->updateScrollPositionFromScrollbars();
73 }
74
75 RenderLayer::RenderLayer(RenderObject* object)
76 : m_object( object ),
77 m_parent( 0 ),
78 m_previous( 0 ),
79 m_next( 0 ),
80 m_first( 0 ),
81 m_last( 0 ),
82 m_relX( 0 ),
83 m_relY( 0 ),
84 m_x( 0 ),
85 m_y( 0 ),
86 m_width( 0 ),
87 m_height( 0 ),
88 m_scrollX( 0 ),
89 m_scrollY( 0 ),
90 m_scrollWidth( 0 ),
91 m_scrollHeight( 0 ),
92 m_hBar( 0 ),
93 m_vBar( 0 ),
94 m_scrollMediator( 0 ),
95 m_posZOrderList( 0 ),
96 m_negZOrderList( 0 ),
97 m_scrollDimensionsDirty( true ),
98 m_zOrderListsDirty( true ),
99 m_usedTransparency( false ),
100 m_marquee( 0 )
101 {
102 }
103
104 RenderLayer::~RenderLayer()
105 {
106     // Child layers will be deleted by their corresponding render objects, so
107     // our destructor doesn't have to do anything.
108     delete m_hBar;
109     delete m_vBar;
110     delete m_scrollMediator;
111     delete m_posZOrderList;
112     delete m_negZOrderList;
113     delete m_marquee;
114 }
115
116 void RenderLayer::computeRepaintRects()
117 {
118     // FIXME: Child object could override visibility.
119     if (m_object->style()->visibility() == VISIBLE)
120         m_object->getAbsoluteRepaintRectIncludingFloats(m_repaintRect, m_fullRepaintRect);
121     for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
122         child->computeRepaintRects();
123 }
124
125 void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint)
126 {
127     if (doFullRepaint) {
128         m_object->repaint();
129         checkForRepaint = doFullRepaint = false;
130     }
131     
132     updateLayerPosition(); // For relpositioned layers or non-positioned layers,
133                            // we need to keep in sync, since we may have shifted relative
134                            // to our parent layer.
135
136     if (m_hBar || m_vBar) {
137         // Need to position the scrollbars.
138         int x = 0;
139         int y = 0;
140         convertToLayerCoords(root(), x, y);
141         QRect layerBounds = QRect(x,y,width(),height());
142         positionScrollbars(layerBounds);
143     }
144
145     // FIXME: Child object could override visibility.
146     if (checkForRepaint && (m_object->style()->visibility() == VISIBLE))
147         m_object->repaintAfterLayoutIfNeeded(m_repaintRect, m_fullRepaintRect);
148     
149     for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
150         child->updateLayerPositions(doFullRepaint, checkForRepaint);
151         
152     // With all our children positioned, now update our marquee if we need to.
153     if (m_marquee)
154         m_marquee->updateMarqueePosition();
155 }
156
157 void RenderLayer::updateLayerPosition()
158 {
159     // The canvas is sized to the docWidth/Height over in RenderCanvas::layout, so we
160     // don't need to ever update our layer position here.
161     if (renderer()->isCanvas())
162         return;
163     
164     int x = m_object->xPos();
165     int y = m_object->yPos();
166
167     if (!m_object->isPositioned()) {
168         // We must adjust our position by walking up the render tree looking for the
169         // nearest enclosing object with a layer.
170         RenderObject* curr = m_object->parent();
171         while (curr && !curr->layer()) {
172             x += curr->xPos();
173             y += curr->yPos();
174             curr = curr->parent();
175         }
176     }
177
178     m_relX = m_relY = 0;
179     if (m_object->isRelPositioned()) {
180         static_cast<RenderBox*>(m_object)->relativePositionOffset(m_relX, m_relY);
181         x += m_relX; y += m_relY;
182     }
183     
184     // Subtract our parent's scroll offset.
185     if (m_object->isPositioned())
186         // For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
187         enclosingPositionedAncestor()->subtractScrollOffset(x, y);
188     else
189         parent()->subtractScrollOffset(x, y);
190     
191     setPos(x,y);
192
193     setWidth(m_object->width());
194     setHeight(m_object->height());
195
196     if (!m_object->hasOverflowClip()) {
197         if (m_object->overflowWidth() > m_object->width())
198             setWidth(m_object->overflowWidth());
199         if (m_object->overflowHeight() > m_object->height())
200             setHeight(m_object->overflowHeight());
201     }    
202 }
203
204 RenderLayer *RenderLayer::stackingContext() const
205 {
206     RenderLayer* curr = parent();
207     for ( ; curr && !curr->m_object->isCanvas() && !curr->m_object->isRoot() &&
208           curr->m_object->style()->hasAutoZIndex();
209           curr = curr->parent());
210     return curr;
211 }
212
213 RenderLayer*
214 RenderLayer::enclosingPositionedAncestor() const
215 {
216     RenderLayer* curr = parent();
217     for ( ; curr && !curr->m_object->isCanvas() && !curr->m_object->isRoot() &&
218          !curr->m_object->isPositioned() && !curr->m_object->isRelPositioned();
219          curr = curr->parent());
220          
221     return curr;
222 }
223
224 #if APPLE_CHANGES
225 bool
226 RenderLayer::isTransparent()
227 {
228     return m_object->style()->opacity() < 1.0f;
229 }
230
231 RenderLayer*
232 RenderLayer::transparentAncestor()
233 {
234     RenderLayer* curr = parent();
235     for ( ; curr && curr->m_object->style()->opacity() == 1.0f; curr = curr->parent());
236     return curr;
237 }
238
239 void RenderLayer::beginTransparencyLayers(QPainter* p)
240 {
241     if (isTransparent() && m_usedTransparency)
242         return;
243     
244     RenderLayer* ancestor = transparentAncestor();
245     if (ancestor)
246         ancestor->beginTransparencyLayers(p);
247     
248     if (isTransparent()) {
249         m_usedTransparency = true;
250         p->beginTransparencyLayer(renderer()->style()->opacity());
251     }
252 }
253
254 #endif
255
256 void* RenderLayer::operator new(size_t sz, RenderArena* renderArena) throw()
257 {
258     return renderArena->allocate(sz);
259 }
260
261 void RenderLayer::operator delete(void* ptr, size_t sz)
262 {
263     assert(inRenderLayerDetach);
264     
265     // Stash size where detach can find it.
266     *(size_t *)ptr = sz;
267 }
268
269 void RenderLayer::detach(RenderArena* renderArena)
270 {
271 #ifndef NDEBUG
272     inRenderLayerDetach = true;
273 #endif
274     delete this;
275 #ifndef NDEBUG
276     inRenderLayerDetach = false;
277 #endif
278     
279     // Recover the size left there for us by operator delete and free the memory.
280     renderArena->free(*(size_t *)this, this);
281 }
282
283 void RenderLayer::addChild(RenderLayer *child, RenderLayer* beforeChild)
284 {
285     RenderLayer* prevSibling = beforeChild ? beforeChild->previousSibling() : lastChild();
286     if (prevSibling) {
287         child->setPreviousSibling(prevSibling);
288         prevSibling->setNextSibling(child);
289     }
290     else
291         setFirstChild(child);
292
293     if (beforeChild) {
294         beforeChild->setPreviousSibling(child);
295         child->setNextSibling(beforeChild);
296     }
297     else
298         setLastChild(child);
299    
300     child->setParent(this);
301
302     // Dirty the z-order list in which we are contained.  The stackingContext() can be null in the
303     // case where we're building up generated content layers.  This is ok, since the lists will start
304     // off dirty in that case anyway.
305     RenderLayer* stackingContext = child->stackingContext();
306     if (stackingContext)
307         stackingContext->dirtyZOrderLists();
308 }
309
310 RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
311 {
312     // remove the child
313     if (oldChild->previousSibling())
314         oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
315     if (oldChild->nextSibling())
316         oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
317
318     if (m_first == oldChild)
319         m_first = oldChild->nextSibling();
320     if (m_last == oldChild)
321         m_last = oldChild->previousSibling();
322
323     // Dirty the z-order list in which we are contained.  When called via the
324     // reattachment process in removeOnlyThisLayer, the layer may already be disconnected
325     // from the main layer tree, so we need to null-check the |stackingContext| value.
326     RenderLayer* stackingContext = oldChild->stackingContext();
327     if (stackingContext)
328         oldChild->stackingContext()->dirtyZOrderLists();
329     
330     oldChild->setPreviousSibling(0);
331     oldChild->setNextSibling(0);
332     oldChild->setParent(0);
333     
334     return oldChild;
335 }
336
337 void RenderLayer::removeOnlyThisLayer()
338 {
339     if (!m_parent)
340         return;
341     
342     // Remove us from the parent.
343     RenderLayer* parent = m_parent;
344     RenderLayer* nextSib = nextSibling();
345     parent->removeChild(this);
346     
347     // Now walk our kids and reattach them to our parent.
348     RenderLayer* current = m_first;
349     while (current) {
350         RenderLayer* next = current->nextSibling();
351         removeChild(current);
352         parent->addChild(current, nextSib);
353         current = next;
354     }
355     
356     detach(renderer()->renderArena());
357 }
358
359 void RenderLayer::insertOnlyThisLayer()
360 {
361     if (!m_parent && renderer()->parent()) {
362         // We need to connect ourselves when our renderer() has a parent.
363         // Find our enclosingLayer and add ourselves.
364         RenderLayer* parentLayer = renderer()->parent()->enclosingLayer();
365         if (parentLayer)
366             parentLayer->addChild(this, 
367                                   renderer()->parent()->findNextLayer(parentLayer, renderer()));
368     }
369     
370     // Remove all descendant layers from the hierarchy and add them to the new position.
371     for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
372         curr->moveLayers(m_parent, this);
373 }
374
375 void 
376 RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const
377 {
378     if (ancestorLayer == this)
379         return;
380         
381     if (m_object->style()->position() == FIXED) {
382         // Add in the offset of the view.  We can obtain this by calling
383         // absolutePosition() on the RenderCanvas.
384         int xOff, yOff;
385         m_object->absolutePosition(xOff, yOff, true);
386         x += xOff;
387         y += yOff;
388         return;
389     }
390  
391     RenderLayer* parentLayer;
392     if (m_object->style()->position() == ABSOLUTE)
393         parentLayer = enclosingPositionedAncestor();
394     else
395         parentLayer = parent();
396     
397     if (!parentLayer) return;
398     
399     parentLayer->convertToLayerCoords(ancestorLayer, x, y);
400
401     if (m_object->style()->position() == ABSOLUTE && parentLayer->renderer()->style()->position() == RELATIVE &&
402         parentLayer->renderer()->isInline() && !parentLayer->renderer()->isReplaced()) {
403         // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
404         // box from the rest of the content, but only in the cases where we know we're positioned
405         // relative to the inline itself.
406         RenderFlow* flow = static_cast<RenderFlow*>(parentLayer->renderer());
407         if (flow->firstLineBox()) {
408             bool isInlineType = m_object->style()->isOriginalDisplayInlineType();
409             if (!m_object->hasStaticX() || (m_object->hasStaticX() && !isInlineType))
410                 x += flow->firstLineBox()->xPos();
411             if (!m_object->hasStaticY())
412                 y += flow->firstLineBox()->yPos();
413         }
414     }
415     
416     x += xPos();
417     y += yPos();
418 }
419
420 void
421 RenderLayer::scrollOffset(int& x, int& y)
422 {
423     x += scrollXOffset();
424     y += scrollYOffset();
425 }
426
427 void
428 RenderLayer::subtractScrollOffset(int& x, int& y)
429 {
430     x -= scrollXOffset();
431     y -= scrollYOffset();
432 }
433
434 void
435 RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint)
436 {
437     if (renderer()->style()->overflow() != OMARQUEE) {
438         if (x < 0) x = 0;
439         if (y < 0) y = 0;
440     
441         // Call the scrollWidth/Height functions so that the dimensions will be computed if they need
442         // to be (for overflow:hidden blocks).
443         int maxX = scrollWidth() - m_object->clientWidth();
444         int maxY = scrollHeight() - m_object->clientHeight();
445         
446         if (x > maxX) x = maxX;
447         if (y > maxY) y = maxY;
448     }
449     
450     // FIXME: Eventually, we will want to perform a blit.  For now never
451     // blit, since the check for blitting is going to be very
452     // complicated (since it will involve testing whether our layer
453     // is either occluded by another layer or clipped by an enclosing
454     // layer or contains fixed backgrounds, etc.).
455     m_scrollX = x;
456     m_scrollY = y;
457
458     // Update the positions of our child layers.
459     for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
460         child->updateLayerPositions();
461     
462 #if APPLE_CHANGES
463     // Move our widgets.
464     m_object->updateWidgetPositions();
465 #endif
466
467     // Fire the scroll DOM event.
468     m_object->element()->dispatchHTMLEvent(EventImpl::SCROLL_EVENT, true, false);
469
470     // Just schedule a full repaint of our object.
471     if (repaint)
472         m_object->repaint(true);
473     
474     if (updateScrollbars) {
475         if (m_hBar)
476             m_hBar->setValue(m_scrollX);
477         if (m_vBar)
478             m_vBar->setValue(m_scrollY);
479     }
480 }
481
482 void
483 RenderLayer::updateScrollPositionFromScrollbars()
484 {
485     bool needUpdate = false;
486     int newX = m_scrollX;
487     int newY = m_scrollY;
488     
489     if (m_hBar) {
490         newX = m_hBar->value();
491         if (newX != m_scrollX)
492            needUpdate = true;
493     }
494
495     if (m_vBar) {
496         newY = m_vBar->value();
497         if (newY != m_scrollY)
498            needUpdate = true;
499     }
500
501     if (needUpdate)
502         scrollToOffset(newX, newY, false);
503 }
504
505 void
506 RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
507 {
508     if (hasScrollbar && !m_hBar) {
509         QScrollView* scrollView = m_object->element()->getDocument()->view();
510         m_hBar = new QScrollBar(Qt::Horizontal, scrollView);
511         scrollView->addChild(m_hBar, 0, -50000);
512         if (!m_scrollMediator)
513             m_scrollMediator = new RenderScrollMediator(this);
514         m_scrollMediator->connect(m_hBar, SIGNAL(valueChanged(int)), SLOT(slotValueChanged(int)));
515     }
516     else if (!hasScrollbar && m_hBar) {
517         m_scrollMediator->disconnect(m_hBar, SIGNAL(valueChanged(int)),
518                                      m_scrollMediator, SLOT(slotValueChanged(int)));
519         delete m_hBar;
520         m_hBar = 0;
521     }
522 }
523
524 void
525 RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
526 {
527     if (hasScrollbar && !m_vBar) {
528         QScrollView* scrollView = m_object->element()->getDocument()->view();
529         m_vBar = new QScrollBar(Qt::Vertical, scrollView);
530         scrollView->addChild(m_vBar, 0, -50000);
531         if (!m_scrollMediator)
532             m_scrollMediator = new RenderScrollMediator(this);
533         m_scrollMediator->connect(m_vBar, SIGNAL(valueChanged(int)), SLOT(slotValueChanged(int)));
534     }
535     else if (!hasScrollbar && m_vBar) {
536         m_scrollMediator->disconnect(m_vBar, SIGNAL(valueChanged(int)),
537                                      m_scrollMediator, SLOT(slotValueChanged(int)));
538         delete m_vBar;
539         m_vBar = 0;
540     }
541 }
542
543 int
544 RenderLayer::verticalScrollbarWidth()
545 {
546     if (!m_vBar)
547         return 0;
548
549     return m_vBar->width();
550 }
551
552 int
553 RenderLayer::horizontalScrollbarHeight()
554 {
555     if (!m_hBar)
556         return 0;
557
558     return m_hBar->height();
559 }
560
561 void
562 RenderLayer::moveScrollbarsAside()
563 {
564     if (m_hBar)
565         m_hBar->move(0, -50000);
566     if (m_vBar)
567         m_vBar->move(0, -50000);
568 }
569
570 void
571 RenderLayer::positionScrollbars(const QRect& absBounds)
572 {
573     if (m_vBar) {
574         m_vBar->move(absBounds.x()+absBounds.width()-m_object->borderRight()-m_vBar->width(),
575                      absBounds.y()+m_object->borderTop());
576         m_vBar->resize(m_vBar->width(), absBounds.height() -
577                        (m_object->borderTop()+m_object->borderBottom()) -
578                        (m_hBar ? m_hBar->height()-1 : 0));
579     }
580
581     if (m_hBar) {
582         m_hBar->move(absBounds.x()+m_object->borderLeft(),
583                      absBounds.y()+absBounds.height()-m_object->borderBottom()-m_hBar->height());
584         m_hBar->resize(absBounds.width() - (m_object->borderLeft()+m_object->borderRight()) -
585                        (m_vBar ? m_vBar->width()-1 : 0),
586                        m_hBar->height());
587     }
588 }
589
590 #define LINE_STEP   10
591 #define PAGE_KEEP   40
592
593 int RenderLayer::scrollWidth()
594 {
595     if (m_scrollDimensionsDirty)
596         computeScrollDimensions();
597     return m_scrollWidth;
598 }
599
600 int RenderLayer::scrollHeight()
601 {
602     if (m_scrollDimensionsDirty)
603         computeScrollDimensions();
604     return m_scrollHeight;
605 }
606
607 void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar)
608 {
609     m_scrollDimensionsDirty = false;
610
611     int rightPos = m_object->rightmostPosition(true, false) - m_object->borderLeft();
612     int bottomPos = m_object->lowestPosition(true, false) - m_object->borderTop();
613
614     int clientWidth = m_object->clientWidth();
615     int clientHeight = m_object->clientHeight();
616
617     m_scrollWidth = kMax(rightPos, clientWidth);
618     m_scrollHeight = kMax(bottomPos, clientHeight);
619
620     if (needHBar)
621         *needHBar = rightPos > clientWidth;
622     if (needVBar)
623         *needVBar = bottomPos > clientHeight;
624 }
625
626 void
627 RenderLayer::updateScrollInfoAfterLayout()
628 {
629     m_scrollDimensionsDirty = true;
630     if (m_object->style()->overflow() == OHIDDEN)
631         return; // All we had to do was dirty.
632
633     bool needHorizontalBar, needVerticalBar;
634     computeScrollDimensions(&needHorizontalBar, &needVerticalBar);
635     
636     bool haveHorizontalBar = m_hBar;
637     bool haveVerticalBar = m_vBar;
638
639     // overflow:scroll should just enable/disable.
640     if (m_object->style()->overflow() == OSCROLL) {
641         m_hBar->setEnabled(needHorizontalBar);
642         m_vBar->setEnabled(needVerticalBar);
643     }
644
645     // overflow:auto may need to lay out again if scrollbars got added/removed.
646     bool scrollbarsChanged = (m_object->hasAutoScrollbars()) &&
647         (haveHorizontalBar != needHorizontalBar || haveVerticalBar != needVerticalBar);    
648     if (scrollbarsChanged) {
649         setHasHorizontalScrollbar(needHorizontalBar);
650         setHasVerticalScrollbar(needVerticalBar);
651        
652         m_object->repaint();
653         if (m_object->style()->overflow() == OAUTO) {
654             // Our proprietary overflow: overlay value doesn't trigger a layout.
655             m_object->setNeedsLayout(true);
656             if (m_object->isRenderBlock())
657                 static_cast<RenderBlock*>(m_object)->layoutBlock(true);
658             else
659                 m_object->layout();
660             return;
661         }
662     }
663
664     // Set up the range (and page step/line step).
665     if (m_hBar) {
666         int clientWidth = m_object->clientWidth();
667         int pageStep = (clientWidth-PAGE_KEEP);
668         if (pageStep < 0) pageStep = clientWidth;
669         m_hBar->setSteps(LINE_STEP, pageStep);
670 #ifdef APPLE_CHANGES
671         m_hBar->setKnobProportion(clientWidth, m_scrollWidth);
672 #else
673         m_hBar->setRange(0, m_scrollWidth-clientWidth);
674         m_object->repaintRectangle(QRect(m_object->borderLeft(), m_object->borderTop() + clientHeight(),
675                                    horizontalScrollbarHeight(),
676                                    m_object->width() - m_object->borderLeft() - m_object->borderRight()));
677 #endif
678     }
679     if (m_vBar) {
680         int clientHeight = m_object->clientHeight();
681         int pageStep = (clientHeight-PAGE_KEEP);
682         if (pageStep < 0) pageStep = clientHeight;
683         m_vBar->setSteps(LINE_STEP, pageStep);
684 #ifdef APPLE_CHANGES
685         m_vBar->setKnobProportion(clientHeight, m_scrollHeight);
686 #else
687         m_vBar->setRange(0, m_scrollHeight-clientHeight);
688 #endif
689         m_object->repaintRectangle(QRect(m_object->borderLeft() + m_object->clientWidth(),
690                                    m_object->borderTop(), verticalScrollbarWidth(), 
691                                    m_object->height() - m_object->borderTop() - m_object->borderBottom()));
692     }
693     
694     m_object->repaint();
695 }
696
697 #if APPLE_CHANGES
698 void
699 RenderLayer::paintScrollbars(QPainter* p, const QRect& damageRect)
700 {
701     if (m_hBar)
702         m_hBar->paint(p, damageRect);
703     if (m_vBar)
704         m_vBar->paint(p, damageRect);
705 }
706 #endif
707
708 void
709 RenderLayer::paint(QPainter *p, const QRect& damageRect, bool selectionOnly, RenderObject *paintingRoot)
710 {
711     paintLayer(this, p, damageRect, false, selectionOnly, paintingRoot);
712 }
713
714 static void setClip(QPainter* p, const QRect& paintDirtyRect, const QRect& clipRect)
715 {
716     if (paintDirtyRect == clipRect)
717         return;
718
719     p->save();
720     
721 #if APPLE_CHANGES
722     p->addClip(clipRect);
723 #else
724     QRect clippedRect = p->xForm(clipRect);
725     QRegion creg(clippedRect);
726     QRegion old = p->clipRegion();
727     if (!old.isNull())
728         creg = old.intersect(creg);
729     p->setClipRegion(creg);
730 #endif
731     
732 }
733
734 static void restoreClip(QPainter* p, const QRect& paintDirtyRect, const QRect& clipRect)
735 {
736     if (paintDirtyRect == clipRect)
737         return;
738     p->restore();
739 }
740
741 void
742 RenderLayer::paintLayer(RenderLayer* rootLayer, QPainter *p,
743                         const QRect& paintDirtyRect, bool haveTransparency, bool selectionOnly,
744                         RenderObject *paintingRoot)
745 {
746     // Calculate the clip rects we should use.
747     QRect layerBounds, damageRect, clipRectToApply;
748     calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply);
749     int x = layerBounds.x();
750     int y = layerBounds.y();
751                              
752     // Ensure our z-order lists are up-to-date.
753     updateZOrderLists();
754
755 #if APPLE_CHANGES
756     if (isTransparent())
757         haveTransparency = true;
758 #endif
759
760     // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which
761     // is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set).
762     // Else, our renderer tree may or may not contain the painting root, so we pass that root along
763     // so it will be tested against as we decend through the renderers.
764     RenderObject *paintingRootForRenderer = 0;
765     if (paintingRoot && !m_object->hasAncestor(paintingRoot)) {
766         paintingRootForRenderer = paintingRoot;
767     }
768     
769     // We want to paint our layer, but only if we intersect the damage rect.
770     bool shouldPaint = intersectsDamageRect(layerBounds, damageRect);
771     if (shouldPaint && !selectionOnly && !damageRect.isEmpty()) {
772 #if APPLE_CHANGES
773         // Begin transparency layers lazily now that we know we have to paint something.
774         if (haveTransparency)
775             beginTransparencyLayers(p);
776 #endif
777         
778         // Paint our background first, before painting any child layers.
779         // Establish the clip used to paint our background.
780         setClip(p, paintDirtyRect, damageRect);
781
782         // Paint the background.
783         RenderObject::PaintInfo info(p, damageRect, PaintActionElementBackground, paintingRootForRenderer);
784         renderer()->paint(info, x - renderer()->xPos(), y - renderer()->yPos());        
785 #if APPLE_CHANGES
786         // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
787         // z-index.  We paint after we painted the background/border, so that the scrollbars will
788         // sit above the background/border.
789         paintScrollbars(p, damageRect);
790 #endif
791         // Restore the clip.
792         restoreClip(p, paintDirtyRect, damageRect);
793     }
794
795     // Now walk the sorted list of children with negative z-indices.
796     if (m_negZOrderList) {
797         uint count = m_negZOrderList->count();
798         for (uint i = 0; i < count; i++) {
799             RenderLayer* child = m_negZOrderList->at(i);
800             child->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, selectionOnly, paintingRoot);
801         }
802     }
803     
804     // Now establish the appropriate clip and paint our child RenderObjects.
805     if (shouldPaint && !clipRectToApply.isEmpty()) {
806 #if APPLE_CHANGES
807         // Begin transparency layers lazily now that we know we have to paint something.
808         if (haveTransparency)
809             beginTransparencyLayers(p);
810 #endif
811
812         // Set up the clip used when painting our children.
813         setClip(p, paintDirtyRect, clipRectToApply);
814
815         int tx = x - renderer()->xPos();
816         int ty = y - renderer()->yPos();
817         RenderObject::PaintInfo info(p, clipRectToApply, 
818                                      selectionOnly ? PaintActionSelection : PaintActionChildBackgrounds,
819                                      paintingRootForRenderer);
820         renderer()->paint(info, tx, ty);
821         if (!selectionOnly) {
822             info.phase = PaintActionFloat;
823             renderer()->paint(info, tx, ty);
824             info.phase = PaintActionForeground;
825             renderer()->paint(info, tx, ty);
826             info.phase = PaintActionOutline;
827             renderer()->paint(info, tx, ty);
828         }
829
830         // Now restore our clip.
831         restoreClip(p, paintDirtyRect, clipRectToApply);
832     }
833     
834     // Now walk the sorted list of children with positive z-indices.
835     if (m_posZOrderList) {
836         uint count = m_posZOrderList->count();
837         for (uint i = 0; i < count; i++) {
838             RenderLayer* child = m_posZOrderList->at(i);
839             child->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, selectionOnly, paintingRoot);
840         }
841     }
842     
843 #if APPLE_CHANGES
844     // End our transparency layer
845     if (isTransparent() && m_usedTransparency) {
846         p->endTransparencyLayer();
847         m_usedTransparency = false;
848     }
849 #endif
850 }
851
852 bool
853 RenderLayer::nodeAtPoint(RenderObject::NodeInfo& info, int x, int y)
854 {
855 #if APPLE_CHANGES
856     // Clear our our scrollbar variable
857     RenderLayer::gScrollBar = 0;
858 #endif
859     
860     QRect damageRect(m_x, m_y, width(), height());
861     RenderLayer* insideLayer = nodeAtPointForLayer(this, info, x, y, damageRect);
862
863     // Now determine if the result is inside an anchor; make sure an image map wins if
864     // it already set URLElement and only use the innermost.
865     DOM::NodeImpl* node = info.innerNode();
866     while (node) {
867         if (node->hasAnchor() && !info.URLElement())
868             info.setURLElement(node);
869         node = node->parentNode();
870     }
871
872     // Next set up the correct :hover/:active state along the new chain.
873     updateHoverActiveState(info);
874
875     // Now return whether we were inside this layer (this will always be true for the root
876     // layer).
877     return insideLayer;
878 }
879
880 RenderLayer*
881 RenderLayer::nodeAtPointForLayer(RenderLayer* rootLayer, RenderObject::NodeInfo& info,
882                                  int xMousePos, int yMousePos, const QRect& hitTestRect)
883 {
884     // Calculate the clip rects we should use.
885     QRect layerBounds, bgRect, fgRect;
886     calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect);
887     
888     // Ensure our z-order lists are up-to-date.
889     updateZOrderLists();
890
891     // This variable tracks which layer the mouse ends up being inside.  The minute we find an insideLayer,
892     // we are done and can return it.
893     RenderLayer* insideLayer = 0;
894     
895     // Begin by walking our list of positive layers from highest z-index down to the lowest
896     // z-index.
897     if (m_posZOrderList) {
898         uint count = m_posZOrderList->count();
899         for (int i = count-1; i >= 0; i--) {
900             RenderLayer* child = m_posZOrderList->at(i);
901             insideLayer = child->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
902             if (insideLayer)
903                 return insideLayer;
904         }
905     }
906
907     // Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
908     if (containsPoint(xMousePos, yMousePos, fgRect) &&
909         renderer()->nodeAtPoint(info, xMousePos, yMousePos,
910                                 layerBounds.x() - renderer()->xPos(),
911                                 layerBounds.y() - renderer()->yPos(),
912                                 HitTestChildrenOnly)) {
913
914         // for positioned generated content, we might still not have a
915         // node by the time we get to the layer level, since none of
916         // the content in the layer has an element. So just walk up
917         // the tree.
918          if (!info.innerNode()) {
919             for (RenderObject *r = renderer(); r != NULL; r = r->parent()) { 
920                 if (r->element()) {
921                     info.setInnerNode(r->element());
922                     break;
923                 }
924             }
925          }
926
927          if (!info.innerNonSharedNode()) {
928              for (RenderObject *r = renderer(); r != NULL; r = r->parent()) { 
929                  if (r->element()) {
930                      info.setInnerNonSharedNode(r->element());
931                      break;
932                  }
933              }
934          }
935
936
937
938         return this;
939     }
940         
941     // Now check our negative z-index children.
942     if (m_negZOrderList) {
943         uint count = m_negZOrderList->count();
944         for (int i = count-1; i >= 0; i--) {
945             RenderLayer* child = m_negZOrderList->at(i);
946             insideLayer = child->nodeAtPointForLayer(rootLayer, info, xMousePos, yMousePos, hitTestRect);
947             if (insideLayer)
948                 return insideLayer;
949         }
950     }
951
952     // Next we want to see if the mouse pos is inside this layer but not any of its children.
953     if (containsPoint(xMousePos, yMousePos, bgRect) &&
954         renderer()->nodeAtPoint(info, xMousePos, yMousePos,
955                                 layerBounds.x() - renderer()->xPos(),
956                                 layerBounds.y() - renderer()->yPos(),
957                                 HitTestSelfOnly))
958         return this;
959
960     // No luck.
961     return 0;
962 }
963
964 void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, QRect& overflowClipRect,
965                                      QRect& posClipRect, QRect& fixedClipRect)
966 {
967     if (parent())
968         parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
969
970     // A fixed object is essentially the root of its containing block hierarchy, so when
971     // we encounter such an object, we reset our clip rects to the fixedClipRect.
972     if (m_object->style()->position() == FIXED) {
973         posClipRect = fixedClipRect;
974         overflowClipRect = fixedClipRect;
975     }
976     else if (m_object->style()->position() == RELATIVE)
977         posClipRect = overflowClipRect;
978     
979     // Update the clip rects that will be passed to child layers.
980     if (m_object->hasOverflowClip() || m_object->hasClip()) {
981         // This layer establishes a clip of some kind.
982         int x = 0;
983         int y = 0;
984         convertToLayerCoords(rootLayer, x, y);
985         
986         if (m_object->hasOverflowClip()) {
987             QRect newOverflowClip = m_object->getOverflowClipRect(x,y);
988             overflowClipRect  = newOverflowClip.intersect(overflowClipRect);
989             if (m_object->isPositioned() || m_object->isRelPositioned())
990                 posClipRect = newOverflowClip.intersect(posClipRect);
991         }
992         if (m_object->hasClip()) {
993             QRect newPosClip = m_object->getClipRect(x,y);
994             posClipRect = posClipRect.intersect(newPosClip);
995             overflowClipRect = overflowClipRect.intersect(newPosClip);
996             fixedClipRect = fixedClipRect.intersect(newPosClip);
997         }
998     }
999 }
1000
1001 void RenderLayer::calculateRects(const RenderLayer* rootLayer, const QRect& paintDirtyRect, QRect& layerBounds,
1002                                  QRect& backgroundRect, QRect& foregroundRect)
1003 {
1004     QRect overflowClipRect = paintDirtyRect;
1005     QRect posClipRect = paintDirtyRect;
1006     QRect fixedClipRect = paintDirtyRect;
1007     if (parent())
1008         parent()->calculateClipRects(rootLayer, overflowClipRect, posClipRect, fixedClipRect);
1009
1010     int x = 0;
1011     int y = 0;
1012     convertToLayerCoords(rootLayer, x, y);
1013     layerBounds = QRect(x,y,width(),height());
1014
1015     backgroundRect = m_object->style()->position() == FIXED ? fixedClipRect :
1016         (m_object->isPositioned() ? posClipRect : overflowClipRect);
1017     foregroundRect = backgroundRect;
1018     
1019     // Update the clip rects that will be passed to child layers.
1020     if (m_object->hasOverflowClip() || m_object->hasClip()) {
1021         // This layer establishes a clip of some kind.
1022         if (m_object->hasOverflowClip())
1023             foregroundRect = foregroundRect.intersect(m_object->getOverflowClipRect(x,y));
1024         if (m_object->hasClip()) {
1025             // Clip applies to *us* as well, so go ahead and update the damageRect.
1026             QRect newPosClip = m_object->getClipRect(x,y);
1027             backgroundRect = backgroundRect.intersect(newPosClip);
1028             foregroundRect = foregroundRect.intersect(newPosClip);
1029         }
1030
1031         // If we establish a clip at all, then go ahead and make sure our background
1032         // rect is intersected with our layer's bounds.
1033         backgroundRect = backgroundRect.intersect(layerBounds);
1034     }
1035 }
1036
1037 bool RenderLayer::intersectsDamageRect(const QRect& layerBounds, const QRect& damageRect) const
1038 {
1039     return (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isBody() ||
1040             (renderer()->hasOverhangingFloats() && !renderer()->hasOverflowClip()) ||
1041             (renderer()->isInline() && !renderer()->isReplaced()) ||
1042             layerBounds.intersects(damageRect));
1043 }
1044
1045 bool RenderLayer::containsPoint(int x, int y, const QRect& damageRect) const
1046 {
1047     return (renderer()->isCanvas() || renderer()->isRoot() || renderer()->isBody() ||
1048             (renderer()->hasOverhangingFloats() && !renderer()->hasOverflowClip()) ||
1049             (renderer()->isInline() && !renderer()->isReplaced()) ||
1050             damageRect.contains(x, y));
1051 }
1052
1053 // This code has been written to anticipate the addition of CSS3-::outside and ::inside generated
1054 // content (and perhaps XBL).  That's why it uses the render tree and not the DOM tree.
1055 static RenderObject* hoverAncestor(RenderObject* obj)
1056 {
1057     return (!obj->isInline() && obj->continuation()) ? obj->continuation() : obj->parent();
1058 }
1059
1060 static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2)
1061 {
1062     if (!obj1 || !obj2)
1063         return 0;
1064
1065     for (RenderObject* currObj1 = obj1; currObj1; currObj1 = hoverAncestor(currObj1))
1066         for (RenderObject* currObj2 = obj2; currObj2; currObj2 = hoverAncestor(currObj2))
1067             if (currObj1 == currObj2)
1068                 return currObj1;
1069
1070     return 0;
1071 }
1072
1073 void RenderLayer::updateHoverActiveState(RenderObject::NodeInfo& info)
1074 {
1075     // We don't update :hover/:active state when the info is marked as readonly.
1076     if (info.readonly())
1077         return;
1078
1079     // Check to see if the hovered node has changed.  If not, then we don't need to
1080     // do anything.  An exception is if we just went from :hover into :hover:active,
1081     // in which case we need to update to get the new :active state.
1082     DOM::DocumentImpl* doc = renderer()->document();
1083     DOM::NodeImpl* oldHoverNode = doc ? doc->hoverNode() : 0;
1084     DOM::NodeImpl* newHoverNode = info.innerNode();
1085
1086     // Update our current hover node.
1087     if (doc)
1088         doc->setHoverNode(newHoverNode);
1089
1090     // We have two different objects.  Fetch their renderers.
1091     RenderObject* oldHoverObj = oldHoverNode ? oldHoverNode->renderer() : 0;
1092     RenderObject* newHoverObj = newHoverNode ? newHoverNode->renderer() : 0;
1093     
1094     // Locate the common ancestor render object for the two renderers.
1095     RenderObject* ancestor = commonAncestor(oldHoverObj, newHoverObj);
1096     
1097     if (oldHoverObj != newHoverObj) {
1098         // The old hover path only needs to be cleared up to (and not including) the common ancestor;
1099         for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = hoverAncestor(curr)) {
1100             curr->setMouseInside(false);
1101             if (curr->element() && !curr->isText()) {
1102                 bool oldActive = curr->element()->active();
1103                 curr->element()->setActive(false);
1104                 if (curr->style()->affectedByHoverRules() ||
1105                     (curr->style()->affectedByActiveRules() && oldActive))
1106                     curr->element()->setChanged();
1107             }
1108         }
1109     }
1110
1111     // Now set the hover state for our new object up to the root.
1112     for (RenderObject* curr = newHoverObj; curr; curr = hoverAncestor(curr)) {
1113         bool oldInside = curr->mouseInside();
1114         curr->setMouseInside(true);
1115         if (curr->element() && !curr->isText()) {
1116             bool oldActive = curr->element()->active();
1117             curr->element()->setActive(info.active());
1118             if ((curr->style()->affectedByHoverRules() && !oldInside) ||
1119                 (curr->style()->affectedByActiveRules() && oldActive != info.active()))
1120                 curr->element()->setChanged();
1121         }
1122     }
1123 }
1124
1125 // Sort the buffer from lowest z-index to highest.  The common scenario will have
1126 // most z-indices equal, so we optimize for that case (i.e., the list will be mostly
1127 // sorted already).
1128 static void sortByZOrder(QPtrVector<RenderLayer>* buffer,
1129                          QPtrVector<RenderLayer>* mergeBuffer,
1130                          uint start, uint end)
1131 {
1132     if (start >= end)
1133         return; // Sanity check.
1134
1135     if (end - start <= 6) {
1136         // Apply a bubble sort for smaller lists.
1137         for (uint i = end-1; i > start; i--) {
1138             bool sorted = true;
1139             for (uint j = start; j < i; j++) {
1140                 RenderLayer* elt = buffer->at(j);
1141                 RenderLayer* elt2 = buffer->at(j+1);
1142                 if (elt->zIndex() > elt2->zIndex()) {
1143                     sorted = false;
1144                     buffer->insert(j, elt2);
1145                     buffer->insert(j+1, elt);
1146                 }
1147             }
1148             if (sorted)
1149                 return;
1150         }
1151     }
1152     else {
1153         // Peform a merge sort for larger lists.
1154         uint mid = (start+end)/2;
1155         sortByZOrder(buffer, mergeBuffer, start, mid);
1156         sortByZOrder(buffer, mergeBuffer, mid, end);
1157
1158         RenderLayer* elt = buffer->at(mid-1);
1159         RenderLayer* elt2 = buffer->at(mid);
1160
1161         // Handle the fast common case (of equal z-indices).  The list may already
1162         // be completely sorted.
1163         if (elt->zIndex() <= elt2->zIndex())
1164             return;
1165
1166         // We have to merge sort.  Ensure our merge buffer is big enough to hold
1167         // all the items.
1168         mergeBuffer->resize(end - start);
1169         uint i1 = start;
1170         uint i2 = mid;
1171
1172         elt = buffer->at(i1);
1173         elt2 = buffer->at(i2);
1174
1175         while (i1 < mid || i2 < end) {
1176             if (i1 < mid && (i2 == end || elt->zIndex() <= elt2->zIndex())) {
1177                 mergeBuffer->insert(mergeBuffer->count(), elt);
1178                 i1++;
1179                 if (i1 < mid)
1180                     elt = buffer->at(i1);
1181             }
1182             else {
1183                 mergeBuffer->insert(mergeBuffer->count(), elt2);
1184                 i2++;
1185                 if (i2 < end)
1186                     elt2 = buffer->at(i2);
1187             }
1188         }
1189
1190         for (uint i = start; i < end; i++)
1191             buffer->insert(i, mergeBuffer->at(i-start));
1192
1193         mergeBuffer->clear();
1194     }
1195 }
1196
1197 void RenderLayer::dirtyZOrderLists()
1198 {
1199     if (m_posZOrderList)
1200         m_posZOrderList->clear();
1201     if (m_negZOrderList)
1202         m_negZOrderList->clear();
1203     m_zOrderListsDirty = true;
1204 }
1205     
1206 void RenderLayer::updateZOrderLists()
1207 {
1208     if (!isStackingContext() || !m_zOrderListsDirty)
1209         return;
1210     
1211     for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
1212         child->collectLayers(m_posZOrderList, m_negZOrderList);
1213
1214     // Sort the two lists.
1215     if (m_posZOrderList) {
1216         QPtrVector<RenderLayer> mergeBuffer;
1217         sortByZOrder(m_posZOrderList, &mergeBuffer, 0, m_posZOrderList->count());
1218     }
1219     if (m_negZOrderList) {
1220         QPtrVector<RenderLayer> mergeBuffer;
1221         sortByZOrder(m_negZOrderList, &mergeBuffer, 0, m_negZOrderList->count());
1222     }
1223
1224     m_zOrderListsDirty = false;
1225 }
1226
1227 void RenderLayer::collectLayers(QPtrVector<RenderLayer>*& posBuffer, QPtrVector<RenderLayer>*& negBuffer)
1228 {
1229     // FIXME: A child render object or layer could override visibility.  Don't remove this
1230     // optimization though until RenderObject's nodeAtPoint is patched to understand what to do
1231     // when visibility is overridden by a child.
1232     if (renderer()->style()->visibility() != VISIBLE)
1233         return;
1234     
1235     // Determine which buffer the child should be in.
1236     QPtrVector<RenderLayer>*& buffer = (zIndex() >= 0) ? posBuffer : negBuffer;
1237
1238     // Create the buffer if it doesn't exist yet.
1239     if (!buffer)
1240         buffer = new QPtrVector<RenderLayer>();
1241     
1242     // Resize by a power of 2 when our buffer fills up.
1243     if (buffer->count() == buffer->size())
1244         buffer->resize(2*(buffer->size()+1));
1245
1246     // Append ourselves at the end of the appropriate buffer.
1247     buffer->insert(buffer->count(), this);
1248
1249     // Recur into our children to collect more layers, but only if we don't establish
1250     // a stacking context.
1251     if (!isStackingContext()) {
1252         for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
1253             child->collectLayers(posBuffer, negBuffer);
1254     }
1255 }
1256
1257 void RenderLayer::repaintIncludingDescendants()
1258 {
1259     m_object->repaint();
1260     for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling())
1261         curr->repaintIncludingDescendants();
1262 }
1263
1264 void RenderLayer::styleChanged()
1265 {
1266     if (m_object->style()->overflow() == OMARQUEE && m_object->style()->marqueeBehavior() != MNONE) {
1267         if (!m_marquee)
1268             m_marquee = new Marquee(this);
1269         m_marquee->updateMarqueeStyle();
1270     }
1271     else if (m_marquee) {
1272         delete m_marquee;
1273         m_marquee = 0;
1274     }
1275 }
1276
1277 void RenderLayer::suspendMarquees()
1278 {
1279     if (m_marquee)
1280         m_marquee->suspend();
1281     
1282     for (RenderLayer* curr = firstChild(); curr; curr = curr->nextSibling())
1283         curr->suspendMarquees();
1284 }
1285
1286 // --------------------------------------------------------------------------
1287 // Marquee implementation
1288
1289 Marquee::Marquee(RenderLayer* l)
1290 :m_layer(l), m_currentLoop(0), m_timerId(0), m_start(0), m_end(0), m_speed(0), m_unfurlPos(0), m_reset(false),
1291  m_suspended(false), m_whiteSpace(NORMAL), m_direction(MAUTO)
1292 {
1293 }
1294
1295 int Marquee::marqueeSpeed() const
1296 {
1297     int result = m_layer->renderer()->style()->marqueeSpeed();
1298     DOM::NodeImpl* elt = m_layer->renderer()->element();
1299     if (elt && elt->id() == ID_MARQUEE) {
1300         HTMLMarqueeElementImpl* marqueeElt = static_cast<HTMLMarqueeElementImpl*>(elt);
1301         result = kMax(result, marqueeElt->minimumDelay());
1302     }
1303     return result;
1304 }
1305
1306 EMarqueeDirection Marquee::direction() const
1307 {
1308     // FIXME: Support the CSS3 "auto" value for determining the direction of the marquee.
1309     // For now just map MAUTO to MBACKWARD
1310     EMarqueeDirection result = m_layer->renderer()->style()->marqueeDirection();
1311     EDirection dir =  m_layer->renderer()->style()->direction();
1312     if (result == MAUTO)
1313         result = MBACKWARD;
1314     if (result == MFORWARD)
1315         result = (dir == LTR) ? MRIGHT : MLEFT;
1316     if (result == MBACKWARD)
1317         result = (dir == LTR) ? MLEFT : MRIGHT;
1318     
1319     // Now we have the real direction.  Next we check to see if the increment is negative.
1320     // If so, then we reverse the direction.
1321     Length increment = m_layer->renderer()->style()->marqueeIncrement();
1322     if (increment.value < 0)
1323         result = static_cast<EMarqueeDirection>(-result);
1324     
1325     return result;
1326 }
1327
1328 bool Marquee::isHorizontal() const
1329 {
1330     return direction() == MLEFT || direction() == MRIGHT;
1331 }
1332
1333 bool Marquee::isUnfurlMarquee() const
1334 {
1335     EMarqueeBehavior behavior = m_layer->renderer()->style()->marqueeBehavior();
1336     return (behavior == MUNFURL);
1337 }
1338
1339 int Marquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge)
1340 {
1341     RenderObject* o = m_layer->renderer();
1342     RenderStyle* s = o->style();
1343     if (isHorizontal()) {
1344         bool ltr = s->direction() == LTR;
1345         int clientWidth = o->clientWidth();
1346         int contentWidth = ltr ? o->rightmostPosition(true, false) : o->leftmostPosition(true, false);
1347         if (ltr)
1348             contentWidth += (o->paddingRight() - o->borderLeft());
1349         else {
1350             contentWidth = o->width() - contentWidth;
1351             contentWidth += (o->paddingLeft() - o->borderRight());
1352         }
1353         if (dir == MRIGHT) {
1354             if (stopAtContentEdge)
1355                 return kMax(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth));
1356             else
1357                 return ltr ? contentWidth : clientWidth;
1358         }
1359         else {
1360             if (stopAtContentEdge)
1361                 return kMin(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth));
1362             else
1363                 return ltr ? -clientWidth : -contentWidth;
1364         }
1365     }
1366     else {
1367         int contentHeight = m_layer->renderer()->lowestPosition(true, false) - 
1368                             m_layer->renderer()->borderTop() + m_layer->renderer()->paddingBottom();
1369         int clientHeight = m_layer->renderer()->clientHeight();
1370         if (dir == MUP) {
1371             if (stopAtContentEdge)
1372                  return kMin(contentHeight - clientHeight, 0);
1373             else
1374                 return -clientHeight;
1375         }
1376         else {
1377             if (stopAtContentEdge)
1378                 return kMax(contentHeight - clientHeight, 0);
1379             else 
1380                 return contentHeight;
1381         }
1382     }    
1383 }
1384
1385 void Marquee::start()
1386 {
1387     if (m_timerId || m_layer->renderer()->style()->marqueeIncrement().value == 0)
1388         return;
1389     
1390     if (!m_suspended) {
1391         if (isUnfurlMarquee()) {
1392             bool forward = direction() == MDOWN || direction() == MRIGHT;
1393             bool isReversed = (forward && m_currentLoop % 2) || (!forward && !(m_currentLoop % 2));
1394             m_unfurlPos = isReversed ? m_end : m_start;
1395             m_layer->renderer()->setChildNeedsLayout(true);
1396         }
1397         else {
1398             if (isHorizontal())
1399                 m_layer->scrollToOffset(m_start, 0, false, false);
1400             else
1401                 m_layer->scrollToOffset(0, m_start, false, false);
1402         }
1403     }
1404     else
1405         m_suspended = false;
1406
1407     m_timerId = startTimer(speed());
1408 }
1409
1410 void Marquee::suspend()
1411 {
1412     if (m_timerId) {
1413         killTimer(m_timerId);
1414         m_timerId = 0;
1415     }
1416     
1417     m_suspended = true;
1418 }
1419
1420 void Marquee::updateMarqueePosition()
1421 {
1422     bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops);
1423     if (activate) {
1424         if (isUnfurlMarquee()) {
1425             if (m_unfurlPos < m_start) {
1426                 m_unfurlPos = m_start;
1427                 m_layer->renderer()->setChildNeedsLayout(true);
1428             }
1429             else if (m_unfurlPos > m_end) {
1430                 m_unfurlPos = m_end;
1431                 m_layer->renderer()->setChildNeedsLayout(true);
1432             }
1433         }
1434         else {
1435             EMarqueeBehavior behavior = m_layer->renderer()->style()->marqueeBehavior();
1436             m_start = computePosition(direction(), behavior == MALTERNATE);
1437             m_end = computePosition(reverseDirection(), behavior == MALTERNATE || behavior == MSLIDE);
1438         }
1439         start();
1440     }
1441 }
1442
1443 void Marquee::updateMarqueeStyle()
1444 {
1445     RenderStyle* s = m_layer->renderer()->style();
1446     
1447     if (m_direction != s->marqueeDirection() || (m_totalLoops != s->marqueeLoopCount() && m_currentLoop >= m_totalLoops))
1448         m_currentLoop = 0; // When direction changes or our loopCount is a smaller number than our current loop, reset our loop.
1449     
1450     m_totalLoops = s->marqueeLoopCount();
1451     m_direction = s->marqueeDirection();
1452     m_whiteSpace = s->whiteSpace();
1453     
1454     if (m_layer->renderer()->isHTMLMarquee()) {
1455         // Hack for WinIE.  In WinIE, a value of 0 or lower for the loop count for SLIDE means to only do
1456         // one loop.
1457         if (m_totalLoops <= 0 && (s->marqueeBehavior() == MSLIDE || s->marqueeBehavior() == MUNFURL))
1458             m_totalLoops = 1;
1459         
1460         // Hack alert: Set the white-space value to nowrap for horizontal marquees with inline children, thus ensuring
1461         // all the text ends up on one line by default.  Limit this hack to the <marquee> element to emulate
1462         // WinIE's behavior.  Someone using CSS3 can use white-space: nowrap on their own to get this effect.
1463         // Second hack alert: Set the text-align back to auto.  WinIE completely ignores text-align on the
1464         // marquee element.
1465         // FIXME: Bring these up with the CSS WG.
1466         if (isHorizontal() && m_layer->renderer()->childrenInline()) {
1467             s->setWhiteSpace(NOWRAP);
1468             s->setTextAlign(TAAUTO);
1469         }
1470     }
1471     
1472     if (speed() != marqueeSpeed()) {
1473         m_speed = marqueeSpeed();
1474         if (m_timerId) {
1475             killTimer(m_timerId);
1476             m_timerId = startTimer(speed());
1477         }
1478     }
1479     
1480     // Check the loop count to see if we should now stop.
1481     bool activate = (m_totalLoops <= 0 || m_currentLoop < m_totalLoops);
1482     if (activate && !m_timerId)
1483         m_layer->renderer()->setNeedsLayout(true);
1484     else if (!activate && m_timerId) {
1485         // Destroy the timer.
1486         killTimer(m_timerId);
1487         m_timerId = 0;
1488     }
1489 }
1490
1491 void Marquee::timerEvent(QTimerEvent* evt)
1492 {
1493     if (m_layer->renderer()->needsLayout())
1494         return;
1495     
1496     if (m_reset) {
1497         m_reset = false;
1498         if (isHorizontal())
1499             m_layer->scrollToXOffset(m_start);
1500         else
1501             m_layer->scrollToYOffset(m_start);
1502         return;
1503     }
1504     
1505     RenderStyle* s = m_layer->renderer()->style();
1506     
1507     int endPoint = m_end;
1508     int range = m_end - m_start;
1509     int newPos;
1510     if (range == 0)
1511         newPos = m_end;
1512     else {  
1513         bool addIncrement = direction() == MUP || direction() == MLEFT;
1514         bool isReversed = s->marqueeBehavior() == MALTERNATE && m_currentLoop % 2;
1515         if (isUnfurlMarquee()) {
1516             isReversed = (!addIncrement && m_currentLoop % 2) || (addIncrement && !(m_currentLoop % 2));
1517             addIncrement = !isReversed;
1518         }
1519         if (isReversed) {
1520             // We're going in the reverse direction.
1521             endPoint = m_start;
1522             range = -range;
1523             if (!isUnfurlMarquee())
1524                 addIncrement = !addIncrement;
1525         }
1526         bool positive = range > 0;
1527         int clientSize = isUnfurlMarquee() ? abs(range) :
1528             (isHorizontal() ? m_layer->renderer()->clientWidth() : m_layer->renderer()->clientHeight());
1529         int increment = kMax(1, abs(m_layer->renderer()->style()->marqueeIncrement().width(clientSize)));
1530         int currentPos = isUnfurlMarquee() ? m_unfurlPos : 
1531             (isHorizontal() ? m_layer->scrollXOffset() : m_layer->scrollYOffset());
1532         newPos =  currentPos + (addIncrement ? increment : -increment);
1533         if (positive)
1534             newPos = kMin(newPos, endPoint);
1535         else
1536             newPos = kMax(newPos, endPoint);
1537     }
1538
1539     if (newPos == endPoint) {
1540         m_currentLoop++;
1541         if (m_totalLoops > 0 && m_currentLoop >= m_totalLoops) {
1542             killTimer(m_timerId);
1543             m_timerId = 0;
1544         }
1545         else if (s->marqueeBehavior() != MALTERNATE && s->marqueeBehavior() != MUNFURL)
1546             m_reset = true;
1547     }
1548     
1549     if (isUnfurlMarquee()) {
1550         m_unfurlPos = newPos;
1551         m_layer->renderer()->setChildNeedsLayout(true);
1552     }
1553     else {
1554         if (isHorizontal())
1555             m_layer->scrollToXOffset(newPos);
1556         else
1557             m_layer->scrollToYOffset(newPos);
1558     }
1559 }
1560