Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for customizing font fallback #16821

Merged
merged 11 commits into from
Mar 26, 2024
Merged

Conversation

lhecker
Copy link
Member

@lhecker lhecker commented Mar 5, 2024

This adds support for specifying more than one font family using a
syntax that is similar to CSS' font-family property.
The implementation is straight-forward and is effectively
just a wrapper around IDWriteFontFallbackBuilder.

Closes #2664

PR Checklist

  • Font fallback
    • Write "「猫」"
    • Use "Consolas" and remember the shape of the glyphs
    • Use "Consolas, MS Gothic" and check that it changed ✅
  • Settings UI autocompletion
    • It completes ✅
    • It filters ✅
    • It recognizes commas and starts a new name ✅
  • All invalid font names are listed in the warning message ✅

@microsoft-github-policy-service microsoft-github-policy-service bot added Issue-Task It's a feature request, but it doesn't really need a major design. Area-Fonts Related to the font Area-Settings Issues related to settings and customizability, for console or terminal Product-Terminal The new Windows Terminal. labels Mar 5, 2024
.github/actions/spelling/expect/expect.txt Fixed Show fixed Hide fixed
tools/Lock-CascadiaFont.ps1 Fixed Show fixed Hide fixed
tools/Lock-CascadiaFont.ps1 Fixed Show fixed Hide fixed

This comment has been minimized.

_actualFont.GetFaceName()) };
auto noticeArgs = winrt::make<NoticeEventArgs>(NoticeLevel::Warning, message);
_RaiseNoticeHandlers(*this, std::move(noticeArgs));
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This went into TermControl.cpp.

{
}

WINRT_PROPERTY(uint64_t, Result);
WINRT_PROPERTY(HRESULT, Result);
WINRT_PROPERTY(winrt::hstring, Parameter);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will allow us to carry messages to the warning popup code in TermControl.

}
}
return _hasPowerlineCharacters.value_or(false);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Font::HasPowerlineCharacters() was moved to AppearanceViewModel::HasPowerlineCharacters(), because "has" is now a function of >1 fonts (= can't be attached to a single Font instance). The detection itself went into _refreshFontFaceDependents below.

@@ -526,7 +618,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation

// find one axis that does not already exist, and add that
// if there are no more possible axes to add, the button is disabled so there shouldn't be a way to get here
const auto possibleAxesTagsAndNames = ProfileViewModel::FindFontWithLocalizedName(FontFace()).FontAxesTagsAndNames();
const auto possibleAxesTagsAndNames = ProfileViewModel::FindFontWithLocalizedName(_primaryFontName).FontAxesTagsAndNames();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are all placeholders until we refactor the font axis/feature code later on.
Refactoring it as part of this PR was not possible unfortunately.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious as to what the refactor entails - do we need to combine all the possible axes/features for all the fonts in the given family?

Copy link
Member Author

@lhecker lhecker Mar 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. We'll have to basically detach the Font object entirely from axes and features. In my opinion we should move the (re)generation of axes and features from Font, ProfileViewModel, and Appearance all over into AppearanceViewModel.
There, we have access to the parsed list of fonts families (which this PR adds) and this allows us to generate the union of axes and features. Then we can split the collection up into those that are currently in use and those that are still available for selection and expose both lists (in whatever form) to the view.

Copy link
Member Author

@lhecker lhecker Mar 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, it may be worth mentioning that we create AppearanceViewModels eagerly when loading the settings UI, which is not great, because this causes all the DirectWrite code to run eagerly too. It'd be nice if they were created lazily somehow. (I mean we don't have to address that now - it's just a thing I noticed.)

@@ -39,20 +39,21 @@ struct ViewModelHelper

#define _BASE_OBSERVABLE_PROJECTED_SETTING(target, name) \
public: \
auto name() const noexcept \
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WinRT function calls are never noexcept so this was always a lie. 😅

// Commas are treated literally inside strings.
break;
}
if (!family.empty())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delayedSpace is ignored here - which I believe is correct?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because we want to strip trailing whitespace.

Copy link
Member

@zadjii-msft zadjii-msft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a ✅ EXCEPT for the very scary sounding FindFontWithLocalizedName comment that doesn't have a linked work item. If that's 1.21 blocking, then we need to make sure we get to it.

