os/graphics/graphicsdeviceinterface/gdi/sgdi/BidiText.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
//
sl@0
    15
sl@0
    16
#include <e32svr.h>
sl@0
    17
#include "BidiTextImp.h"
sl@0
    18
#include "BidiCopy.h"
sl@0
    19
#include "BidiCompact.h"
sl@0
    20
#include <bidi.h>
sl@0
    21
#include <e32base.h>
sl@0
    22
#include <gdi.h>
sl@0
    23
#include <linebreak.h>
sl@0
    24
sl@0
    25
_LIT(KBidiPanicCategory,"Bidi");
sl@0
    26
static const TInt KLineSeparator = 0x2028;
sl@0
    27
static const TInt KParagraphSeparator = 0x2029;
sl@0
    28
static const TInt KCodeCR = 0x000D;
sl@0
    29
static const TInt KCodeLF = 0x000A;
sl@0
    30
static const TInt KCodeEllipsis = 0x2026;
sl@0
    31
sl@0
    32
void DeleteTRunInfo(void* aRunInfo)
sl@0
    33
	{
sl@0
    34
	delete[] reinterpret_cast<TBidirectionalState::TRunInfo*>(aRunInfo);
sl@0
    35
	}
sl@0
    36
sl@0
    37
void BidiPanic(TInt aError)
sl@0
    38
	{
sl@0
    39
	User::Panic(KBidiPanicCategory, aError);
sl@0
    40
	}
sl@0
    41
sl@0
    42
sl@0
    43
// One page-full of TRunInfos
sl@0
    44
const TInt KMaxRunInfoArraySize = 4*1024 / sizeof(TBidirectionalState::TRunInfo);
sl@0
    45
const TInt KBidiTlsHandle = 0x101F633D;
sl@0
    46
sl@0
    47
sl@0
    48
/*
sl@0
    49
* Ref-counted TLS for the shared run info array used by the SetText() method.
sl@0
    50
*/
sl@0
    51
NONSHARABLE_CLASS(CBidiTextTls) : public CObject
sl@0
    52
	{
sl@0
    53
public:	
sl@0
    54
	static CBidiTextTls* NewL();
sl@0
    55
	static CBidiTextTls* GetTls();
sl@0
    56
	~CBidiTextTls();
sl@0
    57
	inline TUint MaxArraySize();
sl@0
    58
	inline TBidirectionalState::TRunInfo* RunArray();
sl@0
    59
sl@0
    60
private:
sl@0
    61
	CBidiTextTls();
sl@0
    62
	void ConstructL(TUint aMaxArraySize);
sl@0
    63
sl@0
    64
private:
sl@0
    65
	TBidirectionalState::TRunInfo* iRunInfoArray;
sl@0
    66
	TUint iMaxArraySize;	
sl@0
    67
	};
sl@0
    68
sl@0
    69
sl@0
    70
sl@0
    71
CBidiTextTls::CBidiTextTls()
sl@0
    72
:	iRunInfoArray(NULL),
sl@0
    73
 	iMaxArraySize(0)
sl@0
    74
	{
sl@0
    75
	}
sl@0
    76
sl@0
    77
sl@0
    78
CBidiTextTls::~CBidiTextTls()
sl@0
    79
	{
sl@0
    80
	UserSvr::DllFreeTls(KBidiTlsHandle);
sl@0
    81
	
sl@0
    82
	if (iRunInfoArray)
sl@0
    83
		{
sl@0
    84
		delete [] iRunInfoArray;	
sl@0
    85
		}
sl@0
    86
	}
sl@0
    87
sl@0
    88
sl@0
    89
TUint CBidiTextTls::MaxArraySize()
sl@0
    90
	{
sl@0
    91
	return iMaxArraySize;
sl@0
    92
	}
sl@0
    93
	
sl@0
    94
sl@0
    95
TBidirectionalState::TRunInfo* CBidiTextTls::RunArray()
sl@0
    96
	{
sl@0
    97
	return iRunInfoArray;
sl@0
    98
	}
sl@0
    99
	
sl@0
   100
	
sl@0
   101
/**
sl@0
   102
 * Helper function provided to simplify reading the TLS data and improve the
sl@0
   103
 * readability of the code 
sl@0
   104
 */
sl@0
   105
CBidiTextTls* CBidiTextTls::GetTls()
sl@0
   106
	{
sl@0
   107
	return reinterpret_cast<CBidiTextTls*>(UserSvr::DllTls(KBidiTlsHandle));
sl@0
   108
	}
sl@0
   109
sl@0
   110
sl@0
   111
CBidiTextTls* CBidiTextTls::NewL()
sl@0
   112
	{
sl@0
   113
	CBidiTextTls* self = new (ELeave) CBidiTextTls;
sl@0
   114
	CleanupClosePushL(*self);
sl@0
   115
	self->ConstructL(KMaxRunInfoArraySize);
sl@0
   116
	CleanupStack::Pop(self);
sl@0
   117
	return self;
sl@0
   118
	}
sl@0
   119
sl@0
   120
sl@0
   121
void CBidiTextTls::ConstructL(TUint aMaxArraySize)
sl@0
   122
	{
sl@0
   123
	iMaxArraySize = aMaxArraySize;
sl@0
   124
	iRunInfoArray = new (ELeave) TBidirectionalState::TRunInfo[aMaxArraySize];
sl@0
   125
	User::LeaveIfError(UserSvr::DllSetTls(KBidiTlsHandle, this));
sl@0
   126
	}
sl@0
   127
sl@0
   128
sl@0
   129
EXPORT_C RRunInfoArray::RRunInfoArray() 
sl@0
   130
:	iTls(NULL)
sl@0
   131
	{
sl@0
   132
	}
sl@0
   133
	
sl@0
   134
sl@0
   135
/** 
sl@0
   136
Creates the run array if necessary and increases the reference count on it.
sl@0
   137
RRunInfoArray::OpenL() must be called prior to calling TBidiText::SetText().
sl@0
   138
 */
sl@0
   139
EXPORT_C void RRunInfoArray::OpenL()
sl@0
   140
	{
sl@0
   141
	if(!iTls)
sl@0
   142
		{
sl@0
   143
		iTls = CBidiTextTls::GetTls();
sl@0
   144
		if(iTls)
sl@0
   145
			{
sl@0
   146
			iTls->Open();	// Increase ref count	
sl@0
   147
			}
sl@0
   148
		else	
sl@0
   149
			{
sl@0
   150
			iTls = CBidiTextTls::NewL();
sl@0
   151
			}
sl@0
   152
		}	
sl@0
   153
	}
sl@0
   154
	
sl@0
   155
	
sl@0
   156
