d6a3cf9cabae3e08c5147d0ba0985a9c16f34d4b
[WebKit-https.git] / WebCore / khtml / rendering / render_object.cpp
1 /**
2  * This file is part of the html renderer for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  *           (C) 2000 Dirk Mueller (mueller@kde.org)
7  * Copyright (C) 2004 Apple Computer, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  *
24  */
25
26 #include "config.h"
27 #include "rendering/render_object.h"
28 #include "rendering/render_table.h"
29 #include "rendering/render_text.h"
30 #include "rendering/render_line.h"
31 #include "rendering/render_list.h"
32 #include "rendering/render_canvas.h"
33 #include "xml/dom_elementimpl.h"
34 #include "xml/dom2_eventsimpl.h"
35 #include "xml/dom_docimpl.h"
36 #include "xml/dom_position.h"
37 #include "xml/EventNames.h"
38 #include "css/cssstyleselector.h"
39 #include <kdebug.h>
40 #include <qpainter.h>
41 #include <qpen.h>
42 #include "khtmlview.h"
43 #include "khtml_part.h"
44 #include "render_arena.h"
45 #include "render_inline.h"
46 #include "render_block.h"
47 #include "render_flexbox.h"
48 #include "htmlnames.h"
49
50 // For accessibility
51 #include "KWQAccObjectCache.h" 
52
53 #include <assert.h>
54
55 using namespace DOM;
56 using namespace DOM::EventNames;
57 using namespace HTMLNames;
58 using namespace khtml;
59
60 #ifndef NDEBUG
61 static void *baseOfRenderObjectBeingDeleted;
62 #endif
63
64 void* RenderObject::operator new(size_t sz, RenderArena* renderArena) throw()
65 {
66     return renderArena->allocate(sz);
67 }
68
69 void RenderObject::operator delete(void* ptr, size_t sz)
70 {
71     assert(baseOfRenderObjectBeingDeleted == ptr);
72     
73     // Stash size where destroy can find it.
74     *(size_t *)ptr = sz;
75 }
76
77 RenderObject *RenderObject::createObject(DOM::NodeImpl* node,  RenderStyle* style)
78 {
79     RenderObject *o = 0;
80     RenderArena* arena = node->getDocument()->renderArena();
81     switch(style->display())
82     {
83     case NONE:
84         break;
85     case INLINE:
86         o = new (arena) RenderInline(node);
87         break;
88     case BLOCK:
89         o = new (arena) RenderBlock(node);
90         break;
91     case INLINE_BLOCK:
92         o = new (arena) RenderBlock(node);
93         break;
94     case LIST_ITEM:
95         o = new (arena) RenderListItem(node);
96         break;
97     case RUN_IN:
98     case COMPACT:
99         o = new (arena) RenderBlock(node);
100         break;
101     case TABLE:
102     case INLINE_TABLE:
103         //kdDebug( 6040 ) << "creating RenderTable" << endl;
104         o = new (arena) RenderTable(node);
105         break;
106     case TABLE_ROW_GROUP:
107     case TABLE_HEADER_GROUP:
108     case TABLE_FOOTER_GROUP:
109         o = new (arena) RenderTableSection(node);
110         break;
111     case TABLE_ROW:
112         o = new (arena) RenderTableRow(node);
113         break;
114     case TABLE_COLUMN_GROUP:
115     case TABLE_COLUMN:
116         o = new (arena) RenderTableCol(node);
117         break;
118     case TABLE_CELL:
119         o = new (arena) RenderTableCell(node);
120         break;
121     case TABLE_CAPTION:
122         o = new (arena) RenderBlock(node);
123         break;
124     case BOX:
125     case INLINE_BOX:
126         o = new (arena) RenderFlexibleBox(node);
127         break;
128     }
129     return o;
130 }
131
132 #ifndef NDEBUG
133 struct RenderObjectCounter { 
134     static int count; 
135     ~RenderObjectCounter() { if (count != 0) fprintf(stderr, "LEAK: %d RenderObject\n", count); } 
136 };
137 int RenderObjectCounter::count;
138 static RenderObjectCounter renderObjectCounter;
139 #endif NDEBUG
140
141 RenderObject::RenderObject(DOM::NodeImpl* node)
142     : CachedObjectClient(),
143 m_style( 0 ),
144 m_node( node ),
145 m_parent( 0 ),
146 m_previous( 0 ),
147 m_next( 0 ),
148 m_verticalPosition( PositionUndefined ),
149 m_needsLayout( false ),
150 m_normalChildNeedsLayout( false ),
151 m_posChildNeedsLayout( false ),
152 m_minMaxKnown( false ),
153 m_floating( false ),
154
155 m_positioned( false ),
156 m_relPositioned( false ),
157 m_paintBackground( false ),
158
159 m_isAnonymous( node == node->getDocument() ),
160 m_recalcMinMax( false ),
161 m_isText( false ),
162 m_inline( true ),
163
164 m_replaced( false ),
165 m_isDragging( false ),
166 m_hasOverflowClip(false)
167 {
168 #ifndef NDEBUG
169     ++RenderObjectCounter::count;
170 #endif
171 }
172
173 RenderObject::~RenderObject()
174 {
175 #ifndef NDEBUG
176     --RenderObjectCounter::count;
177 #endif
178 }
179
180 bool RenderObject::hasAncestor(const RenderObject *obj) const
181 {
182     for (const RenderObject *r = this; r; r = r->m_parent)
183         if (r == obj)
184             return true;
185     return false;
186 }
187
188 bool RenderObject::isRoot() const
189 {
190     return element() && element()->renderer() == this &&
191            element()->getDocument()->documentElement() == element();
192 }
193
194 bool RenderObject::isBody() const
195 {
196     return element() && element()->renderer() == this && element()->hasTagName(bodyTag);
197 }
198
199 bool RenderObject::isHR() const
200 {
201     return element() && element()->hasTagName(hrTag);
202 }
203
204 bool RenderObject::isHTMLMarquee() const
205 {
206     return element() && element()->renderer() == this && element()->hasTagName(marqueeTag);
207 }
208
209 bool RenderObject::canHaveChildren() const
210 {
211     return false;
212 }
213
214 RenderFlow* RenderObject::continuation() const
215 {
216     return 0;
217 }
218
219 bool RenderObject::isInlineContinuation() const
220 {
221     return false;
222 }
223
224 void RenderObject::addChild(RenderObject* , RenderObject *)
225 {
226     KHTMLAssert(0);
227 }
228
229 RenderObject* RenderObject::removeChildNode(RenderObject* )
230 {
231     KHTMLAssert(0);
232     return 0;
233 }
234
235 void RenderObject::removeChild(RenderObject* )
236 {
237     KHTMLAssert(0);
238 }
239
240 void RenderObject::appendChildNode(RenderObject*)
241 {
242     KHTMLAssert(0);
243 }
244
245 void RenderObject::insertChildNode(RenderObject*, RenderObject*)
246 {
247     KHTMLAssert(0);
248 }
249
250 RenderObject *RenderObject::nextRenderer() const
251 {
252     if (firstChild())
253         return firstChild();
254     else if (nextSibling())
255         return nextSibling();
256     else {
257         const RenderObject *r = this;
258         while (r && !r->nextSibling())
259             r = r->parent();
260         if (r)
261             return r->nextSibling();
262     }
263     return 0;
264 }
265
266 RenderObject *RenderObject::previousRenderer() const
267 {
268     if (previousSibling()) {
269         RenderObject *r = previousSibling();
270         while (r->lastChild())
271             r = r->lastChild();
272         return r;
273     }
274     else if (parent()) {
275         return parent();
276     }
277     else {
278         return 0;
279     }
280 }
281
282 bool RenderObject::isEditable() const
283 {
284     RenderText *textRenderer = 0;
285     if (isText()) {
286         textRenderer = static_cast<RenderText *>(const_cast<RenderObject *>(this));
287     }
288
289     return style()->visibility() == VISIBLE && 
290         element() && element()->isContentEditable() &&
291         ((isBlockFlow() && !firstChild()) || 
292         isReplaced() || 
293         isBR() || 
294         (textRenderer && textRenderer->firstTextBox()));
295 }
296
297 RenderObject *RenderObject::nextEditable() const
298 {
299     RenderObject *r = const_cast<RenderObject *>(this);
300     RenderObject *n = firstChild();
301     if (n) {
302         while (n) { 
303             r = n; 
304             n = n->firstChild(); 
305         }
306         if (r->isEditable())
307             return r;
308         else 
309             return r->nextEditable();
310     }
311     n = r->nextSibling();
312     if (n) {
313         r = n;
314         while (n) { 
315             r = n; 
316             n = n->firstChild(); 
317         }
318         if (r->isEditable())
319             return r;
320         else 
321             return r->nextEditable();
322     }
323     n = r->parent();
324     while (n) {
325         r = n;
326         n = r->nextSibling();
327         if (n) {
328             r = n;
329             n = r->firstChild();
330             while (n) { 
331                 r = n; 
332                 n = n->firstChild(); 
333             }
334             if (r->isEditable())
335                 return r;
336             else 
337                 return r->nextEditable();
338         }
339         n = r->parent();
340     }
341     return 0;
342 }
343
344 RenderObject *RenderObject::previousEditable() const
345 {
346     RenderObject *r = const_cast<RenderObject *>(this);
347     RenderObject *n = firstChild();
348     if (n) {
349         while (n) { 
350             r = n; 
351             n = n->lastChild(); 
352         }
353         if (r->isEditable())
354             return r;
355         else 
356             return r->previousEditable();
357     }
358     n = r->previousSibling();
359     if (n) {
360         r = n;
361         while (n) { 
362             r = n; 
363             n = n->lastChild(); 
364         }
365         if (r->isEditable())
366             return r;
367         else 
368             return r->previousEditable();
369     }    
370     n = r->parent();
371     while (n) {
372         r = n;
373         n = r->previousSibling();
374         if (n) {
375             r = n;
376             n = r->lastChild();
377             while (n) { 
378                 r = n; 
379                 n = n->lastChild(); 
380             }
381             if (r->isEditable())
382                 return r;
383             else 
384                 return r->previousEditable();
385         }
386         n = r->parent();
387     }
388     return 0;
389
390
391 RenderObject *RenderObject::firstLeafChild() const
392 {
393     RenderObject *r = firstChild();
394     while (r) {
395         RenderObject *n = 0;
396         n = r->firstChild();
397         if (!n)
398             break;
399         r = n;
400     }
401     return r;
402 }
403
404 RenderObject *RenderObject::lastLeafChild() const
405 {
406     RenderObject *r = lastChild();
407     while (r) {
408         RenderObject *n = 0;
409         n = r->lastChild();
410         if (!n)
411             break;
412         r = n;
413     }
414     return r;
415 }
416
417 static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*& newObject,
418                       RenderLayer*& beforeChild)
419 {
420     if (obj->layer()) {
421         if (!beforeChild && newObject) {
422             // We need to figure out the layer that follows newObject.  We only do
423             // this the first time we find a child layer, and then we update the
424             // pointer values for newObject and beforeChild used by everyone else.
425             beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject);
426             newObject = 0;
427         }
428         parentLayer->addChild(obj->layer(), beforeChild);
429         return;
430     }
431
432     for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling())
433         addLayers(curr, parentLayer, newObject, beforeChild);
434 }
435
436 void RenderObject::addLayers(RenderLayer* parentLayer, RenderObject* newObject)
437 {
438     if (!parentLayer)
439         return;
440     
441     RenderObject* object = newObject;
442     RenderLayer* beforeChild = 0;
443     ::addLayers(this, parentLayer, object, beforeChild);
444 }
445
446 void RenderObject::removeLayers(RenderLayer* parentLayer)
447 {
448     if (!parentLayer)
449         return;
450     
451     if (layer()) {
452         parentLayer->removeChild(layer());
453         return;
454     }
455
456     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
457         curr->removeLayers(parentLayer);
458 }
459
460 void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent)
461 {
462     if (!newParent)
463         return;
464     
465     if (layer()) {
466         if (oldParent)
467             oldParent->removeChild(layer());
468         newParent->addChild(layer());
469         return;
470     }
471
472     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
473         curr->moveLayers(oldParent, newParent);
474 }
475
476 RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint,
477                                          bool checkParent)
478 {
479     // Error check the parent layer passed in.  If it's null, we can't find anything.
480     if (!parentLayer)
481         return 0;
482         
483     // Step 1: Descend into our siblings trying to find the next layer.  If we do find
484     // a layer, and if its parent layer matches our desired parent layer, then we have
485     // a match.
486     for (RenderObject* curr = startPoint ? startPoint->nextSibling() : firstChild();
487          curr; curr = curr->nextSibling()) {
488         RenderLayer* nextLayer = curr->findNextLayer(parentLayer, 0, false);
489         if (nextLayer) {
490             if (nextLayer->parent() == parentLayer)
491                 return nextLayer;
492             return 0;
493         }
494     }
495     
496     // Step 2: If our layer is the desired parent layer, then we're finished.  We didn't
497     // find anything.
498     RenderLayer* ourLayer = layer();
499     if (parentLayer == ourLayer)
500         return 0;
501     
502     // Step 3: If we have a layer, then return that layer.  It will be checked against
503     // the desired parent layer in the for loop above.
504     if (ourLayer)
505         return ourLayer;
506     
507     // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that
508     // follow us to see if we can locate a layer.
509     if (checkParent && parent())
510         return parent()->findNextLayer(parentLayer, this, true);
511     
512     return 0;
513 }
514     
515 RenderLayer* RenderObject::enclosingLayer()
516 {
517     RenderObject* curr = this;
518     while (curr) {
519         RenderLayer *layer = curr->layer();
520         if (layer)
521             return layer;
522         curr = curr->parent();
523     }
524     return 0;
525 }
526
527 bool RenderObject::requiresLayer()
528 {
529     return isRoot() || isPositioned() || isRelPositioned() || style()->opacity() < 1.0f ||
530            hasOverflowClip();
531 }
532
533 RenderBlock* RenderObject::firstLineBlock() const
534 {
535     return 0;
536 }
537
538 void RenderObject::updateFirstLetter()
539 {}
540
541 int RenderObject::offsetLeft() const
542 {
543     int x = xPos();
544     if (!isPositioned()) {
545         if (isRelPositioned()) {
546             int y = 0;
547             ((RenderBox*)this)->relativePositionOffset(x, y);
548         }
549         
550         RenderObject* offsetPar = offsetParent();
551         RenderObject* curr = parent();
552         while (curr && curr != offsetPar) {
553             x += curr->xPos();
554             curr = curr->parent();
555         }
556     }
557     return x;
558 }
559
560 int RenderObject::offsetTop() const
561 {
562     int y = yPos();
563     if (!isPositioned()) {
564         if (isRelPositioned()) {
565             int x = 0;
566             ((RenderBox*)this)->relativePositionOffset(x, y);
567         }
568         RenderObject* offsetPar = offsetParent();
569         RenderObject* curr = parent();
570         while (curr && curr != offsetPar) {
571             y += curr->yPos();
572             curr = curr->parent();
573         }
574     }
575     return y;
576 }
577     
578 RenderObject* RenderObject::offsetParent() const
579 {
580     // FIXME: It feels like this function could almost be written using containing blocks.
581     bool skipTables = isPositioned() || isRelPositioned();
582     RenderObject* curr = parent();
583     while (curr && (!curr->element() || 
584                     (!curr->isPositioned() && !curr->isRelPositioned() && 
585                         !(!style()->htmlHacks() && skipTables ? curr->isRoot() : curr->isBody())))) {
586         if (!skipTables && curr->element() && (curr->isTableCell() || curr->isTable()))
587             break;
588         curr = curr->parent();
589     }
590     return curr;
591 }
592
593 // More IE extensions.  clientWidth and clientHeight represent the interior of an object
594 // excluding border and scrollbar.
595 int
596 RenderObject::clientWidth() const
597 {
598     return width() - borderLeft() - borderRight() -
599         (includeScrollbarSize() ? layer()->verticalScrollbarWidth() : 0);
600 }
601
602 int
603 RenderObject::clientHeight() const
604 {
605     return height() - borderTop() - borderBottom() -
606       (includeScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0);
607 }
608
609 // scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the
610 // object has overflow:hidden/scroll/auto specified and also has overflow.
611 int
612 RenderObject::scrollWidth() const
613 {
614     return hasOverflowClip() ? layer()->scrollWidth() : overflowWidth();
615 }
616
617 int
618 RenderObject::scrollHeight() const
619 {
620     return hasOverflowClip() ? layer()->scrollHeight() : overflowHeight();
621 }
622
623 bool RenderObject::scroll(KWQScrollDirection direction, KWQScrollGranularity granularity, float multiplier)
624 {
625     RenderLayer *l = layer();
626     if (l != 0 && l->scroll(direction, granularity, multiplier)) {
627         return true;
628     }
629     RenderBlock *b = containingBlock();
630     if (b != 0 && !b->isCanvas()) {
631         return b->scroll(direction, granularity, multiplier);
632     }
633     return false;
634 }
635
636 bool
637 RenderObject::hasStaticX() const
638 {
639     return (style()->left().isAuto() && style()->right().isAuto()) ||
640             style()->left().isStatic() ||
641             style()->right().isStatic();
642 }
643
644 bool
645 RenderObject::hasStaticY() const
646 {
647     return (style()->top().isAuto() && style()->bottom().isAuto()) || style()->top().isStatic();
648 }
649
650 void RenderObject::markAllDescendantsWithFloatsForLayout(RenderObject*)
651 {
652 }
653
654 void RenderObject::setNeedsLayout(bool b, bool markParents) 
655 {
656     bool alreadyNeededLayout = m_needsLayout;
657     m_needsLayout = b;
658     if (b) {
659         if (!alreadyNeededLayout && markParents)
660             markContainingBlocksForLayout();
661     }
662     else {
663         m_posChildNeedsLayout = false;
664         m_normalChildNeedsLayout = false;
665     }
666 }
667
668 void RenderObject::setChildNeedsLayout(bool b, bool markParents)
669 {
670     bool alreadyNeededLayout = m_normalChildNeedsLayout;
671     m_normalChildNeedsLayout = b;
672     if (b) {
673         if (!alreadyNeededLayout && markParents)
674             markContainingBlocksForLayout();
675     }
676     else {
677         m_posChildNeedsLayout = false;
678         m_normalChildNeedsLayout = false;
679     }
680 }
681
682 void RenderObject::markContainingBlocksForLayout()
683 {
684     RenderObject *o = container();
685     RenderObject *last = this;
686
687     while (o) {
688         if (!last->isText() && (last->style()->position() == FIXED || last->style()->position() == ABSOLUTE)) {
689             if (o->m_posChildNeedsLayout)
690                 return;
691             o->m_posChildNeedsLayout = true;
692         }
693         else {
694             if (o->m_normalChildNeedsLayout)
695                 return;
696             o->m_normalChildNeedsLayout = true;
697         }
698
699         last = o;
700         o = o->container();
701     }
702
703     last->scheduleRelayout();
704 }
705
706 RenderBlock* RenderObject::containingBlock() const
707 {
708     if(isTableCell())
709         return static_cast<const RenderTableCell *>(this)->table();
710     if (isCanvas())
711         return (RenderBlock*)this;
712
713     RenderObject *o = parent();
714     if (!isText() && m_style->position() == FIXED) {
715         while ( o && !o->isCanvas() )
716             o = o->parent();
717     }
718     else if (!isText() && m_style->position() == ABSOLUTE) {
719         while (o && (o->style()->position() == STATIC || (o->isInline() && !o->isReplaced()))
720                && !o->isRoot() && !o->isCanvas()) {
721             // For relpositioned inlines, we return the nearest enclosing block.  We don't try
722             // to return the inline itself.  This allows us to avoid having a positioned objects
723             // list in all RenderInlines and lets us return a strongly-typed RenderBlock* result
724             // from this method.  The container() method can actually be used to obtain the
725             // inline directly.
726             if (o->style()->position() == RELATIVE && o->isInline() && !o->isReplaced())
727                 return o->containingBlock();
728             o = o->parent();
729         }
730     } else {
731         while (o && ((o->isInline() && !o->isReplaced()) || o->isTableRow() || o->isTableSection()
732                      || o->isTableCol() || o->isFrameSet()
733 #if SVG_SUPPORT
734                      || o->isKCanvasContainer()
735 #endif
736                      ))
737             o = o->parent();
738     }
739
740     if (!o || !o->isRenderBlock())
741         return 0; // Probably doesn't happen any more, but leave just in case. -dwh
742     
743     return static_cast<RenderBlock*>(o);
744 }
745
746 int RenderObject::containingBlockWidth() const
747 {
748     // ###
749     return containingBlock()->contentWidth();
750 }
751
752 int RenderObject::containingBlockHeight() const
753 {
754     // ###
755     return containingBlock()->contentHeight();
756 }
757
758 bool RenderObject::mustRepaintBackgroundOrBorder() const
759 {
760     // If we don't have a background/border, then nothing to do.
761     if (!shouldPaintBackgroundOrBorder())
762         return false;
763     
764     // Ok, let's check the background first.
765     const BackgroundLayer* bgLayer = style()->backgroundLayers();
766     if (bgLayer->next())
767         return true; // Nobody will use multiple background layers without wanting fancy positioning.
768     
769     // Make sure we have a valid background image.
770     CachedImage* bg = bgLayer->backgroundImage();
771     bool shouldPaintBackgroundImage = bg && bg->pixmap_size() == bg->valid_rect().size() && !bg->isTransparent() && !bg->isErrorImage();
772     
773     // These are always percents or auto.
774     if (shouldPaintBackgroundImage && 
775         (bgLayer->backgroundXPosition().length() != 0 || bgLayer->backgroundYPosition().length() != 0))
776         return true; // The background image will shift unpredictably if the size changes.
777         
778     // Background is ok.  Let's check border.
779     if (style()->hasBorder()) {
780         // Border images are not ok.
781         CachedImage* borderImage = style()->borderImage().image();
782         bool shouldPaintBorderImage = borderImage && borderImage->pixmap_size() == borderImage->valid_rect().size() && 
783                                       !borderImage->isTransparent() && !borderImage->isErrorImage();
784         if (shouldPaintBorderImage && borderImage->isLoaded())
785             return true; // If the image hasn't loaded, we're still using the normal border style.
786     }
787
788     return false;
789 }
790
791 void RenderObject::drawBorder(QPainter *p, int x1, int y1, int x2, int y2,
792                               BorderSide s, QColor c, const QColor& textcolor, EBorderStyle style,
793                               int adjbw1, int adjbw2, bool invalidisInvert)
794 {
795     int width = (s==BSTop||s==BSBottom?y2-y1:x2-x1);
796
797     if(style == DOUBLE && width < 3)
798         style = SOLID;
799
800     if(!c.isValid()) {
801         if(invalidisInvert)
802         {
803             p->setRasterOp(Qt::XorROP);
804             c = Qt::white;
805         }
806         else {
807             if(style == INSET || style == OUTSET || style == RIDGE || style ==
808             GROOVE)
809                 c.setRgb(238, 238, 238);
810             else
811                 c = textcolor;
812         }
813     }
814
815     switch(style)
816     {
817     case BNONE:
818     case BHIDDEN:
819         // should not happen
820         if(invalidisInvert && p->rasterOp() == Qt::XorROP)
821             p->setRasterOp(Qt::CopyROP);
822
823         return;
824     case DOTTED:
825         p->setPen(QPen(c, width == 1 ? 0 : width, Qt::DotLine));
826         /* nobreak; */
827     case DASHED:
828         if(style == DASHED)
829             p->setPen(QPen(c, width == 1 ? 0 : width, Qt::DashLine));
830
831         if (width > 0)
832             switch(s)
833             {
834             case BSBottom:
835             case BSTop:
836                 p->drawLine(x1, (y1+y2)/2, x2, (y1+y2)/2);
837                 break;
838             case BSRight:
839             case BSLeft:
840                 p->drawLine((x1+x2)/2, y1, (x1+x2)/2, y2);
841                 break;
842             }
843                 
844         break;
845
846     case DOUBLE:
847     {
848         int third = (width+1)/3;
849
850         if (adjbw1 == 0 && adjbw2 == 0)
851         {
852             p->setPen(Qt::NoPen);
853             p->setBrush(c);
854             switch(s)
855             {
856             case BSTop:
857             case BSBottom:
858                 p->drawRect(x1, y1      , x2-x1, third);
859                 p->drawRect(x1, y2-third, x2-x1, third);
860                 break;
861             case BSLeft:
862                 p->drawRect(x1      , y1+1, third, y2-y1-1);
863                 p->drawRect(x2-third, y1+1, third, y2-y1-1);
864                 break;
865             case BSRight:
866                 p->drawRect(x1      , y1+1, third, y2-y1-1);
867                 p->drawRect(x2-third, y1+1, third, y2-y1-1);
868                 break;
869             }
870         }
871         else
872         {
873             int adjbw1bigthird;
874             if (adjbw1>0) adjbw1bigthird = adjbw1+1;
875             else adjbw1bigthird = adjbw1 - 1;
876             adjbw1bigthird /= 3;
877
878             int adjbw2bigthird;
879             if (adjbw2>0) adjbw2bigthird = adjbw2 + 1;
880             else adjbw2bigthird = adjbw2 - 1;
881             adjbw2bigthird /= 3;
882
883           switch(s)
884             {
885             case BSTop:
886               drawBorder(p, x1+kMax((-adjbw1*2+1)/3,0), y1        , x2-kMax((-adjbw2*2+1)/3,0), y1 + third, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
887               drawBorder(p, x1+kMax(( adjbw1*2+1)/3,0), y2 - third, x2-kMax(( adjbw2*2+1)/3,0), y2        , s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
888               break;
889             case BSLeft:
890               drawBorder(p, x1        , y1+kMax((-adjbw1*2+1)/3,0), x1+third, y2-kMax((-adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
891               drawBorder(p, x2 - third, y1+kMax(( adjbw1*2+1)/3,0), x2      , y2-kMax(( adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
892               break;
893             case BSBottom:
894               drawBorder(p, x1+kMax(( adjbw1*2+1)/3,0), y1      , x2-kMax(( adjbw2*2+1)/3,0), y1+third, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
895               drawBorder(p, x1+kMax((-adjbw1*2+1)/3,0), y2-third, x2-kMax((-adjbw2*2+1)/3,0), y2      , s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
896               break;
897             case BSRight:
898             drawBorder(p, x1      , y1+kMax(( adjbw1*2+1)/3,0), x1+third, y2-kMax(( adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
899             drawBorder(p, x2-third, y1+kMax((-adjbw1*2+1)/3,0), x2      , y2-kMax((-adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
900               break;
901             default:
902               break;
903             }
904         }
905         break;
906     }
907     case RIDGE:
908     case GROOVE:
909     {
910         EBorderStyle s1;
911         EBorderStyle s2;
912         if (style==GROOVE)
913         {
914             s1 = INSET;
915             s2 = OUTSET;
916         }
917         else
918         {
919             s1 = OUTSET;
920             s2 = INSET;
921         }
922
923         int adjbw1bighalf;
924         int adjbw2bighalf;
925         if (adjbw1>0) adjbw1bighalf=adjbw1+1;
926         else adjbw1bighalf=adjbw1-1;
927         adjbw1bighalf/=2;
928
929         if (adjbw2>0) adjbw2bighalf=adjbw2+1;
930         else adjbw2bighalf=adjbw2-1;
931         adjbw2bighalf/=2;
932
933         switch (s)
934         {
935         case BSTop:
936             drawBorder(p, x1+kMax(-adjbw1  ,0)/2,  y1        , x2-kMax(-adjbw2,0)/2, (y1+y2+1)/2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
937             drawBorder(p, x1+kMax( adjbw1+1,0)/2, (y1+y2+1)/2, x2-kMax( adjbw2+1,0)/2,  y2        , s, c, textcolor, s2, adjbw1/2, adjbw2/2);
938             break;
939         case BSLeft:
940             drawBorder(p,  x1        , y1+kMax(-adjbw1  ,0)/2, (x1+x2+1)/2, y2-kMax(-adjbw2,0)/2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
941             drawBorder(p, (x1+x2+1)/2, y1+kMax( adjbw1+1,0)/2,  x2        , y2-kMax( adjbw2+1,0)/2, s, c, textcolor, s2, adjbw1/2, adjbw2/2);
942             break;
943         case BSBottom:
944             drawBorder(p, x1+kMax( adjbw1  ,0)/2,  y1        , x2-kMax( adjbw2,0)/2, (y1+y2+1)/2, s, c, textcolor, s2,  adjbw1bighalf, adjbw2bighalf);
945             drawBorder(p, x1+kMax(-adjbw1+1,0)/2, (y1+y2+1)/2, x2-kMax(-adjbw2+1,0)/2,  y2        , s, c, textcolor, s1, adjbw1/2, adjbw2/2);
946             break;
947         case BSRight:
948             drawBorder(p,  x1        , y1+kMax( adjbw1  ,0)/2, (x1+x2+1)/2, y2-kMax( adjbw2,0)/2, s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf);
949             drawBorder(p, (x1+x2+1)/2, y1+kMax(-adjbw1+1,0)/2,  x2        , y2-kMax(-adjbw2+1,0)/2, s, c, textcolor, s1, adjbw1/2, adjbw2/2);
950             break;
951         }
952         break;
953     }
954     case INSET:
955         if(s == BSTop || s == BSLeft)
956             c = c.dark();
957
958         /* nobreak; */
959     case OUTSET:
960         if(style == OUTSET && (s == BSBottom || s == BSRight))
961             c = c.dark();
962         /* nobreak; */
963     case SOLID:
964         QPointArray quad(4);
965         p->setPen(Qt::NoPen);
966         p->setBrush(c);
967         Q_ASSERT(x2>=x1);
968         Q_ASSERT(y2>=y1);
969         if (adjbw1==0 && adjbw2 == 0)
970           {
971             p->drawRect(x1,y1,x2-x1,y2-y1);
972             return;
973           }
974         switch(s) {
975         case BSTop:
976             quad.setPoints(4,
977                            x1+kMax(-adjbw1,0), y1,
978                            x1+kMax( adjbw1,0), y2,
979                            x2-kMax( adjbw2,0), y2,
980                            x2-kMax(-adjbw2,0), y1);
981             break;
982         case BSBottom:
983             quad.setPoints(4,
984                            x1+kMax( adjbw1,0), y1,
985                            x1+kMax(-adjbw1,0), y2,
986                            x2-kMax(-adjbw2,0), y2,
987                            x2-kMax( adjbw2,0), y1);
988             break;
989         case BSLeft:
990           quad.setPoints(4,
991                          x1, y1+kMax(-adjbw1,0),
992                          x1, y2-kMax(-adjbw2,0),
993                          x2, y2-kMax( adjbw2,0),
994                          x2, y1+kMax( adjbw1,0));
995             break;
996         case BSRight:
997           quad.setPoints(4,
998                          x1, y1+kMax( adjbw1,0),
999                          x1, y2-kMax( adjbw2,0),
1000                          x2, y2-kMax(-adjbw2,0),
1001                          x2, y1+kMax(-adjbw1,0));
1002             break;
1003         }
1004         p->drawConvexPolygon(quad);
1005         break;
1006     }
1007
1008     if(invalidisInvert && p->rasterOp() == Qt::XorROP)
1009         p->setRasterOp(Qt::CopyROP);
1010 }
1011
1012 bool RenderObject::paintBorderImage(QPainter *p, int _tx, int _ty, int w, int h, const RenderStyle* style)
1013 {
1014     CachedImage* borderImage = style->borderImage().image();
1015     if (!borderImage->isLoaded())
1016         return true; // Never paint a border image incrementally, but don't paint the fallback borders either.
1017     
1018     // If we have a border radius, the border image gets clipped to the rounded rect.
1019     bool clipped = false;
1020     if (style->hasBorderRadius()) {
1021         QRect clipRect(_tx, _ty, w, h);
1022         clipRect = p->xForm(clipRect);
1023         p->save();
1024         p->addRoundedRectClip(clipRect, style->borderTopLeftRadius(), style->borderTopRightRadius(),
1025                               style->borderBottomLeftRadius(), style->borderBottomRightRadius());
1026         clipped = true;
1027     }
1028
1029     int imageWidth = borderImage->pixmap().width();
1030     int imageHeight = borderImage->pixmap().height();
1031
1032     int topSlice = kMin(imageHeight, style->borderImage().m_slices.top.width(borderImage->pixmap().height()));
1033     int bottomSlice = kMin(imageHeight, style->borderImage().m_slices.bottom.width(borderImage->pixmap().height()));
1034     int leftSlice = kMin(imageWidth, style->borderImage().m_slices.left.width(borderImage->pixmap().width()));    
1035     int rightSlice = kMin(imageWidth, style->borderImage().m_slices.right.width(borderImage->pixmap().width()));
1036
1037     EBorderImageRule hRule = style->borderImage().m_horizontalRule;
1038     EBorderImageRule vRule = style->borderImage().m_verticalRule;
1039     
1040     bool drawLeft = leftSlice > 0 && style->borderLeftWidth() > 0;
1041     bool drawTop = topSlice > 0 && style->borderTopWidth() > 0;
1042     bool drawRight = rightSlice > 0 && style->borderRightWidth() > 0;
1043     bool drawBottom = bottomSlice > 0 && style->borderBottomWidth() > 0;
1044     bool drawMiddle = (imageWidth - leftSlice - rightSlice) > 0 && (w - style->borderLeftWidth() - style->borderRightWidth()) > 0 &&
1045                       (imageHeight - topSlice - bottomSlice) > 0 && (h - style->borderTopWidth() - style->borderBottomWidth()) > 0;
1046
1047     if (drawLeft) {
1048         // Paint the top and bottom left corners.
1049         
1050         // The top left corner rect is (_tx, _ty, leftWidth, topWidth)
1051         // The rect to use from within the image is obtained from our slice, and is (0, 0, leftSlice, topSlice)
1052         if (drawTop)
1053             p->drawPixmap(_tx, _ty, style->borderLeftWidth(), style->borderTopWidth(),
1054                           borderImage->pixmap(), 0, 0, leftSlice, topSlice);
1055         
1056         // The bottom left corner rect is (_tx, _ty + h - bottomWidth, leftWidth, bottomWidth)
1057         // The rect to use from within the image is (0, imageHeight - bottomSlice, leftSlice, botomSlice)
1058         if (drawBottom)
1059             p->drawPixmap(_tx, _ty + h - style->borderBottomWidth(), style->borderLeftWidth(), style->borderBottomWidth(),
1060                           borderImage->pixmap(), 0, imageHeight - bottomSlice, leftSlice, bottomSlice);
1061                       
1062         // Paint the left edge.
1063         // Have to scale and tile into the border rect.
1064         p->drawScaledAndTiledPixmap(_tx, _ty + style->borderTopWidth(), style->borderLeftWidth(),
1065                                     h - style->borderTopWidth() - style->borderBottomWidth(), borderImage->pixmap(),
1066                                     0, topSlice, leftSlice, imageHeight - topSlice - bottomSlice, 
1067                                     QPainter::STRETCH, (QPainter::TileRule)vRule);
1068     }
1069     
1070     if (drawRight) {
1071         // Paint the top and bottom right corners
1072         // The top right corner rect is (_tx + w - rightWidth, _ty, rightWidth, topWidth)
1073         // The rect to use from within the image is obtained from our slice, and is (imageWidth - rightSlice, 0, rightSlice, topSlice)
1074         if (drawTop)
1075             p->drawPixmap(_tx + w - style->borderRightWidth(), _ty, style->borderRightWidth(), style->borderTopWidth(),
1076                           borderImage->pixmap(), imageWidth - rightSlice, 0, rightSlice, topSlice);
1077         
1078         // The bottom right corner rect is (_tx + w - rightWidth, _ty + h - bottomWidth, rightWidth, bottomWidth)
1079         // The rect to use from within the image is (imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, botomSlice)
1080         if (drawBottom)
1081             p->drawPixmap(_tx + w - style->borderRightWidth(), _ty + h - style->borderBottomWidth(), style->borderRightWidth(), style->borderBottomWidth(),
1082                           borderImage->pixmap(), imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice);
1083                       
1084         // Paint the right edge.
1085         p->drawScaledAndTiledPixmap(_tx + w - style->borderRightWidth(), _ty + style->borderTopWidth(), style->borderRightWidth(),
1086                           h - style->borderTopWidth() - style->borderBottomWidth(), borderImage->pixmap(),
1087                           imageWidth - rightSlice, topSlice, rightSlice, imageHeight - topSlice - bottomSlice,
1088                           QPainter::STRETCH, (QPainter::TileRule)vRule);
1089     }
1090
1091     // Paint the top edge.
1092     if (drawTop)
1093         p->drawScaledAndTiledPixmap(_tx + style->borderLeftWidth(), _ty, w - style->borderLeftWidth() - style->borderRightWidth(),
1094                           style->borderTopWidth(), borderImage->pixmap(),
1095                           leftSlice, 0, imageWidth - rightSlice - leftSlice, topSlice,
1096                           (QPainter::TileRule)hRule, QPainter::STRETCH);
1097     
1098     // Paint the bottom edge.
1099     if (drawBottom)
1100         p->drawScaledAndTiledPixmap(_tx + style->borderLeftWidth(), _ty + h - style->borderBottomWidth(), 
1101                           w - style->borderLeftWidth() - style->borderRightWidth(),
1102                           style->borderBottomWidth(), borderImage->pixmap(),
1103                           leftSlice, imageHeight - bottomSlice, imageWidth - rightSlice - leftSlice, bottomSlice,
1104                           (QPainter::TileRule)hRule, QPainter::STRETCH);
1105     
1106     // Paint the middle.
1107     if (drawMiddle)
1108         p->drawScaledAndTiledPixmap(_tx + style->borderLeftWidth(), _ty + style->borderTopWidth(), w - style->borderLeftWidth() - style->borderRightWidth(),
1109                           h - style->borderTopWidth() - style->borderBottomWidth(), borderImage->pixmap(),
1110                           leftSlice, topSlice, imageWidth - rightSlice - leftSlice, imageHeight - topSlice - bottomSlice,
1111                           (QPainter::TileRule)hRule, (QPainter::TileRule)vRule);
1112     
1113     // Because of the bizarre way we do animations in WebKit, WebCore does not get any sort of notification when the image changes
1114     // animation frames.  We have to tell WebKit about the rect so that it can do the animation itself and invalidate the right
1115     // rect.
1116     borderImage->pixmap().setAnimationRect(QRect(_tx, _ty, w, h));
1117     
1118     // Clear the clip for the border radius.
1119     if (clipped)
1120         p->restore();
1121
1122     return true;
1123 }
1124
1125 void RenderObject::paintBorder(QPainter *p, int _tx, int _ty, int w, int h, const RenderStyle* style, bool begin, bool end)
1126 {
1127     CachedImage* borderImage = style->borderImage().image();
1128     bool shouldPaintBackgroundImage = borderImage && borderImage->pixmap_size() == borderImage->valid_rect().size() && 
1129                                       !borderImage->isTransparent() && !borderImage->isErrorImage();
1130     if (shouldPaintBackgroundImage)
1131         shouldPaintBackgroundImage = paintBorderImage(p, _tx, _ty, w, h, style);
1132     
1133     if (shouldPaintBackgroundImage)
1134         return;
1135
1136     const QColor& tc = style->borderTopColor();
1137     const QColor& bc = style->borderBottomColor();
1138     const QColor& lc = style->borderLeftColor();
1139     const QColor& rc = style->borderRightColor();
1140
1141     bool tt = style->borderTopIsTransparent();
1142     bool bt = style->borderBottomIsTransparent();
1143     bool rt = style->borderRightIsTransparent();
1144     bool lt = style->borderLeftIsTransparent();
1145     
1146     EBorderStyle ts = style->borderTopStyle();
1147     EBorderStyle bs = style->borderBottomStyle();
1148     EBorderStyle ls = style->borderLeftStyle();
1149     EBorderStyle rs = style->borderRightStyle();
1150
1151     bool render_t = ts > BHIDDEN && !tt;
1152     bool render_l = ls > BHIDDEN && begin && !lt;
1153     bool render_r = rs > BHIDDEN && end && !rt;
1154     bool render_b = bs > BHIDDEN && !bt;
1155
1156     // Need sufficient width and height to contain border radius curves.  Sanity check our top/bottom
1157     // values and our width/height values to make sure the curves can all fit. If not, then we won't paint
1158     // any border radii.
1159     bool render_radii = false;
1160     QSize topLeft = style->borderTopLeftRadius();
1161     QSize topRight = style->borderTopRightRadius();
1162     QSize bottomLeft = style->borderBottomLeftRadius();
1163     QSize bottomRight = style->borderBottomRightRadius();
1164
1165     if (style->hasBorderRadius()) {
1166         int requiredWidth = kMax(topLeft.width() + topRight.width(), bottomLeft.width() + bottomRight.width());
1167         int requiredHeight = kMax(topLeft.height() + bottomLeft.height(), topRight.height() + bottomRight.height());
1168         render_radii = (requiredWidth <= w && requiredHeight <= h);
1169     }
1170     
1171     // Clip to the rounded rectangle.
1172     if (render_radii) {
1173         p->save();
1174         p->addRoundedRectClip(QRect(_tx, _ty, w, h), topLeft, topRight, bottomLeft, bottomRight);
1175     }
1176
1177     if (render_t) {
1178         bool ignore_left = (render_radii && topLeft.width() > 0) ||
1179             ((tc == lc) && (tt == lt) &&
1180             (ts >= OUTSET) &&
1181             (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET));
1182
1183         bool ignore_right = (render_radii && topRight.width() > 0) ||
1184             ((tc == rc) && (tt == rt) &&
1185             (ts >= OUTSET) &&
1186             (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET));
1187         
1188         int x = _tx;
1189         int x2 = _tx + w;
1190         if (render_radii) {
1191             x += topLeft.width();
1192             x2 -= topRight.width();
1193         }
1194         
1195         drawBorder(p, x, _ty, x2, _ty +  style->borderTopWidth(), BSTop, tc, style->color(), ts,
1196                    ignore_left ? 0 : style->borderLeftWidth(),
1197                    ignore_right? 0 : style->borderRightWidth());
1198     }
1199
1200     if (render_b) {
1201         bool ignore_left = (render_radii && bottomLeft.width() > 0) ||
1202         ((bc == lc) && (bt == lt) &&
1203         (bs >= OUTSET) &&
1204         (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET));
1205
1206         bool ignore_right = (render_radii && bottomRight.width() > 0) ||
1207             ((bc == rc) && (bt == rt) &&
1208             (bs >= OUTSET) &&
1209             (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET));
1210         
1211         int x = _tx;
1212         int x2 = _tx + w;
1213         if (render_radii) {
1214             x += bottomLeft.width();
1215             x2 -= bottomRight.width();
1216         }
1217
1218         drawBorder(p, x, _ty + h - style->borderBottomWidth(), x2, _ty + h, BSBottom, bc, style->color(), bs,
1219                    ignore_left ? 0 :style->borderLeftWidth(),
1220                    ignore_right? 0 :style->borderRightWidth());
1221     }
1222     
1223     if (render_l) {
1224         bool ignore_top = (render_radii && topLeft.height() > 0) ||
1225           ((tc == lc) && (tt == lt) &&
1226           (ls >= OUTSET) &&
1227           (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET));
1228
1229         bool ignore_bottom = (render_radii && bottomLeft.height() > 0) ||
1230           ((bc == lc) && (bt == lt) &&
1231           (ls >= OUTSET) &&
1232           (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET));
1233
1234         int y = _ty;
1235         int y2 = _ty + h;
1236         if (render_radii) {
1237             y += topLeft.height();
1238             y2 -= bottomLeft.height();
1239         }
1240         
1241         drawBorder(p, _tx, y, _tx + style->borderLeftWidth(), y2, BSLeft, lc, style->color(), ls,
1242                    ignore_top?0:style->borderTopWidth(),
1243                    ignore_bottom?0:style->borderBottomWidth());
1244     }
1245
1246     if (render_r) {
1247         bool ignore_top = (render_radii && topRight.height() > 0) ||
1248           ((tc == rc) && (tt == rt) &&
1249           (rs >= DOTTED || rs == INSET) &&
1250           (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET));
1251
1252         bool ignore_bottom = (render_radii && bottomRight.height() > 0) ||
1253           ((bc == rc) && (bt == rt) &&
1254           (rs >= DOTTED || rs == INSET) &&
1255           (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET));
1256
1257         int y = _ty;
1258         int y2 = _ty + h;
1259         if (render_radii) {
1260             y += topRight.height();
1261             y2 -= bottomRight.height();
1262         }
1263
1264         drawBorder(p, _tx + w - style->borderRightWidth(), y, _tx + w, y2, BSRight, rc, style->color(), rs,
1265                    ignore_top?0:style->borderTopWidth(),
1266                    ignore_bottom?0:style->borderBottomWidth());
1267     }
1268     
1269     if (render_radii)
1270         p->restore(); // Undo the clip.
1271 }
1272
1273 void RenderObject::absoluteRects(QValueList<QRect>& rects, int _tx, int _ty)
1274 {
1275     // For blocks inside inlines, we go ahead and include margins so that we run right up to the
1276     // inline boxes above and below us (thus getting merged with them to form a single irregular
1277     // shape).
1278     if (continuation()) {
1279         rects.append(QRect(_tx, _ty - collapsedMarginTop(), 
1280                            width(), height()+collapsedMarginTop()+collapsedMarginBottom()));
1281         continuation()->absoluteRects(rects, 
1282                                       _tx - xPos() + continuation()->containingBlock()->xPos(),
1283                                       _ty - yPos() + continuation()->containingBlock()->yPos());
1284     }
1285     else
1286         rects.append(QRect(_tx, _ty, width(), height()));
1287 }
1288
1289 QRect RenderObject::absoluteBoundingBoxRect()
1290 {
1291     int x, y;
1292     absolutePosition(x, y);
1293     QValueList<QRect> rects;
1294     absoluteRects(rects, x, y);
1295     
1296     QValueList<QRect>::ConstIterator it = rects.begin();
1297     QRect result = *it;
1298     while (++it != rects.end()) {
1299         result = result.unite(*it);
1300     }
1301     return result;
1302 }
1303
1304 void RenderObject::addAbsoluteRectForLayer(QRect& result)
1305 {
1306     if (layer()) {
1307         result = result.unite(absoluteBoundingBoxRect());
1308     }
1309     for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
1310         current->addAbsoluteRectForLayer(result);
1311     }
1312 }
1313
1314 QRect RenderObject::paintingRootRect(QRect& topLevelRect)
1315 {
1316     QRect result = absoluteBoundingBoxRect();
1317     topLevelRect = result;
1318     for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
1319         current->addAbsoluteRectForLayer(result);
1320     }
1321     return result;
1322 }
1323
1324 void RenderObject::addFocusRingRects(QPainter *p, int _tx, int _ty)
1325 {
1326     // For blocks inside inlines, we go ahead and include margins so that we run right up to the
1327     // inline boxes above and below us (thus getting merged with them to form a single irregular
1328     // shape).
1329     if (continuation()) {
1330         p->addFocusRingRect(_tx, _ty - collapsedMarginTop(), width(), height()+collapsedMarginTop()+collapsedMarginBottom());
1331         continuation()->addFocusRingRects(p, 
1332                                           _tx - xPos() + continuation()->containingBlock()->xPos(),
1333                                           _ty - yPos() + continuation()->containingBlock()->yPos());
1334     }
1335     else
1336         p->addFocusRingRect(_tx, _ty, width(), height());
1337 }
1338
1339 void RenderObject::paintOutline(QPainter *p, int _tx, int _ty, int w, int h, const RenderStyle* style)
1340 {
1341     int ow = style->outlineWidth();
1342     if(!ow) return;
1343
1344     EBorderStyle os = style->outlineStyle();
1345     if (os <= BHIDDEN)
1346         return;
1347     
1348     QColor oc = style->outlineColor();
1349     if (!oc.isValid())
1350         oc = style->color();
1351     
1352     int offset = style->outlineOffset();
1353     
1354     if (style->outlineStyleIsAuto()) {
1355         if (!style->hasAppearance()) {
1356             // Only paint the focus ring by hand if there is no custom appearance
1357             // specified.  Otherwise we let the theme paint the focus ring, since the ring
1358             // might not be rectangular (or match the dimensions of the control exactly).
1359             p->initFocusRing(ow, offset, oc);
1360             addFocusRingRects(p, _tx, _ty);
1361             p->drawFocusRing();
1362             p->clearFocusRing();
1363         }
1364         return;
1365     }
1366
1367     _tx -= offset;
1368     _ty -= offset;
1369     w += 2*offset;
1370     h += 2*offset;
1371     
1372     drawBorder(p, _tx-ow, _ty-ow, _tx, _ty+h+ow, BSLeft,
1373                QColor(oc), style->color(),
1374                os, ow, ow, true);
1375
1376     drawBorder(p, _tx-ow, _ty-ow, _tx+w+ow, _ty, BSTop,
1377                QColor(oc), style->color(),
1378                os, ow, ow, true);
1379
1380     drawBorder(p, _tx+w, _ty-ow, _tx+w+ow, _ty+h+ow, BSRight,
1381                QColor(oc), style->color(),
1382                os, ow, ow, true);
1383
1384     drawBorder(p, _tx-ow, _ty+h, _tx+w+ow, _ty+h+ow, BSBottom,
1385                QColor(oc), style->color(),
1386                os, ow, ow, true);
1387
1388 }
1389
1390 void RenderObject::paint(PaintInfo& i, int tx, int ty)
1391 {
1392 }
1393
1394 void RenderObject::repaint(bool immediate)
1395 {
1396     // Can't use canvas(), since we might be unrooted.
1397     RenderObject* o = this;
1398     while ( o->parent() ) o = o->parent();
1399     if (!o->isCanvas())
1400         return;
1401     RenderCanvas* c = static_cast<RenderCanvas*>(o);
1402     if (c->printingMode())
1403         return; // Don't repaint if we're printing.
1404     c->repaintViewRectangle(getAbsoluteRepaintRect(), immediate);    
1405 }
1406
1407 void RenderObject::repaintRectangle(const QRect& r, bool immediate)
1408 {
1409     // Can't use canvas(), since we might be unrooted.
1410     RenderObject* o = this;
1411     while ( o->parent() ) o = o->parent();
1412     if (!o->isCanvas())
1413         return;
1414     RenderCanvas* c = static_cast<RenderCanvas*>(o);
1415     if (c->printingMode())
1416         return; // Don't repaint if we're printing.
1417     QRect absRect(r);
1418     computeAbsoluteRepaintRect(absRect);
1419     c->repaintViewRectangle(absRect, immediate);
1420 }
1421
1422 bool RenderObject::repaintAfterLayoutIfNeeded(const QRect& oldBounds, const QRect& oldFullBounds)
1423 {
1424     RenderCanvas* c = canvas();
1425     if (c->printingMode())
1426         return false; // Don't repaint if we're printing.
1427             
1428     QRect newBounds, newFullBounds;
1429     getAbsoluteRepaintRectIncludingFloats(newBounds, newFullBounds);
1430     if (newBounds == oldBounds && !selfNeedsLayout())
1431         return false;
1432
1433     bool fullRepaint = selfNeedsLayout() || newBounds.x() != oldBounds.x() ||
1434                        newBounds.y() != oldBounds.y() || 
1435                        mustRepaintBackgroundOrBorder();
1436     if (fullRepaint) {
1437         c->repaintViewRectangle(oldFullBounds);
1438         if (newBounds != oldBounds)
1439             c->repaintViewRectangle(newFullBounds);
1440     } else {
1441         // We didn't move, but we did change size.  Invalidate the delta, which will consist of possibly 
1442         // two rectangles (but typically only one).
1443         int width = abs(newBounds.width() - oldBounds.width());
1444         if (width)
1445             c->repaintViewRectangle(QRect(kMin(newBounds.x() + newBounds.width(), oldBounds.x() + oldBounds.width()),
1446                                     newBounds.y(), 
1447                                     width,
1448                                     kMax(newBounds.height(), oldBounds.height())));
1449         int height = abs(newBounds.height() - oldBounds.height());
1450         if (height)
1451             c->repaintViewRectangle(QRect(newBounds.x(),
1452                                           kMin(newBounds.y() + newBounds.height(), oldBounds.y() + oldBounds.height()),
1453                                           kMax(newBounds.width(), oldBounds.width()),
1454                                           height));
1455         return false;
1456     }
1457     return true;
1458 }
1459
1460 void RenderObject::repaintDuringLayoutIfMoved(int x, int y)
1461 {
1462 }
1463
1464 void RenderObject::repaintFloatingDescendants()
1465 {
1466 }
1467
1468 bool RenderObject::checkForRepaintDuringLayout() const
1469 {
1470     return !document()->view()->needsFullRepaint() && !layer();
1471 }
1472
1473 void RenderObject::repaintObjectsBeforeLayout()
1474 {
1475     if (!needsLayout() || isText())
1476         return;
1477     
1478     bool blockWithInlineChildren = (isRenderBlock() && !isTable() && normalChildNeedsLayout() && childrenInline());
1479     if (selfNeedsLayout()) {
1480         repaint();
1481         if (blockWithInlineChildren)
1482             return;
1483     }
1484
1485     for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
1486         if (!current->isPositioned()) // RenderBlock subclass method handles walking the positioned objects.
1487             current->repaintObjectsBeforeLayout();
1488     }
1489 }
1490
1491 QRect RenderObject::getAbsoluteRepaintRectWithOutline(int ow)
1492 {
1493     QRect r(getAbsoluteRepaintRect());
1494     r.setRect(r.x()-ow, r.y()-ow, r.width()+ow*2, r.height()+ow*2);
1495
1496     if (continuation() && !isInline())
1497         r.setRect(r.x(), r.y()-collapsedMarginTop(), r.width(), r.height()+collapsedMarginTop()+collapsedMarginBottom());
1498     
1499     if (isInlineFlow()) {
1500         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1501             if (!curr->isText()) {
1502                 QRect childRect = curr->getAbsoluteRepaintRectWithOutline(ow);
1503                 r = r.unite(childRect);
1504             }
1505         }
1506     }
1507
1508     return r;
1509 }
1510
1511 QRect RenderObject::getAbsoluteRepaintRect()
1512 {
1513     if (parent())
1514         return parent()->getAbsoluteRepaintRect();
1515     return QRect();
1516 }
1517
1518 void RenderObject::getAbsoluteRepaintRectIncludingFloats(QRect& bounds, QRect& fullBounds)
1519 {
1520     bounds = fullBounds = getAbsoluteRepaintRect();
1521 }
1522
1523 void RenderObject::computeAbsoluteRepaintRect(QRect& r, bool f)
1524 {
1525     if (parent())
1526         return parent()->computeAbsoluteRepaintRect(r, f);
1527 }
1528
1529 void RenderObject::dirtyLinesFromChangedChild(RenderObject* child)
1530 {
1531 }
1532
1533 #ifndef NDEBUG
1534
1535 QString RenderObject::information() const
1536 {
1537     QString str;
1538     QTextStream ts( &str, IO_WriteOnly );
1539     ts << renderName()
1540         << "(" << (style() ? style()->refCount() : 0) << ")"
1541        << ": " << (void*)this << "  ";
1542     if (isInline()) ts << "il ";
1543     if (childrenInline()) ts << "ci ";
1544     if (isFloating()) ts << "fl ";
1545     if (isAnonymous()) ts << "an ";
1546     if (isRelPositioned()) ts << "rp ";
1547     if (isPositioned()) ts << "ps ";
1548     if (needsLayout()) ts << "nl ";
1549     if (m_recalcMinMax) ts << "rmm ";
1550     if (style() && style()->zIndex()) ts << "zI: " << style()->zIndex();
1551     if (element() && element()->active()) ts << "act ";
1552     if (element() && element()->isLink()) ts << "anchor ";
1553     if (element() && element()->focused()) ts << "focus ";
1554     if (element()) ts << " <" <<  element()->localName().qstring() << ">";
1555     ts << " (" << xPos() << "," << yPos() << "," << width() << "," << height() << ")"
1556         << (isTableCell() ?
1557             ( QString::fromLatin1(" [r=") +
1558               QString::number( static_cast<const RenderTableCell *>(this)->row() ) +
1559               QString::fromLatin1(" c=") +
1560               QString::number( static_cast<const RenderTableCell *>(this)->col() ) +
1561               QString::fromLatin1(" rs=") +
1562               QString::number( static_cast<const RenderTableCell *>(this)->rowSpan() ) +
1563               QString::fromLatin1(" cs=") +
1564               QString::number( static_cast<const RenderTableCell *>(this)->colSpan() ) +
1565               QString::fromLatin1("]") ) : QString::null );
1566         return str;
1567 }
1568
1569 void RenderObject::printTree(int indent) const
1570 {
1571     QString ind;
1572     ind.fill(' ', indent);
1573
1574     kdDebug() << ind << information() << endl;
1575
1576     RenderObject *child = firstChild();
1577     while( child != 0 )
1578     {
1579         child->printTree(indent+2);
1580         child = child->nextSibling();
1581     }
1582 }
1583
1584 void RenderObject::dump(QTextStream *stream, QString ind) const
1585 {
1586     if (isAnonymous()) { *stream << " anonymous"; }
1587     if (isFloating()) { *stream << " floating"; }
1588     if (isPositioned()) { *stream << " positioned"; }
1589     if (isRelPositioned()) { *stream << " relPositioned"; }
1590     if (isText()) { *stream << " text"; }
1591     if (isInline()) { *stream << " inline"; }
1592     if (isReplaced()) { *stream << " replaced"; }
1593     if (shouldPaintBackgroundOrBorder()) { *stream << " paintBackground"; }
1594     if (needsLayout()) { *stream << " needsLayout"; }
1595     if (minMaxKnown()) { *stream << " minMaxKnown"; }
1596     *stream << endl;
1597
1598     RenderObject *child = firstChild();
1599     while( child != 0 )
1600     {
1601         *stream << ind << child->renderName() << ": ";
1602         child->dump(stream,ind+"  ");
1603         child = child->nextSibling();
1604     }
1605 }
1606
1607 void RenderObject::showTree() const
1608 {
1609     if (element())
1610         element()->showTree();
1611 }
1612 #endif
1613
1614 static NodeImpl *selectStartNode(const RenderObject *object)
1615 {
1616     DOM::NodeImpl *node = 0;
1617     bool forcedOn = false;
1618
1619     for (const RenderObject *curr = object; curr; curr = curr->parent()) {
1620         if (curr->style()->userSelect() == SELECT_TEXT)
1621             forcedOn = true;
1622         if (!forcedOn && curr->style()->userSelect() == SELECT_NONE)
1623             return 0;
1624
1625         if (!node)
1626             node = curr->element();
1627     }
1628
1629     // somewhere up the render tree there must be an element!
1630     assert(node);
1631
1632     return node;
1633 }
1634
1635 bool RenderObject::canSelect() const
1636 {
1637     return selectStartNode(this) != 0;
1638 }
1639
1640 bool RenderObject::shouldSelect() const
1641 {
1642     NodeImpl *node = selectStartNode(this);
1643     if (!node)
1644         return false;
1645     return node->dispatchHTMLEvent(selectstartEvent, true, true);
1646 }
1647
1648 QColor RenderObject::selectionColor(QPainter *p) const
1649 {
1650     QColor color;
1651     if (style()->userSelect() != SELECT_NONE) {
1652         RenderStyle* pseudoStyle = getPseudoStyle(RenderStyle::SELECTION);
1653         if (pseudoStyle && pseudoStyle->backgroundColor().isValid())
1654             color = pseudoStyle->backgroundColor();
1655         else
1656             color = p->selectedTextBackgroundColor();
1657     }
1658
1659     return color;
1660 }
1661
1662 DOM::NodeImpl* RenderObject::draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const
1663 {
1664     if (!dhtmlOK && !uaOK)
1665         return 0;
1666
1667     const RenderObject* curr = this;
1668     while (curr) {
1669         DOM::NodeImpl *elt = curr->element();
1670         if (elt && elt->nodeType() == Node::TEXT_NODE) {
1671             // Since there's no way for the author to address the -khtml-user-drag style for a text node,
1672             // we use our own judgement.
1673             if (uaOK && canvas()->view()->part()->shouldDragAutoNode(curr->node(), x, y)) {
1674                 dhtmlWillDrag = false;
1675                 return curr->node();
1676             } else if (curr->shouldSelect()) {
1677                 // In this case we have a click in the unselected portion of text.  If this text is
1678                 // selectable, we want to start the selection process instead of looking for a parent
1679                 // to try to drag.
1680                 return 0;
1681             }
1682         } else {
1683             EUserDrag dragMode = curr->style()->userDrag();
1684             if (dhtmlOK && dragMode == DRAG_ELEMENT) {
1685                 dhtmlWillDrag = true;
1686                 return curr->node();
1687             } else if (uaOK && dragMode == DRAG_AUTO
1688                        && canvas()->view()->part()->shouldDragAutoNode(curr->node(), x, y))
1689             {
1690                 dhtmlWillDrag = false;
1691                 return curr->node();
1692             }
1693         }
1694         curr = curr->parent();
1695     }
1696     return 0;
1697 }
1698
1699 void RenderObject::selectionStartEnd(int& spos, int& epos)
1700 {
1701     canvas()->selectionStartEnd(spos, epos);
1702 }
1703
1704 RenderBlock* RenderObject::createAnonymousBlock()
1705 {
1706     RenderStyle *newStyle = new (renderArena()) RenderStyle();
1707     newStyle->inheritFrom(m_style);
1708     newStyle->setDisplay(BLOCK);
1709
1710     RenderBlock *newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
1711     newBox->setStyle(newStyle);
1712     return newBox;
1713 }
1714
1715 void RenderObject::handleDynamicFloatPositionChange()
1716 {
1717     // We have gone from not affecting the inline status of the parent flow to suddenly
1718     // having an impact.  See if there is a mismatch between the parent flow's
1719     // childrenInline() state and our state.
1720     setInline(style()->isDisplayInlineType());
1721     if (isInline() != parent()->childrenInline()) {
1722         if (!isInline()) {
1723             if (parent()->isRenderInline()) {
1724                 // We have to split the parent flow.
1725                 RenderInline* parentInline = static_cast<RenderInline*>(parent());
1726                 RenderBlock* newBox = parentInline->createAnonymousBlock();
1727                 
1728                 RenderFlow* oldContinuation = parent()->continuation();
1729                 parentInline->setContinuation(newBox);
1730
1731                 RenderObject* beforeChild = nextSibling();
1732                 parent()->removeChildNode(this);
1733                 parentInline->splitFlow(beforeChild, newBox, this, oldContinuation);
1734             }
1735             else if (parent()->isRenderBlock())
1736                 static_cast<RenderBlock*>(parent())->makeChildrenNonInline();
1737         }
1738         else {
1739             // An anonymous block must be made to wrap this inline.
1740             RenderBlock* box = createAnonymousBlock();
1741             parent()->insertChildNode(box, this);
1742             box->appendChildNode(parent()->removeChildNode(this));
1743         }
1744     }
1745 }
1746
1747 void RenderObject::setStyle(RenderStyle *style)
1748 {
1749     if (m_style == style)
1750         return;
1751
1752     bool affectsParentBlock = false;
1753     RenderStyle::Diff d = RenderStyle::Equal;
1754     if (m_style) {
1755         // If our z-index changes value or our visibility changes,
1756         // we need to dirty our stacking context's z-order list.
1757         if (style) {
1758             if (m_style->visibility() != style->visibility() ||
1759                 m_style->zIndex() != style->zIndex() ||
1760                 m_style->hasAutoZIndex() != style->hasAutoZIndex())
1761                 document()->setDashboardRegionsDirty(true);
1762
1763             if ((m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
1764                  m_style->zIndex() != style->zIndex() ||
1765                  m_style->visibility() != style->visibility()) && layer()) {
1766                 layer()->stackingContext()->dirtyZOrderLists();
1767                 if (m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
1768                     m_style->visibility() != style->visibility())
1769                     layer()->dirtyZOrderLists();
1770             }
1771         }
1772
1773         d = m_style->diff(style);
1774
1775         // If we have no layer(), just treat a RepaintLayer hint as a normal Repaint.
1776         if (d == RenderStyle::RepaintLayer && !layer())
1777             d = RenderStyle::Repaint;
1778         
1779         // The background of the root element or the body element could propagate up to
1780         // the canvas.  Just dirty the entire canvas when our style changes substantially.
1781         if (d >= RenderStyle::Repaint && element() &&
1782             (element()->hasTagName(htmlTag) || element()->hasTagName(bodyTag)))
1783             canvas()->repaint();
1784         else if (m_parent && !isText()) {
1785             // Do a repaint with the old style first, e.g., for example if we go from
1786             // having an outline to not having an outline.
1787             if (d == RenderStyle::RepaintLayer) {
1788                 layer()->repaintIncludingDescendants();
1789                 if (!(m_style->clip() == style->clip()))
1790                     layer()->clearClipRects();
1791             }
1792             else if (d == RenderStyle::Repaint)
1793                 repaint();
1794         }
1795
1796         // When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could
1797         // end up being destroyed.
1798         if (d == RenderStyle::Layout && layer() &&
1799             (m_style->position() != style->position() ||
1800              m_style->zIndex() != style->zIndex() ||
1801              m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
1802              !(m_style->clip() == style->clip()) ||
1803              m_style->hasClip() != style->hasClip() ||
1804              m_style->opacity() != style->opacity()))
1805             layer()->repaintIncludingDescendants();
1806
1807         // When a layout hint happens and an object's position style changes, we have to do a layout
1808         // to dirty the render tree using the old position value now.
1809         if (d == RenderStyle::Layout && m_parent && m_style->position() != style->position())
1810             setNeedsLayoutAndMinMaxRecalc();
1811         
1812         if (isFloating() && (m_style->floating() != style->floating()))
1813             // For changes in float styles, we need to conceivably remove ourselves
1814             // from the floating objects list.
1815             removeFromObjectLists();
1816         else if (isPositioned() && (style->position() != ABSOLUTE && style->position() != FIXED))
1817             // For changes in positioning styles, we need to conceivably remove ourselves
1818             // from the positioned objects list.
1819             removeFromObjectLists();
1820         
1821         affectsParentBlock = m_style && isFloatingOrPositioned() &&
1822             (!style->isFloating() && style->position() != ABSOLUTE && style->position() != FIXED)
1823             && parent() && (parent()->isBlockFlow() || parent()->isInlineFlow());
1824         
1825         // reset style flags
1826         m_floating = false;
1827         m_positioned = false;
1828         m_relPositioned = false;
1829         m_paintBackground = false;
1830         m_hasOverflowClip = false;
1831     }
1832
1833     RenderStyle *oldStyle = m_style;
1834     m_style = style;
1835
1836     updateBackgroundImages(oldStyle);
1837     
1838     if (m_style)
1839         m_style->ref();
1840     
1841     if (oldStyle)
1842         oldStyle->deref(renderArena());
1843
1844     setShouldPaintBackgroundOrBorder(m_style->hasBorder() || m_style->hasBackground() || m_style->hasAppearance());
1845
1846     if (affectsParentBlock)
1847         handleDynamicFloatPositionChange();
1848     
1849     // No need to ever schedule repaints from a style change of a text run, since
1850     // we already did this for the parent of the text run.
1851     if (d == RenderStyle::Layout && m_parent)
1852         setNeedsLayoutAndMinMaxRecalc();
1853     else if (m_parent && !isText() && (d == RenderStyle::RepaintLayer || d == RenderStyle::Repaint))
1854         // Do a repaint with the new style now, e.g., for example if we go from
1855         // not having an outline to having an outline.
1856         repaint();
1857 }
1858
1859 void RenderObject::setStyleInternal(RenderStyle* st)
1860 {
1861     if (m_style == st)
1862         return;
1863     if (m_style)
1864         m_style->deref(renderArena());
1865     m_style = st;
1866     if (m_style)
1867         m_style->ref();
1868 }
1869
1870 void RenderObject::updateBackgroundImages(RenderStyle* oldStyle)
1871 {
1872     // FIXME: This will be slow when a large number of images is used.  Fix by using a dict.
1873     const BackgroundLayer* oldLayers = oldStyle ? oldStyle->backgroundLayers() : 0;
1874     const BackgroundLayer* newLayers = m_style ? m_style->backgroundLayers() : 0;
1875     for (const BackgroundLayer* currOld = oldLayers; currOld; currOld = currOld->next()) {
1876         if (currOld->backgroundImage() && (!newLayers || !newLayers->containsImage(currOld->backgroundImage())))
1877             currOld->backgroundImage()->deref(this);
1878     }
1879     for (const BackgroundLayer* currNew = newLayers; currNew; currNew = currNew->next()) {
1880         if (currNew->backgroundImage() && (!oldLayers || !oldLayers->containsImage(currNew->backgroundImage())))
1881             currNew->backgroundImage()->ref(this);
1882     }
1883     
1884     CachedImage* oldBorderImage = oldStyle ? oldStyle->borderImage().image() : 0;
1885     CachedImage* newBorderImage = m_style ? m_style->borderImage().image() : 0;
1886     if (oldBorderImage != newBorderImage) {
1887         if (oldBorderImage)
1888             oldBorderImage->deref(this);
1889         if (newBorderImage)
1890             newBorderImage->ref(this);
1891     }
1892 }
1893
1894 QRect RenderObject::viewRect() const
1895 {
1896     return canvas()->viewRect();
1897 }
1898
1899 bool RenderObject::absolutePosition(int &xPos, int &yPos, bool f)
1900 {
1901     RenderObject* o = parent();
1902     if (o) {
1903         o->absolutePosition(xPos, yPos, f);
1904         if (o->hasOverflowClip())
1905             o->layer()->subtractScrollOffset(xPos, yPos); 
1906         return true;
1907     }
1908     else
1909     {
1910         xPos = yPos = 0;
1911         return false;
1912     }
1913 }
1914
1915 QRect RenderObject::caretRect(int offset, EAffinity affinity, int *extraWidthToEndOfLine)
1916 {
1917    if (extraWidthToEndOfLine)
1918        *extraWidthToEndOfLine = 0;
1919
1920     return QRect();
1921 }
1922
1923 int RenderObject::paddingTop() const
1924 {
1925     int w = 0;
1926     Length padding = m_style->paddingTop();
1927     if (padding.isPercent())
1928         w = containingBlock()->contentWidth();
1929     w = padding.minWidth(w);
1930     if ( isTableCell() && padding.isAuto() )
1931         w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
1932     return w;
1933 }
1934
1935 int RenderObject::paddingBottom() const
1936 {
1937     int w = 0;
1938     Length padding = style()->paddingBottom();
1939     if (padding.isPercent())
1940         w = containingBlock()->contentWidth();
1941     w = padding.minWidth(w);
1942     if ( isTableCell() && padding.isAuto() )
1943         w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
1944     return w;
1945 }
1946
1947 int RenderObject::paddingLeft() const
1948 {
1949     int w = 0;
1950     Length padding = style()->paddingLeft();
1951     if (padding.isPercent())
1952         w = containingBlock()->contentWidth();
1953     w = padding.minWidth(w);
1954     if ( isTableCell() && padding.isAuto() )
1955         w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
1956     return w;
1957 }
1958
1959 int RenderObject::paddingRight() const
1960 {
1961     int w = 0;
1962     Length padding = style()->paddingRight();
1963     if (padding.isPercent())
1964         w = containingBlock()->contentWidth();
1965     w = padding.minWidth(w);
1966     if ( isTableCell() && padding.isAuto() )
1967         w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
1968     return w;
1969 }
1970
1971 int RenderObject::tabWidth() const
1972 {
1973     if (style()->collapseWhiteSpace())
1974         return 0;
1975         
1976     return containingBlock()->tabWidth(true);
1977 }
1978
1979 RenderCanvas* RenderObject::canvas() const
1980 {
1981     return static_cast<RenderCanvas*>(document()->renderer());
1982 }
1983
1984 RenderObject *RenderObject::container() const
1985 {
1986     // This method is extremely similar to containingBlock(), but with a few notable
1987     // exceptions.
1988     // (1) It can be used on orphaned subtrees, i.e., it can be called safely even when
1989     // the object is not part of the primary document subtree yet.
1990     // (2) For normal flow elements, it just returns the parent.
1991     // (3) For absolute positioned elements, it will return a relative positioned inline.
1992     // containingBlock() simply skips relpositioned inlines and lets an enclosing block handle
1993     // the layout of the positioned object.  This does mean that calcAbsoluteHorizontal and
1994     // calcAbsoluteVertical have to use container().
1995     EPosition pos = m_style->position();
1996     RenderObject *o = 0;
1997     if (!isText() && pos == FIXED) {
1998         // container() can be called on an object that is not in the
1999         // tree yet.  We don't call canvas() since it will assert if it
2000         // can't get back to the canvas.  Instead we just walk as high up
2001         // as we can.  If we're in the tree, we'll get the root.  If we
2002         // aren't we'll get the root of our little subtree (most likely
2003         // we'll just return 0).
2004         o = parent();
2005         while (o && o->parent()) o = o->parent();
2006     }
2007     else if (!isText() && pos == ABSOLUTE) {
2008         // Same goes here.  We technically just want our containing block, but
2009         // we may not have one if we're part of an uninstalled subtree.  We'll
2010         // climb as high as we can though.
2011         o = parent();
2012         while (o && o->style()->position() == STATIC && !o->isRoot() && !o->isCanvas())
2013             o = o->parent();
2014     }
2015     else
2016         o = parent();
2017     return o;
2018 }
2019
2020 bool RenderObject::isSelectionBorder() const
2021 {
2022     SelectionState st = selectionState();
2023     return st == SelectionStart || st == SelectionEnd || st == SelectionBoth;
2024 }
2025
2026
2027 void RenderObject::removeFromObjectLists()
2028 {
2029     if (isFloating()) {
2030         RenderBlock* outermostBlock = containingBlock();
2031         for (RenderBlock* p = outermostBlock; p && !p->isCanvas(); p = p->containingBlock()) {
2032             if (p->containsFloat(this))
2033                 outermostBlock = p;
2034         }
2035         
2036         if (outermostBlock)
2037             outermostBlock->markAllDescendantsWithFloatsForLayout(this);
2038     }
2039
2040     if (isPositioned()) {
2041         RenderObject *p;
2042         for (p = parent(); p; p = p->parent()) {
2043             if (p->isRenderBlock())
2044                 static_cast<RenderBlock*>(p)->removePositionedObject(this);
2045         }
2046     }
2047 }
2048
2049 RenderArena* RenderObject::renderArena() const
2050 {
2051     DOM::DocumentImpl* doc = document();
2052     return doc ? doc->renderArena() : 0;
2053 }
2054
2055 void RenderObject::remove()
2056 {
2057     // Delete our accessibility object if we have one.
2058     document()->getAccObjectCache()->detach(this);
2059
2060     removeFromObjectLists();
2061
2062     if (parent())
2063         //have parent, take care of the tree integrity
2064         parent()->removeChild(this);
2065     
2066     deleteLineBoxWrapper();
2067 }
2068
2069 void RenderObject::destroy()
2070 {
2071     // By default no ref-counting. RenderWidget::destroy() doesn't call
2072     // this function because it needs to do ref-counting. If anything
2073     // in this function changes, be sure to fix RenderWidget::destroy() as well. 
2074
2075     remove();
2076     
2077     arenaDelete(document()->renderArena(), this);
2078 }
2079
2080 void RenderObject::arenaDelete(RenderArena *arena, void *base)
2081 {
2082     if (m_style->backgroundImage())
2083         m_style->backgroundImage()->deref(this);
2084     if (m_style)
2085         m_style->deref(arena);
2086     
2087 #ifndef NDEBUG
2088     void *savedBase = baseOfRenderObjectBeingDeleted;
2089     baseOfRenderObjectBeingDeleted = base;
2090 #endif
2091     delete this;
2092 #ifndef NDEBUG
2093     baseOfRenderObjectBeingDeleted = savedBase;
2094 #endif
2095     
2096     // Recover the size left there for us by operator delete and free the memory.
2097     arena->free(*(size_t *)base, base);
2098 }
2099
2100 VisiblePosition RenderObject::positionForCoordinates(int x, int y)
2101 {
2102     return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM);
2103 }
2104
2105 bool RenderObject::isDragging() const
2106
2107     return m_isDragging; 
2108 }
2109
2110 void RenderObject::updateDragState(bool dragOn)
2111 {
2112     bool valueChanged = (dragOn != m_isDragging);
2113     m_isDragging = dragOn;
2114     if (valueChanged && style()->affectedByDragRules())
2115         element()->setChanged();
2116     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
2117         curr->updateDragState(dragOn);
2118     if (continuation())
2119         continuation()->updateDragState(dragOn);
2120 }
2121
2122 bool RenderObject::hitTest(NodeInfo& info, int x, int y, int tx, int ty, HitTestFilter hitTestFilter)
2123 {
2124     bool inside = false;
2125     if (hitTestFilter != HitTestSelf) {
2126         // First test the foreground layer (lines and inlines).
2127         inside = nodeAtPoint(info, x, y, tx, ty, HitTestForeground);
2128         
2129         // Test floats next.
2130         if (!inside)
2131             inside = nodeAtPoint(info, x, y, tx, ty, HitTestFloat);
2132
2133         // Finally test to see if the mouse is in the background (within a child block's background).
2134         if (!inside)
2135             inside = nodeAtPoint(info, x, y, tx, ty, HitTestChildBlockBackgrounds);
2136     }
2137     
2138     // See if the mouse is inside us but not any of our descendants
2139     if (hitTestFilter != HitTestDescendants && !inside)
2140         inside = nodeAtPoint(info, x, y, tx, ty, HitTestBlockBackground);
2141         
2142     return inside;
2143 }
2144
2145 void RenderObject::setInnerNode(NodeInfo& info)
2146 {
2147     if (!info.innerNode() && !isInline() && continuation()) {
2148         // We are in the margins of block elements that are part of a continuation.  In
2149         // this case we're actually still inside the enclosing inline element that was
2150         // split.  Go ahead and set our inner node accordingly.
2151         info.setInnerNode(continuation()->element());
2152         if (!info.innerNonSharedNode())
2153             info.setInnerNonSharedNode(continuation()->element());
2154     }
2155
2156     if (!info.innerNode() && element())
2157         info.setInnerNode(element());
2158             
2159     if(!info.innerNonSharedNode() && element())
2160         info.setInnerNonSharedNode(element());
2161 }
2162
2163 bool RenderObject::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
2164                                HitTestAction hitTestAction)
2165 {
2166     return false;
2167 }
2168
2169 short RenderObject::verticalPositionHint( bool firstLine ) const
2170 {
2171     short vpos = m_verticalPosition;
2172     if ( m_verticalPosition == PositionUndefined || firstLine ) {
2173         vpos = getVerticalPosition( firstLine );
2174         if ( !firstLine )
2175             m_verticalPosition = vpos;
2176     }
2177     return vpos;
2178
2179 }
2180
2181 short RenderObject::getVerticalPosition( bool firstLine ) const
2182 {
2183     if (!isInline())
2184         return 0;
2185
2186     // This method determines the vertical position for inline elements.
2187     int vpos = 0;
2188     EVerticalAlign va = style()->verticalAlign();
2189     if ( va == TOP ) {
2190         vpos = PositionTop;
2191     } else if ( va == BOTTOM ) {
2192         vpos = PositionBottom;
2193     } else if ( va == LENGTH ) {
2194         vpos = -style()->verticalAlignLength().width( lineHeight( firstLine ) );
2195     } else  {
2196         bool checkParent = parent()->isInline() && !parent()->isInlineBlockOrInlineTable() && parent()->style()->verticalAlign() != TOP && parent()->style()->verticalAlign() != BOTTOM;
2197         vpos = checkParent ? parent()->verticalPositionHint( firstLine ) : 0;
2198         // don't allow elements nested inside text-top to have a different valignment.
2199         if ( va == BASELINE )
2200             return vpos;
2201
2202         const QFont &f = parent()->font( firstLine );
2203         int fontsize = f.pixelSize();
2204     
2205         if (va == SUB)
2206             vpos += fontsize/5 + 1;
2207         else if (va == SUPER)
2208             vpos -= fontsize/3 + 1;
2209         else if (va == TEXT_TOP)
2210             vpos += baselinePosition( firstLine ) - QFontMetrics(f).ascent();
2211         else if (va == MIDDLE)
2212             vpos += - (int)(QFontMetrics(f).xHeight()/2) - lineHeight( firstLine )/2 + baselinePosition( firstLine );
2213         else if (va == TEXT_BOTTOM) {
2214             vpos += QFontMetrics(f).descent();
2215             if (!isReplaced())
2216                 vpos -= fontMetrics(firstLine).descent();
2217         } else if ( va == BASELINE_MIDDLE )
2218             vpos += - lineHeight( firstLine )/2 + baselinePosition( firstLine );
2219     }
2220     
2221     return vpos;
2222 }
2223
2224 short RenderObject::lineHeight( bool firstLine, bool ) const
2225 {
2226     RenderStyle* s = style(firstLine);
2227     
2228     Length lh = s->lineHeight();
2229
2230     // its "unset", choose nice default
2231     if (lh.value < 0)
2232         return s->fontMetrics().lineSpacing();
2233
2234     if (lh.isPercent())
2235         return lh.minWidth(s->font().pixelSize());
2236
2237     // its fixed
2238     return lh.value;
2239 }
2240
2241 short RenderObject::baselinePosition( bool firstLine, bool isRootLineBox ) const
2242 {
2243     const QFontMetrics &fm = fontMetrics( firstLine );
2244     return fm.ascent() + ( lineHeight( firstLine, isRootLineBox ) - fm.height() ) / 2;
2245 }
2246
2247 void RenderObject::invalidateVerticalPositions()
2248 {
2249     m_verticalPosition = PositionUndefined;
2250     RenderObject *child = firstChild();
2251     while( child ) {
2252         child->invalidateVerticalPositions();
2253         child = child->nextSibling();
2254     }
2255 }
2256
2257 void RenderObject::recalcMinMaxWidths()
2258 {
2259     KHTMLAssert( m_recalcMinMax );
2260
2261 #ifdef DEBUG_LAYOUT
2262     kdDebug( 6040 ) << renderName() << " recalcMinMaxWidths() this=" << this <<endl;
2263 #endif
2264
2265     if (m_recalcMinMax)
2266         updateFirstLetter();
2267     
2268     RenderObject *child = firstChild();
2269     while( child ) {
2270         int cmin = 0;
2271         int cmax = 0;
2272         bool test = false;
2273         if ( ( m_minMaxKnown && child->m_recalcMinMax ) || !child->m_minMaxKnown ) {
2274             cmin = child->minWidth();
2275             cmax = child->maxWidth();
2276             test = true;
2277         }
2278         if ( child->m_recalcMinMax )
2279             child->recalcMinMaxWidths();
2280         if ( !child->m_minMaxKnown )
2281             child->calcMinMaxWidth();
2282         if ( m_minMaxKnown && test && (cmin != child->minWidth() || cmax != child->maxWidth()) )
2283             m_minMaxKnown = false;
2284         child = child->nextSibling();
2285     }
2286
2287     // we need to recalculate, if the contains inline children, as the change could have
2288     // happened somewhere deep inside the child tree. Also do this for blocks or tables that
2289     // are inline (i.e., inline-block and inline-table).
2290     if ((!isInline() || isInlineBlockOrInlineTable()) && childrenInline())
2291         m_minMaxKnown = false;
2292
2293     if ( !m_minMaxKnown )
2294         calcMinMaxWidth();
2295     m_recalcMinMax = false;
2296 }
2297
2298 void RenderObject::scheduleRelayout()
2299 {
2300     if (!isCanvas()) return;
2301     KHTMLView *view = static_cast<RenderCanvas *>(this)->view();
2302     if (view)
2303         view->scheduleRelayout();
2304 }
2305
2306
2307 void RenderObject::removeLeftoverAnonymousBoxes()
2308 {
2309 }
2310
2311 InlineBox* RenderObject::createInlineBox(bool, bool isRootLineBox, bool)
2312 {
2313     KHTMLAssert(!isRootLineBox);
2314     return new (renderArena()) InlineBox(this);
2315 }
2316
2317 void RenderObject::dirtyLineBoxes(bool, bool)
2318 {
2319 }
2320
2321 InlineBox* RenderObject::inlineBoxWrapper() const
2322 {
2323     return 0;
2324 }
2325
2326 void RenderObject::setInlineBoxWrapper(InlineBox* b)
2327 {
2328 }
2329
2330 void RenderObject::deleteLineBoxWrapper()
2331 {
2332 }
2333
2334 RenderStyle* RenderObject::firstLineStyle() const 
2335 {
2336     RenderStyle *s = m_style; 
2337     const RenderObject* obj = isText() ? parent() : this;
2338     if (obj->isBlockFlow()) {
2339         RenderBlock* firstLineBlock = obj->firstLineBlock();
2340         if (firstLineBlock)
2341             s = firstLineBlock->getPseudoStyle(RenderStyle::FIRST_LINE, style());
2342     } else if (!obj->isAnonymous() && obj->isInlineFlow()) {
2343         RenderStyle* parentStyle = obj->parent()->firstLineStyle();
2344         if (parentStyle != obj->parent()->style()) {
2345             // A first-line style is in effect. We need to cache a first-line style
2346             // for ourselves.
2347             style()->setHasPseudoStyle(RenderStyle::FIRST_LINE_INHERITED);
2348             s = obj->getPseudoStyle(RenderStyle::FIRST_LINE_INHERITED, parentStyle);
2349         }
2350     }
2351     return s;
2352 }
2353
2354 RenderStyle* RenderObject::getPseudoStyle(RenderStyle::PseudoId pseudo, RenderStyle* parentStyle) const
2355 {
2356     if (!style()->hasPseudoStyle(pseudo))
2357         return 0;
2358     
2359     if (!parentStyle)
2360         parentStyle = style();
2361
2362     RenderStyle* result = style()->getPseudoStyle(pseudo);
2363     if (result) return result;
2364     
2365     DOM::NodeImpl* node = element();
2366     if (isText())
2367         node = element()->parentNode();
2368     if (!node) return 0;
2369     
2370     if (pseudo == RenderStyle::FIRST_LINE_INHERITED)
2371         result = document()->styleSelector()->styleForElement(static_cast<DOM::ElementImpl*>(node), 
2372                                                               parentStyle, false);
2373     else
2374         result = document()->styleSelector()->pseudoStyleForElement(pseudo, static_cast<DOM::ElementImpl*>(node), 
2375                                                                     parentStyle);
2376     if (result)
2377         style()->addPseudoStyle(result);
2378     return result;
2379 }
2380
2381 void RenderObject::getTextDecorationColors(int decorations, QColor& underline, QColor& overline,
2382                                            QColor& linethrough, bool quirksMode)
2383 {
2384     RenderObject* curr = this;
2385     do {
2386         int currDecs = curr->style()->textDecoration();
2387         if (currDecs) {
2388             if (currDecs & UNDERLINE) {
2389                 decorations &= ~UNDERLINE;
2390                 underline = curr->style()->color();
2391             }
2392             if (currDecs & OVERLINE) {
2393                 decorations &= ~OVERLINE;
2394                 overline = curr->style()->color();
2395             }
2396             if (currDecs & LINE_THROUGH) {
2397                 decorations &= ~LINE_THROUGH;
2398                 linethrough = curr->style()->color();
2399             }
2400         }
2401         curr = curr->parent();
2402         if (curr && curr->isRenderBlock() && curr->continuation())
2403             curr = curr->continuation();
2404     } while (curr && decorations && (!quirksMode || !curr->element() ||
2405                                      (!curr->element()->hasTagName(aTag) && !curr->element()->hasTagName(fontTag))));
2406
2407     // If we bailed out, use the element we bailed out at (typically a <font> or <a> element).
2408     if (decorations && curr) {
2409         if (decorations & UNDERLINE)
2410             underline = curr->style()->color();
2411         if (decorations & OVERLINE)
2412             overline = curr->style()->color();
2413         if (decorations & LINE_THROUGH)
2414             linethrough = curr->style()->color();
2415     }        
2416 }
2417
2418 void RenderObject::updateWidgetPosition()
2419 {
2420 }
2421
2422 QValueList<DashboardRegionValue> RenderObject::computeDashboardRegions()
2423 {
2424     QValueList<DashboardRegionValue> regions;
2425     collectDashboardRegions(regions);
2426     return regions;
2427 }
2428
2429 void RenderObject::addDashboardRegions (QValueList<DashboardRegionValue>& regions)
2430 {
2431     // Convert the style regions to absolute coordinates.
2432     if (style()->visibility() != VISIBLE) 
2433         return;
2434
2435     QValueList<StyleDashboardRegion> styleRegions = style()->dashboardRegions();
2436     if (styleRegions.count() > 0) {
2437         uint i, count = styleRegions.count();
2438         for (i = 0; i < count; i++){
2439             StyleDashboardRegion styleRegion = styleRegions[i];
2440             
2441             int w = width();
2442             int h = height();
2443             
2444             DashboardRegionValue region;
2445             region.label = styleRegion.label;
2446             region.bounds = QRect (
2447                 styleRegion.offset.left.value,
2448                 styleRegion.offset.top.value,
2449                 w - styleRegion.offset.left.value - styleRegion.offset.right.value,
2450                 h - styleRegion.offset.top.value - styleRegion.offset.bottom.value);
2451             region.type = styleRegion.type;
2452
2453             region.clip = region.bounds;
2454             computeAbsoluteRepaintRect(region.clip);
2455             if (region.clip.height() < 0) {
2456                 region.clip.setHeight(0);
2457                 region.clip.setWidth(0);
2458             }
2459
2460             int x, y;
2461             absolutePosition (x, y);
2462             region.bounds.setX (x + styleRegion.offset.left.value);
2463             region.bounds.setY (y + styleRegion.offset.top.value);
2464             
2465             regions.append (region);
2466         }
2467     }
2468 }
2469
2470 void RenderObject::collectDashboardRegions (QValueList<DashboardRegionValue>& regions)
2471 {
2472     // RenderTexts don't have their own style, they just use their parent's style,
2473     // so we don't want to include them.
2474     if (isText())
2475         return;
2476         
2477     addDashboardRegions (regions);
2478     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
2479         curr->collectDashboardRegions(regions);
2480     }
2481 }
2482
2483
2484 void RenderObject::collectBorders(QValueList<CollapsedBorderValue>& borderStyles)
2485 {
2486     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
2487         curr->collectBorders(borderStyles);
2488 }
2489
2490 bool RenderObject::avoidsFloats() const
2491 {
2492     return isReplaced() || isTable() || hasOverflowClip() || isHR() || isFlexibleBox(); 
2493 }
2494
2495 bool RenderObject::usesLineWidth() const
2496 {
2497     // 1. All auto-width objects that avoid floats should always use lineWidth
2498     // 2. For objects with a specified width, we match WinIE's behavior:
2499     // (a) tables use contentWidth
2500     // (b) <hr>s use lineWidth
2501     // (c) all other objects use lineWidth in quirks mode and contentWidth in strict mode.
2502     return (avoidsFloats() && (style()->width().isAuto() || isHR() || (style()->htmlHacks() && !isTable())));
2503 }
2504
2505 QChar RenderObject::backslashAsCurrencySymbol() const
2506 {
2507     NodeImpl *node = element();
2508     if (!node)
2509         return '\\';
2510     DocumentImpl *document = node->getDocument();
2511     if (!document)
2512         return '\\';
2513     Decoder *decoder = document->decoder();
2514     if (!decoder)
2515         return '\\';
2516     const QTextCodec *codec = decoder->codec();
2517     if (!codec)
2518         return '\\';
2519     return codec->backslashAsCurrencySymbol();
2520 }
2521
2522 void RenderObject::setPixmap(const QPixmap&, const QRect&, CachedImage *image)
2523 {
2524     // Repaint when the background image or border image finishes loading.
2525     // This is needed for RenderBox objects, and also for table objects that hold
2526     // backgrounds that are then respected by the table cells (which are RenderBox
2527     // subclasses). It would be even better to find a more elegant way of doing this that
2528     // would avoid putting this function and the CachedObjectClient base class into RenderObject.
2529
2530     if (image && image->pixmap_size() == image->valid_rect().size() && parent()) {
2531         if (canvas() && element() && (element()->hasTagName(htmlTag) || element()->hasTagName(bodyTag)))
2532             canvas()->repaint();    // repaint the entire canvas since the background gets propagated up
2533         else
2534             repaint();              // repaint object, which is a box or a container with boxes inside it
2535     }
2536 }
2537
2538 int RenderObject::maximalOutlineSize(PaintAction p) const
2539 {
2540     if (p != PaintActionOutline)
2541         return 0;
2542     return static_cast<RenderCanvas*>(document()->renderer())->maximalOutlineSize();
2543 }
2544
2545 int RenderObject::caretMinOffset() const
2546 {
2547     return 0;
2548 }
2549
2550 int RenderObject::caretMaxOffset() const
2551 {
2552     return 0;
2553 }
2554
2555 unsigned RenderObject::caretMaxRenderedOffset() const
2556 {
2557     return 0;
2558 }
2559
2560 int RenderObject::previousOffset (int current) const
2561 {
2562     int previousOffset = current - 1;
2563     return previousOffset;
2564 }
2565
2566 int RenderObject::nextOffset (int current) const
2567 {
2568     int nextOffset = current + 1;
2569     return nextOffset;
2570 }
2571
2572 InlineBox *RenderObject::inlineBox(int offset, EAffinity affinity)
2573 {
2574     return inlineBoxWrapper();
2575 }
2576
2577 #if SVG_SUPPORT
2578 QMatrix RenderObject::absoluteTransform() const
2579 {
2580     if (parent())
2581         return parent()->absoluteTransform() * localTransform();
2582     else
2583         return localTransform();
2584 }
2585 #endif