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