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