/**
sl@0
   157
Decreases the reference count on the run array. The run array will be deleted
sl@0
   158
if the reference count reaches zero. The client application must ensure that
sl@0
   159
there is a matching call to Close() for every call to OpenL() or memory will
sl@0
   160
be leaked.
sl@0
   161
 */
sl@0
   162
EXPORT_C void RRunInfoArray::Close()
sl@0
   163
	{
sl@0
   164
	if(iTls)
sl@0
   165
		{
sl@0
   166
		iTls->Close();	
sl@0
   167
		iTls = NULL;
sl@0
   168
		}
sl@0
   169
	}
sl@0
   170
	
sl@0
   171
sl@0
   172
/**
sl@0
   173
@return Pointer to the run array buffer
sl@0
   174
@internalComponent
sl@0
   175
 */
sl@0
   176
TBidirectionalState::TRunInfo* RRunInfoArray::RunArray() const
sl@0
   177
	{
sl@0
   178
	return iTls ? iTls->RunArray() : NULL;
sl@0
   179
	}
sl@0
   180
	
sl@0
   181
sl@0
   182
/**
sl@0
   183
@return Number of bytes needed to hold the TBidiTextImp member variables, plus the 
sl@0
   184
		text data allocated off the end of the TBidiTextImp object.
sl@0
   185
@internalComponent
sl@0
   186
*/
sl@0
   187
TInt TBidiTextImp::RequiredBytes(TInt aLength, TInt aMaxLines, TInt aBdRunArraySize)		
sl@0
   188
	{
sl@0
   189
	// size of TBidiTextImp class
sl@0
   190
	TInt bytes = TBidiTextImp::AlignedSizeOf();
sl@0
   191
	// size of text for logical and visual orderings.
sl@0
   192
	// This includes aMaxLines - 1 line breaks with surrounding
sl@0
   193
	// zero-width joiners, and a truncation character (possibly
sl@0
   194
	// a surrogate pair) plus a zero-width joiner.
sl@0
   195
	bytes += sizeof(TText) * (aLength * 2 + aMaxLines * 3);
sl@0
   196
	// size of line length array
sl@0
   197
	bytes += sizeof(TInt16*) * aMaxLines;
sl@0
   198
	// alignment
sl@0
   199
	bytes = (bytes + 3) & 0xFFFFFFFC;
sl@0
   200
	// array of TRunInfoCompact
sl@0
   201
	bytes += sizeof(TRunInfoCompact) * aBdRunArraySize;
sl@0
   202
	
sl@0
   203
	return bytes;
sl@0
   204
	}
sl@0
   205
sl@0
   206
	
sl@0
   207
/**
sl@0
   208
@return A TBidiTextImp object of sufficient size to hold the amount of text data specified
sl@0
   209
		by the the arguments.
sl@0
   210
@param aLength The number of characters in the text.
sl@0
   211
@param aMaxLines The maximum number of lines 
sl@0
   212
@param aBdRunArraySize The size of the bidi run array. 
sl@0
   213
@internalComponent
sl@0
   214
*/
sl@0
   215
TBidiTextImp* TBidiTextImp::NewL(TInt aLength, TInt aMaxLines, TInt aBdRunArraySize)
sl@0
   216
	{
sl@0
   217
	const TInt bytes = RequiredBytes(aLength, aMaxLines, aBdRunArraySize);
sl@0
   218
	TInt8* mem = static_cast<TInt8*>(User::AllocL(bytes));
sl@0
   219
	TBidiTextImp* me = reinterpret_cast<TBidiTextImp*>(mem);
sl@0
   220
sl@0
   221
	me->iTextLengthAndFlags = aLength;
sl@0
   222
	me->iVisualOrderedTextLength = -1;
sl@0
   223
	me->iWrappingWidth = 0xFFFF;
sl@0
   224
	me->iBidiRunArrayLength = aBdRunArraySize;
sl@0
   225
	me->iLines = static_cast<TUint8>(aMaxLines);
sl@0
   226
	me->iTruncationCharPlane = 0;
sl@0
   227
	me->iTruncationChar16 = KCodeEllipsis;
sl@0
   228
	me->SetAllocatedTextDataBytes(bytes - TBidiTextImp::AlignedSizeOf() - (sizeof(TRunInfoCompact) * aBdRunArraySize));
sl@0
   229
	return me;
sl@0
   230
	}
sl@0
   231
sl@0
   232
/**
sl@0
   233
@return Position of logically-ordered text portion of the heap cell.
sl@0
   234
@internalComponent
sl@0
   235
*/
sl@0
   236
TText* TBidiTextImp::LogicalText()
sl@0
   237
	{
sl@0
   238
	return reinterpret_cast<TText*>(
sl@0
   239
		reinterpret_cast<TInt8*>(this)
sl@0
   240
		+ TBidiTextImp::AlignedSizeOf());
sl@0
   241
	}
sl@0
   242
sl@0
   243
/**
sl@0
   244
@return Position of visually-ordered text portion of the heap cell.
sl@0
   245
@internalComponent
sl@0
   246
*/
sl@0
   247
TText* TBidiTextImp::VisualText()
sl@0
   248
	{
sl@0
   249
	TInt bytes = TBidiTextImp::AlignedSizeOf();
sl@0
   250
	bytes += sizeof(TText) * TextLength();
sl@0
   251
	return reinterpret_cast<TText*>(
sl@0
   252
		reinterpret_cast<TInt8*>(this) + bytes);
sl@0
   253
	}
sl@0
   254
sl@0
   255
/**
sl@0
   256
Returns a pointer to the array containing the width in pixels of each and every line.
sl@0
   257
@return Position of the array of line widths portion of the heap cell.
sl@0
   258
@internalComponent
sl@0
   259
*/
sl@0
   260
TInt16* TBidiTextImp::LineWidthArray()
sl@0
   261
	{
sl@0
   262
	TInt bytes = TBidiTextImp::AlignedSizeOf();
sl@0
   263
	bytes += sizeof(TText) * (TextLength() * 2 + iLines + 2);
sl@0
   264
	return reinterpret_cast<TInt16*>(
sl@0
   265
		reinterpret_cast<TInt8*>(this) + bytes);
sl@0
   266
	}
sl@0
   267
sl@0
   268
/**
sl@0
   269
@return Position of the array of runs portion of the heap cell.
sl@0
   270
@internalComponent
sl@0
   271
*/
sl@0
   272
TRunInfoCompact* TBidiTextImp::BidiRunArray()
sl@0
   273
	{
sl@0
   274
	TInt bytes = TBidiTextImp::AlignedSizeOf();
sl@0
   275
	bytes += sizeof(TText) * (TextLength() * 2 + iLines + 2);
sl@0
   276
	bytes += sizeof(TInt16*) * iLines;
sl@0
   277
	bytes = (bytes + 3) & 0xFFFFFFFC;
sl@0
   278
	return reinterpret_cast<TRunInfoCompact*>(
sl@0
   279
		reinterpret_cast<TInt8*>(this) + bytes);
sl@0
   280
	}
