render_list.cpp Source File (khtml Library)

| # khtml Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# render_list.cpp

    00001
    00026 #include "rendering/render_list.h"
    00027 #include "rendering/render_root.h"
    00028 #include "html/html_listimpl.h"
    00029 #include "misc/helper.h"
    00030 #include "misc/htmltags.h"
    00031
    00032 #include <kdebug.h>
    00033 #include <kglobal.h>
    00034
    00035 //#define BOX_DEBUG
    00036
    00037 using namespace khtml;
    00038
    00039 static QString toRoman( int number, bool upper )
    00040 {
    00041     QString roman;
    00042     QChar ldigits[] = { 'i', 'v', 'x', 'l', 'c', 'd', 'm' };
    00043     QChar udigits[] = { 'I', 'V', 'X', 'L', 'C', 'D', 'M' };
    00044     QChar *digits = upper ? udigits : ldigits;
    00045     int i, d = 0;
    00046
    00047     do
    00048     {
    00049         int num = number % 10;
    00050
    00051         if ( num % 5 < 4 )
    00052             for ( i = num % 5; i > 0; i-- )
    00053                 roman.insert( 0, digits[ d ] );
    00054
    00055         if ( num >= 4 && num <= 8)
    00056             roman.insert( 0, digits[ d+1 ] );
    00057
    00058         if ( num == 9 )
    00059             roman.insert( 0, digits[ d+2 ] );
    00060
    00061         if ( num % 5 == 4 )
    00062             roman.insert( 0, digits[ d ] );
    00063
    00064         number /= 10;
    00065         d += 2;
    00066     }
    00067     while ( number );
    00068
    00069     return roman;
    00070 }
    00071
    00072 static QString toLetter( int number, int base ) {
    00073     number--;
    00074     QString letter = (QChar) (base + (number % 24));
    00075     // Add a "'" at the end of the alphabet
    00076     for (int i = 0; i < (number / 24); i++) {
    00077        letter += QString::fromLatin1("'");
    00078     }
    00079     return letter;
    00080 }
    00081
    00082 static QString toHebrew( int number ) {
    00083     const QChar tenDigit[] = {1497, 1499, 1500, 1502, 1504, 1505, 1506, 1508, 1510};
    00084
    00085     QString letter;
    00086     if (number>999) {
    00087         letter = toHebrew(number/1000) + QString::fromLatin1("'");
    00088         number = number%1000;
    00089     }
    00090
    00091     int hunderts = (number/400);
    00092     if (hunderts > 0) {
    00093         for(int i=0; i<hunderts; i++) {
    00094             letter += QChar(1511 + 3);
    00095         }
    00096     }
    00097     number = number % 400;
    00098     if ((number / 100) != 0) {
    00099         letter += QChar (1511 + (number / 100) -1);
    00100     }
    00101     number = number % 100;
    00102     int tens = number/10;
    00103     if (tens > 0 && !(number == 15 || number == 16)) {
    00104         letter += tenDigit[tens-1];
    00105     }
    00106     if (number == 15 || number == 16) { // special because of religious
    00107         letter += QChar(1487 + 9);       // reasons
    00108         letter += QChar(1487 + number - 9);
    00109     } else {
    00110         number = number % 10;
    00111         if (number != 0) {
    00112             letter += QChar (1487 + number);
    00113         }
    00114     }
    00115     return letter;
    00116 }
    00117
    00118 // -------------------------------------------------------------------------
    00119
    00120 RenderListItem::RenderListItem(DOM::NodeImpl* node)
    00121     : RenderFlow(node)
    00122 {
    00123     // init RenderObject attributes
    00124     setInline(false);   // our object is not Inline
    00125
    00126     predefVal = -1;
    00127     m_marker = 0;
    00128 }
    00129
    00130 void RenderListItem::setStyle(RenderStyle *_style)
    00131 {
    00132     RenderFlow::setStyle(_style);
    00133
    00134     RenderStyle *newStyle = new RenderStyle();
    00135     newStyle->inheritFrom(style());
    00136     if(newStyle->direction() == LTR)
    00137         newStyle->setFloating(FLEFT);
    00138     else
    00139         newStyle->setFloating(FRIGHT);
    00140
    00141     if(!m_marker && style()->listStyleType() != LNONE) {
    00142
    00143         m_marker = new RenderListMarker();
    00144         m_marker->setStyle(newStyle);
    00145         insertChildNode( m_marker, firstChild() );
    00146     } else if ( m_marker && style()->listStyleType() == LNONE) {
    00147         m_marker->detach();
    00148         m_marker = 0;
    00149     }
    00150     else if ( m_marker ) {
    00151         m_marker->setStyle(newStyle);
    00152     }
    00153 }
    00154
    00155 RenderListItem::~RenderListItem()
    00156 {
    00157 }
    00158
    00159 void RenderListItem::calcListValue()
    00160 {
    00161     // only called from the marker so..
    00162     KHTMLAssert(m_marker);
    00163
    00164     if(predefVal != -1)
    00165         m_marker->m_value = predefVal;
    00166     else if(!previousSibling())
    00167         m_marker->m_value = 1;
    00168     else {
    00169         RenderObject *o = previousSibling();
    00170         while ( o && (!o->isListItem() || o->style()->listStyleType() == LNONE) )
    00171             o = o->previousSibling();
    00172         if( o && o->isListItem() && o->style()->listStyleType() != LNONE ) {
    00173             RenderListItem *item = static_cast<RenderListItem *>(o);
    00174             m_marker->m_value = item->value() + 1;
    00175         }
    00176         else if (parent()->element() && parent()->element()->id() == ID_OL)
    00177             m_marker->m_value = static_cast<DOM::HTMLOListElementImpl*>(parent()->element())->start();
    00178         else
    00179             m_marker->m_value = 1;
    00180     }
    00181 }
    00182
    00183 void RenderListItem::layout( )
    00184 {
    00185     KHTMLAssert( !layouted() );
    00186     KHTMLAssert( minMaxKnown() );
    00187
    00188     if (m_marker && !m_marker->layouted())
    00189         m_marker->layout();
    00190     RenderFlow::layout();
    00191
    00192     m_height = kMax ( m_height, int ( lineHeight( true ) ) );
    00193     if (m_marker)
    00194         m_height = kMax( m_height, m_marker->height() );
    00195 }
    00196
    00197 // -----------------------------------------------------------
    00198
    00199 RenderListMarker::RenderListMarker()
    00200     : RenderBox(0), m_listImage(0), m_value(-1)
    00201 {
    00202     // init RenderObject attributes
    00203     setInline(true);   // our object is Inline
    00204     setReplaced(true); // pretend to be replaced
    00205     // val = -1;
    00206     // m_listImage = 0;
    00207 }
    00208
    00209 RenderListMarker::~RenderListMarker()
    00210 {
    00211     if(m_listImage)
    00212         m_listImage->deref(this);
    00213 }
    00214
    00215 void RenderListMarker::setStyle(RenderStyle *s)
    00216 {
    00217     if ( s && style() && s->listStylePosition() != style()->listStylePosition() ) {
    00218         setLayouted( false );
    00219         setMinMaxKnown( false );
    00220     }
    00221     RenderBox::setStyle(s);
    00222
    00223     if ( m_listImage != style()->listStyleImage() ) {
    00224         if(m_listImage)  m_listImage->deref(this);
    00225         m_listImage = style()->listStyleImage();
    00226         if(m_listImage)  m_listImage->ref(this);
    00227     }
    00228 }
    00229
    00230
    00231 void RenderListMarker::paint(QPainter *p, int _x, int _y, int _w, int _h,
    00232                              int _tx, int _ty)
    00233 {
    00234     paintObject(p, _x, _y, _w, _h, _tx, _ty);
    00235 }
    00236
    00237 void RenderListMarker::paintObject(QPainter *p, int, int _y,
    00238                                     int, int _h, int _tx, int _ty)
    00239 {
    00240     if (style()->visibility() != VISIBLE) return;
    00241
    00242 #ifdef DEBUG_LAYOUT
    00243     kdDebug( 6040 ) << nodeName().string() << "(ListMarker)::paintObject(" << _tx << ", " << _ty << ")" << endl;
    00244 #endif
    00245     p->setFont(style()->font());
    00246     const QFontMetrics fm = p->fontMetrics();
    00247     int offset = fm.ascent()*2/3;
    00248
    00249     bool isPrinting = (p->device()->devType() == QInternal::Printer);
    00250     if (isPrinting)
    00251     {
    00252         if (_ty < _y)
    00253         {
    00254             // This has been painted already we suppose.
    00255             return;
    00256         }
    00257         if (_ty + m_height + paddingBottom() + borderBottom() >= _y+_h)
    00258         {
    00259             RenderRoot *rootObj = root();
    00260             if (_ty < rootObj->truncatedAt())
    00261                 rootObj->setTruncatedAt(_ty);
    00262             // Let's paint this on the next page.
    00263             return;
    00264         }
    00265     }
    00266
    00267
    00268     int xoff = m_x;
    00269     int yoff = fm.ascent() - offset;
    00270
    00271
    00272     if ( m_listImage && !m_listImage->isErrorImage()) {
    00273         if ( style()->listStylePosition() != INSIDE ) {
    00274             if ( style()->direction() == LTR )
    00275                 xoff = - m_listImage->pixmap().width();
    00276             else
    00277                 xoff = parent()->width();
    00278         }
    00279         p->drawPixmap( QPoint( _tx + xoff, _ty ), m_listImage->pixmap());
    00280         return;
    00281     }
    00282
    00283     if(style()->listStylePosition() != INSIDE) {
    00284         if(style()->direction() == RTL)
    00285             xoff = 7 + parent()->width();
    00286         else
    00287             xoff = -7 - offset;
    00288
    00289     }
    00290
    00291 #ifdef BOX_DEBUG
    00292     p->setPen( Qt::red );
    00293     p->drawRect( _tx + xoff, _ty + yoff, offset, offset );
    00294 #endif
    00295
    00296     const QColor color( style()->color() );
    00297     p->setPen( color );
    00298
    00299     switch(style()->listStyleType()) {
    00300     case DISC:
    00301         p->setBrush( color );
    00302         p->drawEllipse( _tx + xoff, _ty + (3 * yoff)/2, (offset>>1)+1, (offset>>1)+1 );
    00303         return;
    00304     case CIRCLE:
    00305         p->setBrush( Qt::NoBrush );
    00306         p->drawEllipse( _tx + xoff, _ty + (3 * yoff)/2, (offset>>1)+1, (offset>>1)+1 );
    00307         return;
    00308     case SQUARE:
    00309         p->setBrush( color );
    00310         p->drawRect( _tx + xoff, _ty + (3 * yoff)/2, (offset>>1)+1, (offset>>1)+1 );
    00311         return;
    00312     case LNONE:
    00313         return;
    00314     default:
    00315         if (m_item != QString::null) {
    00316             //_ty += fm.ascent() - fm.height()/2 + 1;
    00317             if(style()->listStylePosition() == INSIDE) {
    00318                 if(style()->direction() == LTR)
    00319                     p->drawText(_tx, _ty, 0, 0, Qt::AlignLeft|Qt::DontClip, m_item);
    00320                 else
    00321                     p->drawText(_tx, _ty, 0, 0, Qt::AlignRight|Qt::DontClip, m_item);
    00322             } else {
    00323                 if(style()->direction() == LTR)
    00324                     p->drawText(_tx-offset/2, _ty, 0, 0, Qt::AlignRight|Qt::DontClip, m_item);
    00325                 else
    00326                     p->drawText(_tx+offset/2 + parent()->width(), _ty, 0, 0, Qt::AlignLeft|Qt::DontClip, m_item);
    00327             }
    00328         }
    00329     }
    00330 }
    00331
    00332 void RenderListMarker::layout()
    00333 {
    00334     KHTMLAssert( !layouted() );
    00335     // ### KHTMLAssert( minMaxKnown() );
    00336     if (m_listImage)
    00337         m_height = m_listImage->pixmap().height();
    00338     else
    00339         m_height = style()->fontMetrics().ascent();
    00340
    00341     if ( !minMaxKnown() )
    00342         calcMinMaxWidth();
    00343     setLayouted();
    00344 }
    00345
    00346 void RenderListMarker::setPixmap( const QPixmap &p, const QRect& r, CachedImage *o)
    00347 {
    00348     if(o != m_listImage) {
    00349         RenderBox::setPixmap(p, r, o);
    00350         return;
    00351     }
    00352
    00353     if(m_width != m_listImage->pixmap_size().width() || m_height != m_listImage->pixmap_size().height())
    00354     {
    00355         setLayouted(false);
    00356         setMinMaxKnown(false);
    00357     }
    00358     else
    00359         repaintRectangle(0, 0, m_width, m_height);
    00360 }
    00361
    00362 void RenderListMarker::calcMinMaxWidth()
    00363 {
    00364     KHTMLAssert( !minMaxKnown() );
    00365
    00366     m_width = 0;
    00367
    00368     if(m_listImage) {
    00369         if(style()->listStylePosition() == INSIDE)
    00370             m_width = m_listImage->pixmap().width();
    00371         setMinMaxKnown();
    00372         return;
    00373     }
    00374
    00375     if (m_value < 0) { // not yet calculated
    00376         RenderObject* p = parent();
    00377         while (p->isAnonymousBox())
    00378             p = p->parent();
    00379         static_cast<RenderListItem*>(p)->calcListValue();
    00380     }
    00381
    00382     const QFontMetrics &fm = style()->fontMetrics();
    00383
    00384     switch(style()->listStyleType())
    00385     {
    00386     case DISC:
    00387     case CIRCLE:
    00388     case SQUARE:
    00389         if(style()->listStylePosition() == INSIDE)
    00390             m_width = fm.ascent();
    00391         goto end;
    00392     case ARMENIAN:
    00393     case GEORGIAN:
    00394     case CJK_IDEOGRAPHIC:
    00395     case HIRAGANA:
    00396     case KATAKANA:
    00397     case HIRAGANA_IROHA:
    00398     case KATAKANA_IROHA:
    00399     case DECIMAL_LEADING_ZERO:
    00400         // ### unsupported, we use decimal instead
    00401     case LDECIMAL:
    00402         m_item.sprintf( "%2ld", m_value );
    00403         break;
    00404     case LOWER_ROMAN:
    00405         m_item = toRoman( m_value, false );
    00406         break;
    00407     case UPPER_ROMAN:
    00408         m_item = toRoman( m_value, true );
    00409         break;
    00410     case LOWER_GREEK:
    00411      {
    00412         int number = m_value - 1;
    00413         int l = (number % 24);
    00414
    00415         if (l>16) {l++;} // Skip GREEK SMALL LETTER FINAL SIGMA
    00416
    00417         m_item = QChar(945 + l);
    00418         for (int i = 0; i < (number / 24); i++) {
    00419             m_item += QString::fromLatin1("'");
    00420         }
    00421         break;
    00422      }
    00423     case HEBREW:
    00424         m_item = toHebrew( m_value );
    00425         break;
    00426     case LOWER_ALPHA:
    00427     case LOWER_LATIN:
    00428         m_item = toLetter( m_value, 'a' );
    00429         break;
    00430     case UPPER_ALPHA:
    00431     case UPPER_LATIN:
    00432         m_item = toLetter( m_value, 'A' );
    00433         break;
    00434     case LNONE:
    00435         break;
    00436     }
    00437     m_item += QString::fromLatin1(". ");
    00438
    00439     if(style()->listStylePosition() == INSIDE)
    00440         m_width = fm.width(m_item);
    00441
    00442 end:
    00443
    00444     m_minWidth = m_width;
    00445     m_maxWidth = m_width;
    00446
    00447     setMinMaxKnown();
    00448 }
    00449
    00450 short RenderListMarker::verticalPositionHint( bool ) const
    00451 {
    00452     return 0;
    00453 }
    00454
    00455 void RenderListMarker::calcWidth()
    00456 {
    00457     RenderBox::calcWidth();
    00458 }
    00459
    00460 #undef BOX_DEBUG

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:36 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001