Hello,
I am facing a serious blocking issue with TextMeshPro 3.2.0-pre.10 causing Unity to hold indefinitely.
It’s pretty simple to reproduce with an empty project :
- Create an empty project
- Import TMPro 3.2.0-pre.10 with essentials
- Create an empty scene
- Create a TMPro UI component
- Set the width of the component (recttransform) to 0
- Type the following text inside the quotes : “] --”
- Unity should enter an infinite loop
- Kill Unity with the Tasks Manager
The problem is not present in the version 3.0.9 of TMPro.
I ran a long debugging session and here’s my findings so far (the method is like 2924 lines, so quite hard to debug…)
- The method incriminated is
TextMeshProUGUI::GenerateTextMesh
- It is the loop line 2664 that is ran endlessly (
for (int i = 0; i < m_TextProcessingArray.Length && m_TextProcessingArray[i].unicode != 0; i++)
) - Calling the method
RestoreWordWrappingState(ref m_SavedSoftLineBreakState)
will case a restoration of a previous state of the variable i - Then the code is getting into the switch case statement at line 3701 (
switch (m_overflowMode)
) - Inserting a new line a looping back to the previsouly new i value
To give aditional details, during the for loop, at the index 3 (i = 3), the method RestoreWordWrappingState
is restoring the value 1, and I think it should be 2, but I might be wrong since the GenerateTextMesh
method is not easy to fully understand. Or maybe there’s a missing call to the method SaveWordWrappingState
that will update the stored values.
Is someone able to reproduce it? I can provide the sample project if needed.
Edit 1 :
Looks like it’s related to the combo “Whitespace followed by the character 0x2D”. Especially in presence of “Hyphen” where the hard line break is not set to true and therefore, not saved. Causing an endless loop.
In this case, we are not doing the test if (isFirstWordOfLine)
below, and therefore, not appending a line break.
I propose the following dirty fix that it seems to work (but since I don’t really know the whole TMPro code architecture, this fix might be not working)
Add the content of the code
else if (isFirstWordOfLine)
{
// Special handling for non-breaking space and soft line breaks
if (isWhiteSpace && charCode != 0xA0 || (charCode == 0xAD && isSoftHyphenIgnored == false))
shouldSaveSoftLineBreak = true;
shouldSaveHardLineBreak = true;
}
Directly here :
if ((isWhiteSpace || charCode == 0x200B || charCode == 0x2D || charCode == 0xAD) && (!m_isNonBreakingSpace || ignoreNonBreakingSpace) && charCode != 0xA0 && charCode != 0x2007 && charCode != 0x2011 && charCode != 0x202F && charCode != 0x2060)
{
// Ignore Hyphen (0x2D) when preceded by a whitespace
if ((charCode == 0x2D && m_characterCount > 0 && char.IsWhiteSpace(m_textInfo.characterInfo[m_characterCount - 1].character)) == false)
{
isFirstWordOfLine = false;
shouldSaveHardLineBreak = true;
// Reset soft line breaking point since we now have a valid hard break point.
m_SavedSoftLineBreakState.previous_WordBreak = -1;
}
else if (isFirstWordOfLine)
{
// Special handling for non-breaking space and soft line breaks
if (isWhiteSpace && charCode != 0xA0 || (charCode == 0xAD && isSoftHyphenIgnored == false))
shouldSaveSoftLineBreak = true;
shouldSaveHardLineBreak = true;
}
}
And now it works, but it’s an ugly copy and paste which is not correct from a programming point of view.