graphicsdeviceinterface/gdi/sgdi/BIDI.CPP
changeset 183 6a1564a2f3e6
parent 168 2bd88482bfe5
child 194 18f84489a694
--- a/graphicsdeviceinterface/gdi/sgdi/BIDI.CPP	Thu Sep 02 21:50:40 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 <bidi.h>
-#include "BidiCopy.h"
-#include <s32std.h>
-
-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<TBidirectionalState::TCategory>(
-		1 << static_cast<TInt>(aCat));
-	}
-
-TBidirectionalState::TCategory TBidirectionalState::UintToBdCat(TUint aCat)
-	{
-	return static_cast<TBidirectionalState::TCategory>(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<TText*>(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<TCategory>(
-			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<TCategory>(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<TCategory>(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<TCategory>(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<TInt>(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<TUint8>(newLevel);
-	state.iOverrideState = static_cast<TOverrideState>(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);
-	}