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