| 
					
				 | 
			
			
				@@ -119,7 +119,7 @@ namespace Avalonia.Media.TextFormatting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public override TextLine Collapse(params TextCollapsingProperties[] collapsingPropertiesList) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public override TextLine Collapse(params TextCollapsingProperties?[] collapsingPropertiesList) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (collapsingPropertiesList.Length == 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -128,6 +128,11 @@ namespace Avalonia.Media.TextFormatting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var collapsingProperties = collapsingPropertiesList[0]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(collapsingProperties is null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return this; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var collapsedRuns = collapsingProperties.Collapse(this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (collapsedRuns is null) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -166,58 +171,122 @@ namespace Avalonia.Media.TextFormatting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (distance <= 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // hit happens before the line, return the first position 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var firstRun = _textRuns[0]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (firstRun is ShapedTextCharacters shapedTextCharacters) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return shapedTextCharacters.GlyphRun.GetCharacterHitFromDistance(distance, out _); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return GetRunCharacterHit(firstRun, FirstTextSourceIndex, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return _resolvedFlowDirection == FlowDirection.LeftToRight ? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    new CharacterHit(FirstTextSourceIndex) : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    new CharacterHit(FirstTextSourceIndex + Length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (distance >= WidthIncludingTrailingWhitespace) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var lastRun = _textRuns[_textRuns.Count - 1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return GetRunCharacterHit(lastRun, FirstTextSourceIndex + Length - lastRun.TextSourceLength, lastRun.Size.Width); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // process hit that happens within the line 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var characterHit = new CharacterHit(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var currentPosition = FirstTextSourceIndex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var currentDistance = 0.0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            foreach (var currentRun in _textRuns) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (var i = 0; i < _textRuns.Count; i++) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                switch (currentRun) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var currentRun = _textRuns[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if(currentRun is ShapedTextCharacters shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    case ShapedTextCharacters shapedRun: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    var rightToLeftIndex = i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    currentPosition += currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    while (rightToLeftIndex + 1 <= _textRuns.Count - 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        var nextShaped = _textRuns[rightToLeftIndex + 1] as ShapedTextCharacters; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (nextShaped == null || nextShaped.ShapedBuffer.IsLeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            characterHit = shapedRun.GlyphRun.GetCharacterHitFromDistance(distance, out _); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            var offset = Math.Max(0, currentPosition - shapedRun.Text.Start); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        currentPosition += nextShaped.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            characterHit = new CharacterHit(characterHit.FirstCharacterIndex + offset, characterHit.TrailingLength); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        rightToLeftIndex++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    for (var j = i; i <= rightToLeftIndex; j++) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if(j > _textRuns.Count - 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        currentRun = _textRuns[j]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if(currentDistance + currentRun.Size.Width <= distance) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            if (distance < currentRun.Size.Width / 2) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                characterHit = new CharacterHit(currentPosition); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                characterHit = new CharacterHit(currentPosition, currentRun.TextSourceLength); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            currentDistance += currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            currentPosition -= currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        characterHit = GetRunCharacterHit(currentRun, currentPosition, distance - currentDistance); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (distance <= currentRun.Size.Width) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (currentDistance + currentRun.Size.Width < distance) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    currentDistance += currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    currentPosition += currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                distance -= currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                currentPosition += currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                characterHit = GetRunCharacterHit(currentRun, currentPosition, distance - currentDistance); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return characterHit; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private static CharacterHit GetRunCharacterHit(DrawableTextRun run, int currentPosition, double distance) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            CharacterHit characterHit; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            switch (run) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                case ShapedTextCharacters shapedRun: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        characterHit = shapedRun.GlyphRun.GetCharacterHitFromDistance(distance, out _); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        var offset = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (shapedRun.GlyphRun.IsLeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            offset = Math.Max(0, currentPosition - shapedRun.Text.Start); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        //else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        //{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        //    offset = Math.Max(0, currentPosition - shapedRun.Text.Start + shapedRun.Text.Length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        //} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        characterHit = new CharacterHit(characterHit.FirstCharacterIndex + offset, characterHit.TrailingLength); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (distance < run.Size.Width / 2) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            characterHit = new CharacterHit(currentPosition); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            characterHit = new CharacterHit(currentPosition, run.TextSourceLength); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return characterHit; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -226,136 +295,168 @@ namespace Avalonia.Media.TextFormatting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc/> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public override double GetDistanceFromCharacterHit(CharacterHit characterHit) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var isTrailingHit = characterHit.TrailingLength > 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var flowDirection = _paragraphProperties.FlowDirection; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var currentDistance = Start; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var currentPosition = FirstTextSourceIndex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var remainingLength = characterIndex - FirstTextSourceIndex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            GlyphRun? lastRun = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var currentDistance = Start; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            for (var index = 0; index < _textRuns.Count; index++) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (flowDirection == FlowDirection.LeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var textRun = _textRuns[index]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                switch (textRun) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                for (var index = 0; index < _textRuns.Count; index++) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    case ShapedTextCharacters shapedTextCharacters: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            var currentRun = shapedTextCharacters.GlyphRun; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    var currentRun = _textRuns[index]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            if (lastRun != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                if (!lastRun.IsLeftToRight && currentRun.IsLeftToRight && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    currentRun.Characters.Start == characterHit.FirstCharacterIndex && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    characterHit.TrailingLength == 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    return currentDistance; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (currentRun is ShapedTextCharacters shapedRun && !shapedRun.ShapedBuffer.IsLeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        var i = index; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        var rightToLeftWidth = currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            //Look for a hit in within the current run 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            if (currentPosition + remainingLength <= currentPosition + textRun.Text.Length) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        while (i + 1 <= _textRuns.Count - 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            var nextRun = _textRuns[i + 1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            if (nextRun is ShapedTextCharacters nextShapedRun && !nextShapedRun.ShapedBuffer.IsLeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                characterHit = new CharacterHit(textRun.Text.Start + remainingLength); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                i++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                var distance = currentRun.GetDistanceFromCharacterHit(characterHit); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                rightToLeftWidth += nextRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                return currentDistance + distance; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            //Look at the left and right edge of the current run 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            if (currentRun.IsLeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if(i > index) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            while (i >= index) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                if (_resolvedFlowDirection == FlowDirection.LeftToRight && (lastRun == null || lastRun.IsLeftToRight)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    if (characterIndex <= currentPosition) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                        return currentDistance; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    if (characterIndex == currentPosition) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                        return currentDistance; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                currentRun = _textRuns[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                if (characterIndex == currentPosition + textRun.Text.Length && isTrailingHit) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    return currentDistance + currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                if (characterIndex == currentPosition) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                rightToLeftWidth -= currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                if (currentPosition + currentRun.TextSourceLength >= characterIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    return currentDistance + currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                var nextRun = index + 1 < _textRuns.Count ? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    _textRuns[index + 1] as ShapedTextCharacters : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                currentPosition += currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                if (nextRun != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    if (nextRun.ShapedBuffer.IsLeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                        if (characterIndex == currentPosition + textRun.Text.Length) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                            return currentDistance; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                        if (currentPosition + nextRun.Text.Length == characterIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                            return currentDistance; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    if (characterIndex > currentPosition + textRun.Text.Length) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                        return currentDistance; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                remainingLength -= currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                i--; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            lastRun = currentRun; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            currentDistance += rightToLeftWidth; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (currentPosition + currentRun.TextSourceLength >= characterIndex &&  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        TryGetDistanceFromCharacterHit(currentRun, characterHit, currentPosition, remainingLength, flowDirection, out var distance, out _)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        return Math.Max(0, currentDistance + distance); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //No hit hit found so we add the full width 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    currentDistance += currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    currentPosition += currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    remainingLength -= currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                currentDistance += WidthIncludingTrailingWhitespace; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                for (var index = _textRuns.Count - 1; index >= 0; index--) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    var currentRun = _textRuns[index]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (TryGetDistanceFromCharacterHit(currentRun, characterHit, currentPosition, remainingLength, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        flowDirection, out var distance, out var currentGlyphRun)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (currentGlyphRun != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            distance = currentGlyphRun.Size.Width - distance; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        return Math.Max(0, currentDistance - distance); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //No hit hit found so we add the full width 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    currentDistance -= currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    currentPosition += currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    remainingLength -= currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return Math.Max(0, currentDistance); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private static bool TryGetDistanceFromCharacterHit( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            DrawableTextRun currentRun, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            CharacterHit characterHit, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int currentPosition, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int remainingLength, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            FlowDirection flowDirection, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            out double distance, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            out GlyphRun? currentGlyphRun) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var characterIndex = characterHit.FirstCharacterIndex + characterHit.TrailingLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var isTrailingHit = characterHit.TrailingLength > 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            distance = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            currentGlyphRun = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            switch (currentRun) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                case ShapedTextCharacters shapedTextCharacters: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        currentGlyphRun = shapedTextCharacters.GlyphRun; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (currentPosition + remainingLength <= currentPosition + currentRun.Text.Length) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            if (characterIndex == currentPosition) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                return currentDistance; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            characterHit = new CharacterHit(currentRun.Text.Start + remainingLength); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            distance = currentGlyphRun.GetDistanceFromCharacterHit(characterHit); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            if (characterIndex == currentPosition + textRun.TextSourceLength) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (currentPosition + remainingLength == currentPosition + currentRun.Text.Length && isTrailingHit) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            if (currentGlyphRun.IsLeftToRight || flowDirection == FlowDirection.RightToLeft) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                return currentDistance + textRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                distance = currentGlyphRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //No hit hit found so we add the full width 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                currentDistance += textRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                currentPosition += textRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                remainingLength -= textRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (characterIndex == currentPosition) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (remainingLength <= 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (characterIndex == currentPosition + currentRun.TextSourceLength) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            distance = currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return currentDistance; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <inheritdoc/> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -440,121 +541,168 @@ namespace Avalonia.Media.TextFormatting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    startX += currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    currentPosition += currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var characterLength = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var endX = startX; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var runWidth = 0.0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                TextRunBounds? currentRunBounds = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (currentRun is ShapedTextCharacters currentShapedRun) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var offset = Math.Max(0, firstTextSourceIndex - currentPosition); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    currentPosition += offset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var currentShapedRun = currentRun as ShapedTextCharacters; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var startIndex = currentRun.Text.Start + offset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (currentShapedRun != null && !currentShapedRun.ShapedBuffer.IsLeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    var rightToLeftIndex = index; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    startX += currentShapedRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                       currentShapedRun.ShapedBuffer.IsLeftToRight ? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            new CharacterHit(startIndex + remainingLength) : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            new CharacterHit(startIndex)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    while (rightToLeftIndex + 1 <= _textRuns.Count - 1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        var nextShapedRun = _textRuns[rightToLeftIndex + 1] as ShapedTextCharacters; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    endX += endOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (nextShapedRun == null || nextShapedRun.ShapedBuffer.IsLeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        currentShapedRun.ShapedBuffer.IsLeftToRight ? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            new CharacterHit(startIndex) : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            new CharacterHit(startIndex + remainingLength)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        startX += nextShapedRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    startX += startOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        rightToLeftIndex++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (TryGetTextRunBoundsRightToLeft(startX, firstTextSourceIndex, characterIndex, rightToLeftIndex, ref currentPosition, ref remainingLength, out currentRunBounds)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        startX = currentRunBounds!.Rectangle.Left; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        endX = currentRunBounds.Rectangle.Right; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    characterLength = Math.Abs(endHit.FirstCharacterIndex + endHit.TrailingLength - startHit.FirstCharacterIndex - startHit.TrailingLength); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        runWidth = currentRunBounds.Rectangle.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    currentDirection = currentShapedRun.ShapedBuffer.IsLeftToRight ? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        FlowDirection.LeftToRight : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        FlowDirection.RightToLeft; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    currentDirection = FlowDirection.RightToLeft; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (currentPosition < firstTextSourceIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (currentShapedRun != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        startX += currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            startX += currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (currentPosition + currentRun.TextSourceLength <= characterIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        endX += currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            currentPosition += currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        characterLength = currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        var offset = Math.Max(0, firstTextSourceIndex - currentPosition); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        currentPosition += offset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        var startIndex = currentRun.Text.Start + offset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        double startOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        double endOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (currentShapedRun.ShapedBuffer.IsLeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            if (currentPosition < startIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                startOffset = endOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        startX += startOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        endX += endOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        characterLength = Math.Abs(endHit.FirstCharacterIndex + endHit.TrailingLength - startHit.FirstCharacterIndex - startHit.TrailingLength); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        currentDirection = FlowDirection.LeftToRight; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            startX += currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (endX < startX) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    (endX, startX) = (startX, endX); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            currentPosition += currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                //Lines that only contain a linebreak need to be covered here 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if(characterLength == 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    characterLength = NewLineLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var runwidth = endX - startX; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var currentRunBounds = new TextRunBounds(new Rect(startX, 0, runwidth, Height), currentPosition, characterLength, currentRun); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (currentPosition < firstTextSourceIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            startX += currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    currentRect = currentRect.WithWidth(currentWidth + runwidth); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (currentPosition + currentRun.TextSourceLength <= characterIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            endX += currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var textBounds = result[result.Count - 1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            characterLength = currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    textBounds.Rectangle = currentRect; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (endX < startX) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        (endX, startX) = (startX, endX); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    textBounds.TextRunBounds.Add(currentRunBounds); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    currentRect = currentRunBounds.Rectangle; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    //Lines that only contain a linebreak need to be covered here 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (characterLength == 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        characterLength = NewLineLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    result.Add(new TextBounds(currentRect, currentDirection, new List<TextRunBounds> { currentRunBounds })); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    runWidth = endX - startX; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    currentRunBounds = new TextRunBounds(new Rect(startX, 0, runWidth, Height), currentPosition, characterLength, currentRun); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                currentWidth += runwidth; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                currentPosition += characterLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    currentPosition += characterLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    remainingLength -= characterLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }                  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (currentDirection == FlowDirection.LeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (currentRunBounds != null && !MathUtilities.IsZero(runWidth) || NewLineLength > 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (currentPosition > characterIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        currentRect = currentRect.WithWidth(currentWidth + runWidth); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        var textBounds = result[result.Count - 1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        textBounds.Rectangle = currentRect; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        textBounds.TextRunBounds.Add(currentRunBounds!); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (currentPosition <= firstTextSourceIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        currentRect = currentRunBounds!.Rectangle; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        result.Add(new TextBounds(currentRect, currentDirection, new List<TextRunBounds> { currentRunBounds })); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                startX = endX; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                lastDirection = currentDirection; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                remainingLength -= characterLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                currentWidth += runWidth; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+               
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (remainingLength <= 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (remainingLength <= 0 || currentPosition >= characterIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                startX = endX; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                lastDirection = currentDirection; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return result; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -571,7 +719,7 @@ namespace Avalonia.Media.TextFormatting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var currentPosition = FirstTextSourceIndex; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var remainingLength = textLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var startX = Start + WidthIncludingTrailingWhitespace; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var startX = WidthIncludingTrailingWhitespace; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             double currentWidth = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var currentRect = Rect.Empty; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -582,7 +730,7 @@ namespace Avalonia.Media.TextFormatting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (currentPosition + currentRun.TextSourceLength < firstTextSourceIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     startX -= currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -601,20 +749,31 @@ namespace Avalonia.Media.TextFormatting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     currentPosition += offset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     var startIndex = currentRun.Text.Start + offset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    double startOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    double endOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        currentShapedRun.ShapedBuffer.IsLeftToRight ? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            new CharacterHit(startIndex + remainingLength) : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            new CharacterHit(startIndex)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (currentShapedRun.ShapedBuffer.IsLeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (currentPosition < startIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            startOffset = endOffset = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    endX += endOffset - currentShapedRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        currentShapedRun.ShapedBuffer.IsLeftToRight ? 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            new CharacterHit(startIndex) : 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            new CharacterHit(startIndex + remainingLength)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    startX += startOffset - currentShapedRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    startX -= currentRun.Size.Width - startOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    endX -= currentRun.Size.Width - endOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -652,53 +811,150 @@ namespace Avalonia.Media.TextFormatting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var runWidth = endX - startX; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var currentRunBounds = new TextRunBounds(new Rect(startX, 0, runWidth, Height), currentPosition, characterLength, currentRun); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, startX)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var currentRunBounds = new TextRunBounds(new Rect(Start + startX, 0, runWidth, Height), currentPosition, characterLength, currentRun); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (!MathUtilities.IsZero(runWidth) || NewLineLength > 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    currentRect = currentRect.WithWidth(currentWidth + runWidth); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (lastDirection == currentDirection && result.Count > 0 && MathUtilities.AreClose(currentRect.Right, Start + startX)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        currentRect = currentRect.WithWidth(currentWidth + runWidth); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var textBounds = result[result.Count - 1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        var textBounds = result[result.Count - 1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    textBounds.Rectangle = currentRect; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        textBounds.Rectangle = currentRect; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    textBounds.TextRunBounds.Add(currentRunBounds); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    currentRect = currentRunBounds.Rectangle; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        textBounds.TextRunBounds.Add(currentRunBounds); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        currentRect = currentRunBounds.Rectangle; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    result.Add(new TextBounds(currentRect, currentDirection, new List<TextRunBounds> { currentRunBounds })); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        result.Add(new TextBounds(currentRect, currentDirection, new List<TextRunBounds> { currentRunBounds })); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 currentWidth += runWidth; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 currentPosition += characterLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (currentDirection == FlowDirection.LeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (currentPosition > characterIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                lastDirection = currentDirection; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                remainingLength -= characterLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (remainingLength <= 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            result.Reverse(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private bool TryGetTextRunBoundsRightToLeft(double startX, int firstTextSourceIndex, int characterIndex, int runIndex, ref int currentPosition, ref int remainingLength, out TextRunBounds? textRunBounds) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            textRunBounds = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (var index = runIndex; index >= 0; index--) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (TextRuns[index] is not DrawableTextRun currentRun) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (currentPosition + currentRun.TextSourceLength <= firstTextSourceIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (currentPosition > characterIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    startX -= currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    currentPosition += currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var characterLength = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var endX = startX; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (currentRun is ShapedTextCharacters currentShapedRun) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    var offset = Math.Max(0, firstTextSourceIndex - currentPosition); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    currentPosition += offset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    var startIndex = currentRun.Text.Start + offset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    double startOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    double endOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (currentShapedRun.ShapedBuffer.IsLeftToRight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        if (currentPosition < startIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            startOffset = endOffset = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        endOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        startOffset = currentShapedRun.GlyphRun.GetDistanceFromCharacterHit(new CharacterHit(startIndex + remainingLength)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    startX -= currentRun.Size.Width - startOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    endX -= currentRun.Size.Width - endOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    var endHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(endOffset, out _); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    var startHit = currentShapedRun.GlyphRun.GetCharacterHitFromDistance(startOffset, out _); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    characterLength = Math.Abs(startHit.FirstCharacterIndex + startHit.TrailingLength - endHit.FirstCharacterIndex - endHit.TrailingLength); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (currentPosition <= firstTextSourceIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (currentPosition + currentRun.TextSourceLength <= characterIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        endX -= currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (currentPosition < firstTextSourceIndex) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        startX -= currentRun.Size.Width; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        characterLength = currentRun.TextSourceLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                lastDirection = currentDirection; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                remainingLength -= characterLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (endX < startX) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    (endX, startX) = (startX, endX); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (remainingLength <= 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                //Lines that only contain a linebreak need to be covered here 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (characterLength == 0) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    characterLength = NewLineLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var runWidth = endX - startX; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                remainingLength -= characterLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                currentPosition += characterLength; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                textRunBounds = new TextRunBounds(new Rect(Start + startX, 0, runWidth, Height), currentPosition, characterLength, currentRun); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return result; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public override IReadOnlyList<TextBounds> GetTextBounds(int firstTextSourceIndex, int textLength) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1280,6 +1536,11 @@ namespace Avalonia.Media.TextFormatting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var textAlignment = _paragraphProperties.TextAlignment; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var paragraphFlowDirection = _paragraphProperties.FlowDirection; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(textAlignment == TextAlignment.Justify) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                textAlignment = TextAlignment.Start; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             switch (textAlignment) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 case TextAlignment.Start: 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1302,8 +1563,14 @@ namespace Avalonia.Media.TextFormatting 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             switch (textAlignment) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 case TextAlignment.Center: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return Math.Max(0, (_paragraphWidth - width) / 2); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    var start = (_paragraphWidth - width) / 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (paragraphFlowDirection == FlowDirection.RightToLeft) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        start -= (widthIncludingTrailingWhitespace - width); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return Math.Max(0, start); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 case TextAlignment.Right: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     return Math.Max(0, _paragraphWidth - widthIncludingTrailingWhitespace); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 |