src/renderer/atlas/AtlasEngine.api.cpp Show resolved Hide resolved
src/renderer/atlas/AtlasEngine.api.cpp Show resolved Hide resolved
src/renderer/atlas/AtlasEngine.api.cpp Show resolved Hide resolved
appearance.FontFace(fontSpec);
}

// TODO: Any use of FindFontWithLocalizedName is broken and requires refactoring in time for version 1.21.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on a scale of 1-scary, this comment sounds scary? Like, ship-blocking scary. Do we have a plan for this?

Copy link
Member Author

@lhecker lhecker Mar 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Font features and axes have multiple blocking bugs right now anyway (I mean even without this PR), so I figured that we can do a follow-up refactoring later where we fix both issues: The existing bugs and the incompatibilities introduced by this one. I'm half done making the changes to fix this and they're highly related.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmk. I'll file something and tag you on it just to make sure we don't lose it.

src/inc/til/string.h Outdated Show resolved Hide resolved
src/cascadia/TerminalSettingsEditor/Appearances.xaml Outdated Show resolved Hide resolved
@DHowett DHowett added this pull request to the merge queue Mar 26, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to a conflict with the base branch Mar 26, 2024
@DHowett DHowett enabled auto-merge March 26, 2024 22:41
@DHowett DHowett added this pull request to the merge queue Mar 26, 2024
Merged via the queue into main with commit de7f931 Mar 26, 2024
20 checks passed
@DHowett DHowett deleted the dev/lhecker/2664-font-fallback branch March 26, 2024 23:38
lhecker added a commit that referenced this pull request Apr 1, 2024
DHowett pushed a commit that referenced this pull request Apr 1, 2024
* Since `FindFontWithLocalizedName` is broken (intentionally and
  temporarily until #16943 is fixed) we have to be extra be careful
  not to return a nullptr `Font`.
* Portable builds may not have a broken font cache, but also not have
  the given font (Cascadia Mono for instance) installed. This requires
  us to load the nearby fonts even if there aren't any exceptions.

## Validation Steps Performed
* Open `src/cascadia/CascadiaResources.build.items`
  and remove the `Condition` for .ttf files
* Deploy on a clean Windows 10 VM
* Cascadia Mono loads without issues ✅
* Open the `Settings > Defaults > Appearance`,
  enter a non-existing font and hit Save
* Doesn't crash ✅
github-merge-queue bot pushed a commit that referenced this pull request May 1, 2024
Due to #16821 everything about #16104 broke. This PR rights the wrongs
by rewriting all the `Font`-based code to not use `Font` at all.
Instead we split the font spec once into font families, do a lot of
complex logic to split font axes/features into used and unused ones
and construct all the UI elements. So. much. boilerplate. code.

Closes #16943

## Validation Steps Performed
There are more edge cases than I can list here... Some ideas:
* Edit the settings.json with invalid axis/feature keys ✅
* ...out of range values ✅
* Settings UI reloads when the settings.json changes ✅
* Adding axes/features works ✅
* Removing axes/features works ✅
* Resetting axes/features works ✅
* Axes/features apply in the renderer when saving ✅
@Laurensdc
Copy link

Laurensdc commented Jul 13, 2024

This doesn't seem to work?

I'm configuring it as follows:

 "profiles": 
    {
        "defaults": 
        {
            "colorScheme": "One Half Dark",
            "experimental.retroTerminalEffect": false,
            "font": 
            {
                "face": "Comic Code Ligatures, FiraCode Nerd Font Mono",
                "features": {
                    "liga": 1
                },
                "size": 10.0,
                "weight": "light"
            },

            "opacity": 80,
            "useAcrylic": true
        },

and get the following error:

image

I'm on version 1.20.11781.0

@lhecker
Copy link
Member Author

lhecker commented Jul 13, 2024

It's in Windows Terminal Preview right now (version 1.21). You can find it in the app store, or here: https://github.com/microsoft/terminal/releases/tag/v1.21.1772.0

@Laurensdc
Copy link

Ah I thought I was going crazy, but makes sense. Thanks a lot! Works like a charm as well!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Fonts Related to the font Area-Settings Issues related to settings and customizability, for console or terminal Issue-Task It's a feature request, but it doesn't really need a major design. Product-Terminal The new Windows Terminal.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow for the configuration of font fallback
6 participants