Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice

Bug Font.HasCharacter ALWAYS returns true if Font is set to Dynamic (& some fonts REQUIRE Dynamic)

Discussion in 'UI Toolkit' started by mikejm_, Aug 12, 2022.

  1. mikejm_

    mikejm_

    Joined:
    Oct 9, 2021
    Posts:
    346
    I am attempting to build my own Font fallback system for Label as the current one does not seem to work as described here. In my system, I would like to test a string letter by letter and if the current font does not have any characters, switch the whole Label to a more comprehensive backup font.

    In theory this can be done with:

    Code (csharp):
    1.        Font font = Resources.Load<Font>("Montserrat-ExtraBold");
    2.        string testString = "Telugu: ఈరోజు బయట వర్షం పడుతోంది."; //test phrase
    3.        foreach (char c in testString) {
    4.             bool hasChar = font.HasCharacter(c);
    5.             Debug.Log(c + " : " + hasChar); //will always return true unless font set to "Unicode"
    6.         }
    However this doesn't work.

    Problem 1: Font.HasCharacter ALWAYS Returns True if Font is Dynamic
    It returns true for all characters, even the ones it blatantly can't display and doesn't have. The above is a special string of Telugu (an Indian language) that is most definitely not covered, and yet it will debug saying true for every single character, even the Telugu ones it can't display.

    Applying this "testString" to a Label and putting in on screen with that Font proves it cannot display these characters either, yet it will still return "true" for all.

    The only way I can see to get the correct output is to set the Font to Unicode. Then Debugs out correctly that it does not have the Telugu characters.

    Problem 2: Many Fonts MUST Be Set Dynamic or They Don't Work At All
    However, this creates another problem as it seems Montserrat and a few other fonts I tested cannot display anything unless they are set to Dynamic.

    If I set the Font to Unicode or ASCII and restart the program (must be restarted to register the change - perhaps another issue), a Label displaying any strings with this Font goes blank.

    Solution?
    The only workaround I just thought of is to add TWO copies of each Font - one set to Unicode (so it will output the right Font.HasCharacter) and another set to Dynamic (which is used for the Labels so it can actually work). This works, but this is crazy isn't it?

    Either Font.HasCharacter should work in Dynamic (ideally) and/or normal common Fonts should still work when they are not set to Dynamic.

    I presume Font.HasCharacter should also NOT check the fallback fonts in its operation if in Dynamic mode or this will also not give you the useful information you would usually want. (I have no way to test to see if it does though as it doesn't work at all.)

    Is this a known issue? Is there something I'm missing? I can submit a bug report. Thanks.
     
    Last edited: Aug 12, 2022
  2. HugoBD-Unity

    HugoBD-Unity

    Unity Technologies

    Joined:
    May 14, 2018
    Posts:
    496
    Hi @mikejm_ !

    I posted a similar answer in your other thread. I would highly recommend switching to using TextCore with FontAsset. You shouldn't need to recreate your own fallback font system as the one offered by TextCore should work out of the box.

    If you are facing issues with TextCore or you see missing features please let us know. I'll do everything I can to address those.
     
    mikejm_ likes this.
  3. mikejm_

    mikejm_

    Joined:
    Oct 9, 2021
    Posts:
    346
    Thanks Hugo, it's very much appreciated. As I replied here I did not realize I was not supposed to loading my TTF/OTF fonts directly. I am now instead converting to Font Assets (then FontDefinition in code) and setting those to Label. The Font Assets do seem to have much better fall back lists. This does seem to work for fallback fonts which is great!

    The main remaining problem then is just the question I raised in that thread: What method can let me find where vertices of letters are in a Label that uses a FontAsset?

    As I explained there, I have currently made custom TextField classes from Label by using a TextGenerator with TextGenerationSettings matching the Label. This TextGenerator can work identically to the Label and then tell me where the vertices are. It works perfectly currently.

    However, if I switch to FontAsset, TextGenerator does not support FontAsset and when a fallback font is used they will desynchronize. I will no longer then know where my Label letters are.

    The only idea I have now is to replace TextGenerator in this usage with a TMP Text object which I think gives per letter vertices as well but then I need a TMP Font Asset as well I think for every font which doubles my fonts (every font then needs Font Asset and TMP Font Asset).

    I understand you are updating your built in TextField for 2023 but either way I will still want to use my own custom objects as I must manage all clicks and input in my app myself. Thus no matter what I must still be able to find where my Label per-letter bounding vertices are.

    Possible solutions that I think would allow Font Asset to be used without making a duplicate TMP Font Asset:

    - Allow TextGenerationSettings to take Font Asset.
    - Have Label store an array of public per-letter bounding vertex information directly inside it like TextGenerator or I think TMP does.

    Or is there something else that would work? Thanks again.
     
    Last edited: Aug 15, 2022
  4. HugoBD-Unity

    HugoBD-Unity

    Unity Technologies

    Joined:
    May 14, 2018
    Posts:
    496
    I am really sorry to hear you've lost time trying to make it work with the legacy Text System. We are considering removing the -unity-font field from the UI Builder to make it more obvious.

    To achieve this, you'll need to use low-level API of the TextEngine and need internal access. I have to warn you that internal APIs are always subject to change.

    I believe you are accessing the Legacy TextGenerator. As mentioned in this post, UI Toolkit is now using TextCore for its TextEngine. So this is the Generator you are looking for UnityEngine.TextCore.Text.TextGenerator.

    As for the vertices of letters, this is currently internal as this area is still subject to change and we are not ready to expose it publicly. If you need the data you could access it through reflection, and it is located here (as of 2022.2) : m_Label.uitkTextHandle.textInfo.

    Out of curiosity, what features do you need that aren't part of the built-in TextField ?
     
  5. mikejm_

    mikejm_

    Joined:
    Oct 9, 2021
    Posts:
    346
    Thanks Hugo! FYI, UnityEngine.TextCore.Text.TextGenerator is protected and we cannot access it. However, with some time and effort and your suggestion, I was able to use some crazy Reflection voodoo I did not know was possible to access the vertices from inside Label.

    So I should be able to work just fine from that. Thanks again. What a relief! I am very happy to have the data.

    The last major problem in my way for my app is then this bug which I posted here:

    https://forum.unity.com/threads/tou...s-functions-in-current-android-unity.1303752/

    https://forum.unity.com/threads/tou...s-functions-in-current-android-unity.1303749/

    And here in reply to Tomas1856:

    https://forum.unity.com/threads/touchscreenkeyboard-hideinput-changes-in-2019-1.666454/#post-8250030

    I submitted a bug report IN-9117 almost two months ago but have seen no activity on it.

    I realize this may not necessarily be your primary domain, but you and your fellow UI Toolkit folks (along with perhaps the video people) seem to be the most active and responsive on these forum. I am wondering if you might know anything about this problem or who would be the right person to share any ideas for solving it (or solve it). If so, might you be able to try to give them a nudge or ensure it is not lost in the shuffle?

    I am sure you get a lot of bug reports but this one is really crippling for the use of the onscreen keyboard in any capacity currently. I hope a solution is possible.

    Thanks for your help as always.
     
    HugoBD-Unity likes this.
  6. HugoBD-Unity

    HugoBD-Unity

    Unity Technologies

    Joined:
    May 14, 2018
    Posts:
    496
    Hi @mikejm_ ! Glad you were able to sort this out using reflection. We know it's not ideal, but we can't commit to exposing this data publicly as it's subject to change. Remember that this may break when upgrading to a newer version of Unity. If you have questions about a particular break after upgrading ask and I'll see if I'm able to help.

    As for the softkeybaord issues, I'll try to send the right people to your thread.
     
    mikejm_ likes this.
  7. HugoBD-Unity

    HugoBD-Unity

    Unity Technologies

    Joined:
    May 14, 2018
    Posts:
    496
    Disclaimer: Some of what is said below is currently internal as we are actively working on adapting TextCore to be the text system used across all of Unity's UI Frameworks.

    The TextCore TextGenerator is also built with a service-like architecture in mind. You can programmatically generate the TextMesh using GenerateTextMesh and calculate the layout using GetPreferredValues.

    In UITK, you can achieve the same using the public method TextElement.MeasureTextSize(), but you are right it is indeed inconvenient as you need to wait for 1 frame before the new style/layout values are processed....
     
    mikejm_ likes this.
  8. mikejm_

    mikejm_

    Joined:
    Oct 9, 2021
    Posts:
    346
    Thank you again! That link was very helpful.

    I understand how it works much better now and I was able to get the TextCore TextGenerator working by reflection. This is perfect for me.
     
    HugoBD-Unity likes this.
  9. NeverTrustShadows

    NeverTrustShadows

    Joined:
    Mar 15, 2020
    Posts:
    15
    This is one confusing thread, has nothing to do with the title and has nothing to do with the first explanation.
    How do we check if certain font has certain character? That is all I would like to know really.
     
    suke_dev likes this.