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