Foreground and background are inverted for certain characters #22591

Open
opened 2026-01-31 08:17:53 +00:00 by claunia · 8 comments
Owner

Originally created by @brunnerh on GitHub (Nov 26, 2024).

Windows Terminal version

1.22.3232.0

Windows build number

10.0.22631.0

Other Software

No response

Steps to reproduce

The Black Large Circle ⬤ (0x2b24) has inverted colors, e.g. printing both Black Circle ● (0x25cf) and the large version in red via PowerShell:

echo "$([char]0x001b)[31m●⬤$([char]0x001b)[0m"

(The explicit coloring is not necessary to show this, though my use case requires the color to indicate various statuses.)

Expected Behavior

In both cases the circle is red.

Actual Behavior

Only for the small circle is red, for the larger one, the background becomes red instead:

screenshot showing inversion

VS Code seems to do this as well in the editor 🤔
screenshot showing inversion in VS code text file

...but its terminal does not
screenshot showing no inversion in VS Code terminal

Originally created by @brunnerh on GitHub (Nov 26, 2024). ### Windows Terminal version 1.22.3232.0 ### Windows build number 10.0.22631.0 ### Other Software _No response_ ### Steps to reproduce The *Black Large Circle* ⬤ (`0x2b24`) has inverted colors, e.g. printing both *Black Circle* ● (`0x25cf`) and the large version in red via PowerShell: ```pwsh echo "$([char]0x001b)[31m●⬤$([char]0x001b)[0m" ``` (The explicit coloring is not necessary to show this, though my use case requires the color to indicate various statuses.) ### Expected Behavior In both cases the circle is red. ### Actual Behavior Only for the small circle is red, for the larger one, the background becomes red instead: ![screenshot showing inversion](https://github.com/user-attachments/assets/18273490-2eb0-46d0-8dcc-f64f1b951f6c) VS Code seems to do this as well in the editor 🤔 ![screenshot showing inversion in VS code text file](https://github.com/user-attachments/assets/a142c610-7482-46c3-9fee-da277174e0cd) ...but its terminal does not ![screenshot showing no inversion in VS Code terminal](https://github.com/user-attachments/assets/0c933aad-f62d-45e0-80c9-9c201ef27b49)
claunia added the Area-RenderingIssue-BugNeeds-ReproProduct-Terminal labels 2026-01-31 08:17:54 +00:00
Author
Owner

@lhecker commented on GitHub (Nov 26, 2024):

I suspect it depends on the font you're using:
Image

So, what font are you using and does it get fixed if you use a different one?

@lhecker commented on GitHub (Nov 26, 2024): I suspect it depends on the font you're using: ![Image](https://github.com/user-attachments/assets/a57aa869-b984-41de-87b7-ee36e2185e50) So, what font are you using and does it get fixed if you use a different one?
Author
Owner

@brunnerh commented on GitHub (Nov 26, 2024):

I tried switching to a few fonts but the ones I picked did not seem to contain the character.
Don't know how to determine what the fallback in Windows Terminal is, but inspecting VS Code shows that Segoe UI Symbol is used for rendering there.

@brunnerh commented on GitHub (Nov 26, 2024): I tried switching to a few fonts but the ones I picked did not seem to contain the character. Don't know how to determine what the fallback in Windows Terminal is, but inspecting VS Code shows that Segoe UI Symbol is used for rendering there.
Author
Owner

@brunnerh commented on GitHub (Nov 30, 2024):

@lhecker Is there any other info I can provide?

@brunnerh commented on GitHub (Nov 30, 2024): @lhecker Is there any other info I can provide?
Author
Owner

@lhecker commented on GitHub (Dec 2, 2024):

I've tried this in a VM with your Windows version and the issue doesn't happen:

Image

Do you have any font modification applications installed like MacType?

Otherwise, compile and run this C++ code:

#include <cstdio>
#include <cwchar>
#include <dwrite.h>

#pragma comment(lib, "dwrite.lib")

