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.
     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