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