20#include "KoTextFormatter.h"
21#include "KoTextParag.h"
22#include "KoTextFormat.h"
23#include "KoTextDocument.h"
24#include "KoTextZoomHandler.h"
25#include "kohyphen/kohyphen.h"
26#include "KoParagCounter.h"
45KoTextFormatter::KoTextFormatter()
49 }
catch ( KoHyphenatorException& e )
55KoTextFormatter::~KoTextFormatter()
61struct TemporaryWordData
68bool KoTextFormatter::format( KoTextDocument *doc, KoTextParag *parag,
69 int start,
const TQMap<int, KoTextParagLineStart*> &,
70 int& y,
int& widthUsed )
72 KoTextFormatterCore formatter(
this, doc, parag, start );
73 bool worked = formatter.format();
74 y = formatter.resultY();
75 widthUsed = formatter.widthUsed();
80 KoTextDocument *_doc, KoTextParag *_parag,
82 : settings(_settings), doc(_doc), parag(_parag), start(_start)
86TQPair<int, int> KoTextFormatterCore::determineCharWidth()
89 KoTextZoomHandler *zh = doc->formattingZoomHandler();
90 if ( c->c !=
'\t' || c->isCustom() ) {
91 KoTextFormat *charFormat = c->format();
92 if ( c->isCustom() ) {
93 ww = c->customItem()->width;
103 pixelww = charFormat->
charWidth( zh,
true, c, parag, i );
107 int nx = parag->nextTab( i, x, availableWidth );
109 ww = availableWidth - x;
112#ifdef DEBUG_FORMATTER
113 kdDebug(32500) <<
"nextTab for x=" << x <<
" returned nx=" << nx <<
" (=> ww=" << ww <<
")" << endl;
121 return qMakePair(ww, pixelww);
125int KoTextFormatterCore::leftMargin(
bool firstLine,
bool includeFirstLineMargin )
const
127 int left = parag->leftMargin() + doc->leftMargin() ;
128 if ( firstLine && !parag->string()->isRightToLeft() )
130 if ( includeFirstLineMargin )
131 left += parag->firstLineMargin();
133 if( parag->counter() &&
134 ( parag->counter()->alignment() == TQt::AlignLeft ||
135 parag->counter()->alignment() == TQt::AlignAuto ) )
136 left += parag->counterWidth();
141int KoTextFormatterCore::rightMargin(
bool firstLine )
const
143 int right = parag->rightMargin();
144 if ( firstLine && parag->string()->isRightToLeft() )
145 right += parag->firstLineMargin();
149bool KoTextFormatterCore::format()
152 KoTextString *
string = parag->string();
154 c = &
string->at( start );
158 KoTextStringChar *firstChar = 0;
159 int left = doc ? leftMargin(
true,
false ) : 0;
160 int initialLMargin = leftMargin(
true );
162 y = parag->breakableTopMargin();
166 if ( !parag->prev() )
170 int shift = doc->flow()->adjustFlow( parag->rect().y(),
182 y += parag->topMargin() - parag->breakableTopMargin();
183 int len = parag->length();
185 int initialHeight = c->height();
187 int currentRightMargin = rightMargin(
true );
188 int initialRMargin = currentRightMargin;
191 parag->tabCache().clear();
198 TQPair<int, int> widths = determineCharWidth();
199 int ww = widths.first;
201 int pixelww = widths.second;
208 doc->flow()->adjustMargins( y + parag->rect().y(), initialHeight,
209 ww, initialLMargin, initialRMargin, dw,
215 int maxY = doc ? doc->flow()->availableHeight() : -1;
217 availableWidth = dw - initialRMargin;
218#if defined(DEBUG_FORMATTER) || defined(DEBUG_FORMATTER_WIDTH)
219 kdDebug(32500) <<
"KoTextFormatter::format formatting parag " << parag->paragId()
220 <<
" text:" << parag->string()->toString() <<
"\n"
221 <<
" left=" << left <<
" initialHeight=" << initialHeight <<
" initialLMargin=" << initialLMargin <<
" initialRMargin=" << initialRMargin <<
" availableWidth=" << availableWidth <<
" maxY=" << maxY << endl;
223 if ( availableWidth == 0 )
224 kdDebug(32500) <<
"KoTextFormatter::format " << parag->paragId() <<
" warning, availableWidth=0" << endl;
226 kdDebug(32500) <<
"KoTextFormatter::format " << parag->paragId() <<
" warning, maxY=0" << endl;
228 bool fullWidth =
true;
238 TQValueList<TemporaryWordData> tempWordData;
240#ifdef DEBUG_FORMATTER
241 kdDebug(32500) <<
"Initial KoTextParagLineStart at y=" << y << endl;
243 KoTextParagLineStart *lineStart =
new KoTextParagLineStart( y, 0, 0 );
244 parag->insertLineStart( 0, lineStart );
248 int tmpBaseLine = 0, tmph = 0;
251 bool lastWasNonInlineCustom =
false;
254 int align = parag->alignment();
255 if ( align == TQt::AlignAuto && doc && doc->alignment() != TQt::AlignAuto )
256 align = doc->alignment();
260 maxAvailableWidth = qMakePair( 0, 0 );
262 KoTextZoomHandler *zh = doc->formattingZoomHandler();
266 KoTextStringChar* lastChr = 0;
267 for ( ; i < len; ++i, ++col ) {
270 c = &
string->at( i );
271 if ( i > 0 && (x > initialLMargin || ww == 0) || lastWasNonInlineCustom ) {
277 tmpBaseLine = c->ascent();
278#ifdef DEBUG_FORMATTER_VERT
279 kdDebug(32500) <<
"New line, initializing tmpBaseLine=" << tmpBaseLine <<
" tmph=" << tmph << endl;
283 if ( c->isCustom() && c->customItem()->placement() != KoTextCustomItem::PlaceInline )
284 lastWasNonInlineCustom =
true;
286 lastWasNonInlineCustom =
false;
288 TQPair<int, int> widths = determineCharWidth();
290 pixelww = widths.second;
302 if ( c->isCustom() && c->customItem()->ownLine() ) {
303#ifdef DEBUG_FORMATTER
304 kdDebug(32500) <<
"i=" << i <<
"/" << len <<
" custom item with ownline" << endl;
306 int rightMargin = currentRightMargin;
309 doc->flow()->adjustMargins( y + parag->rect().y(), parag->rect().height(), 15,
310 x, rightMargin, dw, parag );
311 int w = dw - rightMargin;
312 c->customItem()->resize( w - x );
314 lineStart =
new KoTextParagLineStart( y, c->ascent(), c->height() );
316 lineStart->lineSpacing = doc ? parag->calculateLineSpacing( (
int)parag->lineStartList().count()-1, i, i ) : 0;
317 lineStart->h += lineStart->lineSpacing;
319 parag->insertLineStart( i, lineStart );
320 tempWordData.clear();
328#ifdef DEBUG_FORMATTER
329 kdDebug(32500) <<
"c='" << TQString(c->c) <<
"' i=" << i <<
"/" << len <<
" x=" << x <<
" ww=" << ww <<
" availableWidth=" << availableWidth <<
" (test is x+ww>aW) lastBreak=" << lastBreak <<
" isBreakable=" << settings->isBreakable(
string, i) << endl;
334 ( ( x + ww > availableWidth &&
335 ( lastBreak != -1 || settings->allowBreakInWords() ) )
338 && ( !settings->isBreakable(
string, i ) ||
339 ( i > 1 && lastBreak == i-1 && settings->isBreakable(
string, i-2 ) ) ||
354 || ( lastChr && lastChr->c ==
'\n' && parag->isNewLinesAllowed() && lastBreak > -1 ) )
356#ifdef DEBUG_FORMATTER
357 kdDebug(32500) <<
"BREAKING" << endl;
362 bool hyphenated =
false;
364 if ( settings->hyphenator() && !c->isCustom() )
366 int wordStart = TQMAX(0, lastBreak+1);
368 int maxlen = i - wordStart;
369 TQString word =
string->mid( wordStart, maxlen );
372 while ( wordEnd < len && !settings->isBreakable(
string, wordEnd ) ) {
373 word +=
string->at(wordEnd).c;
376 if ( word.length() > 1 )
378 TQString lang =
string->at(wordStart).format()->language();
379 char * hyphens = settings->hyphenator()->hyphens( word, lang );
380#if defined(DEBUG_HYPHENATION)
381 kdDebug(32500) <<
"Hyphenation: word=" << word <<
" lang=" << lang <<
" hyphens=" << hyphens <<
" maxlen=" << maxlen << endl;
382 kdDebug(32500) <<
"Parag indexes: wordStart=" << wordStart <<
" lastBreak=" << lastBreak <<
" i=" << i << endl;
384 int hylen = strlen(hyphens);
385 Q_ASSERT( maxlen <= hylen );
388 int minPos = TQMAX( 0, (firstChar - &string->at(0)) - wordStart );
391 for (
int hypos = maxlen-1 ; hypos >= minPos ; --hypos )
392 if ( ( hyphens[hypos] % 2 )
393 && string->at(hypos + wordStart).format()->hyphenation() )
395 lineStart->hyphenated =
true;
396 lastBreak = hypos + wordStart;
398#if defined(DEBUG_FORMATTER) || defined(DEBUG_FORMATTER_WIDTH) || defined(DEBUG_HYPHENATION)
399 kdDebug(32500) <<
"Hyphenation: will break at " << lastBreak <<
" using tempworddata at position " << hypos <<
"/" << tempWordData.size() << endl;
401 if ( hypos < (
int)tempWordData.size() )
403 const TemporaryWordData& twd = tempWordData[ hypos ];
404 lineStart->baseLine = twd.baseLine;
405 lineStart->h = twd.height;
406 tmpWused = twd.lineWidth;
415 if ( lastBreak < 0 ) {
423 const bool emptyLine = c->lineStart;
424 if ( !emptyLine && i > 0 )
427 int belowBaseLine = TQMAX( lineStart->h - lineStart->baseLine, tmph - tmpBaseLine );
428 lineStart->baseLine = TQMAX( lineStart->baseLine, tmpBaseLine );
429 lineStart->h = lineStart->baseLine + belowBaseLine;
432 KoTextParagLineStart *lineStart2 = koFormatLine( zh, parag,
string, lineStart, firstChar, c-1, align, availableWidth - x );
434 lineStart = lineStart2;
435#ifdef DEBUG_FORMATTER
436 int linenr = parag->lineStartList().count()-1;
437 kdDebug(32500) <<
"line " << linenr <<
" done (breaking at current char). y now " << y << endl;
441 initialRMargin = currentRightMargin;
444 doc->flow()->adjustMargins( y + parag->rect().y(), tmph,
446 x, initialRMargin, dw, parag );
449 initialHeight = tmph;
451 availableWidth = dw - initialRMargin;
452 if ( parag->isNewLinesAllowed() && c->c ==
'\t' ) {
453 int nx = parag->nextTab( i, x, availableWidth );
455 ww = availableWidth - x;
459 if ( x != left || availableWidth != dw )
462 parag->insertLineStart( i, lineStart );
463 tempWordData.clear();
464 lineStart->baseLine = c->ascent();
465 lineStart->h = c->height();
468 tmpBaseLine = lineStart->baseLine;
478 if ( !emptyLine && maxY > -1 )
480 if ( parag->rect().y() + y < maxY )
482#ifdef DEBUG_FORMATTER
483 kdDebug(32500) <<
"Re-checking formatting for character " << i << endl;
490#ifdef DEBUG_FORMATTER
491 kdDebug(32500) <<
"We're after maxY, time to stop." << endl;
502 if ( maxY > -1 && parag->rect().y() + y + lineStart->h >= maxY ) {
503#ifdef DEBUG_FORMATTER
504 kdDebug(32500) <<
"We're after maxY, time to stop." << endl;
512 c = &
string->at( i );
513 int spaceAfterLine = availableWidth - c->x;
516 spaceAfterLine -= c->width;
519 if ( c->c.unicode() == 0xad || hyphenated )
523 if ( c->c.unicode() == 0xad )
525 spaceAfterLine -= width;
527 KoTextParagLineStart *lineStart2 = koFormatLine( zh, parag,
string, lineStart, firstChar, c, align, spaceAfterLine );
530 lineStart = lineStart2;
531#ifdef DEBUG_FORMATTER
532 kdDebug(32500) <<
"Breaking at a breakable char (" << i <<
"). linenr=" << parag->lineStartList().count()-1 <<
" y=" << y << endl;
535 c = &
string->at( i + 1 );
536#ifdef DEBUG_FORMATTER
537 kdDebug(32500) <<
"Next line will start at i+1=" << i+1 <<
", char=" << TQString(c->c) << endl;
541 initialRMargin = currentRightMargin;
544 doc->flow()->adjustMargins( y + parag->rect().y(), tmph,
546 x, initialRMargin, dw, parag );
549 initialHeight = tmph;
551 availableWidth = dw - initialRMargin;
552 if ( x != left || availableWidth != dw )
555 parag->insertLineStart( i + 1, lineStart );
556 tempWordData.clear();
557 lineStart->baseLine = c->ascent();
558 lineStart->h = c->height();
560 tmpBaseLine = lineStart->baseLine;
569 }
else if ( lineStart && ( settings->isBreakable(
string, i ) || parag->isNewLinesAllowed() && c->c ==
'\n' ) ) {
571 if ( len <= 2 || i < len - 1 ) {
572#ifdef DEBUG_FORMATTER_VERT
573 kdDebug(32500) <<
" Breakable character (i=" << i <<
" len=" << len <<
"):"
574 <<
" combining " << tmpBaseLine <<
"/" << tmph
575 <<
" with " << c->ascent() <<
"/" << c->height() << endl;
578 int belowBaseLine = TQMAX( tmph - tmpBaseLine, c->height() - c->ascent() );
579 tmpBaseLine = TQMAX( tmpBaseLine, c->ascent() );
580 tmph = tmpBaseLine + belowBaseLine;
581#ifdef DEBUG_FORMATTER_VERT
582 kdDebug(32500) <<
" -> tmpBaseLine/tmph : " << tmpBaseLine <<
"/" << tmph << endl;
585 tempWordData.clear();
588 wused = TQMAX( wused, tmpWused );
589#ifdef DEBUG_FORMATTER_WIDTH
590 kdDebug(32500) <<
" Breakable character (i=" << i <<
" len=" << len <<
"): wused=" << wused << endl;
594#ifdef DEBUG_FORMATTER_VERT
595 kdDebug(32500) <<
"Breakable character: combining " << lineStart->baseLine <<
"/" << lineStart->h <<
" with " << tmpBaseLine <<
"/" << tmph << endl;
597 int belowBaseLine = TQMAX( lineStart->h - lineStart->baseLine, tmph - tmpBaseLine );
598 lineStart->baseLine = TQMAX( lineStart->baseLine, tmpBaseLine );
599 lineStart->h = lineStart->baseLine + belowBaseLine;
601#ifdef DEBUG_FORMATTER_VERT
602 kdDebug(32500) <<
" -> line baseLine/height : " << lineStart->baseLine <<
"/" << lineStart->h << endl;
606 if ( doc && lineStart->h > initialHeight )
608 bool firstLine = ( firstChar == &
string->at( 0 ) );
609 int newLMargin = leftMargin( firstLine );
610 int newRMargin = rightMargin( firstLine );
611 int newPageWidth = dw;
612 initialHeight = lineStart->h;
613 doc->flow()->adjustMargins( y + parag->rect().y(), initialHeight,
615 newLMargin, newRMargin, newPageWidth, parag );
617#ifdef DEBUG_FORMATTER
618 kdDebug(32500) <<
"new height: " << initialHeight <<
" => left=" << left <<
" first-char=" << (firstChar==&
string->at(0)) <<
" newLMargin=" << newLMargin <<
" newRMargin=" << newRMargin << endl;
620 if ( newLMargin != initialLMargin || newRMargin != initialRMargin || newPageWidth != dw )
622#ifdef DEBUG_FORMATTER
623 kdDebug(32500) <<
"formatting again" << endl;
625 i = (firstChar - &
string->at(0));
628 availableWidth = dw - newRMargin;
629 initialLMargin = newLMargin;
630 initialRMargin = newRMargin;
632 c = &
string->at( i );
634 tmpBaseLine = c->ascent();
636 lineStart->baseLine = tmpBaseLine;
640#ifdef DEBUG_FORMATTER
641 kdDebug(32500) <<
"Restarting with i=" << i <<
" x=" << x <<
" y=" << y <<
" tmph=" << tmph <<
" initialHeight=" << initialHeight <<
" initialLMargin=" << initialLMargin <<
" initialRMargin=" << initialRMargin <<
" y=" << y << endl;
647 pixelww = c->pixelwidth;
655 if ( i < len - 2 || c->c !=
' ' )
658 }
else if ( i < len - 1 ) {
661#ifdef DEBUG_FORMATTER_VERT
662 kdDebug(32500) <<
" Non-breakable character: combining " << tmpBaseLine <<
"/" << tmph <<
" with " << c->ascent() <<
"/" << c->height() << endl;
665 int belowBaseLine = TQMAX( tmph - tmpBaseLine, c->height() - c->ascent() );
666 tmpBaseLine = TQMAX( tmpBaseLine, c->ascent() );
667 tmph = tmpBaseLine + belowBaseLine;
668#ifdef DEBUG_FORMATTER_VERT
669 kdDebug(32500) <<
" -> tmpBaseLine/tmph : " << tmpBaseLine <<
"/" << tmph << endl;
672 TemporaryWordData twd;
673 twd.baseLine = tmpBaseLine;
675 twd.lineWidth = tmpWused;
676 tempWordData.append( twd );
684#ifdef DEBUG_FORMATTER
685 kdDebug(32500) <<
"LU: x=" << x <<
" [equiv. to pix=" << zh->
layoutUnitToPixelX( x ) <<
"] ; PIX: x=" << pixelx <<
" --> adj=" << c->pixelxadj << endl;
691 lastChr->pixelwidth = pixelx - lastPixelx;
693 tmpWused = TQMAX( tmpWused, x );
703#ifdef DEBUG_FORMATTER
704 kdDebug(32500) <<
"LU: added " << ww <<
" -> now x=" << x <<
" ; PIX: added " << pixelww <<
" -> now pixelx=" << pixelx << endl;
711 c->format()->removeRef();
712 c->setFormat( string->at( len - 2 ).format() );
713 c->format()->addRef();
718#ifdef DEBUG_FORMATTER
719 kdDebug(32500) <<
"Last Line.... linenr=" << (int)parag->lineStartList().count()-1 << endl;
721#ifdef DEBUG_FORMATTER_VERT
722 kdDebug(32500) <<
"Last Line... Combining " << lineStart->baseLine <<
"/" << lineStart->h <<
" with " << tmpBaseLine <<
"/" << tmph << endl;
725 int belowBaseLine = TQMAX( lineStart->h - lineStart->baseLine, tmph - tmpBaseLine );
726 lineStart->baseLine = TQMAX( lineStart->baseLine, tmpBaseLine );
727 lineStart->h = lineStart->baseLine + belowBaseLine;
729#ifdef DEBUG_FORMATTER_WIDTH
730 kdDebug(32500) <<
"Last line: w = dw = " << dw << endl;
732#ifdef DEBUG_FORMATTER_VERT
733 kdDebug(32500) <<
" -> lineStart->baseLine/lineStart->h : " << lineStart->baseLine <<
"/" << lineStart->h << endl;
736 if ( align == TQt::AlignJustify )
737 align = TQt::AlignAuto;
738 int space = availableWidth - x + c->width;
739 KoTextParagLineStart *lineStart2 = koFormatLine( zh, parag,
string, lineStart, firstChar, c, align, space );
744 wused = TQMAX( wused, tmpWused );
745#ifdef DEBUG_FORMATTER_WIDTH
746 kdDebug(32500) <<
"Done, wused=" << wused << endl;
749 int m = parag->bottomMargin();
753 parag->setFullWidth( fullWidth );
756#ifdef DEBUG_FORMATTER_VERT
757 kdDebug(32500) <<
"Adding height of last line(" << lineStart->h <<
") and bottomMargin(" << m <<
") to y(" << y <<
") => " << y+lineStart->h+m << endl;
759 y += lineStart->h + m;
761 tmpWused += currentRightMargin;
766#ifdef DEBUG_FORMATTER
768 int numberOfLines = 0;
769 TQString charPosList;
770 for (
int i = 0 ; i < len; ++i ) {
771 KoTextStringChar *chr = &
string->at( i );
773 assert( chr->lineStart );
774 if ( chr->lineStart ) {
776 charPosList += TQString::number(i) +
" ";
779 kdDebug(32500) << parag->lineStartList().count() <<
" lines. " << numberOfLines <<
" chars with lineStart set: " << charPosList << endl;
780 assert( numberOfLines == (
int)parag->lineStartList().count() );
787 int deltaX,
int deltaPixelX )
798KoTextParagLineStart *KoTextFormatterCore::koFormatLine(
800 KoTextParag *parag, KoTextString *
string, KoTextParagLineStart *line,
801 KoTextStringChar *startChar, KoTextStringChar *lastChar,
int align,
int space )
803 KoTextParagLineStart* ret = 0;
804 if( string->isBidi() ) {
805 ret = koBidiReorderLine( zh, parag,
string, line, startChar, lastChar, align, space );
807 int start = (startChar - &
string->at(0));
808 int last = (lastChar - &
string->at(0) );
814 if ( align & TQt::AlignHCenter || align & TQt::AlignRight ) {
815 if ( align & TQt::AlignHCenter )
818 for (
int j = last; j >= start; --j ) {
819 KoTextStringChar &chr =
string->at( j );
820 moveChar( chr, zh, space, toAddPix );
822 }
else if ( align & TQt::AlignJustify ) {
825 for (
int j = last-1; j >= start; --j ) {
827 if ( string->at( j ).c ==
'\t' ) {
831 if( settings->isStretchable(
string, j ) ) {
837 for (
int k = start + 1; k <= last; ++k ) {
838 KoTextStringChar &chr =
string->at( k );
840 moveChar( chr, zh, toAdd, toAddPix );
841 if( settings->isStretchable(
string, k ) && numSpaces ) {
842 int s = space / numSpaces;
856 KoTextFormat refFormat( *string->at(0).format() );
857 for(
int i=start;i<=last;++i)
859 KoTextFormat* format=
string->at(i).format();
861 if ( (((!format->underline())&&
862 (!format->doubleUnderline())&&
863 (!format->waveUnderline())&&
864 (format->underlineType()!=KoTextFormat::U_SIMPLE_BOLD))
868 double avg=
static_cast<double>(current)/nc;
871 refFormat.setUnderLineWidth( avg );
872 parag->setFormat( i-nc, i, &refFormat,
true, KoTextFormat::UnderLineWidth );
877 else if(format->underline()||
878 format->waveUnderline()||
879 format->doubleUnderline()||
880 (format->underlineType() == KoTextFormat::U_SIMPLE_BOLD))
883 current += format->pointSize();
887 if ( last >= 0 && last < string->length() ) {
888 KoTextStringChar &chr =
string->at( last );
889 line->w = chr.x + chr.width;
891 if ( line->hyphenated )
897 ret =
new KoTextParagLineStart();
901 const int start = (startChar - &
string->at(0));
902 const int last = (lastChar - &
string->at(0) );
903 line->lineSpacing = parag->calculateLineSpacing( (
int)parag->lineStartList().count()-1, start, last );
904 line->h += line->lineSpacing;
910KoTextParagLineStart *KoTextFormatterCore::koBidiReorderLine(
912 KoTextParag * , KoTextString *text, KoTextParagLineStart *line,
913 KoTextStringChar *startChar, KoTextStringChar *lastChar,
int align,
int space )
920 while ( lastChar > startChar && lastChar->whiteSpace ) {
921 space += lastChar->format()->
width(
' ' );
927 int start = (startChar - &text->at(0));
928 int last = (lastChar - &text->at(0) );
929#ifdef DEBUG_FORMATTER
930 kdDebug(32500) <<
"*KoTextFormatter::koBidiReorderLine from " << start <<
" to " << last <<
" space=" << space <<
" startChar->x=" << startChar->x << endl;
932 KoBidiControl *control =
new KoBidiControl( line->context(), line->status );
934 str.setUnicode( 0, last - start + 1 );
936 KoTextStringChar *ch = startChar;
937 TQChar *qch = (TQChar *)str.unicode();
938 while ( ch <= lastChar ) {
943 int x = startChar->x;
945 TQPtrList<KoTextRun> *runs;
946 runs = KoComplexText::bidiReorderLine(control, str, 0, last - start + 1,
947 (text->isRightToLeft() ? TQChar::DirR : TQChar::DirL) );
953 if( align == TQt::AlignAuto ) {
955 if ( text->isRightToLeft() )
956 align = TQt::AlignRight;
959 if ( align & TQt::AlignHCenter ) {
961 }
else if ( align & TQt::AlignRight ) {
963 }
else if ( align & TQt::AlignJustify ) {
964 for (
int j = last - 1; j >= start; --j ) {
966 if ( text->at( j ).c ==
'\t' ) {
970 if( settings->isStretchable( text, j ) ) {
980 KoTextRun *r = runs->first();
981 int xmax = -0xffffff;
983#ifdef DEBUG_FORMATTER
984 kdDebug(32500) <<
"koBidiReorderLine level: " << r->level << endl;
988 int pos = r->stop + start;
989 while(pos >= r->start + start) {
990 KoTextStringChar &chr = text->at(pos);
991 if( numSpaces && !first && settings->isBreakable( text, pos ) ) {
992 int s = space / numSpaces;
999 }
else if ( first ) {
1005 pixelx -= chr.pixelwidth;
1010#ifdef DEBUG_FORMATTER
1011 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;
1013 chr.rightToLeft =
true;
1014 chr.startOfRun =
false;
1016 if ( xmax < x + toAdd + ww ) xmax = x + toAdd + ww;
1018 pixelx += chr.pixelwidth;
1019#ifdef DEBUG_FORMATTER
1020 kdDebug(32500) <<
" ww=" << ww <<
" adding to x, now " << x <<
". pixelwidth=" << chr.pixelwidth <<
" adding to pixelx, now " << pixelx <<
" xmax=" << xmax << endl;
1025 int pos = r->start + start;
1026 while(pos <= r->stop + start) {
1027 KoTextStringChar& chr = text->at(pos);
1028 if( numSpaces && !first && settings->isBreakable( text, pos ) ) {
1029 int s = space / numSpaces;
1034 }
else if ( first ) {
1040 pixelx -= chr.pixelwidth;
1045 chr.rightToLeft =
false;
1046 chr.startOfRun =
false;
1049 if ( xmax < x + toAdd + ww ) xmax = x + toAdd + ww;
1051 pixelx += chr.pixelwidth;
1055 text->at( r->start + start ).startOfRun =
true;
1060 KoTextParagLineStart *ls =
new KoTextParagLineStart( control->context, control->status );
1066void KoTextFormatter::postFormat( KoTextParag* parag )
1068 parag->fixParagWidth( viewFormattingChars() );
static KoHyphenator * self()
Returns the single KoHyphenator instance (singleton pattern) Beware that this might throw an exceptio...
int charWidth(const KoTextZoomHandler *zh, bool applyZoom, const KoTextStringChar *c, const KoTextParag *parag, int i) const
Return the width of one char in one paragraph.
const TQFontMetrics & refFontMetrics() const
int width(const TQChar &c) const
Return the width of one char (from a string, not necessarily from a paragraph) in LU pixels.
int charWidthLU(const KoTextStringChar *c, const KoTextParag *parag, int i) const
Return the width of one char in LU pixels.
We implement our own text formatter to implement WYSIWYG: It is heavily based on KoTextFormatterBaseB...
This class extends KoZoomHandler to add support for WYSIWYG text layouting.
static double ptToLayoutUnitPt(double pt)
Not zoom dependent.
int layoutUnitToPixelX(int lupix) const
The "layout unit pixel" -> "[zoomed] view pixel" conversions.