khtml Library API Documentation

render_object.cpp

00001 
00026 #include "rendering/render_object.h"
00027 #include "rendering/render_table.h"
00028 #include "rendering/render_list.h"
00029 #include "rendering/render_root.h"
00030 #include "xml/dom_elementimpl.h"
00031 #include "misc/htmlhashes.h"
00032 #include <kdebug.h>
00033 #include <qpainter.h>
00034 #include "khtmlview.h"
00035 
00036 #include <assert.h>
00037 using namespace DOM;
00038 using namespace khtml;
00039 
00040 RenderObject *RenderObject::createObject(DOM::NodeImpl* node,  RenderStyle* style)
00041 {
00042     RenderObject *o = 0;
00043     switch(style->display())
00044     {
00045     case NONE:
00046         break;
00047     case INLINE:
00048     case BLOCK:
00049     case TABLE_CAPTION:
00050         o = new RenderFlow(node);
00051         break;
00052     case LIST_ITEM:
00053         o = new RenderListItem(node);
00054         break;
00055     case RUN_IN:
00056     case INLINE_BLOCK:
00057         break;
00058     case TABLE:
00059     case INLINE_TABLE:
00060         style->setFlowAroundFloats(true);
00061         o = new RenderTable(node);
00062         break;
00063     case TABLE_ROW_GROUP:
00064     case TABLE_HEADER_GROUP:
00065     case TABLE_FOOTER_GROUP:
00066         o = new RenderTableSection(node);
00067         break;
00068     case TABLE_ROW:
00069         o = new RenderTableRow(node);
00070         break;
00071     case TABLE_COLUMN_GROUP:
00072     case TABLE_COLUMN:
00073         o = new RenderTableCol(node);
00074         break;
00075     case TABLE_CELL:
00076         o = new RenderTableCell(node);
00077         break;
00078     }
00079     if(o) o->setStyle(style);
00080     return o;
00081 }
00082 
00083 
00084 RenderObject::RenderObject(DOM::NodeImpl* node)
00085     : CachedObjectClient(),
00086 m_style( 0 ),
00087 m_node( node ),
00088 m_parent( 0 ),
00089 m_previous( 0 ),
00090 m_next( 0 ),
00091 m_verticalPosition( PositionUndefined ),
00092 m_layouted( false ),
00093 m_unused( false ),
00094 m_minMaxKnown( false ),
00095 m_floating( false ),
00096 
00097 m_positioned( false ),
00098 m_overhangingContents( false ),
00099 m_relPositioned( false ),
00100 m_paintSpecial( false ),
00101 
00102 m_isAnonymous( false ),
00103 m_recalcMinMax( false ),
00104 m_isText( false ),
00105 m_inline( true ),
00106 
00107 m_replaced( false ),
00108 m_mouseInside( false ),
00109 m_hasFirstLine( false ),
00110 m_isSelectionBorder( false )
00111 {
00112 }
00113 
00114 RenderObject::~RenderObject()
00115 {
00116     if(m_style->backgroundImage())
00117         m_style->backgroundImage()->deref(this);
00118 
00119     if (m_style)
00120         m_style->deref();
00121 }
00122 
00123 
00124 
00125 RenderObject* RenderObject::objectBelow() const
00126 {
00127     RenderObject* obj = firstChild();
00128     if ( !obj ) {
00129         obj = nextSibling();
00130         if ( !obj )
00131         {
00132             obj = parent();
00133             while (obj && !obj->nextSibling())
00134                 obj = obj->parent();
00135             if (obj)
00136                 obj = obj->nextSibling();
00137         }
00138     }
00139     return obj;
00140 }
00141 
00142 RenderObject* RenderObject::objectAbove() const
00143 {
00144     RenderObject* obj = previousSibling();
00145     if ( !obj )
00146         return parent();
00147 
00148     RenderObject* last = obj->lastChild();
00149     while ( last )
00150     {
00151         obj = last;
00152         last = last->lastChild();
00153     }
00154     return obj;
00155 }
00156 
00157 void RenderObject::addChild(RenderObject* , RenderObject *)
00158 {
00159     KHTMLAssert(0);
00160 }
00161 
00162 RenderObject* RenderObject::removeChildNode(RenderObject* )
00163 {
00164     KHTMLAssert(0);
00165     return 0;
00166 }
00167 
00168 void RenderObject::removeChild(RenderObject *o )
00169 {
00170     setLayouted(false);
00171     removeChildNode( o );
00172 }
00173 
00174 void RenderObject::appendChildNode(RenderObject*)
00175 {
00176     KHTMLAssert(0);
00177 }
00178 
00179 void RenderObject::insertChildNode(RenderObject*, RenderObject*)
00180 {
00181     KHTMLAssert(0);
00182 }
00183 
00184 RenderObject *RenderObject::containingBlock() const
00185 {
00186     if(isTableCell())
00187         return parent()->parent()->parent();
00188 
00189     RenderObject *o = parent();
00190     if(m_style->position() == FIXED) {
00191         while ( o && !o->isRoot() )
00192             o = o->parent();
00193     }
00194     else if(m_style->position() == ABSOLUTE) {
00195         while (o && o->style()->position() == STATIC && !o->isHtml() && !o->isRoot())
00196             o = o->parent();
00197     } else {
00198         while(o && o->isInline())
00199             o = o->parent();
00200     }
00201     // this is just to make sure we return a valid element.
00202     // the case below should never happen...
00203     if(!o) {
00204         if(!isRoot()) {
00205 #ifndef NDEBUG
00206             kdDebug( 6040 ) << this << ": " << renderName() << "(RenderObject): No containingBlock!" << endl;
00207             const RenderObject* p = this;
00208             while (p->parent()) p = p->parent();
00209             p->printTree();
00210 #endif
00211         }
00212         return const_cast<RenderObject *>(this);
00213     } else
00214         return o;
00215 }
00216 
00217 short RenderObject::containingBlockWidth() const
00218 {
00219     // ###
00220     return containingBlock()->contentWidth();
00221 }
00222 
00223 int RenderObject::containingBlockHeight() const
00224 {
00225     // ###
00226     return containingBlock()->contentHeight();
00227 }
00228 
00229 void RenderObject::drawBorder(QPainter *p, int x1, int y1, int x2, int y2,
00230                               BorderSide s, QColor c, const QColor& textcolor, EBorderStyle style,
00231                               int adjbw1, int adjbw2, bool invalidisInvert)
00232 {
00233     int width = (s==BSTop||s==BSBottom?y2-y1:x2-x1);
00234 
00235     if(style == DOUBLE && width < 3)
00236         style = SOLID;
00237 
00238     if(!c.isValid()) {
00239         if(invalidisInvert)
00240         {
00241             p->setRasterOp(Qt::XorROP);
00242             c = Qt::white;
00243         }
00244         else {
00245             if(style == INSET || style == OUTSET || style == RIDGE || style ==
00246             GROOVE)
00247                 c.setRgb(238, 238, 238);
00248             else
00249                 c = textcolor;
00250         }
00251     }
00252 
00253     switch(style)
00254     {
00255     case BNONE:
00256     case BHIDDEN:
00257         // should not happen
00258         if(invalidisInvert && p->rasterOp() == Qt::XorROP)
00259             p->setRasterOp(Qt::CopyROP);
00260 
00261         return;
00262     case DOTTED:
00263         p->setPen(QPen(c, width == 1 ? 0 : width, Qt::DotLine));
00264         /* nobreak; */
00265     case DASHED:
00266         if(style == DASHED)
00267             p->setPen(QPen(c, width == 1 ? 0 : width, Qt::DashLine));
00268 
00269         if (width > 0)
00270             switch(s) {
00271             case BSBottom:
00272             case BSTop:
00273                 p->drawLine(x1, (y1+y2)/2, x2, (y1+y2)/2);
00274             case BSRight:
00275             case BSLeft:
00276                 p->drawLine((x1+x2)/2, y1, (x1+x2)/2, y2);
00277             }
00278 
00279         break;
00280     case DOUBLE:
00281     {
00282         int third = (width+1)/3;
00283 
00284         if (adjbw1 == 0 && adjbw2 == 0)
00285         {
00286             p->setPen(Qt::NoPen);
00287             p->setBrush(c);
00288             switch(s)
00289             {
00290             case BSTop:
00291             case BSBottom:
00292                 p->drawRect(x1, y1      , x2-x1, third);
00293                 p->drawRect(x1, y2-third, x2-x1, third);
00294                 break;
00295             case BSLeft:
00296                 p->drawRect(x1      , y1+1, third, y2-y1-1);
00297                 p->drawRect(x2-third, y1+1, third, y2-y1-1);
00298                 break;
00299             case BSRight:
00300                 p->drawRect(x1      , y1+1, third, y2-y1-1);
00301                 p->drawRect(x2-third, y1+1, third, y2-y1-1);
00302                 break;
00303             }
00304         }
00305         else
00306         {
00307             int adjbw1bigthird;
00308             if (adjbw1>0) adjbw1bigthird = adjbw1+1;
00309             else adjbw1bigthird = adjbw1 - 1;
00310             adjbw1bigthird /= 3;
00311 
00312             int adjbw2bigthird;
00313             if (adjbw2>0) adjbw2bigthird = adjbw2 + 1;
00314             else adjbw2bigthird = adjbw2 - 1;
00315             adjbw2bigthird /= 3;
00316 
00317           switch(s)
00318             {
00319             case BSTop:
00320               drawBorder(p, x1+QMAX((-adjbw1*2+1)/3,0), y1        , x2-QMAX((-adjbw2*2+1)/3,0), y1 + third, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
00321               drawBorder(p, x1+QMAX(( adjbw1*2+1)/3,0), y2 - third, x2-QMAX(( adjbw2*2+1)/3,0), y2        , s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
00322               break;
00323             case BSLeft:
00324               drawBorder(p, x1        , y1+QMAX((-adjbw1*2+1)/3,0), x1+third, y2-QMAX((-adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
00325               drawBorder(p, x2 - third, y1+QMAX(( adjbw1*2+1)/3,0), x2      , y2-QMAX(( adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
00326               break;
00327             case BSBottom:
00328               drawBorder(p, x1+QMAX(( adjbw1*2+1)/3,0), y1      , x2-QMAX(( adjbw2*2+1)/3,0), y1+third, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
00329               drawBorder(p, x1+QMAX((-adjbw1*2+1)/3,0), y2-third, x2-QMAX((-adjbw2*2+1)/3,0), y2      , s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
00330               break;
00331             case BSRight:
00332             drawBorder(p, x1      , y1+QMAX(( adjbw1*2+1)/3,0), x1+third, y2-QMAX(( adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
00333             drawBorder(p, x2-third, y1+QMAX((-adjbw1*2+1)/3,0), x2      , y2-QMAX((-adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
00334               break;
00335             default:
00336               break;
00337             }
00338         }
00339         break;
00340     }
00341     case RIDGE:
00342     case GROOVE:
00343     {
00344         EBorderStyle s1;
00345         EBorderStyle s2;
00346         if (style==GROOVE)
00347         {
00348             s1 = INSET;
00349             s2 = OUTSET;
00350         }
00351         else
00352         {
00353             s1 = OUTSET;
00354             s2 = INSET;
00355         }
00356 
00357         int adjbw1bighalf;
00358         int adjbw2bighalf;
00359         if (adjbw1>0) adjbw1bighalf=adjbw1+1;
00360         else adjbw1bighalf=adjbw1-1;
00361         adjbw1bighalf/=2;
00362 
00363         if (adjbw2>0) adjbw2bighalf=adjbw2+1;
00364         else adjbw2bighalf=adjbw2-1;
00365         adjbw2bighalf/=2;
00366 
00367         switch (s)
00368         {
00369         case BSTop:
00370             drawBorder(p, x1+QMAX(-adjbw1  ,0)/2,  y1        , x2-QMAX(-adjbw2,0)/2, (y1+y2+1)/2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
00371             drawBorder(p, x1+QMAX( adjbw1+1,0)/2, (y1+y2+1)/2, x2-QMAX( adjbw2+1,0)/2,  y2        , s, c, textcolor, s2, adjbw1/2, adjbw2/2);
00372             break;
00373         case BSLeft:
00374             drawBorder(p,  x1        , y1+QMAX(-adjbw1  ,0)/2, (x1+x2+1)/2, y2-QMAX(-adjbw2,0)/2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
00375             drawBorder(p, (x1+x2+1)/2, y1+QMAX( adjbw1+1,0)/2,  x2        , y2-QMAX( adjbw2+1,0)/2, s, c, textcolor, s2, adjbw1/2, adjbw2/2);
00376             break;
00377         case BSBottom:
00378             drawBorder(p, x1+QMAX( adjbw1  ,0)/2,  y1        , x2-QMAX( adjbw2,0)/2, (y1+y2+1)/2, s, c, textcolor, s2,  adjbw1bighalf, adjbw2bighalf);
00379             drawBorder(p, x1+QMAX(-adjbw1+1,0)/2, (y1+y2+1)/2, x2-QMAX(-adjbw2+1,0)/2,  y2        , s, c, textcolor, s1, adjbw1/2, adjbw2/2);
00380             break;
00381         case BSRight:
00382             drawBorder(p,  x1        , y1+QMAX( adjbw1  ,0)/2, (x1+x2+1)/2, y2-QMAX( adjbw2,0)/2, s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf);
00383             drawBorder(p, (x1+x2+1)/2, y1+QMAX(-adjbw1+1,0)/2,  x2        , y2-QMAX(-adjbw2+1,0)/2, s, c, textcolor, s1, adjbw1/2, adjbw2/2);
00384             break;
00385         }
00386         break;
00387     }
00388     case INSET:
00389         if(s == BSTop || s == BSLeft)
00390             c = c.dark();
00391 
00392         /* nobreak; */
00393     case OUTSET:
00394         if(style == OUTSET && (s == BSBottom || s == BSRight))
00395             c = c.dark();
00396         /* nobreak; */
00397     case SOLID:
00398         p->setPen(Qt::NoPen);
00399         p->setBrush(c);
00400         Q_ASSERT(x2>=x1);
00401         Q_ASSERT(y2>=y1);
00402         if (adjbw1==0 && adjbw2 == 0) {
00403             p->drawRect(x1,y1,x2-x1,y2-y1);
00404             return;
00405         }
00406         QPointArray quad(4);
00407         switch(s) {
00408         case BSTop:
00409             quad.setPoints(4,
00410                            x1+QMAX(-adjbw1,0), y1,
00411                            x1+QMAX( adjbw1,0), y2,
00412                            x2-QMAX( adjbw2,0), y2,
00413                            x2-QMAX(-adjbw2,0), y1);
00414             break;
00415         case BSBottom:
00416             quad.setPoints(4,
00417                            x1+QMAX( adjbw1,0), y1,
00418                            x1+QMAX(-adjbw1,0), y2,
00419                            x2-QMAX(-adjbw2,0), y2,
00420                            x2-QMAX( adjbw2,0), y1);
00421             break;
00422         case BSLeft:
00423           quad.setPoints(4,
00424                          x1, y1+QMAX(-adjbw1,0),
00425                          x1, y2-QMAX(-adjbw2,0),
00426                          x2, y2-QMAX( adjbw2,0),
00427                          x2, y1+QMAX( adjbw1,0));
00428             break;
00429         case BSRight:
00430           quad.setPoints(4,
00431                          x1, y1+QMAX( adjbw1,0),
00432                          x1, y2-QMAX( adjbw2,0),
00433                          x2, y2-QMAX(-adjbw2,0),
00434                          x2, y1+QMAX(-adjbw1,0));
00435             break;
00436         }
00437         p->drawConvexPolygon(quad);
00438         break;
00439     }
00440 
00441     if(invalidisInvert && p->rasterOp() == Qt::XorROP)
00442         p->setRasterOp(Qt::CopyROP);
00443 }
00444 
00445 void RenderObject::paintBorder(QPainter *p, int _tx, int _ty, int w, int h, const RenderStyle* style, bool begin, bool end)
00446 {
00447     const QColor& tc = style->borderTopColor();
00448     const QColor& bc = style->borderBottomColor();
00449 
00450     EBorderStyle ts = style->borderTopStyle();
00451     EBorderStyle bs = style->borderBottomStyle();
00452     EBorderStyle ls = style->borderLeftStyle();
00453     EBorderStyle rs = style->borderRightStyle();
00454 
00455     bool render_t = ts > BHIDDEN;
00456     bool render_l = ls > BHIDDEN && begin;
00457     bool render_r = rs > BHIDDEN && end;
00458     bool render_b = bs > BHIDDEN;
00459 
00460     if(render_t)
00461         drawBorder(p, _tx, _ty, _tx + w, _ty +  style->borderTopWidth(), BSTop, tc, style->color(), ts,
00462                    (render_l && ls<=DOUBLE?style->borderLeftWidth():0),
00463                    (render_r && rs<=DOUBLE?style->borderRightWidth():0));
00464 
00465     if(render_b)
00466         drawBorder(p, _tx, _ty + h - style->borderBottomWidth(), _tx + w, _ty + h, BSBottom, bc, style->color(), bs,
00467                    (render_l && ls<=DOUBLE?style->borderLeftWidth():0),
00468                    (render_r && rs<=DOUBLE?style->borderRightWidth():0));
00469 
00470     if(render_l)
00471     {
00472         const QColor& lc = style->borderLeftColor();
00473 
00474         bool ignore_top =
00475           (tc == lc) &&
00476           (ls <= OUTSET) &&
00477           (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET);
00478 
00479         bool ignore_bottom =
00480           (bc == lc) &&
00481           (ls <= OUTSET) &&
00482           (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET);
00483 
00484         drawBorder(p, _tx, _ty, _tx + style->borderLeftWidth(), _ty + h, BSLeft, lc, style->color(), ls,
00485                    ignore_top?0:style->borderTopWidth(),
00486                    ignore_bottom?0:style->borderBottomWidth());
00487     }
00488 
00489     if(render_r)
00490     {
00491         const QColor& rc = style->borderRightColor();
00492 
00493         bool ignore_top =
00494           (tc == rc) &&
00495           (rs <= SOLID || rs == INSET) &&
00496           (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET);
00497 
00498         bool ignore_bottom =
00499           (bc == rc) &&
00500           (rs <= SOLID || rs == INSET) &&
00501           (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET);
00502 
00503         drawBorder(p, _tx + w - style->borderRightWidth(), _ty, _tx + w, _ty + h, BSRight, rc, style->color(), rs,
00504                    ignore_top?0:style->borderTopWidth(),
00505                    ignore_bottom?0:style->borderBottomWidth());
00506     }
00507 }
00508 
00509 void RenderObject::paintOutline(QPainter *p, int _tx, int _ty, int w, int h, const RenderStyle* style)
00510 {
00511     int ow = style->outlineWidth();
00512     if(!ow) return;
00513 
00514     const QColor& oc = style->outlineColor();
00515     EBorderStyle os = style->outlineStyle();
00516 
00517     drawBorder(p, _tx-ow, _ty-ow, _tx, _ty+h+ow, BSLeft,
00518                QColor(oc), style->color(),
00519                os, ow, ow, true);
00520 
00521     drawBorder(p, _tx-ow, _ty-ow, _tx+w+ow, _ty, BSTop,
00522                QColor(oc), style->color(),
00523                os, ow, ow, true);
00524 
00525     drawBorder(p, _tx+w, _ty-ow, _tx+w+ow, _ty+h+ow, BSRight,
00526                QColor(oc), style->color(),
00527                os, ow, ow, true);
00528 
00529     drawBorder(p, _tx-ow, _ty+h, _tx+w+ow, _ty+h+ow, BSBottom,
00530                QColor(oc), style->color(),
00531                os, ow, ow, true);
00532 
00533 }
00534 
00535 void RenderObject::paint( QPainter *p, int x, int y, int w, int h, int tx, int ty)
00536 {
00537     paintObject(p, x, y, w, h, tx, ty);
00538 }
00539 
00540 void RenderObject::repaintRectangle(int x, int y, int w, int h, bool f)
00541 {
00542     if(parent()) parent()->repaintRectangle(x, y, w, h, f);
00543 }
00544 
00545 #ifndef NDEBUG
00546 
00547 QString RenderObject::information() const
00548 {
00549     QString str;
00550     QTextStream ts( &str, IO_WriteOnly );
00551     ts << renderName()
00552         << "(" << (style() ? style()->refCount() : 0) << ")"
00553        << ": " << (void*)this << "  ";
00554     if (isInline()) ts << "il ";
00555     if (childrenInline()) ts << "ci ";
00556     if (isFloating()) ts << "fl ";
00557     if (isAnonymousBox()) ts << "an ";
00558     if (isRelPositioned()) ts << "rp ";
00559     if (isPositioned()) ts << "ps ";
00560     if (overhangingContents()) ts << "oc ";
00561     if (layouted()) ts << "lt ";
00562     if (minMaxKnown()) ts << "mmk ";
00563     if (m_recalcMinMax) ts << "rmm ";
00564     if (mouseInside()) ts << "mi ";
00565     if (style() && style()->zIndex()) ts << "zI: " << style()->zIndex();
00566     if (element() && element()->active()) ts << "act ";
00567     if (element() && element()->hasAnchor()) ts << "anchor ";
00568     if (element() && element()->focused()) ts << "focus ";
00569     if (element()) ts << " <" <<  getTagName(element()->id()).string() << ">";
00570     ts << " (" << xPos() << "," << yPos() << "," << width() << "," << height() << ")"
00571        << " [" << minWidth() << "-" << maxWidth() << "]"
00572         << (isTableCell() ?
00573             ( QString::fromLatin1(" [r=") +
00574               QString::number( static_cast<const RenderTableCell *>(this)->row() ) +
00575               QString::fromLatin1(" c=") +
00576               QString::number( static_cast<const RenderTableCell *>(this)->col() ) +
00577               QString::fromLatin1(" rs=") +
00578               QString::number( static_cast<const RenderTableCell *>(this)->rowSpan() ) +
00579               QString::fromLatin1(" cs=") +
00580               QString::number( static_cast<const RenderTableCell *>(this)->colSpan() ) +
00581               QString::fromLatin1("]") ) : QString::null );
00582         return str;
00583 }
00584 
00585 void RenderObject::printTree(int indent) const
00586 {
00587     QString ind;
00588     ind.fill(' ', indent);
00589 
00590     kdDebug() << ind << information() << endl;
00591 
00592     RenderObject *child = firstChild();
00593     while( child != 0 )
00594     {
00595         child->printTree(indent+2);
00596         child = child->nextSibling();
00597     }
00598 }
00599 
00600 void RenderObject::dump(QTextStream *stream, QString ind) const
00601 {
00602     if (isAnonymousBox()) { *stream << " anonymousBox"; }
00603     if (isFloating()) { *stream << " floating"; }
00604     if (isPositioned()) { *stream << " positioned"; }
00605     if (isRelPositioned()) { *stream << " relPositioned"; }
00606     if (isText()) { *stream << " text"; }
00607     if (isInline()) { *stream << " inline"; }
00608     if (isReplaced()) { *stream << " replaced"; }
00609     if (hasSpecialObjects()) { *stream << " specialObjects"; }
00610     if (layouted()) { *stream << " layouted"; }
00611     if (minMaxKnown()) { *stream << " minMaxKnown"; }
00612     if (overhangingContents()) { *stream << " overhangingContents"; }
00613     if (hasFirstLine()) { *stream << " hasFirstLine"; }
00614     *stream << endl;
00615 
00616     RenderObject *child = firstChild();
00617     while( child != 0 )
00618     {
00619         *stream << ind << child->renderName() << ": ";
00620         child->dump(stream,ind+"  ");
00621         child = child->nextSibling();
00622     }
00623 }
00624 #endif
00625 
00626 void RenderObject::selectionStartEnd(int& spos, int& epos)
00627 {
00628     if (parent())
00629         parent()->selectionStartEnd(spos, epos);
00630 }
00631 
00632 void RenderObject::setStyle(RenderStyle *style)
00633 {
00634     if (m_style == style)
00635         return;
00636 
00637     RenderStyle::Diff d = m_style ? m_style->diff( style ) : RenderStyle::Layout;
00638     //qDebug("new style, diff=%d", d);
00639     // reset style flags
00640     m_floating = false;
00641     m_positioned = false;
00642     m_relPositioned = false;
00643     m_paintSpecial = false;
00644     // no support for changing the display type dynamically... object must be
00645     // detached and re-attached as a different type
00646     //m_inline = true;
00647 
00648     RenderStyle *oldStyle = m_style;
00649     m_style = style;
00650 
00651     CachedImage* ob = 0;
00652     CachedImage* nb = 0;
00653 
00654     if (m_style)
00655     {
00656         m_style->ref();
00657         nb = m_style->backgroundImage();
00658     }
00659     if (oldStyle)
00660     {
00661         ob = oldStyle->backgroundImage();
00662         oldStyle->deref();
00663     }
00664 
00665     if( ob != nb ) {
00666         if(ob) ob->deref(this);
00667         if(nb) nb->ref(this);
00668     }
00669 
00670     setSpecialObjects( m_style->backgroundColor().isValid() || m_style->hasBorder() || nb );
00671     m_hasFirstLine = (style->getPseudoStyle(RenderStyle::FIRST_LINE) != 0);
00672 
00673     if ( d >= RenderStyle::Position && m_parent ) {
00674         //qDebug("triggering relayout");
00675         setMinMaxKnown(false);
00676         setLayouted(false);
00677     } else if ( m_parent ) {
00678         //qDebug("triggering repaint");
00679         repaint();
00680     }
00681 }
00682 
00683 void RenderObject::setOverhangingContents(bool p)
00684 {
00685     if (m_overhangingContents == p)
00686         return;
00687 
00688     RenderObject *cb = containingBlock();
00689     if (p)
00690     {
00691         m_overhangingContents = true;
00692         if (cb!=this)
00693             cb->setOverhangingContents();
00694     }
00695     else
00696     {
00697         RenderObject *n;
00698         bool c=false;
00699 
00700         for( n = firstChild(); n != 0; n = n->nextSibling() )
00701         {
00702             if (n->isPositioned() || n->overhangingContents())
00703                 c=true;
00704         }
00705 
00706         if (c)
00707             return;
00708         else
00709         {
00710             m_overhangingContents = false;
00711             if (cb!=this)
00712                 cb->setOverhangingContents(false);
00713         }
00714     }
00715 }
00716 
00717 QRect RenderObject::viewRect() const
00718 {
00719     return containingBlock()->viewRect();
00720 }
00721 
00722 bool RenderObject::absolutePosition(int &xPos, int &yPos, bool f)
00723 {
00724     if(parent())
00725         return parent()->absolutePosition(xPos, yPos, f);
00726     else
00727     {
00728         xPos = yPos = 0;
00729         return false;
00730     }
00731 }
00732 
00733 void RenderObject::cursorPos(int /*offset*/, int &_x, int &_y, int &height)
00734 {
00735     _x = _y = height = -1;
00736 }
00737 
00738 int RenderObject::paddingTop() const
00739 {
00740     int w = 0;
00741     Length padding = m_style->paddingTop();
00742     if (padding.isPercent())
00743         w = containingBlock()->contentWidth();
00744     w = padding.minWidth(w);
00745     if ( isTableCell() && padding.isVariable() )
00746         w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
00747     return w;
00748 }
00749 
00750 int RenderObject::paddingBottom() const
00751 {
00752     int w = 0;
00753     Length padding = style()->paddingBottom();
00754     if (padding.isPercent())
00755         w = containingBlock()->contentWidth();
00756     w = padding.minWidth(w);
00757     if ( isTableCell() && padding.isVariable() )
00758         w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
00759     return w;
00760 }
00761 
00762 int RenderObject::paddingLeft() const
00763 {
00764     int w = 0;
00765     Length padding = style()->paddingLeft();
00766     if (padding.isPercent())
00767         w = containingBlock()->contentWidth();
00768     w = padding.minWidth(w);
00769     if ( isTableCell() && padding.isVariable() )
00770         w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
00771     return w;
00772 }
00773 
00774 int RenderObject::paddingRight() const
00775 {
00776     int w = 0;
00777     Length padding = style()->paddingRight();
00778     if (padding.isPercent())
00779         w = containingBlock()->contentWidth();
00780     w = padding.minWidth(w);
00781     if ( isTableCell() && padding.isVariable() )
00782         w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
00783     return w;
00784 }
00785 
00786 RenderRoot* RenderObject::root() const
00787 {
00788     RenderObject* o = const_cast<RenderObject*>( this );
00789     while ( o->parent() ) o = o->parent();
00790 
00791     KHTMLAssert( o->isRoot() );
00792     return static_cast<RenderRoot*>( o );
00793 }
00794 
00795 RenderObject *RenderObject::container() const
00796 {
00797     EPosition pos = m_style->position();
00798     RenderObject *o = 0;
00799     if( pos == FIXED )
00800         o = root();
00801     else if ( pos == ABSOLUTE )
00802         o = containingBlock();
00803     else
00804         o = parent();
00805     return o;
00806 }
00807 
00808 #if 0  
00809 void RenderObject::invalidateLayout()
00810 {
00811     kdDebug() << "RenderObject::invalidateLayout " << renderName() << endl;
00812     setLayouted(false);
00813     if (m_parent && m_parent->layouted())
00814         m_parent->invalidateLayout();
00815 }
00816 #endif
00817 
00818 void RenderObject::removeFromSpecialObjects()
00819 {
00820     if (isPositioned() || isFloating()) {
00821         RenderObject *p;
00822         for (p = parent(); p; p = p->parent()) {
00823             if (p->isFlow())
00824                 static_cast<RenderFlow*>(p)->removeSpecialObject(this);
00825         }
00826     }
00827 }
00828 
00829 void RenderObject::detach()
00830 {
00831     remove();
00832     // by default no refcounting
00833     delete this;
00834 }
00835 
00836 FindSelectionResult RenderObject::checkSelectionPoint( int _x, int _y, int _tx, int _ty, DOM::NodeImpl*& node, int & offset )
00837 {
00838     NodeInfo info(true, false);
00839     if ( nodeAtPoint( info, _x, _y, _tx, _ty ) && info.innerNode() )
00840     {
00841         RenderObject* r = info.innerNode()->renderer();
00842         if ( r ) {
00843             if ( r == this ) {
00844                 node = info.innerNode();
00845                 offset = 0; // we have no text...
00846                 return SelectionPointInside;
00847             }
00848             else
00849                 return r->checkSelectionPoint( _x, _y, _tx, _ty, node, offset );
00850         }
00851     }
00852     //kdDebug(6030) << "nodeAtPoint Failed. Fallback - hmm, SelectionPointAfter" << endl;
00853     node = 0;
00854     offset = 0;
00855     return SelectionPointAfter;
00856 }
00857 
00858 bool RenderObject::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty)
00859 {
00860     int tx = _tx + xPos();
00861     int ty = _ty + yPos();
00862     if (isRelPositioned())
00863         static_cast<RenderBox*>(this)->relativePositionOffset(tx, ty);
00864 
00865     bool checkPoint = style()->visibility() != HIDDEN && (_y >= ty) && (_y < ty + height());
00866     bool inside = (checkPoint && (_x >= tx) && (_x < tx + width())) || isBody() || isHtml();
00867     bool inner = !info.innerNode();
00868 
00869     // ### table should have its own, more performant method
00870     if (overhangingContents() || isInline() || isRoot() || isTableRow() || isTableSection() || isPositioned() || checkPoint || mouseInside() ) {
00871         for (RenderObject* child = lastChild(); child; child = child->previousSibling())
00872             if (!child->isSpecial() && child->nodeAtPoint(info, _x, _y, tx, ty))
00873                 inside = true;
00874     }
00875 
00876     if (inside && element()) {
00877         if (!info.innerNode())
00878             info.setInnerNode(element());
00879 
00880         if (!info.URLElement()) {
00881             RenderObject* p = this;
00882             while (p) {
00883                 if (p->element() && p->element()->hasAnchor()) {
00884                     info.setURLElement(p->element());
00885                     break;
00886                 }
00887                 if (!isSpecial()) break;
00888                 p = p->parent();
00889             }
00890         }
00891     }
00892 
00893     if (!info.readonly()) {
00894         // lets see if we need a new style
00895         bool oldinside = mouseInside();
00896         setMouseInside(inside && inner);
00897         if (element()) {
00898             bool oldactive = element()->active();
00899             if (oldactive != (inside && info.active() && element() == info.innerNode()))
00900                 element()->setActive(inside && info.active() && element() == info.innerNode());
00901             if ( ((oldinside != mouseInside()) && style()->hasHover()) ||
00902                  ((oldactive != element()->active()) && style()->hasActive()))
00903                 element()->setChanged();
00904         }
00905     }
00906 
00907     return inside;
00908 }
00909 
00910 short RenderObject::verticalPositionHint( bool firstLine ) const
00911 {
00912     short vpos = m_verticalPosition;
00913     if ( m_verticalPosition == PositionUndefined || firstLine ) {
00914         vpos = getVerticalPosition( firstLine );
00915         if ( !firstLine )
00916             const_cast<RenderObject *>(this)->m_verticalPosition = vpos;
00917     }
00918     return vpos;
00919 
00920 }
00921 
00922 short RenderObject::getVerticalPosition( bool firstLine ) const
00923 {
00924     // vertical align for table cells has a different meaning
00925     int vpos = 0;
00926     if ( !isTableCell() ) {
00927         EVerticalAlign va = style()->verticalAlign();
00928         if ( va == TOP ) {
00929             vpos = PositionTop;
00930         } else if ( va == BOTTOM ) {
00931             vpos = PositionBottom;
00932         } else if ( va == LENGTH ) {
00933             vpos = -style()->verticalAlignLength().width( lineHeight( firstLine ) );
00934         } else if ( parent() && parent()->childrenInline() ) {
00935             vpos = parent()->verticalPositionHint( firstLine );
00936             // don't allow elements nested inside text-top to have a different valignment.
00937             if ( va == BASELINE )
00938                 return vpos;
00939 
00940         //     if ( vpos == PositionTop )
00941 //                 vpos = 0;
00942 
00943             const QFont &f = parent()->font( firstLine );
00944             int fontheight = parent()->lineHeight( firstLine );
00945             int fontsize = f.pixelSize();
00946             int halfleading = ( fontheight - fontsize ) / 2;
00947 
00948             if ( va == SUB )
00949                 vpos += fontsize/5 + 1;
00950             else if ( va == SUPER )
00951                 vpos -= fontsize/3 + 1;
00952             else if ( va == TEXT_TOP ) {
00953 //                 qDebug( "got TEXT_TOP vertical pos hint" );
00954 //                 qDebug( "parent:" );
00955 //                 qDebug( "CSSLH: %d, CSS_FS: %d, basepos: %d", fontheight, fontsize, parent()->baselinePosition( firstLine ) );
00956 //                 qDebug( "this:" );
00957 //                 qDebug( "CSSLH: %d, CSS_FS: %d, basepos: %d", lineHeight( firstLine ), style()->font().pixelSize(), baselinePosition( firstLine ) );
00958                 vpos += ( baselinePosition( firstLine ) - parent()->baselinePosition( firstLine ) +
00959                         halfleading );
00960             } else if ( va == MIDDLE ) {
00961                 QRect b = QFontMetrics(f).boundingRect('x');
00962                 vpos += -b.height()/2 - lineHeight( firstLine )/2 + baselinePosition( firstLine );
00963             } else if ( va == TEXT_BOTTOM ) {
00964                 vpos += QFontMetrics(f).descent();
00965                 if ( !isReplaced() )
00966                     vpos -= fontMetrics(firstLine).descent();
00967             } else if ( va == BASELINE_MIDDLE )
00968                 vpos += - lineHeight( firstLine )/2 + baselinePosition( firstLine );
00969         }
00970     }
00971     return vpos;
00972 }
00973 
00974 short RenderObject::lineHeight( bool firstLine ) const
00975 {
00976     Length lh;
00977     if( firstLine && hasFirstLine() ) {
00978         RenderStyle *pseudoStyle  = style()->getPseudoStyle(RenderStyle::FIRST_LINE);
00979         if ( pseudoStyle )
00980             lh = pseudoStyle->lineHeight();
00981     }
00982     else
00983         lh = style()->lineHeight();
00984 
00985     // its "unset", choose nice default
00986     if ( lh.value() < 0 )
00987         return style()->fontMetrics().lineSpacing();
00988 
00989     if ( lh.isPercent() )
00990         return lh.minWidth( style()->font().pixelSize() );
00991 
00992     // its fixed
00993     return lh.value();
00994 }
00995 
00996 short RenderObject::baselinePosition( bool firstLine ) const
00997 {
00998     const QFontMetrics &fm = fontMetrics( firstLine );
00999     return fm.ascent() + ( lineHeight( firstLine ) - fm.height() ) / 2;
01000 }
01001 
01002 void RenderObject::invalidateVerticalPositions()
01003 {
01004     m_verticalPosition = PositionUndefined;
01005     RenderObject *child = firstChild();
01006     while( child ) {
01007         child->invalidateVerticalPositions();
01008         child = child->nextSibling();
01009     }
01010 }
01011 
01012 void RenderObject::recalcMinMaxWidths()
01013 {
01014     KHTMLAssert( m_recalcMinMax );
01015 
01016 #ifdef DEBUG_LAYOUT
01017     kdDebug( 6040 ) << renderName() << " recalcMinMaxWidths() this=" << this <<endl;
01018 #endif
01019 
01020     RenderObject *child = firstChild();
01021     while( child ) {
01022         // gcc sucks. if anybody knows a trick to get rid of the
01023         // warning without adding an extra (unneeded) initialisation,
01024         // go ahead
01025         int cmin, cmax;
01026         bool test = false;
01027         if ( ( m_minMaxKnown && child->m_recalcMinMax ) || !child->m_minMaxKnown ) {
01028             cmin = child->minWidth();
01029             cmax = child->maxWidth();
01030             test = true;
01031         }
01032         if ( child->m_recalcMinMax )
01033             child->recalcMinMaxWidths();
01034         if ( !child->m_minMaxKnown )
01035             child->calcMinMaxWidth();
01036         if ( m_minMaxKnown && test && (cmin != child->minWidth() || cmax != child->maxWidth()) )
01037             m_minMaxKnown = false;
01038         child = child->nextSibling();
01039     }
01040 
01041     // we need to recalculate, if the contains inline children, as the change could have
01042     // happened somewhere deep inside the child tree
01043     if ( !isInline() && childrenInline() )
01044         m_minMaxKnown = false;
01045 
01046     if ( !m_minMaxKnown )
01047         calcMinMaxWidth();
01048     m_recalcMinMax = false;
01049 }
01050 
01051 void RenderObject::scheduleRelayout()
01052 {
01053     if (!isRoot()) return;
01054     KHTMLView *view = static_cast<RenderRoot *>(this)->view();
01055     if ( view )
01056         view->scheduleRelayout();
01057 }
01058 
01059 
01060 void RenderObject::removeLeftoverAnonymousBoxes()
01061 {
01062 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 13:34:38 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001