sl@0
   281
sl@0
   282
/** 
sl@0
   283
Report if the current character is an explicit line break. Both
sl@0
   284
aText[0] and aText[1] must be part of the string.
sl@0
   285
@return Size of line break.
sl@0
   286
@internalComponent 
sl@0
   287
*/
sl@0
   288
TInt SizeLineBreak(const TText* aText, const TText* aTextEnd)
sl@0
   289
	{
sl@0
   290
	if (aText == aTextEnd )
sl@0
   291
		return 0;
sl@0
   292
		
sl@0
   293
	if (*aText == KLineSeparator || *aText == KParagraphSeparator
sl@0
   294
		|| *aText == KCodeLF)
sl@0
   295
		return 1;
sl@0
   296
	if (aText[0] == KCodeCR)
sl@0
   297
		{
sl@0
   298
		// first check for space before checking for LF
sl@0
   299
		if (aText+1 < aTextEnd )
sl@0
   300
			{
sl@0
   301
			return aText[1] == KCodeLF? 2 : 1;
sl@0
   302
			}
sl@0
   303
		else
sl@0
   304
			return 1;
sl@0
   305
		}
sl@0
   306
	return 0;
sl@0
   307
	}
sl@0
   308
sl@0
   309
/** 
sl@0
   310
Find the next line break character.
sl@0
   311
@internalComponent 
sl@0
   312
*/
sl@0
   313
const TText* FindEndOfThisLine(const TText* aStart, const TText* aEnd)
sl@0
   314
	{
sl@0
   315
	while (aStart != aEnd && *aStart != KLineSeparator
sl@0
   316
		&& *aStart != KParagraphSeparator && *aStart != KCodeLF
sl@0
   317
		&& *aStart != KCodeCR)
sl@0
   318
		++aStart;
sl@0
   319
	return aStart;
sl@0
   320
	}
sl@0
   321
sl@0
   322
/**
sl@0
   323
Count number of lines in text.
sl@0
   324
@internalComponent
sl@0
   325
*/
sl@0
   326
TInt NumberOfLines(const TText* aStart, const TText* aEnd)
sl@0
   327
	{
sl@0
   328
	TInt num = 0;
sl@0
   329
	while (aStart != aEnd)
sl@0
   330
		{
sl@0
   331
		aStart = FindEndOfThisLine(aStart, aEnd);
sl@0
   332
		aStart += SizeLineBreak(aStart, aEnd);
sl@0
   333
		++num;
sl@0
   334
		}
sl@0
   335
	return num;
sl@0
   336
	}
sl@0
   337
sl@0
   338
/** Returns the directionality of a given language.
sl@0
   339
@param aLanguage Language.
sl@0
   340
@return The directionality of the given language. */
sl@0
   341
EXPORT_C TBidiText::TDirectionality TBidiText::ScriptDirectionality(
sl@0
   342
	TLanguage aLanguage)
sl@0
   343
	{
sl@0
   344
	const TUint32 DirectionalityBitmap[] =
sl@0
   345
		{
sl@0
   346
		0,
sl@0
   347
		// Arabic, Farsi, Hebrew
sl@0
   348
		0x02040020,
sl@0
   349
		// Urdu
sl@0
   350
		0x40000000
sl@0
   351
		};
sl@0
   352
	TUint index = aLanguage;
sl@0
   353
	if (index < sizeof(DirectionalityBitmap) * 8)
sl@0
   354
		{
sl@0
   355
		index >>= 5;
sl@0
   356
		TInt bit = aLanguage & 31;
sl@0
   357
		return (DirectionalityBitmap[index] >> bit) & 1?
sl@0
   358
			ERightToLeft : ELeftToRight;
sl@0
   359
		}
sl@0
   360
	return ELeftToRight;
sl@0
   361
	}
sl@0
   362
sl@0
   363
sl@0
   364
/** Reports the implicit directionality of a piece of text.
sl@0
   365
sl@0
   366
@param aText The text to be examined. 
sl@0
   367
@param aFound If non-null, returns ETrue if there were any strongly directional 
sl@0
   368
characters and EFalse if there were none. If a piece of text is spread over 
sl@0
   369
several descriptors, They need to be queried in sequence until one returns 
sl@0
   370
ETrue in aFound. 
sl@0
   371
@return The directionality implicit in aText. 131 */ 
sl@0
   372
EXPORT_C TBidiText::TDirectionality TBidiText::TextDirectionality(
sl@0
   373
	const TDesC& aText, TBool* aFound)
sl@0
   374
	{
sl@0
   375
	return BidiCopy::ImplicitDirectionalityIsRightToLeft(
sl@0
   376
		aText.Ptr(), aText.Length(), aFound)?
sl@0
   377
		ERightToLeft : ELeftToRight;
sl@0
   378
	}
sl@0
   379
sl@0
   380
/** Creates a bidirectional text object with directionality determined by
sl@0
   381
aDirectionality. Use this for text that has come from user input.
sl@0
   382
sl@0
   383
@param aText The text in logical order.
sl@0
   384
@param aMaxLines
sl@0
   385
	The maximum number of lines that this text will need to be split into. Must
sl@0
   386
	be at least 1, but should not be too large, as each potential line takes an
sl@0
   387
	extra 8 bytes of memory.
sl@0
   388
@param aDirectionality Direction to use.
sl@0
   389
@return The newly constructed object.
sl@0
   390
 */
sl@0
   391
EXPORT_C TBidiText* TBidiText::NewL(const TDesC& aText, TInt aMaxLines,
sl@0
   392
	TBidiText::TDirectionality aDirectionality)
