wxFont::GetFaceName result is truncated (Issue #25333)

19 views
Skip to first unread message

moi15moi

unread,
Apr 15, 2025, 11:54:32 AM4/15/25
to wx-...@googlegroups.com, Subscribed

Description

On Windows, wxFontEnumerator::GetFacenames and wxFont::GetFaceName use GDI, which truncates the face name to 31 characters. It would be nice if we could get the non-truncated face name.

We can retrieve the non-truncated name via GetOutlineTextMetricsW. I'm not sure if we should use otmpFamilyName or otmpFaceName.

For a example to how to implement it, see this PR: arch1t3cht/Aegisub#155

Platform and version information

  • wxWidgets version: 3.1.4
  • OS: Windows 10.0.26100.3775


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/25333@github.com>

moi15moi created an issue (wxWidgets/wxWidgets#25333)

Description

On Windows, wxFontEnumerator::GetFacenames and wxFont::GetFaceName use GDI, which truncates the face name to 31 characters. It would be nice if we could get the non-truncated face name.

We can retrieve the non-truncated name via GetOutlineTextMetricsW. I'm not sure if we should use otmpFamilyName or otmpFaceName.

For a example to how to implement it, see this PR: arch1t3cht/Aegisub#155

Platform and version information

  • wxWidgets version: 3.1.4
  • OS: Windows 10.0.26100.3775


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/25333@github.com>

VZ

unread,
Apr 15, 2025, 12:42:20 PM4/15/25
to wx-...@googlegroups.com, Subscribed

I didn't know it was even possible to have font names longer than 31 characters under Windows, but I agree that it would be nice to support them if it is.

If the only way to get such a name is from wxFontEnumerator, then it would be better to fix it at this level, perhaps we could check if strlen(lfFaceName) == 31 and use GetOutlineTextMetrics() there in this case? But I also wonder what happens if you try to use a font with longer than 31 characters names in the application, does it work even after truncating it? What happens if there is more than one font on the system with the first 31 characters being equal in all of them?

Concerning the question of which field to use, there is this comment in the sources:

        // FWIW otmpFaceName contains the same thing as otmpFamilyName followed
        // by a possible " Italic" or " Bold" or something else suffix


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/25333/2806812797@github.com>

vadz left a comment (wxWidgets/wxWidgets#25333)

I didn't know it was even possible to have font names longer than 31 characters under Windows, but I agree that it would be nice to support them if it is.

If the only way to get such a name is from wxFontEnumerator, then it would be better to fix it at this level, perhaps we could check if strlen(lfFaceName) == 31 and use GetOutlineTextMetrics() there in this case? But I also wonder what happens if you try to use a font with longer than 31 characters names in the application, does it work even after truncating it? What happens if there is more than one font on the system with the first 31 characters being equal in all of them?

Concerning the question of which field to use, there is this comment in the sources:

        // FWIW otmpFaceName contains the same thing as otmpFamilyName followed
        // by a possible " Italic" or " Bold" or something else suffix


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/25333/2806812797@github.com>

moi15moi

unread,
Apr 15, 2025, 2:32:55 PM4/15/25
to wx-...@googlegroups.com, Subscribed

If you need a font with over 31 characters, you can use this one: fusion-pixel-12px-monospaced-zh_hans.zip

But I also wonder what happens if you try to use a font with longer than 31 characters names in the application, does it work even after truncating it?

I'm not sure what you mean by "does it work?". But, if you try to create a select a font with 31 characters (so truncated) with CreateFontIndirectW and SelectObject, it will select the font successfully.

This sample query ``Fusion Pixel 12px Monospaced zh``
#include <iostream>
#include <dwrite_3.h>
#include <gdiplus.h>
#include <vector>
#include <Windows.h>




int main() {
    HDC dc = CreateCompatibleDC(nullptr);

    if (dc == nullptr) {
        std::cerr << "Could not CreateCompatibleDC" << std::endl;
        return false;
    }

    LOGFONTW lf = { 0 };
    lf.lfCharSet = DEFAULT_CHARSET;
    wcscpy_s(lf.lfFaceName, L"Fusion Pixel 12px Monospaced zh");
    lf.lfItalic = 0;
    lf.lfWeight = 400;
    lf.lfOutPrecision = OUT_TT_PRECIS;
    lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
    lf.lfQuality = ANTIALIASED_QUALITY;
    lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;

    HFONT hfont = CreateFontIndirect(&lf);
    if (hfont == nullptr) {
        std::cerr << "Could not CreateFontIndirect" << std::endl;
        return false;
    }

    SelectObject(dc, hfont);

    UINT otm_size = GetOutlineTextMetricsW(dc, 0, nullptr);
    if (!otm_size) {
        std::cerr << "Failed to initialize the otm_size" << std::endl;
        return false;

    }

    OUTLINETEXTMETRICW* otm = reinterpret_cast<OUTLINETEXTMETRICW*>(malloc(otm_size));

    if (!GetOutlineTextMetricsW(dc, otm_size, otm)) {
        std::cerr << "Failed to initialize the otm" << std::endl;
        return false;
    }

    LPWSTR otmpFamilyName = (LPWSTR)((DWORD_PTR)otm + (DWORD_PTR)otm->otmpFamilyName);
    LPWSTR otmpFaceName = (LPWSTR)((DWORD_PTR)otm + (DWORD_PTR)otm->otmpFaceName);
    LPWSTR otmpStyleName = (LPWSTR)((DWORD_PTR)otm + (DWORD_PTR)otm->otmpStyleName);
    LPWSTR otmpFullName = (LPWSTR)((DWORD_PTR)otm + (DWORD_PTR)otm->otmpFullName);
    std::wcout << L"Family Name: " << otmpFamilyName << std::endl;
    std::wcout << L"Face Name: " << otmpFaceName << std::endl;
    std::wcout << L"Style Name: " << otmpStyleName << std::endl;
    std::wcout << L"Full Name: " << otmpFullName << std::endl;

    int len = GetTextFaceW(dc, 0, nullptr);
    if (!len) {
        std::cerr << "Failed to get lenght GetTextFaceW" << std::endl;
        return false;
    }

    LPWSTR faceName = new WCHAR[len];  // len includes null terminator

    if (!GetTextFaceW(dc, len, faceName)) {
        std::cerr << "Failed to initialize GetTextFaceW" << std::endl;
        return false;
    }
    std::wcout << L"Face Name, but with GetTextFaceW: " << faceName << std::endl;


    free(faceName);
    free(otm);
    DeleteObject(hfont);
    DeleteDC(dc);

    return 0;
}

Here is the result:

Family Name: Fusion Pixel 12px Monospaced zh_hans
Face Name: Fusion Pixel 12px Monospaced zh_hans Regular
Style Name: Regular
Full Name: Fusion-Pixel-12px-Monospaced-zh_hans-Regular;2023.08.24
Face Name, but with GetTextFaceW: Fusion Pixel 12px Monospaced zh_hans

So, as you can see, it is able to query the font and add the truncated text.

then it would be better to fix it at this level, perhaps we could check if strlen(lfFaceName) == 31 and use GetOutlineTextMetrics() there in this case?

Yes, that seems ok.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/25333/2807123865@github.com>

moi15moi left a comment (wxWidgets/wxWidgets#25333)

If you need a font with over 31 characters, you can use this one: fusion-pixel-12px-monospaced-zh_hans.zip

But I also wonder what happens if you try to use a font with longer than 31 characters names in the application, does it work even after truncating it?

I'm not sure what you mean by "does it work?". But, if you try to create a select a font with 31 characters (so truncated) with CreateFontIndirectW and SelectObject, it will select the font successfully.

This sample query ``Fusion Pixel 12px Monospaced zh``
#include <iostream>
#include <dwrite_3.h>
#include <gdiplus.h>
#include <vector>
#include <Windows.h>




int main() {
    HDC dc = CreateCompatibleDC(nullptr);

    if (dc == nullptr) {
        std::cerr << "Could not CreateCompatibleDC" << std::endl;
        return false;
    }

    LOGFONTW lf = { 0 };
    lf.lfCharSet = DEFAULT_CHARSET;
    wcscpy_s(lf.lfFaceName, L"Fusion Pixel 12px Monospaced zh");
    lf.lfItalic = 0;
    lf.lfWeight = 400;
    lf.lfOutPrecision = OUT_TT_PRECIS;
    lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
    lf.lfQuality = ANTIALIASED_QUALITY;
    lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;

    HFONT hfont = CreateFontIndirect(&lf);
    if (hfont == nullptr) {
        std::cerr << "Could not CreateFontIndirect" << std::endl;
        return false;
    }

    SelectObject(dc, hfont);

    UINT otm_size = GetOutlineTextMetricsW(dc, 0, nullptr);
    if (!otm_size) {
        std::cerr << "Failed to initialize the otm_size" << std::endl;
        return false;

    }

    OUTLINETEXTMETRICW* otm = reinterpret_cast<OUTLINETEXTMETRICW*>(malloc(otm_size));

    if (!GetOutlineTextMetricsW(dc, otm_size, otm)) {
        std::cerr << "Failed to initialize the otm" << std::endl;
        return false;
    }

    LPWSTR otmpFamilyName = (LPWSTR)((DWORD_PTR)otm + (DWORD_PTR)otm->otmpFamilyName);
    LPWSTR otmpFaceName = (LPWSTR)((DWORD_PTR)otm + (DWORD_PTR)otm->otmpFaceName);
    LPWSTR otmpStyleName = (LPWSTR)((DWORD_PTR)otm + (DWORD_PTR)otm->otmpStyleName);
    LPWSTR otmpFullName = (LPWSTR)((DWORD_PTR)otm + (DWORD_PTR)otm->otmpFullName);
    std::wcout << L"Family Name: " << otmpFamilyName << std::endl;
    std::wcout << L"Face Name: " << otmpFaceName << std::endl;
    std::wcout << L"Style Name: " << otmpStyleName << std::endl;
    std::wcout << L"Full Name: " << otmpFullName << std::endl;

    int len = GetTextFaceW(dc, 0, nullptr);
    if (!len) {
        std::cerr << "Failed to get lenght GetTextFaceW" << std::endl;
        return false;
    }

    LPWSTR faceName = new WCHAR[len];  // len includes null terminator

    if (!GetTextFaceW(dc, len, faceName)) {
        std::cerr << "Failed to initialize GetTextFaceW" << std::endl;
        return false;
    }
    std::wcout << L"Face Name, but with GetTextFaceW: " << faceName << std::endl;


    free(faceName);
    free(otm);
    DeleteObject(hfont);
    DeleteDC(dc);

    return 0;
}

Here is the result:

Family Name: Fusion Pixel 12px Monospaced zh_hans
Face Name: Fusion Pixel 12px Monospaced zh_hans Regular
Style Name: Regular
Full Name: Fusion-Pixel-12px-Monospaced-zh_hans-Regular;2023.08.24
Face Name, but with GetTextFaceW: Fusion Pixel 12px Monospaced zh_hans

So, as you can see, it is able to query the font and add the truncated text.

then it would be better to fix it at this level, perhaps we could check if strlen(lfFaceName) == 31 and use GetOutlineTextMetrics() there in this case?

Yes, that seems ok.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/25333/2807123865@github.com>

VZ

unread,
Apr 15, 2025, 3:56:56 PM4/15/25
to wx-...@googlegroups.com, Subscribed

I'm not sure what you mean by "does it work?". But, if you try to create a select a font with 31 characters (so truncated) with CreateFontIndirectW and SelectObject, it will select the font successfully.

Yes, this is what I meant, thanks for confirming that this does work. I still wonder what happens if there are 2 different fonts names equal up to 32nd character.

Anyhow, if you can make the changes discussed here and make a PR with them, it would be welcome!


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/25333/2807335565@github.com>

vadz left a comment (wxWidgets/wxWidgets#25333)

I'm not sure what you mean by "does it work?". But, if you try to create a select a font with 31 characters (so truncated) with CreateFontIndirectW and SelectObject, it will select the font successfully.

Yes, this is what I meant, thanks for confirming that this does work. I still wonder what happens if there are 2 different fonts names equal up to 32nd character.

Anyhow, if you can make the changes discussed here and make a PR with them, it would be welcome!


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/25333/2807335565@github.com>

VZ

unread,
Jan 10, 2026, 10:31:51 AM (yesterday) Jan 10
to wx-...@googlegroups.com, Subscribed

Closed #25333 as completed via c73b1b1.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issue/25333/issue_event/21964077113@github.com>

Reply all
Reply to author
Forward
0 new messages