in src/Avalonia.Base/Media/TextFormatting/Unicode/BiDiAlgorithm.cs [410:641]
private void ResolveExplicitEmbeddingLevels()
{
// Redundant?
if (!_hasIsolates && !_hasEmbeddings)
{
return;
}
// Work variables
_statusStack.Clear();
var overflowIsolateCount = 0;
var overflowEmbeddingCount = 0;
var validIsolateCount = 0;
// Constants
const int maxStackDepth = 125;
// Rule X1 - setup initial state
_statusStack.Clear();
// Neutral
_statusStack.Push(new Status(_paragraphEmbeddingLevel, BidiClass.OtherNeutral, false));
// Process all characters
for (var i = 0; i < _originalClasses.Length; i++)
{
switch (_originalClasses[i])
{
case BidiClass.RightToLeftEmbedding:
{
// Rule X2
var newLevel = (sbyte)((_statusStack.Peek().EmbeddingLevel + 1) | 1);
if (newLevel <= maxStackDepth && overflowIsolateCount == 0 && overflowEmbeddingCount == 0)
{
_statusStack.Push(new Status(newLevel, BidiClass.OtherNeutral, false));
_resolvedLevels[i] = newLevel;
}
else if (overflowIsolateCount == 0)
{
overflowEmbeddingCount++;
}
break;
}
case BidiClass.LeftToRightEmbedding:
{
// Rule X3
var newLevel = (sbyte)((_statusStack.Peek().EmbeddingLevel + 2) & ~1);
if (newLevel < maxStackDepth && overflowIsolateCount == 0 && overflowEmbeddingCount == 0)
{
_statusStack.Push(new Status(newLevel, BidiClass.OtherNeutral, false));
_resolvedLevels[i] = newLevel;
}
else if (overflowIsolateCount == 0)
{
overflowEmbeddingCount++;
}
break;
}
case BidiClass.RightToLeftOverride:
{
// Rule X4
var newLevel = (sbyte)((_statusStack.Peek().EmbeddingLevel + 1) | 1);
if (newLevel <= maxStackDepth && overflowIsolateCount == 0 && overflowEmbeddingCount == 0)
{
_statusStack.Push(new Status(newLevel, BidiClass.RightToLeft, false));
_resolvedLevels[i] = newLevel;
}
else if (overflowIsolateCount == 0)
{
overflowEmbeddingCount++;
}
break;
}
case BidiClass.LeftToRightOverride:
{
// Rule X5
var newLevel = (sbyte)((_statusStack.Peek().EmbeddingLevel + 2) & ~1);
if (newLevel <= maxStackDepth && overflowIsolateCount == 0 && overflowEmbeddingCount == 0)
{
_statusStack.Push(new Status(newLevel, BidiClass.LeftToRight, false));
_resolvedLevels[i] = newLevel;
}
else if (overflowIsolateCount == 0)
{
overflowEmbeddingCount++;
}
break;
}
case BidiClass.RightToLeftIsolate:
case BidiClass.LeftToRightIsolate:
case BidiClass.FirstStrongIsolate:
{
// Rule X5a, X5b and X5c
var resolvedIsolate = _originalClasses[i];
if (resolvedIsolate == BidiClass.FirstStrongIsolate)
{
if (!_isolatePairs.TryGetValue(i, out var endOfIsolate))
{
endOfIsolate = _originalClasses.Length;
}
// Rule X5c
if (ResolveEmbeddingLevel(_originalClasses.Slice(i + 1,endOfIsolate - (i + 1))) == 1)
{
resolvedIsolate = BidiClass.RightToLeftIsolate;
}
else
{
resolvedIsolate = BidiClass.LeftToRightIsolate;
}
}
// Replace RLI's level with current embedding level
var tos = _statusStack.Peek();
_resolvedLevels[i] = tos.EmbeddingLevel;
// Apply override
if (tos.OverrideStatus != BidiClass.OtherNeutral)
{
_workingClasses[i] = tos.OverrideStatus;
}
// Work out new level
sbyte newLevel;
if (resolvedIsolate == BidiClass.RightToLeftIsolate)
{
newLevel = (sbyte)((tos.EmbeddingLevel + 1) | 1);
}
else
{
newLevel = (sbyte)((tos.EmbeddingLevel + 2) & ~1);
}
// Valid?
if (newLevel <= maxStackDepth && overflowIsolateCount == 0 && overflowEmbeddingCount == 0)
{
validIsolateCount++;
_statusStack.Push(new Status(newLevel, BidiClass.OtherNeutral, true));
}
else
{
overflowIsolateCount++;
}
break;
}
case BidiClass.BoundaryNeutral:
{
// Mentioned in rule X6 - "for all types besides ..., BN, ..."
// no-op
break;
}
default:
{
// Rule X6
var tos = _statusStack.Peek();
_resolvedLevels[i] = tos.EmbeddingLevel;
if (tos.OverrideStatus != BidiClass.OtherNeutral)
{
_workingClasses[i] = tos.OverrideStatus;
}
break;
}
case BidiClass.PopDirectionalIsolate:
{
// Rule X6a
if (overflowIsolateCount > 0)
{
overflowIsolateCount--;
}
else if (validIsolateCount != 0)
{
overflowEmbeddingCount = 0;
while (!_statusStack.Peek().IsolateStatus)
{
_statusStack.Pop();
}
_statusStack.Pop();
validIsolateCount--;
}
var tos = _statusStack.Peek();
_resolvedLevels[i] = tos.EmbeddingLevel;
if (tos.OverrideStatus != BidiClass.OtherNeutral)
{
_workingClasses[i] = tos.OverrideStatus;
}
break;
}
case BidiClass.PopDirectionalFormat:
{
// Rule X7
if (overflowIsolateCount == 0)
{
if (overflowEmbeddingCount > 0)
{
overflowEmbeddingCount--;
}
else if (!_statusStack.Peek().IsolateStatus && _statusStack.Count >= 2)
{
_statusStack.Pop();
}
}
break;
}
case BidiClass.ParagraphSeparator:
{
// Rule X8
_resolvedLevels[i] = _paragraphEmbeddingLevel;
break;
}
}
}
}