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
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
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) {
00107 letter += QChar(1487 + 9);
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
00124 setInline(false);
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
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
00203 setInline(true);
00204 setReplaced(true);
00205
00206
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
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
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
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
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) {
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
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++;}
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