1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/textandloc/fontservices/textbase/sgdi/BidiText.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,962 @@
1.4 +// Copyright (c) 2002-2010 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include <e32svr.h>
1.20 +#include "BidiTextImp.h"
1.21 +#include "BidiCopy.h"
1.22 +#include "BidiCompact.h"
1.23 +#include <bidi.h>
1.24 +#include <e32base.h>
1.25 +//#include <textbase.h>
1.26 +#include <gdi.h>
1.27 +#include <linebreak.h>
1.28 +
1.29 +_LIT(KBidiPanicCategory,"Bidi");
1.30 +static const TInt KLineSeparator = 0x2028;
1.31 +static const TInt KParagraphSeparator = 0x2029;
1.32 +static const TInt KCodeCR = 0x000D;
1.33 +static const TInt KCodeLF = 0x000A;
1.34 +static const TInt KCodeEllipsis = 0x2026;
1.35 +
1.36 +void DeleteTRunInfo(void* aRunInfo)
1.37 + {
1.38 + delete[] reinterpret_cast<TBidirectionalState::TRunInfo*>(aRunInfo);
1.39 + }
1.40 +
1.41 +void BidiPanic(TInt aError)
1.42 + {
1.43 + User::Panic(KBidiPanicCategory, aError);
1.44 + }
1.45 +
1.46 +
1.47 +// One page-full of TRunInfos
1.48 +const TInt KMaxRunInfoArraySize = 4*1024 / sizeof(TBidirectionalState::TRunInfo);
1.49 +const TInt KBidiTlsHandle = 0x101F633D;
1.50 +
1.51 +
1.52 +/*
1.53 +* Ref-counted TLS for the shared run info array used by the SetText() method.
1.54 +*/
1.55 +NONSHARABLE_CLASS(CBidiTextTls) : public CObject
1.56 + {
1.57 +public:
1.58 + static CBidiTextTls* NewL();
1.59 + static CBidiTextTls* GetTls();
1.60 + ~CBidiTextTls();
1.61 + inline TUint MaxArraySize();
1.62 + inline TBidirectionalState::TRunInfo* RunArray();
1.63 +
1.64 +private:
1.65 + CBidiTextTls();
1.66 + void ConstructL(TUint aMaxArraySize);
1.67 +
1.68 +private:
1.69 + TBidirectionalState::TRunInfo* iRunInfoArray;
1.70 + TUint iMaxArraySize;
1.71 + };
1.72 +
1.73 +
1.74 +
1.75 +CBidiTextTls::CBidiTextTls()
1.76 +: iRunInfoArray(NULL),
1.77 + iMaxArraySize(0)
1.78 + {
1.79 + }
1.80 +
1.81 +
1.82 +CBidiTextTls::~CBidiTextTls()
1.83 + {
1.84 + UserSvr::DllFreeTls(KBidiTlsHandle);
1.85 +
1.86 + if (iRunInfoArray)
1.87 + {
1.88 + delete [] iRunInfoArray;
1.89 + }
1.90 + }
1.91 +
1.92 +
1.93 +TUint CBidiTextTls::MaxArraySize()
1.94 + {
1.95 + return iMaxArraySize;
1.96 + }
1.97 +
1.98 +
1.99 +TBidirectionalState::TRunInfo* CBidiTextTls::RunArray()
1.100 + {
1.101 + return iRunInfoArray;
1.102 + }
1.103 +
1.104 +
1.105 +/**
1.106 + * Helper function provided to simplify reading the TLS data and improve the
1.107 + * readability of the code
1.108 + */
1.109 +CBidiTextTls* CBidiTextTls::GetTls()
1.110 + {
1.111 + return reinterpret_cast<CBidiTextTls*>(UserSvr::DllTls(KBidiTlsHandle));
1.112 + }
1.113 +
1.114 +
1.115 +CBidiTextTls* CBidiTextTls::NewL()
1.116 + {
1.117 + CBidiTextTls* self = new (ELeave) CBidiTextTls;
1.118 + CleanupClosePushL(*self);
1.119 + self->ConstructL(KMaxRunInfoArraySize);
1.120 + CleanupStack::Pop(self);
1.121 + return self;
1.122 + }
1.123 +
1.124 +
1.125 +void CBidiTextTls::ConstructL(TUint aMaxArraySize)
1.126 + {
1.127 + iMaxArraySize = aMaxArraySize;
1.128 + iRunInfoArray = new (ELeave) TBidirectionalState::TRunInfo[aMaxArraySize];
1.129 + User::LeaveIfError(UserSvr::DllSetTls(KBidiTlsHandle, this));
1.130 + }
1.131 +
1.132 +
1.133 +EXPORT_C RRunInfoArray::RRunInfoArray()
1.134 +: iTls(NULL)
1.135 + {
1.136 + }
1.137 +
1.138 +
1.139 +/**
1.140 +Creates the run array if necessary and increases the reference count on it.
1.141 +RRunInfoArray::OpenL() must be called prior to calling TBidiText::SetText().
1.142 + */
1.143 +EXPORT_C void RRunInfoArray::OpenL()
1.144 + {
1.145 + if(!iTls)
1.146 + {
1.147 + iTls = CBidiTextTls::GetTls();
1.148 + if(iTls)
1.149 + {
1.150 + iTls->Open(); // Increase ref count
1.151 + }
1.152 + else
1.153 + {
1.154 + iTls = CBidiTextTls::NewL();
1.155 + }
1.156 + }
1.157 + }
1.158 +
1.159 +
1.160 +/**
1.161 +Decreases the reference count on the run array. The run array will be deleted
1.162 +if the reference count reaches zero. The client application must ensure that
1.163 +there is a matching call to Close() for every call to OpenL() or memory will
1.164 +be leaked.
1.165 + */
1.166 +EXPORT_C void RRunInfoArray::Close()
1.167 + {
1.168 + if(iTls)
1.169 + {
1.170 + iTls->Close();
1.171 + iTls = NULL;
1.172 + }
1.173 + }
1.174 +
1.175 +
1.176 +/**
1.177 +@return Pointer to the run array buffer
1.178 +@internalComponent
1.179 + */
1.180 +TBidirectionalState::TRunInfo* RRunInfoArray::RunArray() const
1.181 + {
1.182 + return iTls ? iTls->RunArray() : NULL;
1.183 + }
1.184 +
1.185 +
1.186 +/**
1.187 +@return Number of bytes needed to hold the TBidiTextImp member variables, plus the
1.188 + text data allocated off the end of the TBidiTextImp object.
1.189 +@internalComponent
1.190 +*/
1.191 +TInt TBidiTextImp::RequiredBytes(TInt aLength, TInt aMaxLines, TInt aBdRunArraySize)
1.192 + {
1.193 + // size of TBidiTextImp class
1.194 + TInt bytes = TBidiTextImp::AlignedSizeOf();
1.195 + // size of text for logical and visual orderings.
1.196 + // This includes aMaxLines - 1 line breaks with surrounding
1.197 + // zero-width joiners, and a truncation character (possibly
1.198 + // a surrogate pair) plus a zero-width joiner.
1.199 + bytes += sizeof(TText) * (aLength * 2 + aMaxLines * 3);
1.200 + // size of line length array
1.201 + bytes += sizeof(TInt16*) * aMaxLines;
1.202 + // alignment
1.203 + bytes = (bytes + 3) & 0xFFFFFFFC;
1.204 + // array of TRunInfoCompact
1.205 + bytes += sizeof(TRunInfoCompact) * aBdRunArraySize;
1.206 +
1.207 + return bytes;
1.208 + }
1.209 +
1.210 +
1.211 +/**
1.212 +@return A TBidiTextImp object of sufficient size to hold the amount of text data specified
1.213 + by the the arguments.
1.214 +@param aLength The number of characters in the text.
1.215 +@param aMaxLines The maximum number of lines
1.216 +@param aBdRunArraySize The size of the bidi run array.
1.217 +@internalComponent
1.218 +*/
1.219 +TBidiTextImp* TBidiTextImp::NewL(TInt aLength, TInt aMaxLines, TInt aBdRunArraySize)
1.220 + {
1.221 + const TInt bytes = RequiredBytes(aLength, aMaxLines, aBdRunArraySize);
1.222 + TInt8* mem = static_cast<TInt8*>(User::AllocL(bytes));
1.223 + TBidiTextImp* me = reinterpret_cast<TBidiTextImp*>(mem);
1.224 +
1.225 + me->iTextLengthAndFlags = aLength;
1.226 + me->iVisualOrderedTextLength = -1;
1.227 + me->iWrappingWidth = 0xFFFF;
1.228 + me->iBidiRunArrayLength = aBdRunArraySize;
1.229 + me->iLines = static_cast<TUint8>(aMaxLines);
1.230 + me->iTruncationCharPlane = 0;
1.231 + me->iTruncationChar16 = KCodeEllipsis;
1.232 + me->SetAllocatedTextDataBytes(bytes - TBidiTextImp::AlignedSizeOf() - (sizeof(TRunInfoCompact) * aBdRunArraySize));
1.233 + return me;
1.234 + }
1.235 +
1.236 +/**
1.237 +@return Position of logically-ordered text portion of the heap cell.
1.238 +@internalComponent
1.239 +*/
1.240 +TText* TBidiTextImp::LogicalText()
1.241 + {
1.242 + return reinterpret_cast<TText*>(
1.243 + reinterpret_cast<TInt8*>(this)
1.244 + + TBidiTextImp::AlignedSizeOf());
1.245 + }
1.246 +
1.247 +/**
1.248 +@return Position of visually-ordered text portion of the heap cell.
1.249 +@internalComponent
1.250 +*/
1.251 +TText* TBidiTextImp::VisualText()
1.252 + {
1.253 + TInt bytes = TBidiTextImp::AlignedSizeOf();
1.254 + bytes += sizeof(TText) * TextLength();
1.255 + return reinterpret_cast<TText*>(
1.256 + reinterpret_cast<TInt8*>(this) + bytes);
1.257 + }
1.258 +
1.259 +/**
1.260 +Returns a pointer to the array containing the width in pixels of each and every line.
1.261 +@return Position of the array of line widths portion of the heap cell.
1.262 +@internalComponent
1.263 +*/
1.264 +TInt16* TBidiTextImp::LineWidthArray()
1.265 + {
1.266 + TInt bytes = TBidiTextImp::AlignedSizeOf();
1.267 + bytes += sizeof(TText) * (TextLength() * 2 + iLines + 2);
1.268 + return reinterpret_cast<TInt16*>(
1.269 + reinterpret_cast<TInt8*>(this) + bytes);
1.270 + }
1.271 +
1.272 +/**
1.273 +@return Position of the array of runs portion of the heap cell.
1.274 +@internalComponent
1.275 +*/
1.276 +TRunInfoCompact* TBidiTextImp::BidiRunArray()
1.277 + {
1.278 + TInt bytes = TBidiTextImp::AlignedSizeOf();
1.279 + bytes += sizeof(TText) * (TextLength() * 2 + iLines + 2);
1.280 + bytes += sizeof(TInt16*) * iLines;
1.281 + bytes = (bytes + 3) & 0xFFFFFFFC;
1.282 + return reinterpret_cast<TRunInfoCompact*>(
1.283 + reinterpret_cast<TInt8*>(this) + bytes);
1.284 + }
1.285 +
1.286 +/**
1.287 +Report if the current character is an explicit line break. Both
1.288 +aText[0] and aText[1] must be part of the string.
1.289 +@return Size of line break.
1.290 +@internalComponent
1.291 +*/
1.292 +TInt SizeLineBreak(const TText* aText, const TText* aTextEnd)
1.293 + {
1.294 + if (aText == aTextEnd )
1.295 + return 0;
1.296 +
1.297 + if (*aText == KLineSeparator || *aText == KParagraphSeparator
1.298 + || *aText == KCodeLF)
1.299 + return 1;
1.300 + if (aText[0] == KCodeCR)
1.301 + {
1.302 + // first check for space before checking for LF
1.303 + if (aText+1 < aTextEnd )
1.304 + {
1.305 + return aText[1] == KCodeLF? 2 : 1;
1.306 + }
1.307 + else
1.308 + return 1;
1.309 + }
1.310 + return 0;
1.311 + }
1.312 +
1.313 +/**
1.314 +Find the next line break character.
1.315 +@internalComponent
1.316 +*/
1.317 +const TText* FindEndOfThisLine(const TText* aStart, const TText* aEnd)
1.318 + {
1.319 + while (aStart != aEnd && *aStart != KLineSeparator
1.320 + && *aStart != KParagraphSeparator && *aStart != KCodeLF
1.321 + && *aStart != KCodeCR)
1.322 + ++aStart;
1.323 + return aStart;
1.324 + }
1.325 +
1.326 +/**
1.327 +Count number of lines in text.
1.328 +@internalComponent
1.329 +*/
1.330 +TInt NumberOfLines(const TText* aStart, const TText* aEnd)
1.331 + {
1.332 + TInt num = 0;
1.333 + while (aStart != aEnd)
1.334 + {
1.335 + aStart = FindEndOfThisLine(aStart, aEnd);
1.336 + aStart += SizeLineBreak(aStart, aEnd);
1.337 + ++num;
1.338 + }
1.339 + return num;
1.340 + }
1.341 +
1.342 +/** Returns the directionality of a given language.
1.343 +@param aLanguage Language.
1.344 +@return The directionality of the given language. */
1.345 +EXPORT_C TBidiText::TDirectionality TBidiText::ScriptDirectionality(
1.346 + TLanguage aLanguage)
1.347 + {
1.348 + const TUint32 DirectionalityBitmap[] =
1.349 + {
1.350 + 0,
1.351 + // Arabic, Farsi, Hebrew
1.352 + 0x02040020,
1.353 + // Urdu
1.354 + 0x40000000
1.355 + };
1.356 + TUint index = aLanguage;
1.357 + if (index < sizeof(DirectionalityBitmap) * 8)
1.358 + {
1.359 + index >>= 5;
1.360 + TInt bit = aLanguage & 31;
1.361 + return (DirectionalityBitmap[index] >> bit) & 1?
1.362 + ERightToLeft : ELeftToRight;
1.363 + }
1.364 + return ELeftToRight;
1.365 + }
1.366 +
1.367 +
1.368 +/** Reports the implicit directionality of a piece of text.
1.369 +
1.370 +@param aText The text to be examined.
1.371 +@param aFound If non-null, returns ETrue if there were any strongly directional
1.372 +characters and EFalse if there were none. If a piece of text is spread over
1.373 +several descriptors, They need to be queried in sequence until one returns
1.374 +ETrue in aFound.
1.375 +@return The directionality implicit in aText. 131 */
1.376 +EXPORT_C TBidiText::TDirectionality TBidiText::TextDirectionality(
1.377 + const TDesC& aText, TBool* aFound)
1.378 + {
1.379 + return BidiCopy::ImplicitDirectionalityIsRightToLeft(
1.380 + aText.Ptr(), aText.Length(), aFound)?
1.381 + ERightToLeft : ELeftToRight;
1.382 + }
1.383 +
1.384 +/** Creates a bidirectional text object with directionality determined by
1.385 +aDirectionality. Use this for text that has come from user input.
1.386 +
1.387 +@param aText The text in logical order.
1.388 +@param aMaxLines
1.389 + The maximum number of lines that this text will need to be split into. Must
1.390 + be at least 1, but should not be too large, as each potential line takes an
1.391 + extra 8 bytes of memory.
1.392 +@param aDirectionality Direction to use.
1.393 +@return The newly constructed object.
1.394 + */
1.395 +EXPORT_C TBidiText* TBidiText::NewL(const TDesC& aText, TInt aMaxLines,
1.396 + TBidiText::TDirectionality aDirectionality)
1.397 + {
1.398 + __ASSERT_ALWAYS(0 < aMaxLines, BidiPanic(EBidiPanic_InvalidMaxline));
1.399 + const TText* text = aText.Ptr();
1.400 + const TInt length = aText.Length();
1.401 + TInt linesInOriginalText = NumberOfLines(text, text + length);
1.402 + if (aMaxLines < linesInOriginalText)
1.403 + aMaxLines = linesInOriginalText;
1.404 +
1.405 + const TInt arraySize = TBidirectionalState::GenerateBdRunArray(text, length, 0, 0);
1.406 + TBidirectionalState::TRunInfo* runInfoArray = new(ELeave) TBidirectionalState::TRunInfo[arraySize];
1.407 + TCleanupItem ci(DeleteTRunInfo, runInfoArray);
1.408 + CleanupStack::PushL(ci);
1.409 + TBidirectionalState::GenerateBdRunArray(text, length, runInfoArray, arraySize);
1.410 + TBidirectionalState state;
1.411 + state.ReorderLine(runInfoArray, arraySize, ETrue, ETrue, aDirectionality,
1.412 + TChar::EOtherNeutral, TChar::EOtherNeutral);
1.413 + TInt compactArraySize = TRunInfoCompact::Convert(0, aText, runInfoArray, arraySize);
1.414 +
1.415 + // size of TBidiTextImp class
1.416 + TBidiTextImp* me = TBidiTextImp::NewL(length, aMaxLines, compactArraySize);
1.417 + me->SetRightToLeftDirectionality(aDirectionality != ELeftToRight);
1.418 +
1.419 + TRunInfoCompact::Convert(me->BidiRunArray(), aText, runInfoArray, arraySize);
1.420 + CleanupStack::PopAndDestroy(runInfoArray);
1.421 +
1.422 + Mem::Copy(me->LogicalText(), text, length * sizeof(TText));
1.423 + return me;
1.424 + }
1.425 +
1.426 +/** Creates a bidirectional text object with directionality determined by the text
1.427 +itself. Use this for text that has been obtained from a resource file.
1.428 +
1.429 +@param aText The text in logical order.
1.430 +@param aMaxLines The maximum number of lines that this text will need to be
1.431 +split into. Must be at least 1, but should not be too large, as each potential
1.432 +line takes an extra 8 bytes of memory.
1.433 +@return The newly constructed object. */
1.434 +EXPORT_C TBidiText* TBidiText::NewL(const TDesC& aText, TInt aMaxLines)
1.435 + {
1.436 + return NewL(aText, aMaxLines, TextDirectionality(aText));
1.437 + }
1.438 +
1.439 +
1.440 +/** Creates a bidirectional text object with enough room for up to aReservedMaxLength
1.441 +number of characters. The number of characters that will actually fit (when calling
1.442 +SetText()) might be slightly less than aReservedMaxLength, as each change between a
1.443 +left-to-right and a right-to-left sub-string (and the other way around) needs about
1.444 +two characters worth of memory.
1.445 +
1.446 +@param aReservedMaxLength The maximum number of characters.
1.447 +@param aMaxLines The maximum number of lines that this text will need to be
1.448 +split into. Must be at least 1, but should not be too large, as each potential
1.449 +line takes an extra 8 bytes of memory.
1.450 +@return The newly constructed object. */
1.451 +EXPORT_C TBidiText* TBidiText::NewL(TInt aReservedMaxLength, TInt aMaxLines)
1.452 + {
1.453 + __ASSERT_ALWAYS(0 < aReservedMaxLength, BidiPanic(EBidiPanic_InvalidReservedMaxLength));
1.454 + __ASSERT_ALWAYS(0 < aMaxLines, BidiPanic(EBidiPanic_InvalidMaxline));
1.455 +
1.456 + const TInt compactArraySize = 1; // Always at least one needed
1.457 +
1.458 + TBidiTextImp* me = TBidiTextImp::NewL(aReservedMaxLength, aMaxLines, compactArraySize);
1.459 + me->SetTextLength(0); // no text yet, just reserved memory
1.460 + return me;
1.461 + }
1.462 +
1.463 +/** Sets the text of the bidirectional text object with directionality determined
1.464 +by the text itself. Use this for text that has been obtained from a resource file.
1.465 +
1.466 +@param aText The text in logical order.
1.467 +@return The number of characters that didn't fit in the available buffer.
1.468 +*/
1.469 +EXPORT_C TInt TBidiText::SetText(const TDesC& aText, RRunInfoArray& aRunInfoArray)
1.470 + {
1.471 + return SetText(aText, TextDirectionality(aText), aRunInfoArray);
1.472 + }
1.473 +
1.474 +
1.475 +/** Sets the text of the bidirectional text with directionality determined by
1.476 +aDirectionality. Use this for text that has come from user input.
1.477 +
1.478 +@param aText The text in logical order.
1.479 +@param aDirectionality Direction to use.
1.480 +@return The number of characters that didn't fit in the available buffer.
1.481 +@panic Bidi EBidiPanic_RunArrayNull The call to RRunInfoArray::OpenL() has not
1.482 +been made prior to this call to TBidiText::SetText()
1.483 +*/
1.484 +EXPORT_C TInt TBidiText::SetText(const TDesC& aText,
1.485 + TDirectionality aDirectionality,
1.486 + RRunInfoArray& aRunInfoArray)
1.487 + {
1.488 + TBidirectionalState::TRunInfo* const runArray = aRunInfoArray.RunArray();
1.489 + __ASSERT_ALWAYS(runArray, BidiPanic(EBidiPanic_RunArrayNull));
1.490 +
1.491 + TBidiTextImp* me = TBidiTextImp::Imp(this);
1.492 + const TInt maxLines = me->iLines;
1.493 + const TText* text = aText.Ptr();
1.494 + TInt length = aText.Length();
1.495 +
1.496 + TInt requiredArraySize = TBidirectionalState::GenerateBdRunArray(text, length, 0, 0);
1.497 + const TInt actualArraySize = aRunInfoArray.iTls->MaxArraySize();
1.498 +
1.499 + if (requiredArraySize > actualArraySize)
1.500 + {
1.501 + // Handle the case where we do not have enough space in the run array
1.502 + // to cope with the input text. The text will be truncated to ensure
1.503 + // we don't overrun the buffer and the number of excess characters
1.504 + // returned as a negative number.
1.505 + requiredArraySize = actualArraySize;
1.506 + TBidirectionalState::GenerateBdRunArray(text, length, runArray, requiredArraySize);
1.507 +
1.508 + length = 0;
1.509 + for (TInt index = 0; index < requiredArraySize; index++)
1.510 + {
1.511 + length += runArray[index].iLength;
1.512 + }
1.513 + }
1.514 + else
1.515 + {
1.516 + TBidirectionalState::GenerateBdRunArray(text, length, runArray, requiredArraySize);
1.517 + }
1.518 +
1.519 +
1.520 +
1.521 + TBidirectionalState state;
1.522 + state.ReorderLine(runArray,
1.523 + requiredArraySize,
1.524 + ETrue,
1.525 + ETrue,
1.526 + aDirectionality,
1.527 + TChar::EOtherNeutral,
1.528 + TChar::EOtherNeutral);
1.529 + const TInt compactArraySize = TRunInfoCompact::Convert(0,
1.530 + aText,
1.531 + runArray,
1.532 + requiredArraySize);
1.533 +
1.534 + // Calculate number of bytes needed to keep text data
1.535 + TInt requiredBytes = sizeof(TText) * (length * 2 + maxLines * 3); // size of text for logical & visual orderings.
1.536 + requiredBytes += sizeof(TInt16*) * maxLines; // size of line length array
1.537 + requiredBytes = (requiredBytes + 3) & 0xFFFFFFFC; // alignment
1.538 +
1.539 + TInt textLength = length;
1.540 + const TInt excessData = Max(0, requiredBytes - me->AllocatedTextDataBytes());
1.541 + TInt excessChars = 0;
1.542 + if(excessData)
1.543 + {
1.544 + // Calculate how much text data that can be fitted into the available bytes,
1.545 + // given the bytes needed for run array data
1.546 + excessChars = excessData / (sizeof(TText) * 2);
1.547 + textLength -= excessChars;
1.548 + }
1.549 + else if (aText.Length() > length)
1.550 + {
1.551 + excessChars = aText.Length() - length;
1.552 + }
1.553 +
1.554 + me->SetTextLength(textLength);
1.555 + me->SetRightToLeftDirectionality(aDirectionality != ELeftToRight);
1.556 + me->iVisualOrderedTextLength = -1;
1.557 + me->iBidiRunArrayLength = static_cast<TUint16>(compactArraySize);
1.558 +
1.559 + TRunInfoCompact::Convert(me->BidiRunArray(), aText, runArray, requiredArraySize);
1.560 + Mem::Copy(me->LogicalText(), text, textLength * sizeof(TText));
1.561 +
1.562 + return excessChars;
1.563 + }
1.564 +
1.565 +/** Sets the character that will be added at the end of the text if the whole text
1.566 +cannot fit into the space specified.
1.567 +
1.568 +@param aTruncateWith The truncation char. */
1.569 +EXPORT_C void TBidiText::SetTruncationChar(TChar aTruncateWith)
1.570 + {
1.571 + TBidiTextImp* me = TBidiTextImp::Imp(this);
1.572 + me->iTruncationCharPlane = static_cast<TUint8>(aTruncateWith >> 16);
1.573 + me->iTruncationChar16 = static_cast<TUint16>(aTruncateWith);
1.574 + }
1.575 +
1.576 +TInt RemoveTrailingSpaces(const MLineBreaker* aBreaker,
1.577 + const TText* aInput, TInt aMinPos, TInt aEndPos)
1.578 + {
1.579 + // Ignore space characters at the end of the line.
1.580 + // Don't bother to ignore spaces made of surrogate pairs:
1.581 + // more processing than it's worth.
1.582 + TUint dummy1, dummy2;
1.583 + while (aEndPos != aMinPos && MLineBreaker::ESpLineBreakClass
1.584 + == aBreaker->LineBreakClass(aInput[aEndPos - 1], dummy1, dummy2))
1.585 + {
1.586 + --aEndPos;
1.587 + }
1.588 + return aEndPos;
1.589 + }
1.590 +
1.591 +/** Prepares the visually-ordered text according to the wrapping width and font
1.592 +specified. Text cannot be drawn until this has been done.
1.593 +@param aWrappingWidth
1.594 + The maximum width of the text in pixels. Note that this distance should be
1.595 + slightly less than the available width to allow for characters such as "W"
1.596 + which can have side-bearings that leak into the margins.
1.597 +@param aFont The font that will provide the character metrics.
1.598 +@param aBreaker
1.599 + An object for breaking the lines. May be NULL for default behaviour.
1.600 +@param aMaxLines
1.601 + Number of lines to restrict wrapping to. The truncation character will be
1.602 + used if the text is too long for this number of lines. The number of lines
1.603 + wrapped to may not be greater than the figure passed to NewL.
1.604 +*/
1.605 +EXPORT_C void TBidiText::WrapText(TInt aWrappingWidth, const CFont& aFont,
1.606 + const MLineBreaker* aBreaker, TInt aMaxLines)
1.607 + {
1.608 + TBidiTextImp* me = TBidiTextImp::Imp(this);
1.609 + me->iWrappingWidth = aWrappingWidth;
1.610 +
1.611 + TInt16* lineWidths = me->LineWidthArray();
1.612 + TText* output = me->VisualText();
1.613 +
1.614 + TInt numLines = 0;
1.615 + DoWrapText(aWrappingWidth, aFont, aBreaker, aMaxLines, output, numLines, lineWidths);
1.616 + me->iVisualOrderedTextLength = output - me->VisualText();
1.617 + }
1.618 +
1.619 +/** Calculate the minimum size needed to draw the current text, given the specified
1.620 +wrapping width, font, and line gap. Calling this method will not rewrap the object's
1.621 +text.
1.622 +
1.623 +@param aWrappingWidth
1.624 + The maximum width of the text in pixels. Note that this distance should be
1.625 + slightly less than the available width to allow for characters such as "W"
1.626 + which can have side-bearings that leak into the margins.
1.627 +@param aFont The font that will provide the character metrics.
1.628 +@param aLineGap The number of empty pixels between two lines of text.
1.629 + Note that this is not the same as the baseline spacing, which is the font
1.630 + height plus the line gap.
1.631 +@param aMaxLines
1.632 + Number of lines to restrict wrapping to. The truncation character will be
1.633 + used if the text is too long for this number of lines. The number of lines
1.634 + wrapped to may be greater than the figure passed to NewL, and that figure
1.635 + will be used if the number of lines is specified as -1. If 0 (zero) is specified
1.636 + no limit is applied.
1.637 +@param aBreaker
1.638 + An object for breaking the lines. May be NULL for default behaviour.
1.639 +*/
1.640 +EXPORT_C TSize TBidiText::MinimumSize(TInt aWrappingWidth, const CFont& aFont, TInt aLineGap,
1.641 + TInt aMaxLines, const MLineBreaker* aBreaker) const
1.642 + {
1.643 + __ASSERT_ALWAYS(0 <= aWrappingWidth, BidiPanic(EBidiPanic_InvalidWrappingWidth));
1.644 + __ASSERT_ALWAYS(0 <= aLineGap, BidiPanic(EBidiPanic_InvalidLineGap));
1.645 + __ASSERT_ALWAYS(-1 <= aMaxLines, BidiPanic(EBidiPanic_InvalidMaxline));
1.646 +
1.647 + TInt numLines = 0;
1.648 + TText* output = NULL;
1.649 + const TInt minWidth = DoWrapText(aWrappingWidth,
1.650 + aFont,
1.651 + aBreaker,
1.652 + (aMaxLines = 0 ? KMaxTInt : aMaxLines),
1.653 + output,
1.654 + numLines,
1.655 + NULL);
1.656 + const TInt minHeight = (aFont.FontMaxHeight() + aLineGap) * numLines - aLineGap;
1.657 + return TSize(minWidth, minHeight);
1.658 + }
1.659 +
1.660 +
1.661 +TInt TBidiText::DoWrapText(TInt aWrappingWidth, const CFont& aFont, const MLineBreaker* aBreaker,
1.662 + TInt aMaxLines, TText*& aOutputText, TInt& aNumLines, TInt16* aLineWidthArray) const
1.663 + {
1.664 + MLineBreaker defaultBreaker;
1.665 + if (!aBreaker)
1.666 + aBreaker = &defaultBreaker;
1.667 +
1.668 + const TBidiTextImp* me = TBidiTextImp::Imp(this);
1.669 + if (me->iLines < aMaxLines)
1.670 + aMaxLines = me->iLines;
1.671 +
1.672 + const TRunInfoCompact* runArray = me->BidiRunArray();
1.673 + const TRunInfoCompact* runArrayEnd = runArray + me->iBidiRunArrayLength;
1.674 +
1.675 + const TText* input = me->LogicalText();
1.676 + const TInt inputLength = me->TextLength();
1.677 + TPtrC textDes(input, inputLength);
1.678 + const TText* output = me->VisualText();
1.679 +
1.680 + TRunInfoCompact::TReorderingContext context;
1.681 + context.iSource = input;
1.682 + context.iTruncation = 0xFFFF;
1.683 + context.iJoinsAtEnd = EFalse;
1.684 +
1.685 + TInt start = 0;
1.686 + CFont::TMeasureTextInput measureInput;
1.687 + measureInput.iMaxAdvance = aWrappingWidth;
1.688 + measureInput.iEndInputChar = FindEndOfThisLine(input, input + inputLength) - input;
1.689 + CFont::TMeasureTextOutput measureOutput;
1.690 + TBool truncated;
1.691 +
1.692 + TInt widestLineWidth = 0;
1.693 + TBool bLastLine = EFalse;
1.694 + for (aNumLines = 0; aNumLines != aMaxLines && start < inputLength; ++aNumLines)
1.695 + {
1.696 + truncated=EFalse;
1.697 + context.iJoinsAtStart = context.iJoinsAtEnd;
1.698 + if(aNumLines != 0 && aOutputText)
1.699 + *(aOutputText++) = KLineSeparator;
1.700 +
1.701 + measureInput.iStartInputChar = start;
1.702 + TInt advance = aFont.MeasureText(textDes, &measureInput, &measureOutput);
1.703 + TInt breakPos = measureOutput.iChars;
1.704 + TInt endOfLine = breakPos;
1.705 + // truncationCharWidth is the width of any truncation character on this
1.706 + // line only.
1.707 + TInt truncationCharWidth = 0;
1.708 + if (endOfLine == measureInput.iEndInputChar)
1.709 + {
1.710 + //handle the dangling lines here
1.711 + TInt sizeLineBreak = SizeLineBreak(input + endOfLine, input + inputLength);
1.712 + if((measureInput.iEndInputChar < inputLength - sizeLineBreak) && (aNumLines == aMaxLines - 1))
1.713 + bLastLine = ETrue;
1.714 + }
1.715 + else if (aNumLines == aMaxLines - 1)
1.716 + {
1.717 + bLastLine = ETrue;
1.718 + }
1.719 + else
1.720 + { // Not last line, so find a legal line break.
1.721 + aBreaker->GetLineBreak(textDes,
1.722 + start + 1,
1.723 + measureOutput.iChars,
1.724 + EFalse,
1.725 + 0,
1.726 + breakPos,
1.727 + endOfLine);
1.728 + }
1.729 +
1.730 + if (bLastLine)
1.731 + {
1.732 + // Last line, so re-measure leaving enough room for
1.733 + // truncation character.
1.734 + context.iTruncation = me->TruncationChar();
1.735 + truncationCharWidth = aFont.CharWidthInPixels(context.iTruncation);
1.736 + measureInput.iMaxAdvance = aWrappingWidth - truncationCharWidth;
1.737 + advance = aFont.MeasureText(textDes, &measureInput, &measureOutput) + truncationCharWidth;
1.738 + breakPos = RemoveTrailingSpaces(aBreaker, input, start, measureOutput.iChars);
1.739 + truncated=ETrue;
1.740 + bLastLine = EFalse;
1.741 + }
1.742 +
1.743 + // if the break position has changed, we need to remeasure
1.744 + if (breakPos != measureOutput.iChars)
1.745 + {
1.746 + const TInt oldEnd = measureInput.iEndInputChar;
1.747 + measureInput.iEndInputChar = breakPos;
1.748 + advance = aFont.MeasureText(textDes, &measureInput, &measureOutput) + truncationCharWidth;
1.749 + measureInput.iEndInputChar = oldEnd;
1.750 + truncated=ETrue;
1.751 + }
1.752 +
1.753 + //width may be greater than advance
1.754 + advance = Max(advance,measureOutput.iBounds.Width());
1.755 +
1.756 + if(widestLineWidth < advance)
1.757 + widestLineWidth = advance;
1.758 +
1.759 + if(aLineWidthArray)
1.760 + *(aLineWidthArray++) = static_cast<TInt16>(advance);
1.761 +
1.762 + context.iStart = start;
1.763 + context.iEnd = breakPos;
1.764 + if (truncated)
1.765 + {
1.766 + context.iJoinsAtEnd = breakPos < inputLength?
1.767 + TRunInfoCompact::JoinBefore(input, breakPos) : EFalse;
1.768 + }
1.769 + else
1.770 + {
1.771 + context.iJoinsAtEnd = endOfLine < inputLength?
1.772 + TRunInfoCompact::JoinBefore(input, endOfLine) : EFalse;
1.773 + }
1.774 + if (aOutputText)
1.775 + {
1.776 + for (const TRunInfoCompact* p = runArray; p != runArrayEnd; ++p)
1.777 + aOutputText = p->Reorder(aOutputText, context);
1.778 + }
1.779 + // Set 'start' to the beginning of the next line...
1.780 + start = endOfLine;
1.781 +
1.782 + // ...move it past any line break...
1.783 + const TInt sizeOfLineBreak = SizeLineBreak(input + start, input + inputLength);
1.784 + if (sizeOfLineBreak != 0)
1.785 + {
1.786 + start += sizeOfLineBreak;
1.787 + // ...and find the end of this next line.
1.788 + const TText* endLine = FindEndOfThisLine(input + start, input + inputLength);
1.789 + measureInput.iEndInputChar = endLine - input;
1.790 + }
1.791 + }
1.792 +
1.793 + return widestLineWidth;
1.794 + }
1.795 +
1.796 +
1.797 +/** Prepares the visually-ordered text according to the wrapping width and font
1.798 +specified. Text cannot be drawn until this has been done.
1.799 +
1.800 +@param aWrappingWidth The maximum width of the text in pixels. Note that this
1.801 +distance should be slightly less than the available width to allow for characters
1.802 +such as "W" which can have side-bearings that leak into the margins.
1.803 +@param aFont The font that will provide the character metrics.
1.804 +@param aBreaker An object for breaking the lines. May be NULL for default behaviour. */
1.805 +EXPORT_C void TBidiText::WrapText(TInt aWrappingWidth, const CFont& aFont,
1.806 + const MLineBreaker* aBreaker)
1.807 + {
1.808 + WrapText(aWrappingWidth, aFont, aBreaker, KMaxTInt);
1.809 + }
1.810 +
1.811 +/** Returns the original logically-ordered text supplied in the constructor.
1.812 +@return The original logically-ordered text supplied in the constructor. */
1.813 +EXPORT_C TPtrC TBidiText::Text() const
1.814 + {
1.815 + const TBidiTextImp* me = TBidiTextImp::Imp(this);
1.816 + const TText* text = me->LogicalText();
1.817 + return TPtrC(text, me->TextLength());
1.818 + }
1.819 +
1.820 +/** Returns the text as prepared for display, provided that WrapText has been called.
1.821 +If WrapText has not been called, a panic will result.
1.822 +
1.823 +@return The text as prepared for display */
1.824 +EXPORT_C TPtrC TBidiText::DisplayText() const
1.825 + {
1.826 + const TBidiTextImp* me = TBidiTextImp::Imp(this);
1.827 + __ASSERT_ALWAYS(me->iVisualOrderedTextLength >= 0, BidiPanic(EBidiPanic_InvalidVisualOrderedTextLength));
1.828 + const TText* text = me->VisualText();
1.829 + return TPtrC(text, me->iVisualOrderedTextLength);
1.830 + }
1.831 +
1.832 +/** Returns the wrapping width previously supplied to WrapText.
1.833 +
1.834 +@return The wrapping. */
1.835 +EXPORT_C TInt TBidiText::WrappingWidth() const
1.836 + {
1.837 + const TBidiTextImp* me = TBidiTextImp::Imp(this);
1.838 + return me->iWrappingWidth;
1.839 + }
1.840 +
1.841 +/** Returns the directionality of the text.
1.842 +
1.843 +@return The directionality. */
1.844 +EXPORT_C TBidiText::TDirectionality TBidiText::Directionality() const
1.845 + {
1.846 + const TBidiTextImp* me = TBidiTextImp::Imp(this);
1.847 + return me->HasRightToLeftDirectionality() ? ERightToLeft : ELeftToRight;
1.848 + }
1.849 +
1.850 +/** Returns the truncation character used.
1.851 +
1.852 +@return The truncation character. */
1.853 +EXPORT_C TChar TBidiText::TruncationChar() const
1.854 + {
1.855 + const TBidiTextImp* me = TBidiTextImp::Imp(this);
1.856 + return me->TruncationChar();
1.857 + }
1.858 +
1.859 +/** Reports the number of lines in the text to be drawn.
1.860 +
1.861 +WrapText must have been called already.
1.862 +@return
1.863 + The number of lines in the text which would be drawn by DrawText.
1.864 +*/
1.865 +EXPORT_C TInt TBidiText::NumberOfLinesInDisplayText() const
1.866 + {
1.867 + const TBidiTextImp* me = TBidiTextImp::Imp(this);
1.868 + if (me->iVisualOrderedTextLength <0)
1.869 + {
1.870 + return 0;
1.871 + }
1.872 + const TText* text = me->VisualText();
1.873 + const TText* textEnd = text + me->iVisualOrderedTextLength;
1.874 + return NumberOfLines(text, textEnd);
1.875 + }
1.876 +
1.877 +/** Returns the text as prepared for display, provided that WrapText has been called.
1.878 +If WrapText has not been called, a panic will result.
1.879 +@param aLine Line number to retrieve.
1.880 +@param aWidth Returns the width in pixels of the line retrieved.
1.881 +@return The text as prepared for display. */
1.882 +EXPORT_C TPtrC TBidiText::LineOfDisplayText(TInt aLine, TInt& aWidthInPixels) const
1.883 + {
1.884 + const TBidiTextImp* me = TBidiTextImp::Imp(this);
1.885 + __ASSERT_ALWAYS(me->iVisualOrderedTextLength >= 0, BidiPanic(EBidiPanic_InvalidVisualOrderedTextLength));
1.886 + __ASSERT_ALWAYS(0 <= aLine && aLine < me->iLines, BidiPanic(EBidiPanic_InvalidLineNumber));
1.887 + aWidthInPixels = me->LineWidthArray()[aLine];
1.888 + const TText* text = me->VisualText();
1.889 + const TText* textEnd = text + me->iVisualOrderedTextLength;
1.890 + for (; aLine != 0; --aLine)
1.891 + {
1.892 + text = FindEndOfThisLine(text, textEnd);
1.893 + text += SizeLineBreak(text, textEnd);
1.894 + }
1.895 + const TText* endOfLine = FindEndOfThisLine(text, textEnd);
1.896 + return TPtrC(text, endOfLine - text);
1.897 + }
1.898 +
1.899 +/** Draws all of the text. WrapText must have been called already.
1.900 +
1.901 +@param aGc The graphics context to draw the text to. The graphics context's
1.902 +font is assumed to have been set to the same font that was passed to the previous
1.903 +call to WrapText.
1.904 +@param aLeft The left extreme of the baseline. Note that this should not be
1.905 +at the very edge of the available space, or characters such as "W" with left
1.906 +side bearings may be truncated.
1.907 +@param aBaseLineSpacing The spacing between each line. If 0, only the first
1.908 +line is drawn.
1.909 +@param aAlignment How to position the text horizontally. */
1.910 +EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft,
1.911 + TInt aBaseLineSpacing, CGraphicsContext::TTextAlign aAlignment) const
1.912 + {
1.913 + TPoint origin;
1.914 + origin.iY = aLeft.iY;
1.915 + TInt lines = aBaseLineSpacing == 0? 1 : NumberOfLinesInDisplayText();
1.916 + TInt wrappingWidth = WrappingWidth();
1.917 + for (TInt i = 0; i != lines; ++i)
1.918 + {
1.919 + TInt width;
1.920 + TPtrC textLine = LineOfDisplayText(i, width);
1.921 + origin.iX = aLeft.iX;
1.922 + if (aAlignment != CGraphicsContext::ELeft)
1.923 + {
1.924 + TInt excess = wrappingWidth - width;
1.925 + origin.iX += aAlignment != CGraphicsContext::ECenter?
1.926 + excess : excess >> 1;
1.927 + }
1.928 + aGc.DrawText(textLine, origin);
1.929 + origin.iY += aBaseLineSpacing;
1.930 + }
1.931 + }
1.932 +
1.933 +/** Draws all of the text. Alignment is taken from the directionality of the text.
1.934 +WrapText must have been called already.
1.935 +
1.936 +@param aGc The graphics context to draw the text to. The graphics context's
1.937 +font is assumed to have been set to the same font that was passed to the previous
1.938 +call to WrapText.
1.939 +@param aLeft The left extreme of the baseline. Note that this should not be
1.940 +at the very edge of the available space, or characters such as "W" with left
1.941 +side bearings may be truncated.
1.942 +@param aBaseLineSpacing The spacing between each line. If 0, only the first
1.943 +line is drawn. */
1.944 +EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft,
1.945 + TInt aBaseLineSpacing) const
1.946 + {
1.947 + DrawText(aGc, aLeft, aBaseLineSpacing,
1.948 + Directionality() == ELeftToRight?
1.949 + CGraphicsContext::ELeft : CGraphicsContext::ERight);
1.950 + }
1.951 +
1.952 +/** Draws the first line of the text. WrapText must have been called already. Alignment
1.953 +is taken from the directionality of the text.
1.954 +
1.955 +@param aGc The graphics context to draw the text to. The graphics context's
1.956 +font is assumed to have been set to the same font that was passed to the previous
1.957 +call to WrapText.
1.958 +@param aLeft The left extreme of the baseline. Note that this should not be
1.959 +at the very edge of the available space, or characters such as "W" with left
1.960 +side bearings may be truncated. */
1.961 +EXPORT_C void TBidiText::DrawText(CGraphicsContext& aGc, const TPoint& aLeft) const
1.962 + {
1.963 + DrawText(aGc, aLeft, 0);
1.964 + }
1.965 +