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