sl@0
   393
	{
sl@0
   394
	__ASSERT_ALWAYS(0 < aMaxLines, BidiPanic(EBidiPanic_InvalidMaxline));
sl@0
   395
	const TText* text = aText.Ptr();
sl@0
   396
	const TInt length = aText.Length();
sl@0
   397
	TInt linesInOriginalText = NumberOfLines(text, text + length);
sl@0
   398
	if (aMaxLines < linesInOriginalText)
sl@0
   399
		aMaxLines = linesInOriginalText;
sl@0
   400
sl@0
   401
	const TInt arraySize = TBidirectionalState::GenerateBdRunArray(text, length, 0, 0);
sl@0
   402
	TBidirectionalState::TRunInfo* runInfoArray = new(ELeave) TBidirectionalState::TRunInfo[arraySize];
sl@0
   403
	TCleanupItem ci(DeleteTRunInfo, runInfoArray);
sl@0
   404
	CleanupStack::PushL(ci);
sl@0
   405
	TBidirectionalState::GenerateBdRunArray(text, length, runInfoArray, arraySize);
sl@0
   406
	TBidirectionalState state;
sl@0
   407
	state.ReorderLine(runInfoArray, arraySize, ETrue, ETrue, aDirectionality,
sl@0
   408
		TChar::EOtherNeutral, TChar::EOtherNeutral);
sl@0
   409
	TInt compactArraySize = TRunInfoCompact::Convert(0, aText, runInfoArray, arraySize);
sl@0
   410
sl@0
   411
	// size of TBidiTextImp class
sl@0
   412
	TBidiTextImp* me = TBidiTextImp::NewL(length, aMaxLines, compactArraySize);
sl@0
   413
	me->SetRightToLeftDirectionality(aDirectionality != ELeftToRight);
sl@0
   414
		
sl@0
   415
	TRunInfoCompact::Convert(me->BidiRunArray(), aText, runInfoArray, arraySize);
sl@0
   416
	CleanupStack::PopAndDestroy(runInfoArray);
sl@0
   417
sl@0
   418
	Mem::Copy(me->LogicalText(), text, length * sizeof(TText));
sl@0
   419
	return me;
sl@0
   420
	}
sl@0
   421
sl@0
   422
/** Creates a bidirectional text object with directionality determined by the text 
sl@0
   423
itself. Use this for text that has been obtained from a resource file. 
sl@0
   424
sl@0
   425
@param aText The text in logical order.
sl@0
   426
@param aMaxLines The maximum number of lines that this text will need to be 
sl@0
   427
split into. Must be at least 1, but should not be too large, as each potential 
sl@0
   428
line takes an extra 8 bytes of memory.
sl@0
   429
@return The newly constructed object. */
sl@0
   430
EXPORT_C TBidiText* TBidiText::NewL(const TDesC& aText, TInt aMaxLines)
sl@0
   431
	{
sl@0
   432
	return NewL(aText, aMaxLines, TextDirectionality(aText));
sl@0
   433
	}
sl@0
   434
sl@0
   435
sl@0
   436
/** Creates a bidirectional text object with enough room for up to aReservedMaxLength
sl@0
   437
number of characters. The number of characters that will actually fit (when calling 
sl@0
   438
SetText()) might be slightly less than aReservedMaxLength, as each change between a 
sl@0
   439
left-to-right and a right-to-left sub-string (and the other way around) needs about
sl@0
   440
two characters worth of memory.
sl@0
   441
sl@0
   442
@param aReservedMaxLength The maximum number of characters.
sl@0
   443
@param aMaxLines The maximum number of lines that this text will need to be 
sl@0
   444
split into. Must be at least 1, but should not be too large, as each potential 
sl@0
   445
line takes an extra 8 bytes of memory.
sl@0
   446
@return The newly constructed object. */
sl@0
   447
EXPORT_C TBidiText* TBidiText::NewL(TInt aReservedMaxLength, TInt aMaxLines)
sl@0
   448
	{
sl@0
   449
	__ASSERT_ALWAYS(0 < aReservedMaxLength, BidiPanic(EBidiPanic_InvalidReservedMaxLength));
sl@0
   450
	__ASSERT_ALWAYS(0 < aMaxLines,          BidiPanic(EBidiPanic_InvalidMaxline));
sl@0
   451
	
sl@0
   452
	const TInt compactArraySize = 1;	// Always at least one needed
sl@0
   453
	
sl@0
   454
	TBidiTextImp* me = TBidiTextImp::NewL(aReservedMaxLength, aMaxLines, compactArraySize);
sl@0
   455
	me->SetTextLength(0);	// no text yet, just reserved memory
sl@0
   456
	return me;
sl@0
   457
	}
sl@0
   458
sl@0
   459
/** Sets the text of the bidirectional text object with directionality determined 
sl@0
   460
by the text itself. Use this for text that has been obtained from a resource file. 
sl@0
   461
sl@0
   462
@param aText The text in logical order.
sl@0
   463
@return The number of characters that didn't fit in the available buffer.
sl@0
   464
*/
sl@0
   465
EXPORT_C TInt TBidiText::SetText(const TDesC& aText, RRunInfoArray& aRunInfoArray)
sl@0
   466
	{
sl@0
   467
	return SetText(aText, TextDirectionality(aText), aRunInfoArray);
sl@0
   468
	}
sl@0
   469
sl@0
   470
sl@0
   471
/** Sets the text of the bidirectional text with directionality determined by
sl@0
   472
aDirectionality. Use this for text that has come from user input.
sl@0
   473
sl@0
   474
@param aText The text in logical order.
sl@0
   475
@param aDirectionality Direction to use.
sl@0
   476
@return The number of characters that didn't fit in the available buffer.
sl@0
   477
@panic Bidi EBidiPanic_RunArrayNull The call to RRunInfoArray::OpenL() has not
sl@0
   478
been made prior to this call to TBidiText::SetText()
sl@0
   479
*/
sl@0
   480
EXPORT_C TInt TBidiText::SetText(const TDesC& aText,
sl@0
   481
								 TDirectionality aDirectionality, 
sl@0
   482
								 RRunInfoArray& aRunInfoArray)
