Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Bug TextMeshPro

Discussion in 'UGUI & TextMesh Pro' started by Chunikus, Apr 25, 2022.

  1. Chunikus

    Chunikus

    Joined:
    Sep 5, 2020
    Posts:
    28
    Hi.

    in TMPro_MeshUtilities.cs

    method GetWord() can null out on some phantom 0 length word.


    So for this string.

    "Are you sure you want to <gradient="TooltipPreset"><link="tip">fire</link></gradient> this <gradient="TooltipPreset"><link="tip">employee</link></gradient>?"




    Code (CSharp):
    1. var tmpInfo = tmpField.textInfo;
    2.  
    3. for (var i = 0; i < tmpInfo.wordInfo.Length; i++)
    4. {
    5.     var wordInfo = tmpInfo.wordInfo[i] ;
    6.  
    7.     Debug.Log(wordInfo.characterCount + " iterator " +i);
    8.  
    9.     Debug.Log(wordInfo.GetWord());
    10. }

    It will null out after word employee for a word of length=0 iteration i=9.

    Also GetWord() method is a garbage collectors dream since it creates new string after adding each char.
    There is string s= new string(charArr, index, index) method that would be best, if there is some char array stored somewhere. Or maybe a StringBuilder.

    Tmp is great. Thanks for all the work !
     
    Last edited: Apr 25, 2022
  2. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,260
    First thing, always use code blocks to display code, it won't eat the indexer and is the preferred way to read code.

    Not sure why you are getting a null string on the last word which should be index 8, maybe @Stephan_B can enlighten us.

    As for GetWord() generating a new string, that is the nature of strings. Modifying the string will create a new one. Even if it's stored as a char array or a StringBuilder it will need to create a new one to give you the string object. Strings are immutable objects, meaning you cannot modify them only create and read them. If changes are made a new string is allocated. StringBuilder will minimize those allocations when manipulating, but in the end it will still give you a new string object discarding the old.

    These are some examples that will create a new string, every time they are called.
    Code (CSharp):
    1. string s= new string(charArr, index, index);
    2. string s2 = stringBuilder.ToString();
    3. string s3 = stringBuilder.ToString();//There is no caching mechanism so calling it multiple times creates multiple strings even when containing the exact same text.
    4. s += "Hello World";
    5. s2 += s + s3;
     
  3. Chunikus

    Chunikus

    Joined:
    Sep 5, 2020
    Posts:
    28
    You probably didn't look up the method in question.

    This is how it looks.

    Code (CSharp):
    1. public string GetWord()
    2.         {
    3.             string word = string.Empty;
    4.             TMP_CharacterInfo[] charInfo = textComponent.textInfo.characterInfo;
    5.  
    6.             for (int i = firstCharacterIndex; i < lastCharacterIndex + 1; i++)
    7.             {
    8.                 word += charInfo[i].character;
    9.             }
    10.  
    11.             return word;
    12.         }
    It will create 9 new strings for 10 char word.

    This would create just one string, and one chararray that each string has inside it, so the least allocation possible. Also it probably wouldn't get null pointer exception, although i'm not sure why it does null out in the first place.

    Code (CSharp):
    1. public string GetWord()
    2.     {
    3.         if (characterCount <= 0)
    4.         {
    5.             return string.Empty;
    6.         }
    7.  
    8.         char[] charArrayToFill = new char[characterCount];
    9.            
    10.         TMP_CharacterInfo[] charInfo = textComponent.textInfo.characterInfo;
    11.         int iterator2 = 0;
    12.  
    13.         for (int i = firstCharacterIndex; i < lastCharacterIndex + 1; i++)
    14.         {
    15.             charArrayToFill[iterator2] = charInfo[i].character;
    16.             iterator2++;
    17.         }
    18.  
    19.            
    20.         return new string(charArrayToFill);
    21.     }
    Cheers.
     
  4. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,260
    Can't even find the TMP_WordInfo class to confirm. Damn packages, can't look up the class in VS to even find where it is.
     
  5. Chunikus

    Chunikus

    Joined:
    Sep 5, 2020
    Posts:
    28
    it's TMPro_MeshUtilities.cs

    public struct TMP_WordInfo{} is in there.

    UnityProjectName\Library\PackageCache\com.unity.textmeshpro@3.0.6\Scripts\Runtime is the folder with the scripts..