lib Library API Documentation

kotextformatter.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001 David Faure <faure@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017    Boston, MA 02111-1307, USA.
00018 */
00019 
00020 #include <qglobal.h>
00021 #if QT_VERSION >= 0x030200
00022 #define INDIC
00023 #endif
00024 
00025 #include "kotextformatter.h"
00026 #include "kotextformat.h"
00027 #include "kotextdocument.h"
00028 #include "kozoomhandler.h"
00029 #include "kohyphen/kohyphen.h"
00030 #include "koparagcounter.h"
00031 
00032 #include <kdebug.h>
00033 
00034 //#define DEBUG_FORMATTER
00035 
00036 // Vertical info (height, baseline etc.)
00037 //#define DEBUG_FORMATTER_VERT
00038 
00039 // Line and paragraph width
00040 //#define DEBUG_FORMATTER_WIDTH
00041 
00042 // Hyphenation
00043 //#define DEBUG_HYPHENATION
00044 
00046 //#define REF_IS_LU
00047 
00048 KoTextFormatter::KoTextFormatter()
00049 {
00050     try {
00051         m_hyphenator = KoHyphenator::self();
00052     } catch ( KoHyphenatorException& e )
00053     {
00054         m_hyphenator = 0L;
00055     }
00056 }
00057 
00058 KoTextFormatter::~KoTextFormatter()
00059 {
00060 }
00061 
00062 // Hyphenation can break anywhere in the word, so
00063 // remember the temp data for every char.
00064 struct TemporaryWordData
00065 {
00066     int baseLine;
00067     int height;
00068     int lineWidth; // value of wused
00069 };
00070 
00071 bool KoTextFormatter::format( KoTextDocument *doc, KoTextParag *parag,
00072                               int start, const QMap<int, KoTextParagLineStart*> &,
00073                               int& y, int& widthUsed )
00074 {
00075     KoTextFormatterCore formatter( this, doc, parag, start );
00076     bool worked = formatter.format();
00077     y = formatter.resultY();
00078     widthUsed = formatter.widthUsed();
00079     return worked;
00080 }
00081 
00082 KoTextFormatterCore::KoTextFormatterCore( KoTextFormatter* _settings,
00083                                           KoTextDocument *_doc, KoTextParag *_parag,
00084                                           int _start )
00085     : settings(_settings), doc(_doc), parag(_parag), start(_start)
00086 {
00087 }
00088 
00089 QPair<int, int> KoTextFormatterCore::determineCharWidth()
00090 {
00091     int ww, pixelww;
00092     KoZoomHandler *zh = doc->formattingZoomHandler();
00093     if ( c->c != '\t' || c->isCustom() ) {
00094         KoTextFormat *charFormat = c->format();
00095         if ( c->isCustom() ) {
00096             ww = c->customItem()->width;
00097             Q_ASSERT( ww >= 0 );
00098             ww = QMAX(0, ww);
00099 #ifndef REF_IS_LU
00100             pixelww = zh->layoutUnitToPixelX( ww );
00101 #endif
00102         } else {
00103             ww = charFormat->charWidthLU( c, parag, i );
00104 #ifndef REF_IS_LU
00105             // Pixel size - we want the metrics of the font that's going to be used.
00106             pixelww = charFormat->charWidth( zh, true, c, parag, i );
00107 #endif
00108         }
00109     } else { // tab
00110         int nx = parag->nextTab( i, x );
00111         if ( nx < x )
00112             ww = availableWidth - x;
00113         else
00114             ww = nx - x + 1;
00115 #ifndef REF_IS_LU
00116         pixelww = zh->layoutUnitToPixelX( ww );
00117 #endif
00118     }
00119     Q_ASSERT( ww >= 0 );
00120     c->width = ww;
00121     return qMakePair(ww, pixelww);
00122 }
00123 
00124 
00125 int KoTextFormatterCore::leftMargin( bool firstLine ) const
00126 {
00127     int left = /*doc ?*/ parag->leftMargin() + doc->leftMargin() /*: 0*/;
00128     if ( firstLine && !parag->string()->isRightToLeft() )
00129     {
00130         left += parag->firstLineMargin();
00131         // Add the width of the paragraph counter - first line of parag only.
00132         if( parag->counter() &&
00133             ( parag->counter()->alignment() == Qt::AlignLeft ||
00134               parag->counter()->alignment() == Qt::AlignAuto ) )
00135             left += parag->counterWidth(); // in LU pixels
00136     }
00137     return left;
00138 }
00139 
00140 int KoTextFormatterCore::rightMargin( bool firstLine ) const
00141 {
00142     int right = parag->rightMargin(); // 'rm' in QRT
00143     if ( /*doc &&*/ firstLine && parag->string()->isRightToLeft() )
00144         right += parag->firstLineMargin();
00145     return right;
00146 }
00147 
00148 bool KoTextFormatterCore::format()
00149 {
00150     start = 0; // we don't do partial formatting yet
00151     KoTextString *string = parag->string();
00152     if ( start == 0 )
00153         c = &string->at( start );
00154     else
00155         c = 0;
00156 
00157     KoTextStringChar *firstChar = 0;
00158     int left = doc ? parag->leftMargin() + doc->leftMargin() : 0;
00159     int initialLMargin = leftMargin( true );
00160 
00161     y = doc && doc->addMargins() ? parag->topMargin() : 0;
00162     // #57555, top margin doesn't apply if parag at top of page
00163     // (but a portion of the margin can be needed, to complete the prev page)
00164     // So we apply formatVertically() on the top margin, to find where to break it.
00165     if ( !parag->prev() )
00166         y = 0; // no top margin on very first parag
00167     else if ( parag->breakableTopMargin() )
00168     {
00169         int shift = doc->flow()->adjustFlow( parag->rect().y(),
00170                                              0 /*w, unused*/,
00171                                              parag->breakableTopMargin() );
00172         if ( shift > 0 )
00173         {
00174             // The shift is in fact the amount of top-margin that should remain
00175             // The remaining portion should be eaten away.
00176             y = shift;
00177         }
00178 
00179     }
00180     // Now add the rest of the top margin (e.g. the one for the border)
00181     y += parag->topMargin() - parag->breakableTopMargin();
00182     int len = parag->length();
00183 
00184     int initialHeight = c->height(); // remember what adjustMargins was called with
00185 
00186     int currentRightMargin = rightMargin( true );
00187     int initialRMargin = currentRightMargin;
00188     // Those three things must be done before calling determineCharWidth
00189     i = start;
00190     parag->tabCache().clear();
00191     x = 0;
00192 
00193     // We need the width of the first char for adjustMargins
00194     // The result might not be 100% accurate when using a tab (it'll use x=0
00195     // but with counters/margins this might be different). This is why
00196     // we call determineCharWidth() again from within the loop.
00197     QPair<int, int> widths = determineCharWidth();
00198     int ww = widths.first; // width in layout units
00199 #ifndef REF_IS_LU
00200     int pixelww = widths.second; // width in pixels
00201 #endif
00202 
00203     // dw is the document width, i.e. the maximum available width, all included.
00204     // We are in a variable-width design, so it is returned by each call to adjustMargins.
00205     int dw = 0;
00206     //if (doc) // always true in kotext
00207     doc->flow()->adjustMargins( y + parag->rect().y(), initialHeight, // input params
00208                                 ww, initialLMargin, initialRMargin, dw,  // output params
00209                                 parag );
00210     //else dw = parag->documentVisibleWidth();
00211 
00212     x = initialLMargin; // as modified by adjustMargins
00213 
00214     int maxY = doc ? doc->flow()->availableHeight() : -1;
00215 
00216     availableWidth = dw - initialRMargin; // 'w' in QRT
00217 #if defined(DEBUG_FORMATTER) || defined(DEBUG_FORMATTER_WIDTH)
00218     kdDebug(32500) << "KoTextFormatter::format formatting parag " << parag->paragId()
00219                    << " text:" << parag->string()->toString() << "\n"
00220                    << " left=" << left << " initialHeight=" << initialHeight << " initialLMargin=" << initialLMargin << " initialRMargin=" << initialRMargin << " availableWidth=" << availableWidth << " maxY=" << maxY << endl;
00221 #else
00222     if ( availableWidth == 0 )
00223         kdDebug(32500) << "KoTextFormatter::format " << parag->paragId() << " warning, availableWidth=0" << endl;
00224     if ( maxY == 0 )
00225         kdDebug(32500) << "KoTextFormatter::format " << parag->paragId() << " warning, maxY=0" << endl;
00226 #endif
00227     bool fullWidth = TRUE;
00228     //int marg = left + initialRMargin;
00229 
00230     // minw is the really minimum width needed for this paragraph, i.e.
00231     // the width of the longest set of non-breakable characters together.
00232     // Currently unused.
00233     //int minw = 0;
00234 
00235     wused = 0;
00236 
00237     bool wrapEnabled = settings->isWrapEnabled( parag );
00238     QValueList<TemporaryWordData> tempWordData;
00239 
00240 #ifdef DEBUG_FORMATTER
00241     kdDebug(32500) << "Initial KoTextParagLineStart at y=" << y << endl;
00242 #endif
00243     KoTextParagLineStart *lineStart = new KoTextParagLineStart( y, 0, 0 );
00244     parag->insertLineStart( 0, lineStart );
00245     int lastBreak = -1;
00246     // tmph, tmpBaseLine and tminw are used after the last breakable char
00247     // we don't know yet if we'll break there, or later.
00248     int tmpBaseLine = 0, tmph = 0;
00249     //int tminw = marg;
00250     int tmpWused = 0;
00251     bool lastWasNonInlineCustom = FALSE;
00252     bool abort = false;
00253 
00254     int align = parag->alignment();
00255     if ( align == Qt::AlignAuto && doc && doc->alignment() != Qt::AlignAuto )
00256         align = doc->alignment();
00257 
00258     int col = 0;
00259 
00260     maxAvailableWidth = qMakePair( 0, 0 );
00261 
00262     KoZoomHandler *zh = doc->formattingZoomHandler();
00263     int pixelx = zh->layoutUnitToPixelX( x );
00264     int lastPixelx = 0;
00265 
00266     KoTextStringChar* lastChr = 0;
00267     for ( ; i < len; ++i, ++col ) {
00268         if ( c )
00269             lastChr = c;
00270         c = &string->at( i );
00271         if ( i > 0 && (x > initialLMargin || ww == 0) || lastWasNonInlineCustom ) {
00272             c->lineStart = 0;
00273         } else {
00274             c->lineStart = 1;
00275             firstChar = c;
00276             tmph = c->height();
00277             tmpBaseLine = c->ascent();
00278 #ifdef DEBUG_FORMATTER_VERT
00279             kdDebug(32500) << "New line, initializing tmpBaseLine=" << tmpBaseLine << " tmph=" << tmph << endl;
00280 #endif
00281         }
00282 
00283         if ( c->isCustom() && c->customItem()->placement() != KoTextCustomItem::PlaceInline )
00284             lastWasNonInlineCustom = TRUE;
00285         else
00286             lastWasNonInlineCustom = FALSE;
00287 
00288         QPair<int, int> widths = determineCharWidth();
00289         ww = widths.first;
00290         pixelww = widths.second;
00291 
00292         // We're "aborting" the formatting. This still means we need to set the
00293         // lineStart bools to false (trouble ahead, otherwise!), and while we're at
00294         // it we also calculate the widths etc.
00295         if ( abort ) {
00296             x += ww;
00297             c->x = x;
00298             continue; // yeah, this seems a bit confusing :)
00299         }
00300 
00301         //code from qt-3.1beta2
00302         if ( c->isCustom() && c->customItem()->ownLine() ) {
00303 #ifdef DEBUG_FORMATTER
00304             kdDebug(32500) << "i=" << i << "/" << len << " custom item with ownline" << endl;
00305 #endif
00306             int rightMargin = currentRightMargin;
00307             x = left;
00308             if ( doc )
00309                 doc->flow()->adjustMargins( y + parag->rect().y(), parag->rect().height(), 15,
00310                                             x, rightMargin, dw, parag );
00311             int w = dw - rightMargin;
00312             c->customItem()->resize( w - x );
00313             y += lineStart->h;
00314             lineStart = new KoTextParagLineStart( y, c->ascent(), c->height() );
00315             // Added for kotext (to be tested)
00316             lineStart->lineSpacing = doc ? parag->lineSpacing( (int)parag->lineStartList().count()-1 ) : 0;
00317             lineStart->h += lineStart->lineSpacing;
00318             lineStart->w = dw;
00319             parag->insertLineStart( i, lineStart );
00320             tempWordData.clear();
00321             c->lineStart = 1;
00322             firstChar = c;
00323             x = 0xffffff;
00324             // Hmm, --i or setting lineStart on next char too?
00325             continue;
00326         }
00327 
00328 #ifdef DEBUG_FORMATTER
00329         kdDebug(32500) << "c='" << QString(c->c) << "' i=" << i << "/" << len << " x=" << x << " ww=" << ww << " availableWidth=" << availableWidth << " (test is x+ww>aW) lastBreak=" << lastBreak << " isBreakable=" << settings->isBreakable(string, i) << endl;
00330 #endif
00331         // Wrapping at end of line - one big if :)
00332         if ( wrapEnabled
00333              // Check if should break (i.e. we are after the max X for the end of the line)
00334              && ( /*wrapAtColumn() == -1 &&*/ x + ww > availableWidth &&
00335                   ( lastBreak != -1 || settings->allowBreakInWords() )
00336                   /*|| wrapAtColumn() != -1 && col >= wrapAtColumn()*/ )
00337 
00338              // Allow two breakable chars next to each other (e.g. '  ') but not more
00339              && ( !settings->isBreakable( string, i ) ||
00340                   ( i > 1 && lastBreak == i-1 && settings->isBreakable( string, i-2 ) ) ||
00341                   lastBreak == -2 ) // ... used to be a special case...
00342 
00343              // Ensure that there is at least one char per line, otherwise, on
00344              // a very narrow document and huge chars, we could loop forever.
00345              // checkVerticalBreak takes care of moving down the lines where no
00346              // char should be, anyway.
00347              // Hmm, it doesn't really do so. To be continued...
00349 
00350              // Or maybe we simply encountered a '\n'
00351              || lastChr->c == '\n' && parag->isNewLinesAllowed() && lastBreak > -1 )
00352         {
00353 #ifdef DEBUG_FORMATTER
00354             kdDebug(32500) << "BREAKING" << endl;
00355 #endif
00356             //if ( wrapAtColumn() != -1 )
00357             //    minw = QMAX( minw, x + ww );
00358 
00359             bool hyphenated = false;
00360             // Hyphenation: check if we can break somewhere between lastBreak and i
00361             if ( settings->hyphenator() )
00362             {
00363                 int wordStart = QMAX(0, lastBreak+1);
00364                 // Breaking after i isn't possible, i is too far already
00365                 int maxlen = i - wordStart; // we can't accept to break after maxlen
00366                 QString word = string->mid( wordStart, maxlen );
00367                 int wordEnd = i;
00368                 // but we need to compose the entire word, to hyphenate it
00369                 while ( wordEnd < len && !settings->isBreakable( string, wordEnd ) ) {
00370                     word += string->at(wordEnd).c;
00371                     wordEnd++;
00372                 }
00373                 if ( word.length() > 1 ) // don't call the hyphenator for empty or one-letter words
00374                 {
00375                     QString lang = string->at(wordStart).format()->language();
00376                     char * hyphens = settings->hyphenator()->hyphens( word, lang );
00377 #if defined(DEBUG_FORMATTER) || defined(DEBUG_HYPHENATION)
00378                     kdDebug(32500) << "Hyphenation: word=" << word << " lang=" << lang << " hyphens=" << hyphens << " maxlen=" << maxlen << endl;
00379                     kdDebug(32500) << "Parag indexes: wordStart=" << wordStart << " lastBreak=" << lastBreak << " i=" << i << endl;
00380 #endif
00381                     int hylen = strlen(hyphens);
00382                     Q_ASSERT( maxlen <= hylen );
00383                     // If this word was already hyphenated (at the previous line),
00384                     // don't break it there again. We can only break after firstChar.
00385                     int minPos = QMAX( 0, (firstChar - &string->at(0)) - wordStart );
00386 
00387                     // Check hyphenation positions from the end
00388                     for ( int hypos = maxlen-1 ; hypos >= minPos ; --hypos )
00389                         if ( ( hyphens[hypos] % 2 ) // odd number -> can break there...
00390                                && string->at(hypos + wordStart).format()->hyphenation() ) // ...if the user is ok with that
00391                         {
00392                             lineStart->hyphenated = true;
00393                             lastBreak = hypos + wordStart;
00394                             hyphenated = true;
00395 #if defined(DEBUG_FORMATTER) || defined(DEBUG_FORMATTER_WIDTH) || defined(DEBUG_HYPHENATION)
00396                             kdDebug(32500) << "Hyphenation: will break at " << lastBreak << " using tempworddata at position " << hypos << "/" << tempWordData.size() << endl;
00397 #endif
00398                             if ( hypos < (int)tempWordData.size() )
00399                             {
00400                                 const TemporaryWordData& twd = tempWordData[ hypos ];
00401                                 lineStart->baseLine = twd.baseLine;
00402                                 lineStart->h = twd.height;
00403                                 tmpWused = twd.lineWidth;
00404                             }
00405                             break;
00406                         }
00407                     delete[] hyphens;
00408                 }
00409             }
00410 
00411             // No breakable char found -> break at current char (i.e. before 'i')
00412             if ( lastBreak < 0 ) {
00413                 bool formatLine = true;
00414                 if ( c->lineStart ) // ouch, empty line
00415                 {
00416                     // Remember where the biggest availableWidth was, so that if we really
00417                     // find nowhere for this big character, we'll come back here.
00418                     if ( availableWidth > maxAvailableWidth.second )
00419                     {
00420                         maxAvailableWidth.first = y;
00421                         maxAvailableWidth.second = availableWidth;
00422                     }
00423                     // Check if we're at the bottom of the doc, we won't find better then
00424                     // (and the check further down would abort)
00425                     // Instead we go back to where there was most width for it.
00426                     if ( maxY > -1 && parag->rect().y() + y >= maxY )
00427                     {
00428                         kdDebug(32500) << parag->rect().y() + y << " over maxY=" << maxY
00429                                        << " -> final choice for the line: y=" << maxAvailableWidth.first << endl;
00430                         y = maxAvailableWidth.first;
00431                         if ( availableWidth )
00432                             Q_ASSERT( maxAvailableWidth.second != 0 );
00433                         lineStart->y = y;
00434                         // In this case we want to actually format the line,
00435                         // so we don't set emptyLine
00436                     }
00437                     else
00438                     {
00439                         // We don't know yet what to do with this line that needs to go down
00440                         // Ideally KWTextFrameSet would tell us how much we need to move
00441                         // ("validHeight" idea). For now we keep the old behavior:
00442                         y += tmph;
00443                         kdDebug(32500) << "KoTextFormatter: moving down empty line by h=" << tmph << ": y=" << y << endl;
00444                         formatLine = false; // line is not ready yet
00445                     }
00446                 }
00447                 if ( formatLine && i > 0 )
00448                 {
00449                     // (combine lineStart->baseLine/lineStart->h and tmpBaseLine/tmph)
00450                     int belowBaseLine = QMAX( lineStart->h - lineStart->baseLine, tmph - tmpBaseLine );
00451                     lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
00452                     lineStart->h = lineStart->baseLine + belowBaseLine;
00453                     lineStart->w = dw;
00454 
00455                     KoTextParagLineStart *lineStart2 = koFormatLine( zh, parag, string, lineStart, firstChar, c-1, align, availableWidth - x );
00456                     lineStart->lineSpacing = parag->lineSpacing( (int)parag->lineStartList().count()-1 );
00457                     lineStart->h += lineStart->lineSpacing;
00458                     y += lineStart->h;
00459                     lineStart = lineStart2;
00460 #ifdef DEBUG_FORMATTER
00461                     int linenr = parag->lineStartList().count()-1;
00462                     kdDebug(32500) << "line " << linenr << " done (breaking at current char). y now " << y << endl;
00463 #endif
00464                     tmph = c->height();
00465 
00466                     initialRMargin = currentRightMargin;
00467                     x = left;
00468                     if ( doc )
00469                         doc->flow()->adjustMargins( y + parag->rect().y(), tmph,
00470                                                     ww, // ## correct?
00471                                                     x, initialRMargin, dw, parag );
00472 
00473                     pixelx = zh->layoutUnitToPixelX( x );
00474                     initialHeight = tmph;
00475                     initialLMargin = x;
00476                     availableWidth = dw - initialRMargin;
00477                     if ( parag->isNewLinesAllowed() && c->c == '\t' ) {
00478                         int nx = parag->nextTab( i, x );
00479                         if ( nx < x )
00480                             ww = availableWidth - x;
00481                         else
00482                             ww = nx - x + 1;
00483                     }
00484                     if ( x != left || availableWidth != dw )
00485                         fullWidth = FALSE;
00486                     lineStart->y = y;
00487                     parag->insertLineStart( i, lineStart );
00488                     tempWordData.clear();
00489                     lineStart->baseLine = c->ascent();
00490                     lineStart->h = c->height();
00491                     c->lineStart = 1;
00492                     firstChar = c;
00493                     tmpBaseLine = lineStart->baseLine;
00494                     lastBreak = -1;
00495                     col = 0;
00496                     //tminw = marg; // not in QRT?
00497                     tmpWused = 0;
00498                 }
00499                 // recalc everything for 'i', it might still not be ok where it is...
00500                 // (e.g. if there's no room at all on this line)
00501                 // But we don't want to do this forever, so we check against maxY (if known)
00502                 if ( formatLine && maxY > -1 )
00503                 {
00504                     if ( parag->rect().y() + y < maxY )
00505                     {
00506                         --i; // so that the ++i in for() is a noop
00507                         continue;
00508                     }
00509                     else // we're after maxY, time to stop.
00510                     {
00511 #ifdef DEBUG_FORMATTER
00512                         kdDebug(32500) << "We're after maxY, time to stop." << endl;
00513 #endif
00514                         // No solution for now. Hopefully KWord will create more pages...
00515                         abort = true;
00516                     }
00517                 }
00518                 // maxY not known -> keep going ('i' remains where it is)
00519                 // (that's the initial QRT behaviour)
00520             } else {
00521                 // If breaking means we're after maxY, then we won't do it.
00522                 // Hopefully KWord will create more pages.
00523                 if ( maxY > -1 && parag->rect().y() + y + lineStart->h >= maxY ) {
00524 #ifdef DEBUG_FORMATTER
00525                     kdDebug(32500) << "We're after maxY, time to stop." << endl;
00526 #endif
00527                     abort = true;
00528                 }
00529                 else
00530                 {
00531                     // Break the line at the last breakable character
00532                     i = lastBreak;
00533                     c = &string->at( i ); // The last char in the last line
00534                     int spaceAfterLine = availableWidth - c->x;
00535                     // ?? AFAICS we should always deduce the char's width from the available space....
00536                     //if ( string->isRightToLeft() && lastChr->c == '\n' )
00537                     spaceAfterLine -= c->width;
00538 
00539                     //else
00540                     if ( c->c.unicode() == 0xad || hyphenated ) // soft hyphen or hyphenation
00541                     {
00542                         // Recalculate its width, the hyphen will appear finally (important for the parag rect)
00543                         int width = KoTextZoomHandler::ptToLayoutUnitPt( c->format()->refFontMetrics().width( QChar(0xad) ) );
00544                         if ( c->c.unicode() == 0xad )
00545                             c->width = width;
00546                         spaceAfterLine -= width;
00547                     }
00548                     KoTextParagLineStart *lineStart2 = koFormatLine( zh, parag, string, lineStart, firstChar, c, align, spaceAfterLine );
00549                     lineStart->lineSpacing = doc ? parag->lineSpacing( (int)parag->lineStartList().count()-1 ) : 0;
00550                     lineStart->w = dw;
00551                     lineStart->h += lineStart->lineSpacing;
00552                     y += lineStart->h;
00553                     lineStart = lineStart2;
00554 #ifdef DEBUG_FORMATTER
00555                     kdDebug(32500) << "Breaking at a breakable char (" << i << "). linenr=" << parag->lineStartList().count()-1 << " y=" << y << endl;
00556 #endif
00557 
00558                     c = &string->at( i + 1 ); // The first char in the new line
00559 #ifdef DEBUG_FORMATTER
00560                     kdDebug(32500) << "Next line will start at i+1=" << i+1 << ", char=" << QString(c->c) << endl;
00561 #endif
00562                     tmph = c->height();
00563 
00564                     initialRMargin = currentRightMargin;
00565                     x = left;
00566                     if ( doc )
00567                         doc->flow()->adjustMargins( y + parag->rect().y(), tmph,
00568                                                     c->width,
00569                                                     x, initialRMargin, dw, parag );
00570 
00571                     pixelx = zh->layoutUnitToPixelX( x );
00572                     initialHeight = tmph;
00573                     initialLMargin = x;
00574                     availableWidth = dw - initialRMargin;
00575                     if ( x != left || availableWidth != dw )
00576                         fullWidth = FALSE;
00577                     lineStart->y = y;
00578                     parag->insertLineStart( i + 1, lineStart );
00579                     tempWordData.clear();
00580                     lineStart->baseLine = c->ascent();
00581                     lineStart->h = c->height();
00582                     firstChar = c;
00583                     tmpBaseLine = lineStart->baseLine;
00584                     lastBreak = -1;
00585                     col = 0;
00586                     //tminw = marg;
00587                     tmpWused = 0;
00588                     c->lineStart = 1; // only do this if we will actually create a line for it
00589                     continue;
00590                 }
00591             }
00592         } else if ( lineStart && ( settings->isBreakable( string, i ) || parag->isNewLinesAllowed() && c->c == '\n' ) ) {
00593             // Breakable character
00594             if ( len <= 2 || i < len - 1 ) {
00595 #ifdef DEBUG_FORMATTER_VERT
00596                 kdDebug(32500) << " Breakable character (i=" << i << " len=" << len << "):"
00597                                << " combining " << tmpBaseLine << "/" << tmph
00598                                << " with " << c->ascent() << "/" << c->height() << endl;
00599 #endif
00600                 // (combine tmpBaseLine/tmph and this character)
00601                 int belowBaseLine = QMAX( tmph - tmpBaseLine, c->height() - c->ascent() );
00602                 tmpBaseLine = QMAX( tmpBaseLine, c->ascent() );
00603                 tmph = tmpBaseLine + belowBaseLine;
00604 #ifdef DEBUG_FORMATTER_VERT
00605                 kdDebug(32500) << " -> tmpBaseLine/tmph : " << tmpBaseLine << "/" << tmph << endl;
00606 #endif
00607             }
00608             tempWordData.clear();
00609             //minw = QMAX( minw, tminw );
00610             //tminw = marg + ww;
00611             wused = QMAX( wused, tmpWused );
00612 #ifdef DEBUG_FORMATTER_WIDTH
00613             kdDebug(32500) << " Breakable character (i=" << i << " len=" << len << "): wused=" << wused << endl;
00614 #endif
00615             tmpWused = 0;
00616             // (combine lineStart and tmpBaseLine/tmph)
00617 #ifdef DEBUG_FORMATTER_VERT
00618             kdDebug(32500) << "Breakable character: combining " << lineStart->baseLine << "/" << lineStart->h << " with " << tmpBaseLine << "/" << tmph << endl;
00619 #endif
00620             int belowBaseLine = QMAX( lineStart->h - lineStart->baseLine, tmph - tmpBaseLine );
00621             lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
00622             lineStart->h = lineStart->baseLine + belowBaseLine;
00623             lineStart->w = dw;
00624 #ifdef DEBUG_FORMATTER_VERT
00625             kdDebug(32500) << " -> line baseLine/height : " << lineStart->baseLine << "/" << lineStart->h << endl;
00626 #endif
00627             // if h > initialHeight,  call adjustMargins, and if the result is != initial[LR]Margin,
00628             // format this line again
00629             if ( doc && lineStart->h > initialHeight )
00630             {
00631                 bool firstLine = ( firstChar == &string->at( 0 ) );
00632                 int newLMargin = leftMargin( firstLine );
00633                 int newRMargin = rightMargin( firstLine );
00634                 int newPageWidth = dw;
00635                 initialHeight = lineStart->h;
00636                 doc->flow()->adjustMargins( y + parag->rect().y(), initialHeight,
00637                                             firstChar->width,
00638                                             newLMargin, newRMargin, newPageWidth, parag );
00639 
00640 #ifdef DEBUG_FORMATTER
00641                 kdDebug(32500) << "new height: " << initialHeight << " => left=" << left << " first-char=" << (firstChar==&string->at(0)) << " newLMargin=" << newLMargin << " newRMargin=" << newRMargin << endl;
00642 #endif
00643                 if ( newLMargin != initialLMargin || newRMargin != initialRMargin || newPageWidth != dw )
00644                 {
00645 #ifdef DEBUG_FORMATTER
00646                     kdDebug(32500) << "formatting again" << endl;
00647 #endif
00648                     i = (firstChar - &string->at(0));
00649                     x = newLMargin;
00650                     pixelx = zh->layoutUnitToPixelX( x );
00651                     availableWidth = dw - newRMargin;
00652                     initialLMargin = newLMargin;
00653                     initialRMargin = newRMargin;
00654                     dw = newPageWidth;
00655                     c = &string->at( i );
00656                     tmph = c->height();
00657                     tmpBaseLine = c->ascent();
00658                     lineStart->h = tmph;
00659                     lineStart->baseLine = tmpBaseLine;
00660                     lastBreak = -1;
00661                     col = 0;
00662                     //minw = x;
00663 #ifdef DEBUG_FORMATTER
00664                     kdDebug(32500) << "Restarting with i=" << i << " x=" << x << " y=" << y << " tmph=" << tmph << " initialHeight=" << initialHeight << " initialLMargin=" << initialLMargin << " initialRMargin=" << initialRMargin << " y=" << y << endl;
00665 #endif
00666                     // ww and pixelww already calculated and stored, no need to duplicate
00667                     // code like QRT does.
00668                     ww = c->width;
00669 #ifndef REF_IS_LU
00670                     pixelww = c->pixelwidth;
00671 #endif
00672                     //tminw = x + ww;
00673                     tmpWused = 0;
00674                 }
00675             }
00676 
00677             //kdDebug(32500) << " -> lineStart->baseLine/lineStart->h : " << lineStart->baseLine << "/" << lineStart->h << endl;
00678             if ( i < len - 2 || c->c != ' ' )
00679                 lastBreak = i;
00680 
00681         } else {
00682             // Non-breakable character
00683             //tminw += ww;
00684 #ifdef DEBUG_FORMATTER_VERT
00685             kdDebug(32500) << " Non-breakable character: combining " << tmpBaseLine << "/" << tmph << " with " << c->ascent() << "/" << c->height() << endl;
00686 #endif
00687             // (combine tmpBaseLine/tmph and this character)
00688             int belowBaseLine = QMAX( tmph - tmpBaseLine, c->height() - c->ascent() );
00689             tmpBaseLine = QMAX( tmpBaseLine, c->ascent() );
00690             tmph = tmpBaseLine + belowBaseLine;
00691 #ifdef DEBUG_FORMATTER_VERT
00692             kdDebug(32500) << " -> tmpBaseLine/tmph : " << tmpBaseLine << "/" << tmph << endl;
00693 #endif
00694 
00695             TemporaryWordData twd;
00696             twd.baseLine = tmpBaseLine;
00697             twd.height = tmph;
00698             twd.lineWidth = tmpWused;
00699             tempWordData.append( twd );
00700         }
00701 
00702         c->x = x;
00703         // pixelxadj is the adjustement to add to lu2pixel(x), to find pixelx
00704         // (pixelx would be too expensive to store directly since it would require an int)
00705         c->pixelxadj = pixelx - zh->layoutUnitToPixelX( x );
00706         //c->pixelwidth = pixelww; // done as pixelx - lastPixelx below
00707 #ifdef DEBUG_FORMATTER
00708         kdDebug(32500) << "LU: x=" << x << " [equiv. to pix=" << zh->layoutUnitToPixelX( x ) << "] ; PIX: x=" << pixelx << "  --> adj=" << c->pixelxadj << endl;
00709 #endif
00710 
00711         x += ww;
00712 
00713         if ( i > 0 )
00714             lastChr->pixelwidth = pixelx - lastPixelx;
00715         if ( i < len - 1 )
00716             tmpWused = QMAX( tmpWused, x );
00717         else // trailing space
00718             c->pixelwidth = zh->layoutUnitToPixelX( ww ); // was: pixelww;
00719 
00720         lastPixelx = pixelx;
00721 #ifdef REF_IS_LU
00722         pixelx = zh->layoutUnitToPixelX( x ); // no accumulating rounding errors anymore
00723 #else
00724         pixelx += pixelww;
00725 #endif
00726 #ifdef DEBUG_FORMATTER
00727         kdDebug(32500) << "LU: added " << ww << " -> now x=" << x << " ; PIX: added " << pixelww << " -> now pixelx=" << pixelx << endl;
00728 #endif
00729     }
00730 
00731     // ### hack. The last char in the paragraph is always invisible, and somehow sometimes has a wrong format. It changes between
00732     // layouting and printing. This corrects some layouting errors in BiDi mode due to this.
00733     if ( len > 1 /*&& !c->isAnchor()*/ ) {
00734         c->format()->removeRef();
00735         c->setFormat( string->at( len - 2 ).format() );
00736         c->format()->addRef();
00737     }
00738 
00739     // Finish formatting the last line
00740     if ( lineStart ) {
00741 #ifdef DEBUG_FORMATTER
00742         kdDebug(32500) << "Last Line.... linenr=" << (int)parag->lineStartList().count()-1 << endl;
00743 #endif
00744 #ifdef DEBUG_FORMATTER_VERT
00745         kdDebug(32500) << "Last Line... Combining " << lineStart->baseLine << "/" << lineStart->h << " with " << tmpBaseLine << "/" << tmph << endl;
00746 #endif
00747         // (combine lineStart and tmpBaseLine/tmph)
00748         int belowBaseLine = QMAX( lineStart->h - lineStart->baseLine, tmph - tmpBaseLine );
00749         lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine );
00750         lineStart->h = lineStart->baseLine + belowBaseLine;
00751         lineStart->w = dw;
00752 #ifdef DEBUG_FORMATTER_WIDTH
00753         kdDebug(32500) << "Last line: w = dw = " << dw << endl;
00754 #endif
00755 #ifdef DEBUG_FORMATTER_VERT
00756         kdDebug(32500) << " -> lineStart->baseLine/lineStart->h : " << lineStart->baseLine << "/" << lineStart->h << endl;
00757 #endif
00758         // last line in a paragraph is not justified
00759         if ( align == Qt::AlignJustify )
00760             align = Qt::AlignAuto;
00761         int space = availableWidth - x + c->width; // don't count the trailing space (it breaks e.g. centering)
00762         KoTextParagLineStart *lineStart2 = koFormatLine( zh, parag, string, lineStart, firstChar, c, align, space );
00763         lineStart->lineSpacing = doc ? parag->lineSpacing( (int)parag->lineStartList().count()-1 ) : 0;
00764         lineStart->h += lineStart->lineSpacing;
00765         delete lineStart2;
00766     }
00767 
00768     //minw = QMAX( minw, tminw );
00769     wused = QMAX( wused, tmpWused );
00770 #ifdef DEBUG_FORMATTER_WIDTH
00771     kdDebug(32500) << "Done, wused=" << wused << endl;
00772 #endif
00773 
00774     int m = parag->bottomMargin();
00775     // ##### Does OOo add margins or does it max them?
00776     //if ( parag->next() && doc && !doc->addMargins() )
00777     //  m = QMAX( m, parag->next()->topMargin() );
00778     parag->setFullWidth( fullWidth );
00779     //if ( parag->next() && parag->next()->isLineBreak() )
00780     //    m = 0;
00781 #ifdef DEBUG_FORMATTER_VERT
00782     kdDebug(32500) << "Adding height of last line(" << lineStart->h << ") and bottomMargin(" << m << ") to y(" << y << ") => " << y+lineStart->h+m << endl;
00783 #endif
00784     y += lineStart->h + m;
00785 
00786     tmpWused += currentRightMargin; // ### this can break with a variable right-margin
00787     //if ( !wrapEnabled || wrapAtColumn() != -1  )
00788     //    minw = QMAX(minw, wused);
00789     //thisminw = minw;
00790 
00791 #ifdef DEBUG_FORMATTER
00792     // Sanity checking
00793     int numberOfLines = 0;
00794     QString charPosList;
00795     for ( int i = 0 ; i < len; ++i ) {
00796         KoTextStringChar *chr = &string->at( i );
00797         if ( i == 0 )
00798             assert( chr->lineStart );
00799         if ( chr->lineStart ) {
00800             ++numberOfLines;
00801             charPosList += QString::number(i) + " ";
00802         }
00803     }
00804     kdDebug(32500) << parag->lineStartList().count() << " lines. " << numberOfLines << " chars with lineStart set: " << charPosList << endl;
00805     assert( numberOfLines == (int)parag->lineStartList().count() );
00806 #endif
00807     return !abort;
00808 }
00809 
00810 // Helper for koFormatLine and koBidiReorderLine
00811 void KoTextFormatterCore::moveChar( KoTextStringChar& chr, KoZoomHandler *zh,
00812                                     int deltaX, int deltaPixelX )
00813 {
00814 #ifndef REF_IS_LU
00815     int pixelx = chr.pixelxadj + zh->layoutUnitToPixelX( chr.x );
00816 #endif
00817     chr.x += deltaX;
00818 #ifndef REF_IS_LU
00819     chr.pixelxadj = pixelx + deltaPixelX - zh->layoutUnitToPixelX( chr.x );
00820 #endif
00821 }
00822 
00823 KoTextParagLineStart *KoTextFormatterCore::koFormatLine(
00824     KoZoomHandler *zh,
00825     KoTextParag *parag, KoTextString *string, KoTextParagLineStart *line,
00826     KoTextStringChar *startChar, KoTextStringChar *lastChar, int align, int space )
00827 {
00828     if( string->isBidi() )
00829         return koBidiReorderLine( zh, parag, string, line, startChar, lastChar, align, space );
00830     space = QMAX( space, 0 ); // #### with nested tables this gets negative because of a bug I didn't find yet, so workaround for now. This also means non-left aligned nested tables do not work at the moment
00831     int start = (startChar - &string->at(0));
00832     int last = (lastChar - &string->at(0) );
00833 #ifdef INDIC
00834 
00835     KoTextStringChar *ch = lastChar;
00836     while ( ch > startChar && ch->whiteSpace ) {
00837         space += ch->format()->width( ' ' );
00838         --ch;
00839     }
00840 
00841     if (space < 0)
00842         space = 0;
00843 
00844 #endif
00845     // do alignment Auto == Left in this case
00846     if ( align & Qt::AlignHCenter || align & Qt::AlignRight ) {
00847         if ( align & Qt::AlignHCenter )
00848             space /= 2;
00849         int toAddPix = zh->layoutUnitToPixelX( space );
00850         for ( int j = last; j >= start; --j ) {
00851             KoTextStringChar &chr = string->at( j );
00853             if ( chr.c == '\t' ) {
00854                 break;
00855             }
00856             moveChar( chr, zh, space, toAddPix );
00857         }
00858     } else if ( align & Qt::AlignJustify ) {
00859         int numSpaces = 0;
00860         // End at "last-1", the last space ends up with a width of 0
00861         for ( int j = last-1; j >= start; --j ) {
00863             if ( string->at( j ).c == '\t' ) {
00864                 start = j+1;
00865                 break;
00866             }
00867             if( settings->isStretchable( string, j ) ) {
00868                 numSpaces++;
00869             }
00870         }
00871         int toAdd = 0;
00872         int toAddPix = 0;
00873         for ( int k = start + 1; k <= last; ++k ) {
00874             KoTextStringChar &chr = string->at( k );
00875             if ( toAdd != 0 )
00876                 moveChar( chr, zh, toAdd, toAddPix );
00877             if( settings->isStretchable( string, k ) && numSpaces ) {
00878                 int s = space / numSpaces;
00879                 toAdd += s;
00880                 toAddPix = zh->layoutUnitToPixelX( toAdd );
00881                 space -= s;
00882                 numSpaces--;
00883                 chr.width += s;
00884 #ifndef REF_IS_LU
00885                 chr.pixelwidth += zh->layoutUnitToPixelX( s ); // ### rounding problem, recalculate
00886 #endif
00887             }
00888         }
00889     }
00890     int current=0;
00891     int nc=0; // Not double, as we check it against 0 and to avoid gcc warnings
00892     KoTextFormat refFormat( *string->at(0).format() ); // we need a ref format, doesn't matter where it comes from
00893     for(int i=start;i<=last;++i)
00894     {
00895         KoTextFormat* format=string->at(i).format();
00896         // End of underline
00897         if ( (((!format->underline())&&
00898                (!format->doubleUnderline())&&
00899                (!format->waveUnderline())&&
00900                (format->underlineType()!=KoTextFormat::U_SIMPLE_BOLD))
00901               || i == last)
00902              && nc )
00903         {
00904             double avg=static_cast<double>(current)/nc;
00905             avg/=18.0;
00906             // Apply underline width "avg" from i-nc to i
00907             refFormat.setUnderLineWidth( avg );
00908             parag->setFormat( i-nc, i, &refFormat, true, KoTextFormat::UnderLineWidth );
00909             nc=0;
00910             current=0;
00911         }
00912         // Inside underline
00913         else if(format->underline()||
00914                 format->waveUnderline()||
00915                 format->doubleUnderline()||
00916                 (format->underlineType() == KoTextFormat::U_SIMPLE_BOLD))
00917         {
00918             ++nc;
00919             current += format->pointSize(); //pointSize() is independent of {Sub,Super}Script in contrast to height()
00920         }
00921     }
00922 #if 0
00923     if ( last >= 0 && last < string->length() ) {
00924         KoTextStringChar &chr = string->at( last );
00925         line->w = chr.x + chr.width; //string->width( last );
00926         // Add width of hyphen (so that it appears)
00927         if ( line->hyphenated )
00928             line->w += KoTextZoomHandler::ptToLayoutUnitPt( chr.format()->refFontMetrics().width( QChar(0xad) ) );
00929     } else
00930         line->w = 0;
00931 #endif
00932 
00933     return new KoTextParagLineStart();
00934 }
00935 
00936 // collects one line of the paragraph and transforms it to visual order
00937 KoTextParagLineStart *KoTextFormatterCore::koBidiReorderLine(
00938     KoZoomHandler *zh,
00939     KoTextParag * /*parag*/, KoTextString *text, KoTextParagLineStart *line,
00940     KoTextStringChar *startChar, KoTextStringChar *lastChar, int align, int space )
00941 {
00942     // This comes from Qt (3.3.x) but seems wrong: the last space is where we draw
00943     // the "end of paragraph" sign, so it needs to be correctly positioned too.
00944 #if 0
00945     // ignore white space at the end of the line.
00946     int endSpaces = 0;
00947     while ( lastChar > startChar && lastChar->whiteSpace ) {
00948         space += lastChar->format()->width( ' ' );
00949         --lastChar;
00950         ++endSpaces;
00951     }
00952 #endif
00953 
00954     int start = (startChar - &text->at(0));
00955     int last = (lastChar - &text->at(0) );
00956 #ifdef DEBUG_FORMATTER
00957     kdDebug(32500) << "*KoTextFormatter::koBidiReorderLine from " << start << " to " << last << " space=" << space << " startChar->x=" << startChar->x << endl;
00958 #endif
00959     KoBidiControl *control = new KoBidiControl( line->context(), line->status );
00960     QString str;
00961     str.setUnicode( 0, last - start + 1 );
00962     // fill string with logically ordered chars.
00963     KoTextStringChar *ch = startChar;
00964     QChar *qch = (QChar *)str.unicode();
00965     while ( ch <= lastChar ) {
00966         *qch = ch->c;
00967         qch++;
00968         ch++;
00969     }
00970     int x = startChar->x;
00971 
00972     QPtrList<KoTextRun> *runs;
00973     runs = KoComplexText::bidiReorderLine(control, str, 0, last - start + 1,
00974                                          (text->isRightToLeft() ? QChar::DirR : QChar::DirL) );
00975 
00976     // now construct the reordered string out of the runs...
00977 
00978     int numSpaces = 0;
00979     // set the correct alignment. This is a bit messy....
00980     if( align == Qt::AlignAuto ) {
00981         // align according to directionality of the paragraph...
00982         if ( text->isRightToLeft() )
00983             align = Qt::AlignRight;
00984     }
00985 
00986     if ( align & Qt::AlignHCenter ) {
00987         x += space/2;
00988     } else if ( align & Qt::AlignRight ) {
00989         x += space;
00990     } else if ( align & Qt::AlignJustify ) {
00991         for ( int j = last - 1; j >= start; --j ) {
00993             if ( text->at( j ).c == '\t' ) {
00994                 start = j+1;
00995                 break;
00996             }
00997             if( settings->isStretchable( text, j ) ) {
00998                 numSpaces++;
00999             }
01000         }
01001     }
01002 // TODO #ifndef REF_IS_LU or remove
01003     int pixelx = zh->layoutUnitToPixelX( x );
01004     int toAdd = 0;
01005     int toAddPix = 0;
01006     bool first = TRUE;
01007     KoTextRun *r = runs->first();
01008     int xmax = -0xffffff;
01009     while ( r ) {
01010 #ifdef DEBUG_FORMATTER
01011         kdDebug(32500) << "koBidiReorderLine level: " << r->level << endl;
01012 #endif
01013         if(r->level %2) {
01014             // odd level, need to reverse the string
01015             int pos = r->stop + start;
01016             while(pos >= r->start + start) {
01017                 KoTextStringChar &chr = text->at(pos);
01018                 if( numSpaces && !first && settings->isBreakable( text, pos ) ) {
01019                     int s = space / numSpaces;
01020                     toAdd += s;
01021                     toAddPix = zh->layoutUnitToPixelX( toAdd );
01022                     space -= s;
01023                     numSpaces--;
01024                     chr.width += s;
01025                     chr.pixelwidth += zh->layoutUnitToPixelX( s ); // ### rounding problem, recalculate
01026                 } else if ( first ) {
01027                     first = FALSE;
01028                     if ( chr.c == ' ' ) // trailing space
01029                     {
01030                         //x -= chr.format()->width( ' ' );
01031                         x -= chr.width;
01032                         pixelx -= chr.pixelwidth;
01033                     }
01034                 }
01035                 chr.x = x + toAdd;
01036                 chr.pixelxadj = pixelx + toAddPix - zh->layoutUnitToPixelX( chr.x );
01037 #ifdef DEBUG_FORMATTER
01038                 kdDebug(32500) << "koBidiReorderLine: pos=" << pos << " x(LU)=" << x << " toAdd(LU)=" << toAdd << " -> chr.x=" << chr.x << " pixelx=" << pixelx << "+" << zh->layoutUnitToPixelX( toAdd ) << ", pixelxadj=" << pixelx+zh->layoutUnitToPixelX( toAdd )-zh->layoutUnitToPixelX( chr.x ) << endl;
01039 #endif
01040                 chr.rightToLeft = TRUE;
01041                 chr.startOfRun = FALSE;
01042                 int ww = chr.width;
01043                 if ( xmax < x + toAdd + ww ) xmax = x + toAdd + ww;
01044                 x += ww;
01045                 pixelx += chr.pixelwidth;
01046 #ifdef DEBUG_FORMATTER
01047                 kdDebug(32500) << "              ww=" << ww << " adding to x, now " << x << ". pixelwidth=" << chr.pixelwidth << " adding to pixelx, now " << pixelx << " xmax=" << xmax << endl;
01048 #endif
01049                 pos--;
01050             }
01051         } else {
01052             int pos = r->start + start;
01053             while(pos <= r->stop + start) {
01054                 KoTextStringChar& chr = text->at(pos);
01055                 if( numSpaces && !first && settings->isBreakable( text, pos ) ) {
01056                     int s = space / numSpaces;
01057                     toAdd += s;
01058                     toAddPix = zh->layoutUnitToPixelX( toAdd );
01059                     space -= s;
01060                     numSpaces--;
01061                 } else if ( first ) {
01062                     first = FALSE;
01063                     if ( chr.c == ' ' ) // trailing space
01064                     {
01065                         //x -= chr.format()->width( ' ' );
01066                         x -= chr.width;
01067                         pixelx -= chr.pixelwidth;
01068                     }
01069                 }
01070                 chr.x = x + toAdd;
01071                 chr.pixelxadj = pixelx + toAddPix - zh->layoutUnitToPixelX( chr.x );
01072                 chr.rightToLeft = FALSE;
01073                 chr.startOfRun = FALSE;
01074                 int ww = chr.width;
01075                 //kdDebug(32500) << "setting char " << pos << " at pos " << chr.x << endl;
01076                 if ( xmax < x + toAdd + ww ) xmax = x + toAdd + ww;
01077                 x += ww;
01078                 pixelx += chr.pixelwidth;
01079                 pos++;
01080             }
01081         }
01082         text->at( r->start + start ).startOfRun = TRUE;
01083         r = runs->next();
01084     }
01085 
01086     //line->w = xmax /*+ 10*/; // Why +10 ?
01087     KoTextParagLineStart *ls = new KoTextParagLineStart( control->context, control->status );
01088     delete control;
01089     delete runs;
01090     return ls;
01091 }
01092 
01093 void KoTextFormatter::postFormat( KoTextParag* parag )
01094 {
01095     parag->fixParagWidth( viewFormattingChars() );
01096 }
KDE Logo
This file is part of the documentation for lib Library Version 1.3.5.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Mar 11 11:47:44 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003