sl@0
   483
	{
sl@0
   484
	TBidirectionalState::TRunInfo* const runArray = aRunInfoArray.RunArray();
sl@0
   485
	__ASSERT_ALWAYS(runArray, BidiPanic(EBidiPanic_RunArrayNull));
sl@0
   486
	
sl@0
   487
	TBidiTextImp* me = TBidiTextImp::Imp(this);
sl@0
   488
	const TInt maxLines = me->iLines;	
sl@0
   489
	const TText* text = aText.Ptr();
sl@0
   490
	TInt length = aText.Length();
sl@0
   491
	
sl@0
   492
	TInt requiredArraySize = TBidirectionalState::GenerateBdRunArray(text, length, 0, 0);
sl@0
   493
	const TInt actualArraySize = aRunInfoArray.iTls->MaxArraySize();
sl@0
   494
		
sl@0
   495
	if (requiredArraySize > actualArraySize)
sl@0
   496
		{
sl@0
   497
		// Handle the case where we do not have enough space in the run array
sl@0
   498
		// to cope with the input text. The text will be truncated to ensure
sl@0
   499
		// we don't overrun the buffer and the number of excess characters 
sl@0
   500
		// returned as a negative number.
sl@0
   501
		requiredArraySize = actualArraySize;
sl@0
   502
		TBidirectionalState::GenerateBdRunArray(text, length, runArray, requiredArraySize);
sl@0
   503
		
sl@0
   504
		length = 0;
sl@0
   505
		for (TInt index = 0; index < requiredArraySize; index++)
sl@0
   506
			{
sl@0
   507
			length += runArray[index].iLength;
sl@0
   508
			}
sl@0
   509
		}
sl@0
   510
	else
sl@0
   511
		{
sl@0
   512
		TBidirectionalState::GenerateBdRunArray(text, length, runArray, requiredArraySize);
sl@0
   513
		}
sl@0
   514
	
sl@0
   515
	
sl@0
   516
sl@0
   517
	TBidirectionalState state;
sl@0
   518
	state.ReorderLine(runArray, 
sl@0
   519
					  requiredArraySize, 
sl@0
   520
					  ETrue, 
sl@0
   521
					  ETrue, 
sl@0
   522
					  aDirectionality, 
sl@0
   523
					  TChar::EOtherNeutral, 
sl@0
   524
					  TChar::EOtherNeutral);
sl@0
   525
	const TInt compactArraySize = TRunInfoCompact::Convert(0, 
sl@0
   526
														   aText, 
sl@0
   527
														   runArray, 
sl@0
   528
														   requiredArraySize);
sl@0
   529
sl@0
   530
	// Calculate number of bytes needed to keep text data
sl@0
   531
	TInt requiredBytes = sizeof(TText) * (length * 2 + maxLines * 3); // size of text for logical & visual orderings.
sl@0
   532
	requiredBytes += sizeof(TInt16*) * maxLines;					  // size of line length array
sl@0
   533
	requiredBytes = (requiredBytes + 3) & 0xFFFFFFFC;				  // alignment
sl@0
   534
	
sl@0
   535
	TInt textLength = length;
sl@0
   536
	const TInt excessData = Max(0, requiredBytes - me->AllocatedTextDataBytes());
sl@0
   537
	TInt excessChars = 0;
sl@0
   538
	if(excessData)
sl@0
   539
		{
sl@0
   540
		// Calculate how much text data that can be fitted into the available bytes, 
sl@0
   541
		// given the bytes needed for run array data
sl@0
   542
		excessChars = excessData / (sizeof(TText) * 2);
sl@0
   543
		textLength -= excessChars;
sl@0
   544
		}
sl@0
   545
	else if (aText.Length() > length)
sl@0
   546
		{
sl@0
   547
		excessChars = aText.Length() - length;
sl@0
   548
		}
sl@0
   549
	
sl@0
   550
	me->SetTextLength(textLength);
sl@0
   551
	me->SetRightToLeftDirectionality(aDirectionality != ELeftToRight);			
sl@0
   552
	me->iVisualOrderedTextLength = -1;
sl@0
   553
	me->iBidiRunArrayLength = static_cast<TUint16>(compactArraySize);
sl@0
   554
sl@0
   555
	TRunInfoCompact::Convert(me->BidiRunArray(), aText, runArray, requiredArraySize);
sl@0
   556
	Mem::Copy(me->LogicalText(), text, textLength * sizeof(TText));
sl@0
   557
sl@0
   558
	return excessChars;
sl@0
   559
	}
sl@0
   560
sl@0
   561
/** Sets the character that will be added at the end of the text if the whole text 
sl@0
   562
cannot fit into the space specified. 
sl@0
   563
sl@0
   564
@param aTruncateWith The truncation char. */
sl@0
   565
EXPORT_C void TBidiText::SetTruncationChar(TChar aTruncateWith)
sl@0
   566
	{
sl@0
   567
	TBidiTextImp* me = TBidiTextImp::Imp(this);
sl@0
   568
	me->iTruncationCharPlane = static_cast<TUint8>(aTruncateWith >> 16);
sl@0
   569
	me->iTruncationChar16 = static_cast<TUint16>(aTruncateWith);
sl@0
   570
	}
sl@0
   571
sl@0
   572
TInt RemoveTrailingSpaces(const MLineBreaker* aBreaker,
sl@0
   573
	const TText* aInput, TInt aMinPos, TInt aEndPos)
sl@0
   574
	{
sl@0
   575
	// Ignore space characters at the end of the line.
sl@0
   576
	// Don't bother to ignore spaces made of surrogate pairs:
sl@0
   577
	// more processing than it's worth.
sl@0
   578
	TUint dummy1, dummy2;
sl@0
   579
	while (aEndPos != aMinPos && MLineBreaker::ESpLineBreakClass
sl@0
   580
		== aBreaker->LineBreakClass(aInput[aEndPos - 1], dummy1, dummy2))
sl@0
   581
		{
sl@0
   582
		--aEndPos;
sl@0
   583
		}
sl@0
   584
	return aEndPos;
sl@0
   585
	}
sl@0
   586
sl@0
   587
/** Prepares the visually-ordered text according to the wrapping width and font
sl@0
   588
specified. Text cannot be drawn until this has been done.
sl@0
   589
@param aWrappingWidth
sl@0
   590
	The maximum width of the text in pixels. Note that this distance should be
sl@0
   591
	slightly less than the available width to allow for characters such as "W"
sl@0
   592
	which can have side-bearings that leak into the margins.
sl@0
   593
@param aFont The font that will provide the character metrics.
sl@0
   594
@param aBreaker
sl@0
   595
	An object for breaking the lines. May be NULL for default behaviour.
sl@0
   596
@param aMaxLines
sl@0
   597
	Number of lines to restrict wrapping to. The truncation character will be
sl@0
   598
	used if the text is too long for this number of lines. The number of lines
sl@0
   599
	wrapped to may not be greater than the figure passed to NewL.
sl@0
   600
*/
sl@0
   601
EXPORT_C void TBidiText::WrapText(TInt aWrappingWidth, const CFont& aFont,
sl@0
   602
	const MLineBreaker* aBreaker, TInt aMaxLines)
sl@0
   603
	{
sl@0
   604
	TBidiTextImp* me = TBidiTextImp::Imp(this);
sl@0
   605
	me->iWrappingWidth = aWrappingWidth;
sl@0
   606
	
sl@0
   607
	TInt16* lineWidths = me->LineWidthArray();
sl@0
   608
	TText* output = me->VisualText();
sl@0
   609
	
sl@0
   610
	TInt numLines = 0;
sl@0
   611
	DoWrapText(aWrappingWidth, aFont, aBreaker, aMaxLines, output, numLines, lineWidths);	
sl@0
   612
	me->iVisualOrderedTextLength = output - me->VisualText();
sl@0
   613
	}
sl@0
   614
sl@0
   615
