mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-07 02:08:17 +02:00
Use Rune for rendering text instead of char.
Fixes crashes with surrogates.
This commit is contained in:
@@ -385,16 +385,16 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var offsetY = (int) (box.Height - font.GetHeight(UIScale)) / 2;
|
||||
var baseLine = new Vector2i(0, offsetY + font.GetAscent(UIScale)) + box.TopLeft;
|
||||
|
||||
foreach (var chr in text)
|
||||
foreach (var rune in text.EnumerateRunes())
|
||||
{
|
||||
if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
|
||||
if (!font.TryGetCharMetrics(rune, UIScale, out var metrics))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(baseLine.X < box.Left || baseLine.X + metrics.Advance > box.Right))
|
||||
{
|
||||
font.DrawChar(handle, chr, baseLine, UIScale, color);
|
||||
font.DrawChar(handle, rune, baseLine, UIScale, color);
|
||||
}
|
||||
|
||||
baseLine += (metrics.Advance, 0);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Animations;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -180,15 +181,15 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
var baseLine = CalcBaseline();
|
||||
|
||||
foreach (var chr in _text)
|
||||
foreach (var rune in _text.EnumerateRunes())
|
||||
{
|
||||
if (chr == '\n')
|
||||
if (rune == new Rune('\n'))
|
||||
{
|
||||
newlines += 1;
|
||||
baseLine = CalcBaseline();
|
||||
}
|
||||
|
||||
var advance = font.DrawChar(handle, chr, baseLine, UIScale, actualFontColor);
|
||||
var advance = font.DrawChar(handle, rune, baseLine, UIScale, actualFontColor);
|
||||
baseLine += (advance, 0);
|
||||
}
|
||||
}
|
||||
@@ -252,16 +253,16 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
var font = ActualFont;
|
||||
var height = font.GetHeight(UIScale);
|
||||
foreach (var chr in _text)
|
||||
foreach (var rune in _text.EnumerateRunes())
|
||||
{
|
||||
if (chr == '\n')
|
||||
if (rune == new Rune('\n'))
|
||||
{
|
||||
_cachedTextWidths.Add(0);
|
||||
height += font.GetLineHeight(UIScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
var metrics = font.GetCharMetrics(chr, UIScale);
|
||||
var metrics = font.GetCharMetrics(rune, UIScale);
|
||||
if (metrics == null)
|
||||
{
|
||||
continue;
|
||||
|
||||
@@ -555,9 +555,9 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var index = 0;
|
||||
var chrPosX = contentBox.Left - _drawOffset;
|
||||
var lastChrPostX = contentBox.Left - _drawOffset;
|
||||
foreach (var chr in _text)
|
||||
foreach (var rune in _text.EnumerateRunes())
|
||||
{
|
||||
if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
|
||||
if (!font.TryGetCharMetrics(rune, UIScale, out var metrics))
|
||||
{
|
||||
index += 1;
|
||||
continue;
|
||||
@@ -767,7 +767,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var posX = 0;
|
||||
var actualCursorPosition = 0;
|
||||
var actualSelectionStartPosition = 0;
|
||||
foreach (var chr in renderedText)
|
||||
foreach (var chr in renderedText.EnumerateRunes())
|
||||
{
|
||||
if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
|
||||
{
|
||||
@@ -816,9 +816,9 @@ namespace Robust.Client.UserInterface.Controls
|
||||
var baseLine = (-drawOffset, offsetY + font.GetAscent(UIScale)) +
|
||||
contentBox.TopLeft;
|
||||
|
||||
foreach (var chr in renderedText)
|
||||
foreach (var rune in renderedText.EnumerateRunes())
|
||||
{
|
||||
if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
|
||||
if (!font.TryGetCharMetrics(rune, UIScale, out var metrics))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -832,7 +832,7 @@ namespace Robust.Client.UserInterface.Controls
|
||||
// Make sure we're not off the left edge of the box.
|
||||
if (baseLine.X + metrics.BearingX + metrics.Width >= contentBox.Left)
|
||||
{
|
||||
font.DrawChar(handle, chr, baseLine, UIScale, renderedTextColor);
|
||||
font.DrawChar(handle, rune, baseLine, UIScale, renderedTextColor);
|
||||
}
|
||||
|
||||
baseLine += (metrics.Advance, 0);
|
||||
|
||||
@@ -163,9 +163,9 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
var titleLength = 0;
|
||||
// Get string length.
|
||||
foreach (var chr in title)
|
||||
foreach (var rune in title.EnumerateRunes())
|
||||
{
|
||||
if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
|
||||
if (!font.TryGetCharMetrics(rune, UIScale, out var metrics))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -196,14 +196,14 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
var baseLine = new Vector2(0, font.GetAscent(UIScale)) + contentBox.TopLeft;
|
||||
|
||||
foreach (var chr in title)
|
||||
foreach (var rune in title.EnumerateRunes())
|
||||
{
|
||||
if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
|
||||
if (!font.TryGetCharMetrics(rune, UIScale, out var metrics))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
font.DrawChar(handle, chr, baseLine, UIScale, active ? fontColorActive : fontColorInactive);
|
||||
font.DrawChar(handle, rune, baseLine, UIScale, active ? fontColorActive : fontColorInactive);
|
||||
baseLine += new Vector2(metrics.Advance, 0);
|
||||
}
|
||||
|
||||
@@ -295,9 +295,9 @@ namespace Robust.Client.UserInterface.Controls
|
||||
|
||||
var titleLength = 0;
|
||||
// Get string length.
|
||||
foreach (var chr in title)
|
||||
foreach (var rune in title.EnumerateRunes())
|
||||
{
|
||||
if (!font.TryGetCharMetrics(chr, UIScale, out var metrics))
|
||||
if (!font.TryGetCharMetrics(rune, UIScale, out var metrics))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -219,9 +219,9 @@ namespace Robust.Client.UserInterface.Controls
|
||||
{
|
||||
var offset = itemSelected.GetContentOffset(Vector2.Zero);
|
||||
var baseLine = offset + (hOffset, vOffset + font.GetAscent(UIScale));
|
||||
foreach (var chr in item.Text)
|
||||
foreach (var rune in item.Text.EnumerateRunes())
|
||||
{
|
||||
baseLine += (font.DrawChar(handle, chr, baseLine, UIScale, Color.White), 0);
|
||||
baseLine += (font.DrawChar(handle, rune, baseLine, UIScale, Color.White), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
@@ -65,7 +66,7 @@ namespace Robust.Client.UserInterface
|
||||
var wordSizePixels = 0;
|
||||
// The horizontal position of the text cursor.
|
||||
var posX = 0;
|
||||
var lastChar = 'A';
|
||||
var lastRune = new Rune('A');
|
||||
// If a word is larger than maxSizeX, we split it.
|
||||
// We need to keep track of some data to split it into two words.
|
||||
(int breakIndex, int wordSizePixels)? forceSplitData = null;
|
||||
@@ -83,14 +84,14 @@ namespace Robust.Client.UserInterface
|
||||
|
||||
var text = tagText.Text;
|
||||
// And go over every character.
|
||||
for (var i = 0; i < text.Length; i++, breakIndexCounter++)
|
||||
foreach (var rune in text.EnumerateRunes())
|
||||
{
|
||||
var chr = text[i];
|
||||
breakIndexCounter += 1;
|
||||
|
||||
if (IsWordBoundary(lastChar, chr) || chr == '\n')
|
||||
if (IsWordBoundary(lastRune, rune) || rune == new Rune('\n'))
|
||||
{
|
||||
// Word boundary means we know where the word ends.
|
||||
if (posX > maxSizeX && lastChar != ' ')
|
||||
if (posX > maxSizeX && lastRune != new Rune(' '))
|
||||
{
|
||||
DebugTools.Assert(wordStartBreakIndex.HasValue,
|
||||
"wordStartBreakIndex can only be null if the word begins at a new line, in which case this branch shouldn't be reached as the word would be split due to being longer than a single line.");
|
||||
@@ -109,22 +110,22 @@ namespace Robust.Client.UserInterface
|
||||
forceSplitData = null;
|
||||
|
||||
// Just manually handle newlines.
|
||||
if (chr == '\n')
|
||||
if (rune == new Rune('\n'))
|
||||
{
|
||||
LineBreaks.Add(breakIndexCounter);
|
||||
Height += font.GetLineHeight(uiScale);
|
||||
maxUsedWidth = Math.Max(maxUsedWidth, posX);
|
||||
posX = 0;
|
||||
lastChar = chr;
|
||||
lastRune = rune;
|
||||
wordStartBreakIndex = null;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Uh just skip unknown characters I guess.
|
||||
if (!font.TryGetCharMetrics(chr, uiScale, out var metrics))
|
||||
if (!font.TryGetCharMetrics(rune, uiScale, out var metrics))
|
||||
{
|
||||
lastChar = chr;
|
||||
lastRune = rune;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -165,7 +166,7 @@ namespace Robust.Client.UserInterface
|
||||
}
|
||||
}
|
||||
|
||||
lastChar = chr;
|
||||
lastRune = rune;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +186,7 @@ namespace Robust.Client.UserInterface
|
||||
Logger.Error("wordStartBreakIndex: null (duh)");
|
||||
Logger.Error($"wordSizePixels: {wordSizePixels}");
|
||||
Logger.Error($"posX: {posX}");
|
||||
Logger.Error($"lastChar: {lastChar}");
|
||||
Logger.Error($"lastChar: {lastRune}");
|
||||
Logger.Error($"forceSplitData: {forceSplitData}");
|
||||
Logger.Error($"LineBreaks: {string.Join(", ", LineBreaks)}");
|
||||
|
||||
@@ -247,9 +248,10 @@ namespace Robust.Client.UserInterface
|
||||
case FormattedMessage.TagText tagText:
|
||||
{
|
||||
var text = tagText.Text;
|
||||
for (var i = 0; i < text.Length; i++, globalBreakCounter++)
|
||||
foreach (var rune in text.EnumerateRunes())
|
||||
{
|
||||
var chr = text[i];
|
||||
globalBreakCounter += 1;
|
||||
|
||||
if (lineBreakIndex < LineBreaks.Count &&
|
||||
LineBreaks[lineBreakIndex] == globalBreakCounter)
|
||||
{
|
||||
@@ -257,7 +259,7 @@ namespace Robust.Client.UserInterface
|
||||
lineBreakIndex += 1;
|
||||
}
|
||||
|
||||
var advance = font.DrawChar(handle, chr, baseLine, uiScale, currentColorTag.Color);
|
||||
var advance = font.DrawChar(handle, rune, baseLine, uiScale, currentColorTag.Color);
|
||||
baseLine += new Vector2(advance, 0);
|
||||
}
|
||||
|
||||
@@ -268,9 +270,9 @@ namespace Robust.Client.UserInterface
|
||||
}
|
||||
|
||||
[Pure]
|
||||
private static bool IsWordBoundary(char a, char b)
|
||||
private static bool IsWordBoundary(Rune a, Rune b)
|
||||
{
|
||||
return a == ' ' || b == ' ' || a == '-' || b == '-';
|
||||
return a == new Rune(' ') || b == new Rune(' ') || a == new Rune('-') || b == new Rune('-');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user