os/graphics/graphicsdeviceinterface/gdi/sgdi/BidiText.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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