/** Calculate the minimum size needed to draw the current text, given the specified
sl@0
   616
wrapping width, font, and line gap. Calling this method will not rewrap the object's
sl@0
   617
text.
sl@0
   618
sl@0
   619
@param aWrappingWidth
sl@0
   620
	The maximum width of the text in pixels. Note that this distance should be
sl@0
   621
	slightly less than the available width to allow for characters such as "W"
sl@0
   622
	which can have side-bearings that leak into the margins.
sl@0
   623
@param aFont The font that will provide the character metrics.
sl@0
   624
@param aLineGap The number of empty pixels between two lines of text. 
sl@0
   625
	Note that this is not the same as the baseline spacing, which is the font 
sl@0
   626
	height plus the line gap.
sl@0
   627
@param aMaxLines
sl@0
   628
	Number of lines to restrict wrapping to. The truncation character will be
sl@0
   629
	used if the text is too long for this number of lines. The number of lines
sl@0
   630
	wrapped to may be greater than the figure passed to NewL, and that figure
sl@0
   631
	will be used if the number of lines is specified as -1. If 0 (zero) is specified
sl@0
   632
	no limit is applied.
sl@0
   633
@param aBreaker
sl@0
   634
	An object for breaking the lines. May be NULL for default behaviour.
sl@0
   635
*/
sl@0
   636
EXPORT_C TSize TBidiText::MinimumSize(TInt aWrappingWidth, const CFont& aFont, TInt aLineGap, 
sl@0
   637
									TInt aMaxLines, const MLineBreaker* aBreaker) const
sl@0
   638
	{
sl@0
   639
	__ASSERT_ALWAYS(0  <= aWrappingWidth, BidiPanic(EBidiPanic_InvalidWrappingWidth));
sl@0
   640
	__ASSERT_ALWAYS(0  <=  aLineGap,       BidiPanic(EBidiPanic_InvalidLineGap));
sl@0
   641
	__ASSERT_ALWAYS(-1 <= aMaxLines,      BidiPanic(EBidiPanic_InvalidMaxline));
sl@0
   642
sl@0
   643
	TInt numLines = 0;
sl@0
   644
	TText* output = NULL;
sl@0
   645
	const TInt minWidth = DoWrapText(aWrappingWidth, 
sl@0
   646
									 aFont, 
sl@0
   647
									 aBreaker, 
sl@0
   648
									 (aMaxLines = 0 ? KMaxTInt : aMaxLines), 
sl@0
   649
									 output, 
sl@0
   650
									 numLines, 
sl@0
   651
									 NULL);
sl@0
   652
	const TInt minHeight = (aFont.FontMaxHeight() + aLineGap) * numLines - aLineGap; 
sl@0
   653
	return TSize(minWidth, minHeight);	
sl@0
   654
	}
sl@0
   655
sl@0
   656
sl@0
   657
TInt TBidiText::DoWrapText(TInt aWrappingWidth, const CFont& aFont, const MLineBreaker* aBreaker, 
sl@0
   658
	TInt aMaxLines, TText*& aOutputText, TInt& aNumLines, TInt16* aLineWidthArray) const
sl@0
   659
	{
sl@0
   660
	MLineBreaker defaultBreaker;
sl@0
   661
	if (!aBreaker)
sl@0
   662
		aBreaker = &defaultBreaker;
sl@0
   663
	
sl@0
   664
	const TBidiTextImp* me = TBidiTextImp::Imp(this);
sl@0
   665
	if (me->iLines < aMaxLines)
sl@0
   666
		aMaxLines = me->iLines;
sl@0
   667
	
sl@0
   668
	const TRunInfoCompact* runArray = me->BidiRunArray();	
sl@0
   669
	const TRunInfoCompact* runArrayEnd = runArray + me->iBidiRunArrayLength;
sl@0
   670
	
sl@0
   671
	const TText* input = me->LogicalText();
sl@0
   672
	const TInt inputLength = me->TextLength();
sl@0
   673
	TPtrC textDes(input, inputLength);
sl@0
   674
	const TText* output = me->VisualText();
sl@0
   675
sl@0
   676
	TRunInfoCompact::TReorderingContext context;
sl@0
   677
	context.iSource = input;
sl@0
   678
	context.iTruncation = 0xFFFF;
sl@0
   679
	context.iJoinsAtEnd = EFalse;
sl@0
   680
	
sl@0
   681
	TInt start = 0;
sl@0
   682
	CFont::TMeasureTextInput measureInput;
sl@0
   683
	measureInput.iMaxAdvance = aWrappingWidth;
sl@0
   684
	measureInput.iEndInputChar = FindEndOfThisLine(input, input + inputLength) - input;
sl@0
   685
	CFont::TMeasureTextOutput measureOutput;
sl@0
   686
	TBool truncated;
sl@0
   687
sl@0
   688
	TInt widestLineWidth = 0;
sl@0
   689
	TBool bLastLine = EFalse;
sl@0
   690
	for (aNumLines = 0; aNumLines != aMaxLines && start < inputLength; ++aNumLines)
sl@0
   691
		{
sl@0
   692
		truncated=EFalse;
sl@0
   693
		context.iJoinsAtStart = context.iJoinsAtEnd;
sl@0
   694
		if(aNumLines != 0 && aOutputText)
sl@0
   695
			*(aOutputText++) = KLineSeparator;
sl@0
   696
		
sl@0
   697
		measureInput.iStartInputChar = start;
sl@0
   698
		TInt advance = aFont.MeasureText(textDes, &measureInput, &measureOutput);
sl@0
   699
		TInt breakPos = measureOutput.iChars;
sl@0
   700
		TInt endOfLine = breakPos;
sl@0
   701
		// truncationCharWidth is the width of any truncation character on this
sl@0
   702
		// line only.
sl@0
   703
		TInt truncationCharWidth = 0;
sl@0
   704
		if (endOfLine == measureInput.iEndInputChar)
sl@0
   705
			{
sl@0
   706
			//handle the dangling lines here
sl@0
   707
			TInt sizeLineBreak = SizeLineBreak(input + endOfLine, input + inputLength);
sl@0
   708
			if((measureInput.iEndInputChar < inputLength - sizeLineBreak) && (aNumLines == aMaxLines - 1))
sl@0
   709
				bLastLine = ETrue;
sl@0
   710
			}
sl@0
   711
		else if (aNumLines == aMaxLines - 1)
sl@0
   712
			{
sl@0
   713
			bLastLine = ETrue;
sl@0
   714
			}
sl@0
   715
		else 
sl@0
   716
			{ // Not last line, so find a legal line break.
sl@0
   717
			aBreaker->GetLineBreak(textDes, 
sl@0
   718
								   start + 1, 
sl@0
   719
								   measureOutput.iChars, 
sl@0
   720
								   EFalse, 
sl@0
   721
								   0, 
sl@0
   722
								   breakPos, 
sl@0
   723
								   endOfLine);
sl@0
   724
			}
sl@0
   725
sl@0
   726
		if (bLastLine)
sl@0
   727
			{
sl@0
   728
			// Last line, so re-measure leaving enough room for
sl@0
   729
			// truncation character.
sl@0
   730
			context.iTruncation = me->TruncationChar();
sl@0
   731
			truncationCharWidth = aFont.CharWidthInPixels(context.iTruncation);
sl@0
   732
			measureInput.iMaxAdvance = aWrappingWidth - truncationCharWidth;
sl@0
   733
			advance = aFont.MeasureText(textDes, &measureInput, &measureOutput) + truncationCharWidth;
sl@0
   734
			breakPos = RemoveTrailingSpaces(aBreaker, input, start, measureOutput.iChars);
sl@0
   735
			truncated=ETrue;
sl@0
   736
			bLastLine = EFalse;
sl@0
   737
			}
sl@0
   738
sl@0
   739
		// if the break position has changed, we need to remeasure
sl@0
   740
		if (breakPos != measureOutput.iChars)
sl@0
   741
			{
sl@0
   742
			const TInt oldEnd = measureInput.iEndInputChar;
sl@0
   743
			measureInput.iEndInputChar = breakPos;
sl@0
   744
			advance = aFont.MeasureText(textDes, &measureInput, &measureOutput) + truncationCharWidth;
sl@0
   745
			measureInput.iEndInputChar = oldEnd;
sl@0
   746
			truncated=ETrue;
sl@0
   747
			}
sl@0
   748
sl@0
   749
		//width may be greater than advance
sl@0
   750
		advance = Max(advance,measureOutput.iBounds.Width());
sl@0
   751
sl@0
   752
		if(widestLineWidth < advance)
sl@0
   753
			widestLineWidth = advance;
sl@0
   754
		
sl@0
   755
		if(aLineWidthArray)
sl@0
   756
			*(aLineWidthArray++) = static_cast<TInt16>(advance);
sl@0
   757
sl@0
   758
		context.iStart = start;
sl@0
   759
		context.iEnd = breakPos;
sl@0
   760
		if (truncated)
sl@0
   761
			{
sl@0
   762
			context.iJoinsAtEnd = breakPos < inputLength?
sl@0
   763
				TRunInfoCompact::JoinBefore(input, breakPos) : EFalse;
sl@0
   764
			}
sl@0
   765
		else
sl@0
   766
			{
sl@0
   767
			context.iJoinsAtEnd = endOfLine < inputLength?
sl@0
   768
				TRunInfoCompact::JoinBefore(input, endOfLine) : EFalse;
sl@0
   769
			}
sl@0
   770
		if (aOutputText)
sl@0
   771
			{
sl@0
   772
			for (const TRunInfoCompact* p = runArray; p != runArrayEnd; ++p)
sl@0
   773
				aOutputText = p->Reorder(aOutputText, context);
sl@0
   774
			}
sl@0
   775
		// Set 'start' to the beginning of the next line...
sl@0
   776
		start = endOfLine;
sl@0
   777
		
sl@0
   778
		// ...move it past any line break...
sl@0
   779
		const TInt sizeOfLineBreak = SizeLineBreak(input + start, input + inputLength);
sl@0
   780
		if (sizeOfLineBreak != 0)
sl@0
   781
			{
sl@0
   782
			start += sizeOfLineBreak;
sl@0
   783
			// ...and find the end of this next line.
sl@0
   784
			const TText* endLine = FindEndOfThisLine(input + start, input + inputLength);
sl@0
   785
			measureInput.iEndInputChar = endLine - input;
sl@0
   786
			}
sl@0
   787
		}
sl@0
   788
		
sl@0
   789
	return widestLineWidth;	
sl@0
   790
	}
