diff options
Diffstat (limited to 'tqtinterface/qt4/src/kernel/tqtextlayout.cpp')
| -rw-r--r-- | tqtinterface/qt4/src/kernel/tqtextlayout.cpp | 818 | 
1 files changed, 818 insertions, 0 deletions
| diff --git a/tqtinterface/qt4/src/kernel/tqtextlayout.cpp b/tqtinterface/qt4/src/kernel/tqtextlayout.cpp new file mode 100644 index 0000000..1a007a8 --- /dev/null +++ b/tqtinterface/qt4/src/kernel/tqtextlayout.cpp @@ -0,0 +1,818 @@ +/**************************************************************************** +** +** ??? +** +** Copyright (C) 2005-2008 Trolltech ASA.  All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file.  Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include <tqtglobaldefines.h> +// Nasty, nasty horrid HACK to get access to QTextLine's private members +// This is TERRIBLE and I wish there was a way around it +// This is a good example of the new, broken & irritating Qt4 API, +// and the corresponding loss in functionality versus Qt3. +// See also tqrect.cpp +#define private protected +#include <Qt/qtextlayout.h> +#undef private + +#include "tqtextlayout_p.h" +#include "tqtextengine_p.h" + +#include <tqfont.h> +#include <tqapplication.h> +#include <tqpainter.h> + +#ifdef USE_QT4 +#include "private/qt4_qtextengine_p.h" +#endif // USE_QT4 + +#ifdef USE_QT4 + +TQTextItem::TQTextItem(int line, QTextEngine *e) : QTextLine(line, e) {} + +// TQt internal functions +// Do not modify unless you know what you are doing! +QTextEngine* TQTextItem::tqt_textEngine() const { +	return eng; +} + +TQString TQTextItem::tqt_textString() const { +	return eng->layoutData->string; +} + +void TQTextItem::tqt_tqdrawTextItem( TQPainter* p, int x,  int y, const TQTextItem &ti, int textFlags ) const { +	// [FIXME] This needs serious help--it ignores the selected font, font size, etc. +	#warning TQTextItem::tqt_tqdrawTextItem( TQPainter* p, int x,  int y, const TQTextItem &ti, int textFlags ) unimplemented +	printf("[WARNING] TQTextItem::tqt_tqdrawTextItem( TQPainter* p, int x,  int y, const TQTextItem &ti, int textFlags ) partially implemented\n\r"); + +	// Cheat! +	TQString textToPaint = ti.tqt_textString(); +	p->save(); +	p->setFont(eng->font()); +	p->drawText( x, y, textToPaint, textToPaint.length()); +// 	p->drawText( x, y, TQString("BAD WOLF"), 8); +	p->restore(); +} + +// End TQt internal functions + +// // [FIXME] +TQTextItem TQTextLayout::nextItem() { +	tqtl_currentItem++; +	 +	if ( tqtl_currentItem >= numItems() ) +		return TQTextItem(); +	 +// 	d->tqshape( tqtl_currentItem ); +	return TQTextItem( tqtl_currentItem, d ); +} + +TQTextItem TQTextLayout::currentItem() { +	if ( tqtl_currentItem >= numItems() ) +		return TQTextItem(); +	 +// 	d->tqshape( tqtl_currentItem ); +	return TQTextItem( tqtl_currentItem, d ); +} + +bool TQTextItem::isRightToLeft() const +{ +// 	if (textDirection() == Qt::RightToLeft) { +// 		return true; +// 	} +// 	else { +// 		return false; +// 	} +	printf("[WARNING] bool TQTextItem::isRightToLeft() const unimplemented\n\r"); +	return false; +} + +bool TQTextItem::isObject() const +{ +	printf("[WARNING] bool TQTextItem::isObject() const unimplemented\n\r"); +	return false; +} + +bool TQTextItem::isSpace() const +{ +	printf("[WARNING] bool TQTextItem::isSpace() const unimplemented\n\r"); +	return false; +} + +bool TQTextItem::isTab() const +{ +	printf("[WARNING] bool TQTextItem::isTab() const unimplemented\n\r"); +	return false; +} + +int TQTextLayout::availableWidth() const +{ +	return tqtl_lineWidth - tqtl_widthUsed; +} + +int TQTextItem::from() const +{ +// 	return engine->items[item].position; +	return textStart(); + +// 	printf("[WARNING] int TQTextItem::from() const unimplemented\n\r"); +// 	return 0; +} + +int TQTextItem::length() const +{ +// 	return engine->length(item); +	return textLength(); + +// 	printf("[WARNING] int TQTextItem::length() const unimplemented\n\r"); +// 	return 0; +} + +void TQTextLayout::beginLine( int width ) { +	tqtl_widthUsed = 0; +	tqtl_lineWidth = width; +	QTextLine line = createLine(); +	tqtl_currentItem = numItems() - 1; +	line.setLineWidth(width); +} + +bool TQTextLayout::atEnd() const +{ +	return tqtl_currentItem >= numItems(); +} + +int TQTextLayout::widthUsed() { +	return tqtl_widthUsed; +} + +TQTextLayout::Result TQTextLayout::addCurrentItem() { +	if (currentItem().isValid()) { +		tqtl_widthUsed = currentItem().naturalTextWidth(); +	} +	else { +		tqtl_widthUsed = 0; +	} +	tqtl_currentItem++; +	printf("[WARNING] TextLayout::Result TQTextLayout::addCurrentItem() partially implemented -- some of its functionality has been moved to beginLine()\n\r"); +	return Ok; +// 	return (tqtl_widthUsed <= tqtl_lineWidth || (tqtl_currentItem < d->items.size() && d->items[tqtl_currentItem].isSpace)) ? Ok : LineFull; +} + +TQTextLayout::Result TQTextLayout::endLine( int x, int y, int tqalignment, int *ascent, int *descent, int *lineLeft, int *lineRight ) +{ +// [FIXME] This crashes... +// 	QTextLine line = itemAt(tqtl_currentItem); +// 	line.setPosition(QPointF(x,y)); +// 	TQ_UNUSED(tqalignment); +// 	TQ_UNUSED(ascent); +// 	TQ_UNUSED(descent); +// 	TQ_UNUSED(lineLeft); +// 	TQ_UNUSED(lineRight); + +	TQ_UNUSED(x); +	TQ_UNUSED(y); +	TQ_UNUSED(tqalignment); +	TQ_UNUSED(ascent); +	TQ_UNUSED(descent); +	TQ_UNUSED(lineLeft); +	TQ_UNUSED(lineRight); +	// tqtl_currentItem must be dealt with here as well +	printf("[WARNING] TQTextLayout::Result TQTextLayout::endLine( int x, int y, int tqalignment, int *ascent, int *descent, int *lineLeft, int *lineRight ) unimplemented\n\r"); +	return Ok; +} + +void TQTextLayout::setDirection(TQChar::Direction dir) { +	printf("[WARNING] void TQTextLayout::setDirection(TQChar::Direction dir) unimplemented\n\r"); +} + +#else // USE_QT4 + +TQRect TQTextItem::rect() const +{ +    TQScriptItem& si = engine->items[item]; +    return TQRect( si.x, si.y, si.width, si.ascent+si.descent ); +} + +int TQTextItem::x() const +{ +    return engine->items[item].x; +} + +int TQTextItem::y() const +{ +    return engine->items[item].y; +} + +int TQTextItem::width() const +{ +    return engine->items[item].width; +} + +int TQTextItem::ascent() const +{ +    return engine->items[item].ascent; +} + +int TQTextItem::descent() const +{ +    return engine->items[item].descent; +} + +void TQTextItem::setWidth( int w ) +{ +    engine->items[item].width = w; +} + +void TQTextItem::setAscent( int a ) +{ +    engine->items[item].ascent = a; +} + +void TQTextItem::setDescent( int d ) +{ +    engine->items[item].descent = d; +} + +int TQTextItem::from() const +{ +    return engine->items[item].position; +} + +int TQTextItem::length() const +{ +    return engine->length(item); +} + + +int TQTextItem::cursorToX( int *cPos, Edge edge ) const +{ +    int pos = *cPos; +    TQScriptItem *si = &engine->items[item]; + +    engine->tqshape( item ); +    advance_t *advances = engine->advances( si ); +    GlyphAttributes *glyphAttributes = engine->glyphAttributes( si ); +    unsigned short *logClusters = engine->logClusters( si ); + +    int l = engine->length( item ); +    if ( pos > l ) +	pos = l; +    if ( pos < 0 ) +	pos = 0; + +    int glyph_pos = pos == l ? si->num_glyphs : logClusters[pos]; +    if ( edge == Trailing ) { +	// trailing edge is leading edge of next cluster +	while ( glyph_pos < si->num_glyphs && !glyphAttributes[glyph_pos].clusterStart ) +	    glyph_pos++; +    } + +    int x = 0; +    bool reverse = engine->items[item].analysis.bidiLevel % 2; + +    if ( reverse ) { +	for ( int i = si->num_glyphs-1; i >= glyph_pos; i-- ) +	    x += advances[i]; +    } else { +	for ( int i = 0; i < glyph_pos; i++ ) +	    x += advances[i]; +    } +//     qDebug("cursorToX: pos=%d, gpos=%d x=%d", pos, glyph_pos, x ); +    *cPos = pos; +    return x; +} + +int TQTextItem::xToCursor( int x, CursorPosition cpos ) const +{ +    TQScriptItem *si = &engine->items[item]; +    engine->tqshape( item ); +    advance_t *advances = engine->advances( si ); +    unsigned short *logClusters = engine->logClusters( si ); + +    int l = engine->length( item ); +    bool reverse = si->analysis.bidiLevel % 2; +    if ( x < 0 ) +	return reverse ? l : 0; + + +    if ( reverse ) { +	int width = 0; +	for ( int i = 0; i < si->num_glyphs; i++ ) { +	    width += advances[i]; +	} +	x = -x + width; +    } +    int cp_before = 0; +    int cp_after = 0; +    int x_before = 0; +    int x_after = 0; + +    int lastCluster = 0; +    for ( int i = 1; i <= l; i++ ) { +	int newCluster = i < l ? logClusters[i] : si->num_glyphs; +	if ( newCluster != lastCluster ) { +	    // calculate cluster width +	    cp_before = cp_after; +	    x_before = x_after; +	    cp_after = i; +	    for ( int j = lastCluster; j < newCluster; j++ ) +		x_after += advances[j]; +	    // 		qDebug("cluster boundary: lastCluster=%d, newCluster=%d, x_before=%d, x_after=%d", +	    // 		       lastCluster, newCluster, x_before, x_after ); +	    if ( x_after > x ) +		break; +	    lastCluster = newCluster; +	} +    } + +    bool before = ( cpos == OnCharacters || (x - x_before) < (x_after - x) ); + +//     qDebug("got cursor position for %d: %d/%d, x_ba=%d/%d using %d", +// 	   x, cp_before,cp_after,  x_before, x_after,  before ? cp_before : cp_after ); + +    return before ? cp_before : cp_after; + +} + + +bool TQTextItem::isRightToLeft() const +{ +    return (engine->items[item].analysis.bidiLevel % 2); +} + +bool TQTextItem::isObject() const +{ +    return engine->items[item].isObject; +} + +bool TQTextItem::isSpace() const +{ +    return engine->items[item].isSpace; +} + +bool TQTextItem::isTab() const +{ +    return engine->items[item].isTab; +} + +TQTextLayout::TQTextLayout() +    :d(0) {} + +TQTextLayout::TQTextLayout( const TQString& string, TQPainter *p ) +{ +    TQFontPrivate *f = p ? ( p->pfont ? p->pfont->d : p->cfont.d ) : TQApplication::font().d; +    d = new TQTextEngine( (string.isNull() ? (const TQString&)TQString::tqfromLatin1("") : string), f ); +} + +TQTextLayout::TQTextLayout( const TQString& string, const TQFont& fnt ) +{ +    d = new TQTextEngine( (string.isNull() ? (const TQString&)TQString::tqfromLatin1("") : string), fnt.d ); +} + +TQTextLayout::~TQTextLayout() +{ +    delete d; +} + +void TQTextLayout::setText( const TQString& string, const TQFont& fnt ) +{ +    delete d; +    d = new TQTextEngine( (string.isNull() ? (const TQString&)TQString::tqfromLatin1("") : string), fnt.d ); +} + +/* add an additional item boundary eg. for style change */ +void TQTextLayout::setBoundary( int strPos ) +{ +    if ( strPos <= 0 || strPos >= (int)d->string.length() ) +	return; + +    int itemToSplit = 0; +    while ( itemToSplit < d->items.size() && d->items[itemToSplit].position <= strPos ) +	itemToSplit++; +    itemToSplit--; +    if ( d->items[itemToSplit].position == strPos ) { +	// already a split at the requested position +	return; +    } +    d->splitItem( itemToSplit, strPos - d->items[itemToSplit].position ); +} + + +int TQTextLayout::numItems() const +{ +    return d->items.size(); +} + +TQTextItem TQTextLayout::itemAt( int i ) const +{ +    return TQTextItem( i, d ); +} + + +TQTextItem TQTextLayout::tqfindItem( int strPos ) const +{ +    if ( strPos == 0 && d->items.size() ) +	return TQTextItem( 0, d ); +    // ## TODO use bsearch +    for ( int i = d->items.size()-1; i >= 0; --i ) { +	if ( d->items[i].position < strPos ) +	    return TQTextItem( i, d ); +    } +    return TQTextItem(); +} + + +void TQTextLayout::beginLayout( TQTextLayout::LayoutMode m ) +{ +    d->items.clear(); +    TQTextEngine::Mode mode = TQTextEngine::Full; +    if (m == NoBidi) +	mode = TQTextEngine::NoBidi; +    else if (m == SingleLine) +	mode = TQTextEngine::SingleLine; +    d->itemize( mode ); +    d->currentItem = 0; +    d->firstItemInLine = -1; +} + +void TQTextLayout::beginLine( int width ) +{ +    d->lineWidth = width; +    d->widthUsed = 0; +    d->firstItemInLine = -1; +} + +bool TQTextLayout::atEnd() const +{ +    return d->currentItem >= d->items.size(); +} + +TQTextItem TQTextLayout::nextItem() +{ +    d->currentItem++; + +    if ( d->currentItem >= d->items.size() ) +	return TQTextItem(); + +    d->tqshape( d->currentItem ); +    return TQTextItem( d->currentItem, d ); +} + +TQTextItem TQTextLayout::currentItem() +{ +    if ( d->currentItem >= d->items.size() ) +	return TQTextItem(); + +    d->tqshape( d->currentItem ); +    return TQTextItem( d->currentItem, d ); +} + +/* ## maybe also currentItem() */ +void TQTextLayout::setLineWidth( int newWidth ) +{ +    d->lineWidth = newWidth; +} + +int TQTextLayout::lineWidth() const +{ +    return d->lineWidth; +} + +int TQTextLayout::widthUsed() const +{ +    return d->widthUsed; +} + +int TQTextLayout::availableWidth() const +{ +    return d->lineWidth - d->widthUsed; +} + + +/* returns true if completely added */ +TQTextLayout::Result TQTextLayout::addCurrentItem() +{ +    if ( d->firstItemInLine == -1 ) +	d->firstItemInLine = d->currentItem; +    TQScriptItem ¤t = d->items[d->currentItem]; +    d->tqshape( d->currentItem ); +    d->widthUsed += current.width; +//     qDebug("trying to add item %d with width %d, remaining %d", d->currentItem, current.width, d->lineWidth-d->widthUsed ); + +    d->currentItem++; + +    return (d->widthUsed <= d->lineWidth +	    || (d->currentItem < d->items.size() && d->items[d->currentItem].isSpace)) ? Ok : LineFull; +} + +TQTextLayout::Result TQTextLayout::endLine( int x, int y, int tqalignment, +					  int *ascent, int *descent, int *lineLeft, int *lineRight ) +{ +    int available = d->lineWidth; +    int numRuns = 0; +    int numSpaceItems = 0; +    TQ_UINT8 _levels[128]; +    int _visual[128]; +    TQ_UINT8 *levels = _levels; +    int *visual = _visual; +    int i; +    TQTextLayout::Result result = LineEmpty; + +//    qDebug("endLine x=%d, y=%d, first=%d, current=%d lw=%d wu=%d", x,  y, d->firstItemInLine, d->currentItem, d->lineWidth, d->widthUsed ); +    int width_nobreak_found = d->widthUsed; +    if ( d->firstItemInLine == -1 ) +	goto end; + +    if ( !(tqalignment & (TQt::SingleLine|TQt::IncludeTrailingSpaces)) +	&& d->currentItem > d->firstItemInLine && d->items[d->currentItem-1].isSpace ) { +	int i = d->currentItem-1; +	while ( i > d->firstItemInLine && d->items[i].isSpace ) { +	    numSpaceItems++; +	    d->widthUsed -= d->items[i--].width; +	} +    } + +    if ( (tqalignment & (TQt::WordBreak|TQt::BreakAnywhere)) && +	 d->widthUsed > d->lineWidth ) { +	// tqfind linebreak + +	// even though we removed trailing spaces the line was too wide. We'll have to break at an earlier +	// position. To not confuse the layouting below, reset the number of space items +	numSpaceItems = 0; + + +	bool breakany = tqalignment & TQt::BreakAnywhere; + +	const TQCharAttributes *attrs = d->attributes(); +	int w = 0; +	int itemWidth = 0; +	int breakItem = d->firstItemInLine; +	int breakPosition = -1; +#if 0 +	// we iterate backwards or forward depending on what we guess is closer +	if ( d->widthUsed - d->lineWidth < d->lineWidth ) { +	    // backwards search should be faster + +	} else +#endif +	{ +	    int tmpWidth = 0; +	    int swidth = 0; +	    // forward search is probably faster +	    for ( int i = d->firstItemInLine; i < d->currentItem; i++ ) { +		const TQScriptItem *si = &d->items[i]; +		int length = d->length( i ); +		const TQCharAttributes *itemAttrs = attrs + si->position; + +		advance_t *advances = d->advances( si ); +		unsigned short *logClusters = d->logClusters( si ); + +		int lastGlyph = 0; +		int tmpItemWidth = 0; + +//     		qDebug("looking for break in item %d, isSpace=%d", i, si->isSpace ); +		if(si->isSpace && !(tqalignment & (TQt::SingleLine|TQt::IncludeTrailingSpaces))) { +		    swidth += si->width; +		} else { +		    tmpWidth += swidth; +		    swidth = 0; +		    for ( int pos = 0; pos < length; pos++ ) { +//  			qDebug("advance=%d, w=%d, tmpWidth=%d, softbreak=%d, whitespace=%d", +//                                *advances, w, tmpWidth, itemAttrs->softBreak, itemAttrs->whiteSpace ); +			int glyph = logClusters[pos]; +			if ( lastGlyph != glyph ) { +			    while ( lastGlyph < glyph ) +				tmpItemWidth += advances[lastGlyph++]; +			    if ( breakPosition != -1 && w + tmpWidth + tmpItemWidth > d->lineWidth ) { +// 				qDebug("found break at w=%d, tmpWidth=%d, tmpItemWidth=%d", w, tmpWidth, tmpItemWidth); +				d->widthUsed = w; +				goto found; +			    } +			} +			if ( (itemAttrs->softBreak || +			      ( breakany && itemAttrs->charStop ) ) && +			     (i != d->firstItemInLine || pos != 0) ) { +			    if ( breakItem != i ) +				itemWidth = 0; +			    if (itemAttrs->softBreak) +				breakany = FALSE; +			    breakItem = i; +			    breakPosition = pos; +//     			    qDebug("found possible break at item %d, position %d (absolute=%d), w=%d, tmpWidth=%d, tmpItemWidth=%d", breakItem, breakPosition, d->items[breakItem].position+breakPosition, w, tmpWidth, tmpItemWidth); +			    w += tmpWidth + tmpItemWidth; +			    itemWidth += tmpItemWidth; +			    tmpWidth = 0; +			    tmpItemWidth = 0; +			} +			itemAttrs++; +		    } +		    while ( lastGlyph < si->num_glyphs ) +			tmpItemWidth += advances[lastGlyph++]; +		    tmpWidth += tmpItemWidth; +		    if ( w + tmpWidth > d->lineWidth ) { +			d->widthUsed = w; +			goto found; +		    } +		} +	    } +	} + +    found: +	// no valid break point found +	if ( breakPosition == -1 ) { +            d->widthUsed = width_nobreak_found; +	    goto nobreak; +        } + +//   	qDebug("linebreak at item %d, position %d, wu=%d", breakItem, breakPosition, d->widthUsed ); +	// split the line +	if ( breakPosition > 0 ) { +// 	    int length = d->length( breakItem ); + +//   	    qDebug("splitting item, itemWidth=%d", itemWidth); +	    // not a full item, need to break +	    d->splitItem( breakItem, breakPosition ); +	    d->currentItem = breakItem+1; +	} else { +	    d->currentItem = breakItem; +	} +    } + +    result = Ok; + + nobreak: +    // position the objects in the line +    available -= d->widthUsed; + +    numRuns = d->currentItem - d->firstItemInLine - numSpaceItems; +    if ( numRuns > 127 ) { +	levels = new TQ_UINT8[numRuns]; +	visual = new int[numRuns]; +    } + +//     qDebug("reordering %d runs, numSpaceItems=%d", numRuns, numSpaceItems ); +    for ( i = 0; i < numRuns; i++ ) { +	levels[i] = d->items[i+d->firstItemInLine].analysis.bidiLevel; +// 	qDebug("    level = %d", d->items[i+d->firstItemInLine].analysis.bidiLevel ); +    } +    d->bidiReorder( numRuns, levels, visual ); + + end: +    // ### FIXME +    if ( tqalignment & TQt::AlignJustify ) { +	// #### justify items +	tqalignment = TQt::AlignAuto; +    } +    if ( (tqalignment & TQt::AlignHorizontal_Mask) == TQt::AlignAuto ) +	tqalignment = TQt::AlignLeft; +    if ( tqalignment & TQt::AlignRight ) +	x += available; +    else if ( tqalignment & TQt::AlignHCenter ) +	x += available/2; + + +    int asc = ascent ? *ascent : 0; +    int desc = descent ? *descent : 0; + +    for ( i = 0; i < numRuns; i++ ) { +	TQScriptItem &si = d->items[d->firstItemInLine+visual[i]]; +	asc = TQMAX( asc, si.ascent ); +	desc = TQMAX( desc, si.descent ); +    } + +    int left = x; +    for ( i = 0; i < numRuns; i++ ) { +	TQScriptItem &si = d->items[d->firstItemInLine+visual[i]]; +//  	qDebug("positioning item %d with width %d (from=%d/length=%d) at %d", d->firstItemInLine+visual[i], si.width, si.position, +// 	       d->length(d->firstItemInLine+visual[i]), x ); +	si.x = x; +	si.y = y + asc; +	x += si.width; +    } +    int right = x; + +    if ( numSpaceItems ) { +	if ( d->items[d->firstItemInLine+numRuns].analysis.bidiLevel % 2 ) { +	    x = left; +	    for ( i = 0; i < numSpaceItems; i++ ) { +		TQScriptItem &si = d->items[d->firstItemInLine + numRuns + i]; +		x -= si.width; +		si.x = x; +		si.y = y + asc; +	    } +	} else { +	    for ( i = 0; i < numSpaceItems; i++ ) { +		TQScriptItem &si = d->items[d->firstItemInLine + numRuns + i]; +		si.x = x; +		si.y = y + asc; +		x += si.width; +	    } +	} +    } + +    if ( lineLeft ) +	*lineLeft = left; +    if ( lineRight ) +	*lineRight = right; +    if ( ascent ) +	*ascent = asc; +    if ( descent ) +	*descent = desc; + +    if (levels != _levels) +	delete []levels; +    if (visual != _visual) +	delete []visual; + +    return result; +} + +void TQTextLayout::endLayout() +{ +    // nothing to do currently +} + + +int TQTextLayout::nextCursorPosition( int oldPos, CursorMode mode ) const +{ +//     qDebug("looking for next cursor pos for %d", oldPos ); +    const TQCharAttributes *attributes = d->attributes(); +    int len = d->string.length(); +    if ( oldPos >= len ) +	return oldPos; +    oldPos++; +    if ( mode == SkipCharacters ) { +	while ( oldPos < len && !attributes[oldPos].charStop ) +	    oldPos++; +    } else { +	while ( oldPos < len && !attributes[oldPos].wordStop && !attributes[oldPos-1].whiteSpace ) +	    oldPos++; +    } +//     qDebug("  -> %d",  oldPos ); +    return oldPos; +} + +int TQTextLayout::previousCursorPosition( int oldPos, CursorMode mode ) const +{ +//     qDebug("looking for previous cursor pos for %d", oldPos ); +    const TQCharAttributes *attributes = d->attributes(); +    if ( oldPos <= 0 ) +	return 0; +    oldPos--; +    if ( mode == SkipCharacters ) { +	while ( oldPos && !attributes[oldPos].charStop ) +	    oldPos--; +    } else { +	while ( oldPos && !attributes[oldPos].wordStop && !attributes[oldPos-1].whiteSpace ) +	    oldPos--; +    } +//     qDebug("  -> %d",  oldPos ); +    return oldPos; +} + + +bool TQTextLayout::validCursorPosition( int pos ) const +{ +    const TQCharAttributes *attributes = d->attributes(); +    if ( pos < 0 || pos > (int)d->string.length() ) +	return FALSE; +    return attributes[pos].charStop; +} + +void TQTextLayout::setDirection(TQChar::Direction dir) +{ +    d->direction = dir; +} + +#endif // USE_QT4
\ No newline at end of file | 