#define IFR(expr)                                       \
    {                                                   \
        hr = expr;                                      \
        if (FAILED(hr)) {                               \
            printf("error 0x%08x in: %s\n", hr, #expr); \
            return hr;                                  \
        }                                               \
    }

int main() {
    const auto fontFiles = new IDWriteFontFile*[1024];
    const auto filePath = new wchar_t[64 * 1024];
    HRESULT hr = S_OK;

    IDWriteFactory* factory = nullptr;
    IFR(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&factory)));

    IDWriteFontCollection* fontCollection = nullptr;
    IFR(factory->GetSystemFontCollection(&fontCollection));

    UINT32 familyCount = fontCollection->GetFontFamilyCount();

    for (UINT32 i = 0; i < familyCount; ++i) {
        IDWriteFontFamily* fontFamily = nullptr;
        IFR(fontCollection->GetFontFamily(i, &fontFamily));

        IDWriteFont* font = nullptr;
        IFR(fontFamily->GetFirstMatchingFont(DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font));

        IDWriteFontFace* fontFace = nullptr;
        IFR(font->CreateFontFace(&fontFace));

        const UINT32 codePoint = 0x2B24; // ⬤
        UINT16 glyphIndex;
        IFR(fontFace->GetGlyphIndicesW(&codePoint, 1, &glyphIndex));
        if (FAILED(hr) || glyphIndex == 0) {
            continue;
        }

        UINT32 fileCount = 0;
        IFR(fontFace->GetFiles(&fileCount, nullptr));
        IFR(fontFace->GetFiles(&fileCount, fontFiles));

        for (UINT32 j = 0; j < fileCount; ++j) {
            IDWriteFontFile* fontFile = fontFiles[j];

            const void* referenceKey;
            UINT32 referenceKeySize;
            IFR(fontFile->GetReferenceKey(&referenceKey, &referenceKeySize));

            IDWriteFontFileLoader* loader = nullptr;
            IFR(fontFile->GetLoader(&loader));

            IDWriteLocalFontFileLoader* localLoader = nullptr;
            if (FAILED(loader->QueryInterface(__uuidof(localLoader), (void**)&localLoader))) {
                continue;
            }

            UINT32 filePathLength;
            IFR(localLoader->GetFilePathLengthFromKey(referenceKey, referenceKeySize, &filePathLength));
            IFR(localLoader->GetFilePathFromKey(referenceKey, referenceKeySize, filePath, filePathLength + 1));

            const auto h = CreateFileW(filePath, 0, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
            GetFinalPathNameByHandleW(h, filePath, 64 * 1024, FILE_NAME_NORMALIZED);
            CloseHandle(h);

            auto path = filePath;
            if (wcslen(path) > 5 && wmemcmp(path, L"\\\\?\\", 4) == 0 && path[5] == L':') {
                path += 4;
            }
            printf("%S\n", path);
        }
    }

    return 0;
}

If you don't want to compile it, you can download an .exe here: issue_18249.zip

If everything is correct on your system, it should print this (the WindowsTerminal path may be different):

