diff -r 969102054596 -r 414d4b727fd9 graphicsdeviceinterface/gdi/sgdi/BIDI.CPP --- a/graphicsdeviceinterface/gdi/sgdi/BIDI.CPP Wed Aug 25 08:17:25 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1163 +0,0 @@ -// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). -// All rights reserved. -// This component and the accompanying materials are made available -// under the terms of "Eclipse Public License v1.0" -// which accompanies this distribution, and is available -// at the URL "http://www.eclipse.org/legal/epl-v10.html". -// -// Initial Contributors: -// Nokia Corporation - initial contribution. -// -// Contributors: -// -// Description: -// Bidirectional text reordering; based on the Unicode Bidirectional Reordering Algorithm. -// -// - -#include -#include "BidiCopy.h" -#include - -const TInt KBidirectionalStateOverrideStreamValueNone = 0; -const TInt KBidirectionalStateOverrideStreamValueLeftToRight = 1; -const TInt KBidirectionalStateOverrideStreamValueRightToLeft = 2; - -inline TBool IsSupplementary(TUint aChar) -/** -@param aChar The 32-bit code point value of a Unicode character. - -@return True, if aChar is supplementary character; false, otherwise. -*/ - { - return (aChar > 0xFFFF); - } - -inline TBool IsHighSurrogate(TText16 aInt16) -/** -@return True, if aText16 is high surrogate; false, otherwise. -*/ - { - return (aInt16 & 0xFC00) == 0xD800; - } - -inline TBool IsLowSurrogate(TText16 aInt16) -/** -@return True, if aText16 is low surrogate; false, otherwise. -*/ - { - return (aInt16 & 0xFC00) == 0xDC00; - } - -inline TUint JoinSurrogate(TText16 aHighSurrogate, TText16 aLowSurrogate) -/** -Combine a high surrogate and a low surrogate into a supplementary character. - -@return The 32-bit code point value of the generated Unicode supplementary - character. -*/ - { - return ((aHighSurrogate - 0xD7F7) << 10) + aLowSurrogate; - } - -TBool TextDefaultsToRightToLeft(const TDesC& aText, TBool* aFound); - -TBidirectionalState::TCategory TBidirectionalState::CharToBdCat(TChar::TBdCategory aCat) - { - return static_cast( - 1 << static_cast(aCat)); - } - -TBidirectionalState::TCategory TBidirectionalState::UintToBdCat(TUint aCat) - { - return static_cast(1 << aCat); - } - -void TBidirectionalState::TReorderContext::SetNextCategory( - TChar::TBdCategory aCat) - { - iNextCategory = CharToBdCat(aCat); - } - -void TBidirectionalState::TReorderContext::SetNextStrongCategory( - TChar::TBdCategory aCat) - { - iNextStrongCategory = CharToBdCat(aCat); - } - - -EXPORT_C void TBidirectionalState::ReverseGroups(TText* aStart,TInt aLength) -/** A utility to reverse text apart from combining characters, which remains after -their base characters. This is what is needed when drawing right-to-left text. - -@param aStart Start position of text to be reversed. -@param aLength Length of text to be reversed. */ - { - BidiCopy::ReverseCodes(aStart, aLength); - BidiCopy::DeleteUnreversedSurrogates(aStart, aLength); - BidiCopy::SubstituteMirrorImages(aStart, aLength); - BidiCopy::CorrectGroups(aStart, aLength); - BidiCopy::CorrectSurrogatePairs(aStart, aLength); - } - - -// A local helper function. Get the next character from a buffer. This -// function won't check buffer length. -// -// @param aText The text buffer to read character from. -// @param aCharacterIndex Count of characters to skip in aText. -// @return The character. -TUint GetOneCharacter(const TText16 *aText, TInt aCharacterIndex) - { - const TText16 *p = aText; - TUint c = 0xFFFF; - while (aCharacterIndex >= 0) - { - c = *p++; - ASSERT(!IsLowSurrogate(c)); - if (IsHighSurrogate(c)) - { - ASSERT(IsLowSurrogate(*p)); - c = JoinSurrogate(c, *p++); - } - --aCharacterIndex; - } - return c; - } - - -TInt TBidirectionalState::GenerateBdRunArray(const TText* aText, TInt aLength, - TBidirectionalState::TRunInfo* aRun, TInt aMaxRuns) -/** Analyse the input text for runs of characters that share the same -bidirectional class. Categories TChar::EEuropeanNumberSeparator and -TChar::ECommonNumberSeparator are kept as singletons due to a limitation in -the reordering logic. -@param aText The text to be analysed. -@param aLength The length of the text to be analysed. -@param aRun Output buffer for the runs after analysis. May be null if there -is to be no output. -@param aMaxRuns The size of the aRun array. No more than this number of runs -will be output. -@return The number of runs that are required for the full results of the -analysis. -@internalTechnology */ - { - if (aLength == 0) - { - if (aRun && 0 < aMaxRuns) - { - aRun[0].iCategory = TChar::EOtherNeutral; - aRun[0].iStart = 0; - aRun[0].iLength = 0; - } - return 1; - } - int runs = 0; - int run_start = 0; - int run_end = 1; - const TText* p = aText; - const TText* q = p + aLength; - - // get the character pointed by 'p', then move 'p' to next character, and adjust 'run_end' if need - TChar pc = ::GetOneCharacter(p, 0); - TChar::TBdCategory cur_cat = pc.GetBdCategory(); - ++p; - if (IsSupplementary(pc)) - { - ++p; - run_end = 2; // run_end points to "end" of current character - } - - while (p < q) - { - // get the character pointed by 'p' - pc = ::GetOneCharacter(p, 0); - - TChar::TBdCategory new_cat = pc.GetBdCategory(); - if (new_cat != cur_cat) - { - if (new_cat == TChar::ENonSpacingMark && - cur_cat != TChar::ELeftToRightEmbedding && - cur_cat != TChar::ELeftToRightOverride && - cur_cat != TChar::ERightToLeftEmbedding && - cur_cat != TChar::ERightToLeftOverride && - cur_cat != TChar::EPopDirectionalFormat) - new_cat = cur_cat; - else if (p < q - 1 && - (new_cat == TChar::EWhitespace || - new_cat == TChar::EEuropeanNumberSeparator || - new_cat == TChar::ECommonNumberSeparator)) - { - TChar nextChar = ::GetOneCharacter(p, 1); - TChar::TBdCategory next_cat = nextChar.GetBdCategory(); - if (new_cat == TChar::EWhitespace) - { - if ((cur_cat == TChar::ELeftToRight || - cur_cat == TChar::ERightToLeft || - cur_cat == TChar::ERightToLeftArabic) && cur_cat == next_cat) - new_cat = cur_cat; - } - else if (cur_cat == TChar::EEuropeanNumber && next_cat == TChar::EEuropeanNumber) - new_cat = TChar::EEuropeanNumber; - } - } - - if (new_cat != cur_cat || - cur_cat == TChar::EEuropeanNumberSeparator || - cur_cat == TChar::ECommonNumberSeparator) - { - if (aRun && runs < aMaxRuns) - { - aRun[runs].iCategory = cur_cat; - aRun[runs].iStart = run_start; - aRun[runs].iLength = run_end - run_start; - } - - runs++; - run_start = run_end; - } - - p++; - run_end++; - - // adjust 'p' and 'run_end' - if (IsSupplementary(pc)) - { - p++; - run_end++; - } - - cur_cat = new_cat; - } - - if (aRun && runs < aMaxRuns) - { - aRun[runs].iCategory = cur_cat; - aRun[runs].iStart = run_start; - aRun[runs].iLength = run_end - run_start; - } - - return runs + 1; - } - - -EXPORT_C TInt TBidirectionalState::ReorderText(const TText* aText,TInt aLength,TBool aParRightToLeft, - TText*& aNewText) -/** Reorders text according to the Unicode Bidirectional Reordering algorithm. - -Reorders the input text from logical order (which may be bidirectional) to -display order (strictly left to right). - -@param aText The input text in logical order. -@param aLength The length of the input text. -@param aParRightToLeft ETrue if the default directionality of the text to be -re-ordered is right-to-left. -@param aNewText Returns the re-ordered text. If the text did not need re-ordering, -or if there was an error, aText will be returned. Otherwise, ownership of -a newly allocated buffer will be returned to the caller. This buffer must -be deleted with delete[] (or CleanupArrayDeletePushL()) and not delete (or -CleanupStack::PushL()). -@return A system-wide error value if there has been an error; KErrNone if there -has not. */ - { - aNewText = const_cast(aText); - if (aLength < 2) - return KErrNone; - - int error = KErrNone; - TBidirectionalState::TRunInfo run_info; - run_info.iDirection = 0; - run_info.iIndex = 0; - run_info.iStart = 0; - run_info.iLength = aLength; - TBidirectionalState::TRunInfo* run_info_array = &run_info; - TBidirectionalState::TRunInfo* allocated_run_info_array = 0; - int runs = GenerateBdRunArray(aText, aLength, run_info_array, 1); - if (runs > 1) - { - allocated_run_info_array = new TBidirectionalState::TRunInfo[runs]; - if (allocated_run_info_array) - { - run_info_array = allocated_run_info_array; - GenerateBdRunArray(aText, aLength, run_info_array, runs); - } - else - { - // the run cannot be allocated: stick with our single l-to-r run - error = KErrNoMemory; - runs = 1; - } - } - if (error == KErrNone) - { - TBidirectionalState state; - state.ReorderLine(run_info_array, runs, ETrue, ETrue, aParRightToLeft, - TChar::EOtherNeutral, TChar::EOtherNeutral); - } - - // If there was only one run and it's left-to-right, we've finished. - if (!allocated_run_info_array && run_info.iDirection == 0) - return error; - - // Reorder the text into a new buffer. - TText* buffer = new TText[aLength]; - if (!buffer) - { - delete [] allocated_run_info_array; - return KErrNoMemory; - } - const TBidirectionalState::TRunInfo* r = run_info_array; - TText* dest = buffer; - for (int i = 0; i < runs; i++, r++) - { - const TText* source = &aText[r->iStart]; - int length = r->iLength; - Mem::Copy(dest,source,length * sizeof(TText)); - if (r->iDirection) - ReverseGroups(dest,length); - dest += length; - } - - delete [] allocated_run_info_array; - aNewText = buffer; - return KErrNone; - } - - -EXPORT_C TBidirectionalState::TBidirectionalState() -/** Standard constructor. */ - { - Reset(); - } - - -/** Reorders a line of text and updates the bidirectional state for the next line. - -@param aRunInfo An array of objects representing runs of characters with the -same bidirectional category. Any number of characters can be combined into -a run if they have the same category, except for the categories TChar::EEuropeanNumberSeparator -and TChar::ECommonNumberSeparator, which should be put into single-character -runs because the reordering logic depends on this. -@param aRuns Number of 'run info' objects. -@param aParStart Tells the function whether the line is the first line of a -paragraph. -@param aParEnd Tells the function whether the line is the last line of a paragraph. -@param aParRightToLeft ETrue if the default directionality of the text to be -re-ordered is right-to-left. -@param aNextCategory The category of the character immediately after the end -of the line. This is ignored if aParEnd is ETrue. -@param aNextStrongCategory The category of the first strong character (one -of the categories ELeftToRight, ELeftToRightEmbedding, ELeftToRightOverride, -ERightToLeft, ERightToLeftArabic, ERightToLeftEmbedding or ERightToLeftOverride) -after the end of the line. This is ignored if aParEnd is ETrue. -@param aVisualEndIsAmbiguous EFalse if the logical end of this line is at the -visual end and the logical beginning of the next line is at the visual beginning. -*/ -EXPORT_C void TBidirectionalState::ReorderLine(TRunInfo* aRunInfo, TInt aRuns, - TBool aParStart, TBool aParEnd, TBool aParRightToLeft, - TChar::TBdCategory aNextCategory, TChar::TBdCategory aNextStrongCategory, - TBool& aVisualEndIsAmbiguous) - { - ReorderLine(aRunInfo, aRuns, aParStart, aParEnd, aParRightToLeft, - aNextCategory, aNextStrongCategory); - if (iStackLevel != 0) - { - aVisualEndIsAmbiguous = ETrue; - return; - } - TCategory nextCat = CharToBdCat(aNextCategory); - TCategory nextStrong = CharToBdCat(aNextStrongCategory); - const TUint KAllStrongLeftToRight = - ELeftToRight | ELeftToRightEmbedding | ELeftToRightOverride; - const TUint KAllStrongRightToLeft = - ERightToLeft | ERightToLeftArabic | ERightToLeftEmbedding | ERightToLeftOverride; - if (aParRightToLeft) - { - // Ambiguous if any of the surrounding categories are strongly left-to-right - aVisualEndIsAmbiguous = - (iPreviousStrongCategory | iPreviousCategory | nextCat | nextStrong) - & KAllStrongLeftToRight; - } - else - { - // Ambiguous if any of the surrounding categories are strongly right-to-left - aVisualEndIsAmbiguous = - (iPreviousStrongCategory | iPreviousCategory | nextCat | nextStrong) - & KAllStrongRightToLeft; - } - } -/** Reorders a line of text and updates the bidirectional state for the next line. - -@param aRunInfo An array of objects representing runs of characters with the -same bidirectional category. Any number of characters can be combined into -a run if they have the same category, except for the categories TChar::EEuropeanNumberSeparator -and TChar::ECommonNumberSeparator, which should be put into single-character -runs because the reordering logic depends on this. -@param aRuns Number of 'run info' objects. -@param aParStart Tells the function whether the line is the first line of a -paragraph. -@param aParEnd Tells the function whether the line is the last line of a paragraph. -@param aParRightToLeft ETrue if the default directionality of the text to be -re-ordered is right-to-left. -@param aNextCategory The category of the character immediately after the end -of the line. This is ignored if aParEnd is ETrue. -@param aNextStrongCategory The category of the first strong character (one -of the categories ELeftToRight, ELeftToRightEmbedding, ELeftToRightOverride, -ERightToLeft, ERightToLeftArabic, ERightToLeftEmbedding or ERightToLeftOverride) -after the end of the line. This is ignored if aParEnd is ETrue. */ -EXPORT_C void TBidirectionalState::ReorderLine(TRunInfo* aRunInfo, TInt aRuns, - TBool aParStart, TBool aParEnd, TBool aParRightToLeft, - TChar::TBdCategory aNextCategory, TChar::TBdCategory aNextStrongCategory) - { - // Reset if this is a new paragraph. - if (aParStart) - { - Reset(); - iPreviousCategory = EOtherNeutral; - if (aParRightToLeft) - { - iStack[0].iEmbeddingLevel = 1; - iPreviousStrongCategory = ERightToLeft; - } - } - - // Initialise the context object. - TReorderContext context; - context.iRunInfo = aRunInfo; - context.iRuns = aRuns; - context.iLastStrongCategory = iPreviousStrongCategory; - if (aParEnd) - context.iNextCategory = context.iNextStrongCategory = EOtherNeutral; - else - { - context.iNextCategory = CharToBdCat(aNextCategory); - context.iNextStrongCategory = CharToBdCat(aNextStrongCategory); - } - - // Initialise output data and find out what categories are present so that unnecessary steps can be skipped. - context.iCategories = iPreviousCategory | context.iNextCategory | context.iNextStrongCategory; - for (TInt i = 0; i != aRuns; ++i) - { - aRunInfo[i].iEmbeddingLevel = iStack[0].iEmbeddingLevel; - aRunInfo[i].iDirection = 0; - aRunInfo[i].iIndex = i; - aRunInfo[i].iCategory = UintToBdCat(aRunInfo[i].iCategory); - context.iCategories |= aRunInfo[i].iCategory; - } - - // Do nothing if no right-to-left material is present. - if (aRuns == 0 || - (iStackLevel == 0 && iStack[0].iEmbeddingLevel == 0 && - !(context.iCategories & (ERightToLeftGroup | EBdControlsGroup)))) - return; - - // Perform the bidirectional algorithm. - if ((context.iCategories & EBdControlsGroup) || - State().iOverrideState != ENoOverrideState) - HandleBdControls(context); - ResolveWeakTypesW1W2W3(context); - ResolveWeakTypesW4W5W6(context); - ResolveWeakTypesW7(context); - if (context.iCategories & EOtherNeutral) - ResolveNeutralTypes(context); - ResolveImplicitLevels(context); - PrepareForNextLine(context); - ReorderRuns(context); - } - - -void TBidirectionalState::PrepareForNextLine(const TReorderContext& aContext) -/** -Fold context information back into TBidirectionalState. -@internalComponent -*/ - { - if (aContext.iRuns != 0) - { - iPreviousCategory = static_cast( - aContext.iRunInfo[aContext.iRuns - 1].iCategory); - iPreviousStrongCategory = aContext.iLastStrongCategory; - } - } - - -void TBidirectionalState::HandleBdControls(TReorderContext& aContext) -/** -Handle LRO, RLO, LRE, RLE and PDF. After this phase, these categories will no -longer be found. - -This corresponds to Unicode(3.2) Bidirectional Algorithm phases X1-X7. -Phase X8 is not required as the run is assumed to be all in one paragraph. -Phases X9-X10 are implicit in other functions. - -@internalComponent -*/ - { - aContext.iCategories = iPreviousCategory | aContext.iNextCategory; - for (TInt i = 0; i != aContext.iRuns; ++i) - { - TRunInfo* r = aContext.iRunInfo + i; - TCategory nextCatInLine = i < aContext.iRuns - 1? - (TCategory)(r[1].iCategory) : ENoCategory; - - TBool was_pdf = FALSE; - if (r->iCategory & EBdControlsGroup) - { - if (r->iCategory == EPopDirectionalFormat) - { - if (iStackLevel > 0) - { - was_pdf = TRUE; - r->iEmbeddingLevel = State().iEmbeddingLevel; - if (nextCatInLine == State().iStartCategory) - // Ignore POP-PUSH pair with nothing between. - // This is surely wrong? Perhaps it is a hack to - // help other parts of the algorithm. Must investigate. - // TPB. - r->iCategory = r[1].iCategory = EBoundaryNeutral; - else - { - r->iCategory = Pop(); - } - } - else - r->iCategory = EBoundaryNeutral; - } - else - { - // Category is LRE, RLE, LRO or RLO. - if (nextCatInLine == EPopDirectionalFormat) - // Ignore PUSH-POP pair with nothing between. - r->iCategory = r[1].iCategory = EBoundaryNeutral; - else - r->iCategory = Push(static_cast(r->iCategory)); - } - } - - if (!was_pdf) - { - switch (State().iOverrideState) - { - case ELeftToRightOverrideState: - r->iCategory = ELeftToRight; - break; - case ERightToLeftOverrideState: - r->iCategory = ERightToLeft; - break; - default: - break; - } - r->iEmbeddingLevel = State().iEmbeddingLevel; - } - if (r->iCategory & EStrongGroup) - aContext.iLastStrongCategory = static_cast(r->iCategory); - aContext.iCategories |= r->iCategory; - } - } - - -void TBidirectionalState::ResolveWeakTypesW1W2W3(TReorderContext& aContext) -/** -Unicode(3.2) Bidirectional Algorithm phases W1, W2 and W3. -@internalComponent -*/ - { - if (!(aContext.iCategories - & (ENonSpacingMark | ERightToLeftArabic | EEuropeanNumber))) - return; - - TRunInfo* endOfRuns = aContext.iRunInfo + aContext.iRuns; - TCategory prev_cat = iPreviousCategory; - TBool european_to_arabic_number = iPreviousStrongCategory == ERightToLeftArabic; - - aContext.iCategories = iPreviousCategory | aContext.iNextCategory; - for (TRunInfo* r = aContext.iRunInfo; r != endOfRuns; r++) - { - switch (r->iCategory) - { - case ENonSpacingMark: // non-spacing marks change to the previous category - r->iCategory = prev_cat; - break; - case ELeftToRight: - european_to_arabic_number = EFalse; - break; - case ERightToLeft: - european_to_arabic_number = EFalse; - break; - case ERightToLeftArabic: // Arabic letters change to R - european_to_arabic_number = ETrue; - r->iCategory = ERightToLeft; - break; - case EEuropeanNumber: // European numbers change to Arabic if last strong category was R - if (european_to_arabic_number) - r->iCategory = EArabicNumber; - break; - default: - break; - } - aContext.iCategories |= r->iCategory; - prev_cat = static_cast(r->iCategory); - } - } -/** -This phase removes categories NSM, AL, ES, ET, CS, BS, S, WS and BN, leaving -only L, R, EN, AN and ON. -@internalComponent -*/ -void TBidirectionalState::ResolveWeakTypesW4W5W6(TReorderContext& aContext) - { - int i; - TRunInfo* r; - TCategory prev_cat = iPreviousCategory; - TCategory next_cat = EOtherNeutral; - - // Phase P0b. - prev_cat = iPreviousCategory; - if (aContext.iCategories & EBoundaryNeutral) - { - for (i = 0, aContext.iCategories = iPreviousCategory | aContext.iNextCategory, r = aContext.iRunInfo; - i < aContext.iRuns; - i++, aContext.iCategories |= r->iCategory, r++) - { - if (r->iCategory == EBoundaryNeutral) // runs of boundary neutrals change to EN, ET or AN if adjacent to - { // one of these, otherwise to ON - int end = i + 1; - while (end < aContext.iRuns && aContext.iRunInfo[end].iCategory == EBoundaryNeutral) - end++; - next_cat = end < aContext.iRuns ? (TCategory)(aContext.iRunInfo[end].iCategory) : aContext.iNextCategory; - TCategory c = EOtherNeutral; - if (prev_cat == EEuropeanNumber || next_cat == EEuropeanNumber) - c = EEuropeanNumber; - else if (prev_cat == EEuropeanNumberTerminator || next_cat == EEuropeanNumberTerminator) - c = EEuropeanNumberTerminator; - else if (prev_cat == EArabicNumber || next_cat == EArabicNumber) - c = EArabicNumber; - for (int j = i; j < end; j++) - aContext.iRunInfo[j].iCategory = c; - i = end - 1; - r = &aContext.iRunInfo[i]; - } - prev_cat = (TCategory)r->iCategory; - } - } - - // Phase P1. - prev_cat = iPreviousCategory; - if (aContext.iCategories & (EEuropeanNumberSeparator | ECommonNumberSeparator)) - { - for (i = 0, aContext.iCategories = iPreviousCategory | aContext.iNextCategory, r = aContext.iRunInfo; - i < aContext.iRuns; - i++, aContext.iCategories |= r->iCategory, r++) - { - next_cat = i < aContext.iRuns - 1 ? (TCategory)(r[1].iCategory) : aContext.iNextCategory; - switch (r->iCategory) - { - case EEuropeanNumberSeparator: // European separators change to EN if between two ENs, else to ON - if (prev_cat == EEuropeanNumber && next_cat == EEuropeanNumber) - r->iCategory = EEuropeanNumber; - else - r->iCategory = EOtherNeutral; - break; - case ECommonNumberSeparator: // CSs change to EN or AN if between two of the same, else to ON - if (prev_cat == EEuropeanNumber && next_cat == EEuropeanNumber) - r->iCategory = EEuropeanNumber; - else if (prev_cat == EArabicNumber && next_cat == EArabicNumber) - r->iCategory = EArabicNumber; - else - r->iCategory = EOtherNeutral; - break; - default: - break; - } - prev_cat = (TCategory)r->iCategory; - } - } - - /* - Phase L1: tabs, whitespace before tabs, and trailing whitespace, is set to the base embedding level. - We ought to do this just before the final reordering, but the whitespace and segment separator - categories have disappeared by then so we use the sentinel value 255 which tells - ResolveImplicitLevels what to do. - */ - TBool demote_whitespace = TRUE; - for (i = aContext.iRuns - 1, r = &aContext.iRunInfo[i]; i >= 0; i--, r--) - { - switch (r->iCategory) - { - case EWhitespace: - break; - case ESegmentSeparator: - demote_whitespace = TRUE; - break; - default: - demote_whitespace = FALSE; - break; - } - if (demote_whitespace) - r->iEmbeddingLevel = 255; - } - - // Phases P2 and P3. - prev_cat = iPreviousCategory; - if (aContext.iCategories & (EEuropeanNumberTerminator | ESegmentSeparator | EWhitespace)) - { - for (i = 0, aContext.iCategories = iPreviousCategory | aContext.iNextCategory, r = aContext.iRunInfo; - i < aContext.iRuns; - i++, aContext.iCategories |= r->iCategory, r++) - { - next_cat = i < aContext.iRuns - 1 ? (TCategory)(r[1].iCategory) : aContext.iNextCategory; - switch (r->iCategory) - { - case EEuropeanNumberTerminator: // runs of ETs change to ENs if next to an EN, else to ON - { - int end = i + 1; - while (end < aContext.iRuns && aContext.iRunInfo[end].iCategory == EEuropeanNumberTerminator) - end++; - next_cat = end < aContext.iRuns ? (TCategory)(aContext.iRunInfo[end].iCategory) : aContext.iNextCategory; - TCategory c = EOtherNeutral; - if (prev_cat == EEuropeanNumber || next_cat == EEuropeanNumber) - c = EEuropeanNumber; - for (int j = i; j < end; j++) - aContext.iRunInfo[j].iCategory = c; - i = end - 1; - r = &aContext.iRunInfo[i]; - } - break; - case ESegmentSeparator: // S and WS change to ON - case EWhitespace: - r->iCategory = EOtherNeutral; - break; - default: - break; - } - prev_cat = (TCategory)r->iCategory; - } - } - } - -void TBidirectionalState::ResolveWeakTypesW7(TReorderContext& aContext) - { - if (!(aContext.iCategories & EEuropeanNumber)) - return; - - TCategory prev_strong_cat = iPreviousStrongCategory; - - aContext.iCategories = iPreviousCategory | aContext.iNextCategory; - TRunInfo* endOfRuns = aContext.iRunInfo + aContext.iRuns; - for (TRunInfo* r = aContext.iRunInfo; r != endOfRuns; r++) - { - switch (r->iCategory) - { - case ELeftToRight: - prev_strong_cat = ELeftToRight; - break; - case ERightToLeft: - prev_strong_cat = ERightToLeft; - break; - case EEuropeanNumber: - if (prev_strong_cat == ELeftToRight) - r->iCategory = ELeftToRight; - break; - default: - break; - } - aContext.iCategories |= r->iCategory; - } - } - - - -void TBidirectionalState::DeneutralizeRuns(TRunInfo* aStart, TRunInfo* aEnd, - TCategory aStartCategory, TCategory aEndCategory) -/** -Turn all ON (Other Neutral) into non-neutrals according to the rules N1 and N2. -@param aStart The start of the run array to be altered. -@param aEnd One past the end of the run array to be altered. -@param aStartCategory - The last non-neutral before the run, must be ELeftToRight or ERightToLeft. -@param aEndCategory - The first non-neutral after the run, must be ELeftToRight or ERightToLeft. -@internalComponent -*/ { - // if sandwiched by the same category, neutrals become that. - if (aStartCategory == aEndCategory) - { - for (; aStart != aEnd; ++aStart) - aStart->iCategory = aStartCategory; - return; - } - // otherwise look at the embedding level in each case - for (; aStart != aEnd; ++aStart) - { - aStart->iCategory = aStart->iEmbeddingLevel & 1? - ERightToLeft : ELeftToRight; - } - } - - -void TBidirectionalState::ResolveNeutralTypes(TReorderContext& aContext) - /** -This phase removes the ON (Other Neutral) category, leaving only L, R, EN, and -AN; no need to update aContext.iCategories. -@internalComponent -*/ - { - // Really we should find if any number intervenes, but this would require - // a BC break. - TCategory prevNonNeutral = iPreviousStrongCategory; - if (prevNonNeutral & ELeftToRightGroup) - prevNonNeutral = ELeftToRight; - else if (prevNonNeutral & ERightToLeftGroup) - prevNonNeutral = ERightToLeft; - TRunInfo *prevNonNeutralRun = aContext.iRunInfo; // one past the last non-neutral found - TRunInfo *endOfRuns = aContext.iRunInfo + aContext.iRuns; - - // All neutrals have now been changed to ON; change them to L or R depending on context. - for (TRunInfo *p = aContext.iRunInfo; p != endOfRuns; ++p) - { - TCategory nonNeutral = EOtherNeutral; - switch (p->iCategory) - { - case ELeftToRight: - nonNeutral = ELeftToRight; - break; - case ERightToLeft: - nonNeutral = ERightToLeft; - break; - case EArabicNumber: - case EEuropeanNumber: - nonNeutral = ERightToLeft; - break; - default: - break; - } - if (nonNeutral != EOtherNeutral) - { - if (p != prevNonNeutralRun) - DeneutralizeRuns(prevNonNeutralRun, p, - prevNonNeutral, nonNeutral); - prevNonNeutral = nonNeutral; - prevNonNeutralRun = p + 1; - } - } - DeneutralizeRuns(prevNonNeutralRun, endOfRuns, prevNonNeutral, - aContext.iNextStrongCategory); - } - - -void TBidirectionalState::ResolveImplicitLevels(TReorderContext& aContext) -/** -Phases I1 and I2. -@internalComponent -*/ { - int i; - TRunInfo* r; - for (i = 0, r = aContext.iRunInfo; i < aContext.iRuns; i++, r++) - { - if (r->iEmbeddingLevel == 255) // sentinel indicating this is a tab or segment-final whitespace - r->iEmbeddingLevel = iStack[0].iEmbeddingLevel; - else switch (r->iCategory) - { - case ELeftToRight: - if (r->iEmbeddingLevel & 1) - r->iEmbeddingLevel++; - break; - case ERightToLeft: - if (!(r->iEmbeddingLevel & 1)) - r->iEmbeddingLevel++; - break; - case EEuropeanNumber: case EArabicNumber: - if (r->iEmbeddingLevel & 1) - r->iEmbeddingLevel++; - else - r->iEmbeddingLevel += 2; - break; - default: - break; - } - } - } - - -void TBidirectionalState::ReorderRuns(TReorderContext& aContext) -/** -Phase L2. -@internalComponent -*/ { - // Find the highest level and lowest odd level. - int i; - TRunInfo* r; - int highest = 0; - int lowest_odd = EMaxLevel; - int level = 0; - for (i = 0, r = aContext.iRunInfo; i < aContext.iRuns; i++, r++) - { - level = r->iEmbeddingLevel; - if (level > highest) - highest = level; - if ((level & 1) && level < lowest_odd) - lowest_odd = level; - } - - // From the highest level to the lowest odd level, reverse any run at that level or higher. - for (level = highest; level >= lowest_odd; level--) - { - int run_start = 0; - r = aContext.iRunInfo; - while (run_start < aContext.iRuns) - { - while (run_start < aContext.iRuns && r->iEmbeddingLevel < level) - { - run_start++; - r++; - } - int run_end = run_start; - while (run_end < aContext.iRuns && r->iEmbeddingLevel >= level) - { - r->iDirection = !r->iDirection; - run_end++; - r++; - } - TRunInfo* p = &aContext.iRunInfo[run_start]; - TRunInfo* q = &aContext.iRunInfo[run_end - 1]; - while (p < q) - { - TRunInfo temp = *p; - *p = *q; - *q = temp; - p++; - q--; - } - run_start = run_end; - } - } - } - - -TBidirectionalState::TCategory TBidirectionalState::Push(TCategory aStartCategory) -/** @internalComponent */ - { - TInt rightToLeftFlag = (static_cast(aStartCategory) - & ERightToLeftGroup)? 1 : 0; - TInt oldLevel = State().iEmbeddingLevel; - TInt newLevel = oldLevel + 1; - // And add an extra one if the bottom bit is not correct. - newLevel += (newLevel & 1) ^ rightToLeftFlag; - - if (EMaxExplicitLevel < newLevel) - { - if (oldLevel == 60) - ++iPushesBeyond60; - else - ++iPushesBeyond61; - return EBoundaryNeutral; - } - - ++iStackLevel; - TStackItem& state = iStack[iStackLevel]; - state.iEmbeddingLevel = static_cast(newLevel); - state.iOverrideState = static_cast(aStartCategory - & (ELeftToRightOverride | ERightToLeftOverride)); - state.iStartCategory = aStartCategory; - - return rightToLeftFlag? ERightToLeft : ELeftToRight; - } - - -TBidirectionalState::TCategory TBidirectionalState::Pop() -/** @internalComponent */ - { - __ASSERT_DEBUG(0 < iStackLevel, User::Invariant()); - TInt level = State().iEmbeddingLevel; - if (level < 60) - --iStackLevel; - else if (iPushesBeyond61 != 0) - --iPushesBeyond61; - else if (level == 61) - --iStackLevel; - else if (iPushesBeyond60) - --iPushesBeyond60; - else - --iStackLevel; - return (level & 1)? ERightToLeft : ELeftToRight; - } - - -EXPORT_C void TBidirectionalState::Reset() -/** Sets the object to its default 'start of paragraph' state. */ - { - iStackLevel = 0; - iPushesBeyond60 = 0; - iPushesBeyond61 = 0; - iStack[0].iEmbeddingLevel = 0; - iStack[0].iOverrideState = ENoOverrideState; - iStack[0].iStartCategory = EOtherNeutral; - iPreviousCategory = ELeftToRight; - iPreviousStrongCategory = ELeftToRight; - } - - -EXPORT_C TBool TBidirectionalState::IsDefault() const -/** Returns Gets the default 'start of paragraph' state. - -@return ETrue if the object is in its default 'start of paragraph' state. */ - { - return iStackLevel == 0 && - iStack[0].iEmbeddingLevel == 0 && - iStack[0].iOverrideState == ENoOverrideState && - iStack[0].iStartCategory == EOtherNeutral && - iPreviousCategory == ELeftToRight && - iPreviousStrongCategory == ELeftToRight; - } - - -EXPORT_C TBool TBidirectionalState::operator==(const TBidirectionalState& aState) const -/** Return ETrue if two bidirectional states are identical. - -@param aState A bidirectional state. -@return ETrue if two bidirectional states are identical. */ - { - if (iPreviousCategory != aState.iPreviousCategory || - iPreviousStrongCategory != aState.iPreviousStrongCategory || - iStackLevel != aState.iStackLevel) - return FALSE; - const TStackItem* p = iStack; - const TStackItem* q = aState.iStack; - for (int i = 0; i <= iStackLevel; i++, p++, q++) - { - if (p->iStartCategory != q->iStartCategory || - p->iOverrideState != q->iOverrideState || - p->iEmbeddingLevel != q->iEmbeddingLevel) - return FALSE; - } - return TRUE; - } - - -TInt TBidirectionalState::CatToNumber(TInt aCat) -/** -Finds the highest bit set in the input. Used to convert -TBidirectionalState::TCategory into TChar::TBdCategory. -@param aCat a TBidirectionalState::TCategory. -@return The equivalent TChar::TBdCategory. -@internalComponent -*/ { - TInt shifts = 0; - TInt bits = 32; - TInt mask = ~0L; - while (bits != 0) - { - bits >>= 1; - mask <<= bits; - if ((aCat & mask) == 0) - { - aCat <<= bits; - shifts += bits; - } - } - return 31 - shifts; - } - - -EXPORT_C void TBidirectionalState::ExternalizeL(RWriteStream& aDest) -/** Serializes a bidirectional state to an output stream. - -@param aDest An output stream. */ - { - //+ put the prev cat, prev strong cat and stack levels in one number? - // Write the previous category and previous strong category. - aDest.WriteInt8L(CatToNumber(iPreviousCategory)); - aDest.WriteInt8L(CatToNumber(iPreviousStrongCategory)); - - // Write the number of stack levels - aDest.WriteInt8L(iStackLevel); - - /* - Write each stack level as a single number: 5 bits for the start category, 2 for the override state, - 6 for the embedding level. - */ - for (int i = 0; i <= iStackLevel; i++) - { - TInt x = CatToNumber(iStack[i].iStartCategory); - if (iStack[i].iOverrideState == ELeftToRightOverrideState) - { - x |= (KBidirectionalStateOverrideStreamValueLeftToRight << 5); - } - else if (iStack[i].iOverrideState == ERightToLeftOverrideState) - { - x |= (KBidirectionalStateOverrideStreamValueRightToLeft << 5); - } - x |= ((TInt)iStack[i].iEmbeddingLevel << 7); - aDest.WriteInt16L(x); - } - - TInt level = State().iEmbeddingLevel; - if (60 <= level) - { - aDest.WriteInt8L(iPushesBeyond60); - aDest.WriteInt8L(iPushesBeyond61); - } - } - - -EXPORT_C void TBidirectionalState::InternalizeL(RReadStream& aSource) -/** Reads a bidirectional state from an input stream, translating it from its serialized -form. - -@param aSource A source stream. */ - { - // Read the previous category and the previous strong category. - TInt x = aSource.ReadInt8L(); - iPreviousCategory = (TCategory)(1 << x); - x = aSource.ReadInt8L(); - iPreviousStrongCategory = (TCategory)(1 << x); - - // Read the number of stack levels. - iStackLevel = aSource.ReadInt8L(); - - // Read the stack levels. - for (int i = 0; i <= iStackLevel; i++) - { - x = aSource.ReadInt16L(); - iStack[i].iStartCategory = (TCategory)(1 << (x & 0x1F)); - switch ((x >> 5) & 3) - { - case KBidirectionalStateOverrideStreamValueLeftToRight: - iStack[i].iOverrideState = ELeftToRightOverrideState; - break; - case KBidirectionalStateOverrideStreamValueRightToLeft: - iStack[i].iOverrideState = ERightToLeftOverrideState; - break; - case KBidirectionalStateOverrideStreamValueNone: - default: iStack[i].iOverrideState = ENoOverrideState; break; - }; - iStack[i].iEmbeddingLevel = (TUint8)(x >> 7); - } - - TInt level = State().iEmbeddingLevel; - if (60 <= level) - { - iPushesBeyond60 = aSource.ReadInt8L(); - iPushesBeyond61 = aSource.ReadInt8L(); - } - else - { - iPushesBeyond60 = 0; - iPushesBeyond61 = 0; - } - } - - -TBidirectionalState::TBidirectionalState(TChar::TBdCategory aPrevCat, - TChar::TBdCategory aPrevStrongCat, - TBool aParRightToLeft) - /** -Constructor suitable for test code. -@internalComponent -*/ - { - Reset(); - iPreviousCategory = CharToBdCat(aPrevCat); - iPreviousStrongCategory = CharToBdCat(aPrevStrongCat); - iStack[0].iEmbeddingLevel = (TUint8) (aParRightToLeft? 1 : 0); - }