khtml Library API Documentation

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
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:22:42 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001