C:\Windows\Fonts\seguisym.ttf
C:\Program Files\WindowsApps\Microsoft.WindowsTerminalPreview_1.22.3232.0_x64__8wekyb3d8bbwe\CascadiaCode.ttf
C:\Program Files\WindowsApps\Microsoft.WindowsTerminalPreview_1.22.3232.0_x64__8wekyb3d8bbwe\CascadiaMono.ttf
@lhecker commented on GitHub (Dec 2, 2024): I've tried this in a VM with your Windows version and the issue doesn't happen: ![Image](https://github.com/user-attachments/assets/bfc9bffc-6d3d-4222-96af-5206a70e43e6) Do you have any font modification applications installed like MacType? Otherwise, compile and run this C++ code: ```cpp #include <cstdio> #include <cwchar> #include <dwrite.h> #pragma comment(lib, "dwrite.lib") #define IFR(expr) \ { \ hr = expr; \ if (FAILED(hr)) { \ printf("error 0x%08x in: %s\n", hr, #expr); \ return hr; \ } \ } int main() { const auto fontFiles = new IDWriteFontFile*[1024]; const auto filePath = new wchar_t[64 * 1024]; HRESULT hr = S_OK; IDWriteFactory* factory = nullptr; IFR(DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown**>(&factory))); IDWriteFontCollection* fontCollection = nullptr; IFR(factory->GetSystemFontCollection(&fontCollection)); UINT32 familyCount = fontCollection->GetFontFamilyCount(); for (UINT32 i = 0; i < familyCount; ++i) { IDWriteFontFamily* fontFamily = nullptr; IFR(fontCollection->GetFontFamily(i, &fontFamily)); IDWriteFont* font = nullptr; IFR(fontFamily->GetFirstMatchingFont(DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STYLE_NORMAL, &font)); IDWriteFontFace* fontFace = nullptr; IFR(font->CreateFontFace(&fontFace)); const UINT32 codePoint = 0x2B24; // ⬤ UINT16 glyphIndex; IFR(fontFace->GetGlyphIndicesW(&codePoint, 1, &glyphIndex)); if (FAILED(hr) || glyphIndex == 0) { continue; } UINT32 fileCount = 0; IFR(fontFace->GetFiles(&fileCount, nullptr)); IFR(fontFace->GetFiles(&fileCount, fontFiles)); for (UINT32 j = 0; j < fileCount; ++j) { IDWriteFontFile* fontFile = fontFiles[j]; const void* referenceKey; UINT32 referenceKeySize; IFR(fontFile->GetReferenceKey(&referenceKey, &referenceKeySize)); IDWriteFontFileLoader* loader = nullptr; IFR(fontFile->GetLoader(&loader)); IDWriteLocalFontFileLoader* localLoader = nullptr; if (FAILED(loader->QueryInterface(__uuidof(localLoader), (void**)&localLoader))) { continue; } UINT32 filePathLength; IFR(localLoader->GetFilePathLengthFromKey(referenceKey, referenceKeySize, &filePathLength)); IFR(localLoader->GetFilePathFromKey(referenceKey, referenceKeySize, filePath, filePathLength + 1)); const auto h = CreateFileW(filePath, 0, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); GetFinalPathNameByHandleW(h, filePath, 64 * 1024, FILE_NAME_NORMALIZED); CloseHandle(h); auto path = filePath; if (wcslen(path) > 5 && wmemcmp(path, L"\\\\?\\", 4) == 0 && path[5] == L':') { path += 4; } printf("%S\n", path); } } return 0; } ``` If you don't want to compile it, you can download an .exe here: [issue_18249.zip](https://github.com/user-attachments/files/17981765/issue_18249.zip) If everything is correct on your system, it should print this (the WindowsTerminal path may be different): ``` C:\Windows\Fonts\seguisym.ttf C:\Program Files\WindowsApps\Microsoft.WindowsTerminalPreview_1.22.3232.0_x64__8wekyb3d8bbwe\CascadiaCode.ttf C:\Program Files\WindowsApps\Microsoft.WindowsTerminalPreview_1.22.3232.0_x64__8wekyb3d8bbwe\CascadiaMono.ttf ```
Author
Owner

@brunnerh commented on GitHub (Dec 2, 2024):

Do you have any font modification applications installed like MacType?

Not that I know of.
I do have the Japanese language pack & and its IME installed in case that matters (the OS is set to EN and the IME is usually not active, though).

test program output

@brunnerh commented on GitHub (Dec 2, 2024): > Do you have any font modification applications installed like MacType? Not that I know of. I do have the Japanese language pack & and its IME installed in case that matters (the OS is set to EN and the IME is usually not active, though). ![test program output](https://github.com/user-attachments/assets/fe840133-96f2-4a2e-938f-5ed1e6807a22)
Author
Owner

@lhecker commented on GitHub (Dec 3, 2024):

Hmm that looks good. At this point I'm out of ideas.
The Needs-Attention tag will ensure that we come back to triage this issue on Wednesday. Maybe someone else on the team has an idea how to debug this.

In the meantime, you could consider upgrading to Windows 11 24H2. It should be available as an optional update. I recommend searching for known 24H2 bugs before you do that though. For me personally, it's been running fine. 24H2 should theoretically have a new version of seguisym.ttf and so maybe that fixes the issue.

@lhecker commented on GitHub (Dec 3, 2024): Hmm that looks good. At this point I'm out of ideas. The `Needs-Attention` tag will ensure that we come back to triage this issue on Wednesday. Maybe someone else on the team has an idea how to debug this. In the meantime, you could consider upgrading to Windows 11 24H2. It should be available as an optional update. I recommend searching for known 24H2 bugs before you do that though. For me personally, it's been running fine. 24H2 should theoretically have a new version of `seguisym.ttf` and so maybe that fixes the issue.
Author
Owner

@carlos-zamora commented on GitHub (Dec 4, 2024):

Chatted as a team. We still don't have an idea for why this occurs and we're unable to get a repro. Hoping updating to 24H2 will fix it.

@carlos-zamora commented on GitHub (Dec 4, 2024): Chatted as a team. We still don't have an idea for why this occurs and we're unable to get a repro. Hoping updating to 24H2 will fix it.
Author
Owner

@brunnerh commented on GitHub (Dec 9, 2024):

Hoping updating to 24H2 will fix it.

(This is a work machine which is not managed by myself, so I unfortunately don't know when that update will be applied.)

@brunnerh commented on GitHub (Dec 9, 2024): > Hoping updating to 24H2 will fix it. (This is a work machine which is not managed by myself, so I unfortunately don't know when that update will be applied.)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#22591