sl@0
   791
sl@0
   792
sl@0
   793
/** Prepares the visually-ordered text according to the wrapping width and font 
sl@0
   794
specified. Text cannot be drawn until this has been done. 
sl@0
   795
sl@0
   796
@param aWrappingWidth The maximum width of the text in pixels. Note that this 
sl@0
   797
distance should be slightly less than the available width to allow for characters 
sl@0
   798
such as "W" which can have side-bearings that leak into the margins.
sl@0
   799
@param aFont The font that will provide the character metrics.
sl@0
   800
@param aBreaker An object for breaking the lines. May be NULL for default behaviour. */
sl@0
   801
EXPORT_C void TBidiText::WrapText(TInt aWrappingWidth, const CFont& aFont,
sl@0
   802
	const MLineBreaker* aBreaker)
sl@0
   803
	{
sl@0
   804
	WrapText(aWrappingWidth, aFont, aBreaker, KMaxTInt);
sl@0
   805
	}
sl@0
   806
sl@0
   807
/** Returns the original logically-ordered text supplied in the constructor. 
sl@0
   808
@return The original logically-ordered text supplied in the constructor. */
sl@0
   809
EXPORT_C TPtrC TBidiText::Text() const
sl@0
   810
	{
sl@0
   811
	const TBidiTextImp* me = TBidiTextImp::Imp(this);
sl@0
   812
	const TText* text = me->LogicalText();
sl@0
   813
	return TPtrC(text, me->TextLength());
sl@0
   814
	}
sl@0
   815
sl@0
   816
/** Returns the text as prepared for display, provided that WrapText has been called. 
sl@0
   817
If WrapText has not been called, a panic will result. 
sl@0
   818
sl@0
   819
@return The text as prepared for display */
sl@0
   820
EXPORT_C TPtrC TBidiText::DisplayText() const
sl@0
   821
	{
sl@0
   822
	const TBidiTextImp* me = TBidiTextImp::Imp(this);
sl@0
   823
	__ASSERT_ALWAYS(me->iVisualOrderedTextLength >= 0, BidiPanic(EBidiPanic_InvalidVisualOrderedTextLength));
sl@0
   824
	const TText* text = me->VisualText();
sl@0
   825
	return TPtrC(text, me->iVisualOrderedTextLength);
sl@0
   826
	}
sl@0
   827
sl@0
   828
/** Returns the wrapping width previously supplied to WrapText. 
sl@0
   829
sl@0
   830
@return The wrapping. */
sl@0
   831
EXPORT_C TInt TBidiText::WrappingWidth() const
sl@0
   832
	{
sl@0
   833
	const TBidiTextImp* me = TBidiTextImp::Imp(this);
sl@0
   834
	return me->iWrappingWidth;
sl@0
   835
	}
sl@0
   836
sl@0
   837
/** Returns the directionality of the text. 
sl@0
   838
sl@0
   839
@return The directionality. */
sl@0
   840
EXPORT_C TBidiText::TDirectionality TBidiText::Directionality() const
sl@0
   841
	{
sl@0
   842
	const TBidiTextImp* me = TBidiTextImp::Imp(this);
sl@0
   843
	return me->HasRightToLeftDirectionality() ? ERightToLeft : ELeftToRight;
sl@0
   844
	}
sl@0
   845
sl@0
   846
/** Returns the truncation character used. 
sl@0
   847
sl@0
   848
@return The truncation character. */
sl@0
   849
EXPORT_C TChar TBidiText::TruncationChar() const
sl@0
   850
	{
sl@0
   851
	const TBidiTextImp* me = TBidiTextImp::Imp(this);
sl@0
   852
	return me->TruncationChar();
sl@0
   853
	}
sl@0
   854
sl@0
   855
/** Reports the number of lines in the text to be drawn.
sl@0
   856
sl@0
   857
WrapText must have been called already.
sl@0
   858
@return
sl@0
   859
	The number of lines in the text which would be drawn by DrawText.
sl@0
   860
*/
sl@0
   861
EXPORT_C TInt TBidiText::NumberOfLinesInDisplayText() const
sl@0
   862
	{
sl@0
   863
	const TBidiTextImp* me = TBidiTextImp::Imp(this);
sl@0
   864
	if (me->iVisualOrderedTextLength <0)
sl@0
   865
		{
sl@0
   866
		return 0;
sl@0
   867
		}
sl@0
   868
	const TText* text = me->VisualText();
sl@0
   869
	const TText* textEnd = text + me->iVisualOrderedTextLength;
sl@0
   870
	return NumberOfLines(text, textEnd);
sl@0
   871
	}
sl@0
   872
sl@0
   873
/** Returns the text as prepared for display, provided that WrapText has been called. 
sl@0
   874
If WrapText has not been called, a panic will result. 
sl@0
   875
@param aLine Line number to retrieve.
sl@0
   876
@param aWidth Returns the width in pixels of the line retrieved.
sl@0
   877
@return The text as prepared for display. */
sl@0
   878
EXPORT_C TPtrC TBidiText::LineOfDisplayText(TInt aLine, TInt& aWidthInPixels) const
sl@0
   879
	{
sl@0
   880
	const TBidiTextImp* me = TBidiTextImp::Imp(this);
sl@0
   881
	__ASSERT_ALWAYS(me->iVisualOrderedTextLength >= 0, BidiPanic(EBidiPanic_InvalidVisualOrderedTextLength));
sl@0
   882
	__ASSERT_ALWAYS(0 <= aLine && aLine < me->iLines, BidiPanic(EBidiPanic_InvalidLineNumber));
sl@0
   883
	aWidthInPixels = me->LineWidthArray()[aLine];
sl@0
   884
	const TText* text = me->VisualText();
sl@0
   885
	const TText* textEnd = text + me->iVisualOrderedTextLength;
sl@0
   886
	for (; aLine != 0; --aLine)
sl@0
   887
		{
sl@0
   888
		text = FindEndOfThisLine(text, textEnd);
sl@0
   889
		text += SizeLineBreak(text, textEnd);
sl@0
   890
		}
sl@0
   891
	const TText* endOfLine = FindEndOfThisLine(text, textEnd);
sl@0
   892
	return TPtrC(text, endOfLine - text);
sl@0
   893
	}
sl@0
   894
sl@0
   895
/** Draws all of the text. WrapText must have been called already. 
sl@0
   896
sl@0
   897
@param aGc The graphics context to draw the text to. The graphics context's 
sl@0
   898
font is assumed to have been set to the same font that was passed to the previous 
sl@0
   899
call to WrapText.
sl@0
   900
@param aLeft The left extreme of the baseline. Note that this should not be 
sl@0
   901
at the very edge of the available space, or characters such as "W" with left 
sl@0
   902
side bearings may be truncated.
sl@0
   903
@param aBaseLineSpacing The spacing between each line. If 0, only the first 
sl@0
   904
line is drawn.
sl@0
   905
@param aAlignment How to position the text horizontally. */
sl@0
   906
EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft,
sl@0
   907
	TInt aBaseLineSpacing, CGraphicsContext::TTextAlign aAlignment) const
sl@0
   908
	{
sl@0
   909
	TPoint origin;
sl@0
   910
	origin.iY = aLeft.iY;
sl@0
   911
	TInt lines = aBaseLineSpacing == 0? 1 : NumberOfLinesInDisplayText();
sl@0
   912
	TInt wrappingWidth = WrappingWidth();
sl@0
   913
	for (TInt i = 0; i != lines; ++i)
sl@0
   914
		{
sl@0
   915
		TInt width;
sl@0
   916
		TPtrC textLine = LineOfDisplayText(i, width);
sl@0
   917
		origin.iX = aLeft.iX;
sl@0
   918
		if (aAlignment != CGraphicsContext::ELeft)
sl@0
   919
			{
sl@0
   920
			TInt excess = wrappingWidth - width;
sl@0
   921
			origin.iX += aAlignment != CGraphicsContext::ECenter?
sl@0
   922
				excess : excess >> 1;
sl@0
   923
			}
sl@0
   924
		aGc.DrawText(textLine, origin);
sl@0
   925
		origin.iY += aBaseLineSpacing;
sl@0
   926
		}
sl@0
   927
	}
sl@0
   928
sl@0
   929
/** Draws all of the text. Alignment is taken from the directionality of the text. 
sl@0
   930
WrapText must have been called already. 
sl@0
   931
sl@0
   932
@param aGc The graphics context to draw the text to. The graphics context's 
sl@0
   933
font is assumed to have been set to the same font that was passed to the previous 
sl@0
   934
call to WrapText.
sl@0
   935
@param aLeft The left extreme of the baseline. Note that this should not be 
sl@0
   936
at the very edge of the available space, or characters such as "W" with left 
sl@0
   937
side bearings may be truncated.
sl@0
   938
@param aBaseLineSpacing The spacing between each line. If 0, only the first 
sl@0
   939
line is drawn. */
sl@0
   940
EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft,
sl@0
   941
	TInt aBaseLineSpacing) const
sl@0
   942
	{
sl@0
   943
	DrawText(aGc, aLeft, aBaseLineSpacing,
sl@0
   944
		Directionality() == ELeftToRight?
sl@0
   945
		CGraphicsContext::ELeft : CGraphicsContext::ERight);
sl@0
   946
	}
sl@0
   947
sl@0
   948
/** Draws the first line of the text. WrapText must have been called already. Alignment 
sl@0
   949
is taken from the directionality of the text. 
sl@0
   950
sl@0
   951
@param aGc The graphics context to draw the text to. The graphics context's 
sl@0
   952
font is assumed to have been set to the same font that was passed to the previous 
sl@0
   953
call to WrapText.
sl@0
   954
@param aLeft The left extreme of the baseline. Note that this should not be 
sl@0
   955
at the very edge of the available space, or characters such as "W" with left 
sl@0
   956
side bearings may be truncated. */
sl@0
   957
EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft) const
sl@0
   958
	{
sl@0
   959
	DrawText(aGc, aLeft, 0);
sl@0
   960
	}
sl@0
   961