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

Implement cell size customizations #14255

Merged
merged 8 commits into from
Feb 14, 2023
Merged

Conversation

lhecker
Copy link
Member

@lhecker lhecker commented Oct 19, 2022

Does what it says in the title. After this commit you can customize the height
and width of the terminal's cells. This commit supports parts of CSS'
<length-percentage> data type: Font-size relative sizes as multiples (1.2),
percentage (120%), or advance-width relative (1.2ch), as well as absolute
sizes in CSS pixels (px) or points (pt).

This PR is neither bug free in DxEngine, nor in AtlasEngine.
The former fails to implement glyph advance corrections (for instance #9381),
as well as disallowing glyphs to overlap rows. The latter has the same
overlap issue, but more severely as it tries to shrink glyphs to fit in.

Closes #3498
Closes #14068

Validation Steps Performed

  • Setting height to 1 creates 12pt tall rows ✅
  • Setting height to 1ch creates square cells ✅
  • Setting width to 1 creates square cells ✅
  • Setting width or height to Npx or Npt works ✅
  • Trailing zeroes are trimmed properly during serialization ✅
  • Patching the PR to allow >100 line heights and entering "100.123456"
    displays 6 fractional digits ✅

@ghost ghost added Area-Rendering Text rendering, emoji, complex glyph & font-fallback issues 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. labels Oct 19, 2022
@lhecker lhecker force-pushed the dev/lhecker/3498-line-heights branch from 3660b47 to aaec2a5 Compare October 19, 2022 17:38
Comment on lines +191 to +192
IncrementNumberRounder rounder;
rounder.Increment(1e-6);
Copy link
Member Author

@lhecker lhecker Oct 19, 2022

Choose a reason for hiding this comment

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

@lhecker
Copy link
Member Author

lhecker commented Oct 20, 2022

Finally, after decade waiting for this 😂😘

Before you get too excited, I have to mention again that this PR doesn't work great by itself. Neither the old/stable nor new/preview text renderer work correctly with line heights less than approx. 1.2, which is what a significant portion of people in #3498 have asked for though. I'm working on that separately, but that will unfortunately take another couple months to complete on the side.

Copy link
Member

@carlos-zamora carlos-zamora left a comment

Choose a reason for hiding this comment

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

Mainly concerned about inheritance being done properly. It feels weird to introduce two settings in the cellSize object but then store them as two different members in the settings model.

Also confused why this isn't going in the FontConfig.

@ghost ghost added Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something and removed Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something labels Oct 20, 2022
@ghost ghost added Area-AtlasEngine Issue-Bug It either shouldn't be doing this or needs an investigation. Priority-2 A description (P2) labels Nov 5, 2022
@carlos-zamora carlos-zamora added the Needs-Discussion Something that requires a team discussion before we can proceed label Nov 28, 2022
@github-actions

This comment has been minimized.

@lhecker lhecker force-pushed the dev/lhecker/3498-line-heights branch from 0c945b6 to 9554470 Compare December 6, 2022 16:00
@github-actions

This comment has been minimized.

@lhecker
Copy link
Member Author

lhecker commented Dec 6, 2022

I've moved the two fields into the font config object now. With the primary target being the line height customization, the resulting config might look something like this to the user:

{
    "profiles":
    {
        "defaults":
        {
            "font":
            {
                "face": "Consolas",
                "size": 13,
                "cellHeight": "1.4"
            }
        }
    }
}

@carlos-zamora carlos-zamora removed their assignment Dec 9, 2022
@carlos-zamora carlos-zamora removed the Needs-Discussion Something that requires a team discussion before we can proceed label Dec 9, 2022
carlos-zamora added a commit that referenced this pull request Dec 14, 2022
@zadjii-msft zadjii-msft added this to the Terminal v1.18 milestone Jan 10, 2023
@lhecker lhecker added the AutoMerge Marked for automatic merge by the bot when requirements are met label Feb 14, 2023
@lhecker lhecker merged commit b6e6dd8 into main Feb 14, 2023
@lhecker lhecker deleted the dev/lhecker/3498-line-heights branch February 14, 2023 21:42
Copy link
Member

@DHowett DHowett left a comment

Choose a reason for hiding this comment

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

I have to trust the math in AtlasEngine.api.cpp. I did however check the math in Dx :)

@@ -39,6 +39,7 @@ namespace Microsoft.Terminal.Settings.Editor

OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, FontFace);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Single, FontSize);
OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Double, LineHeight);
Copy link
Member

Choose a reason for hiding this comment

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

one's a single, one's a double!

Copy link
Member Author

Choose a reason for hiding this comment

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

Double is technically the better one, because that's what WinUI's setters and getters use. But we use float and Single throughout the project (which is alright - we don't need more than 2-3 decimal places for anything), including for the FontSize property. LineHeight on the other hand is a custom getter/setter and I felt like it'd be better to use Double if we can when interfacing with WinUI.

@@ -219,7 +219,6 @@
Visibility="{x:Bind Appearance.IsDefault, Mode=OneWay}">
<muxc:NumberBox x:Name="_fontSizeBox"
x:Uid="Profile_FontSizeBox"
AcceptsExpression="False"
Copy link
Member

Choose a reason for hiding this comment

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

Does it accept expressions now?

Copy link
Member Author

Choose a reason for hiding this comment

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

false is the default!

<comment>A description for what the "line height" setting does. Presented near "Profile_LineHeight".</comment>
</data>
<data name="Profile_LineHeightBox.PlaceholderText" xml:space="preserve">
<value>1.2</value>
Copy link
Member

Choose a reason for hiding this comment

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

will users be confused that it says 1.2 but the default is not 1.2?

Copy link
Member Author

Choose a reason for hiding this comment

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

I felt like a placeholder made the input feel a little less confusing. 1.2 is reasonably close to the line height of most fonts (I've seen anything between about 1.15 and 1.35).

// Font settings
const auto fontInfoImpl = winrt::get_self<FontConfig>(_FontInfo);
if (fontInfoImpl->HasAnyOptionSet())
if (auto fontJSON = winrt::get_self<FontConfig>(_FontInfo)->ToJson(); !fontJSON.empty())
Copy link
Member

Choose a reason for hiding this comment

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

interesting. serialize first, then check!

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep! I felt like that it made the code a lot simpler.


CSSLengthPercentage CSSLengthPercentage::FromString(const wchar_t* str)
{
auto& errnoRef = errno; // Nonzero cost, pay it once.
Copy link
Member

Choose a reason for hiding this comment

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

What is the cost and how does this ensure we pay it only once? Is it the thread safety?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think it's because errno is a thread-local variable and this gets the reference to the actual storage early. I took the code and the comment from the STL.

}
else
{
return {};
Copy link
Member

Choose a reason for hiding this comment

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

silent discard - OK?

i notice we have no way of expressing a failure to parse this via the settings warning dialog

Copy link
Member Author

@lhecker lhecker Feb 14, 2023

Choose a reason for hiding this comment

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

It's not okay, but I tried the alternative by implementing a WinRT runtimeclass for CSSLengthPercentage and using that as the value for CellWidth/Height and that was quite the mess. I would not mind adding an extra check during the settings loading. I could call CSSLengthPercentage::FromString inside the FontConfig::LayerJson to check if it's valid since wcstof and wcscmp aren't /that/ expensive. But I wasn't personally convinced it's worth it (by asking myself "Would anyone notice if I don't check this?"). Would you say I should do it?


float CSSLengthPercentage::Resolve(float factor) const noexcept
{
return _value * factor;
Copy link
Member

Choose a reason for hiding this comment

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

I don't love how we have two functions, same name, one of which uses the local reference frame and one of which doesn't. Gotta look more to see what it means

@@ -11,6 +11,7 @@
<Import Project="$(SolutionDir)src\common.build.pre.props" />
<Import Project="$(SolutionDir)src\common.nugetversions.props" />
<ItemGroup>
<ClCompile Include="..\CSSLengthPercentage.cpp" />
Copy link
Member

Choose a reason for hiding this comment

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

Do you need to add this to sources, or will it be okay to not link anything related to CSSLengthPercentage inside Windows?

src/renderer/inc/CSSLengthPercentage.h Show resolved Hide resolved
const auto lineHeight = desired.GetCellHeight().Resolve(defaultHeight, dpiF, heightDesired, widthAdvanceInPx);
const auto baseline = fullPixelAscent + (lineHeight - defaultHeight) / 2.0f;

lineSpacing.height = roundf(lineHeight);
Copy link
Member

Choose a reason for hiding this comment

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

This isn't going to result in a different outcome for users who haven't customized cellHeight, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, because defaultHeight is an integer and that's what Resolve() returns if no cellHeight is set.

@daymxn
Copy link

daymxn commented Feb 21, 2023

with line heights less than approx. 1.2, which is what a significant portion of people in #3498 have asked for though.

Just for the sake of clarity; while a lot of the vocal majority are wanting smaller line heights- there are folk like me out there who want the opposite. I want more distance between my lines. As such, I speak for us all when I say- thank you for doing this. It's the small QoL stuff like this that honestly adds up.

lhecker added a commit that referenced this pull request Feb 28, 2023
lhecker added a commit that referenced this pull request Feb 28, 2023
This just removes some leftover code that I forgot to remove before the merge.
Additionally I forgot to add a newly added file to our `sources` build file.
@Diablo-D3
Copy link

I would love to have access to this feature. Is 1.18 on the horizon?

@zadjii-msft
Copy link
Member

I would love to have access to this feature. Is 1.18 on the horizon?

Yep, probably not for a couple months though. We're working on some... bigger... features that might take longer to bake. We're still discussing the finer points of our plan here though.

microsoft-github-policy-service bot pushed a commit that referenced this pull request Apr 26, 2023
This is practically a from scratch rewrite of AtlasEngine.

The initial approach used a very classic monospace text renderer, where
the viewport is subdivided into cells and each cell is assigned one
glyph texture, just like how real terminals used to work.
While we knew that it would have problems with overly large glyphs,
like those found in less often used languages, we didn't expect the
absolutely massive number of fonts that this approach would break.
For one, the assumption that monospace fonts are actually mostly
monospace has turned out to be a complete lie and we can't force users
to use better designed fonts. But more importantly, we can't just
design an entire Unicode fallback font collection from scratch where
every major glyph is monospace either. This is especially problematic
for vertical overhangs which are extremely difficult to handle in a
way that outperforms the much simpler alternative approach:
Just implementing a bog-standard, modern, quad-based text renderer.

Such an approach is both, less code and runs faster due to a less
complex CPU-side. The text shaping engine (in our case DirectWrite)
has to resolve text into glyph indices anyways, so using them directly
for text rendering allows reduces the effort of turning it back into
text ranges and hashing those. It's memory overhead is also reduced,
because we can now break up long ligatures into their individual glyphs.
Especially on AMD APUs I found this approach to run much faster.

A list of issues I think are either obsolete (and could be closed)
or resolved with this PR in combination with #14255:

Closes #6864
Closes #6974
Closes #8993
Closes #9940
Closes #10128
Closes #12537
Closes #13064
Closes #13527
Closes #13662
Closes #13700
Closes #13989
Closes #14022
Closes #14057
Closes #14094
Closes #14098
Closes #14117
Closes #14533
Closes #14877

## PR Checklist
* Enabling software rendering enables D2D mode ✅
* Both D2D and D3D:
  * Background appears correctly ✅✅
  * Text appears correctly
    * Cascadia Code Regular ✅✅
    * Cascadia Code Bold ✅✅
    * Cascadia Code Italic ✅✅
    * Cascadia Code block chars leave (almost) no gaps ✅✅
    * Terminus TTF at 13.5pt leaves no gaps between block chars ✅✅
    * ``"`u{e0b2}`u{e0b0}"`` in Fira Code Nerd Font forms a square ✅✅
  * Cursor appears correctly
    * Legacy small/medium/large ✅✅
    * Vertical bar ✅✅
    * Underscore ✅✅
    * Empty box ✅✅
    * Full box ✅✅
    * Double underscore ✅✅
  * Changing the cursor color works ✅✅
  * Selection appears correctly ✅✅
  * Scrolling in various manners always renders correctly ✅✅
  * Changing the text antialising mode works ✅✅
  * Semi-transparent backgrounds work ✅✅
  * Scroll-zooming the font size works ✅✅
  * Double-size characters work ✅✅
  * Resizing while text is printing works ✅✅
  * DWM `+Heatmap_ShowDirtyRegions` shows that only the cursor
    region is dirty when it's blinking ✅✅
* D2D
  * Margins are filled with background color ❌
    They're filled with the neighboring's cell background color for
    convenience, as D2D doesn't support `D3D11_TEXTURE_ADDRESS_BORDER`
* D3D
  * Margins are filled with background color ✅
  * Soft fonts work ✅
  * Custom shaders enable continous redraw if time constant is used ✅
  * Retro shader appears correctly ✅
  * Resizing while a custom shader is running works ✅
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-AtlasEngine Area-Rendering Text rendering, emoji, complex glyph & font-fallback issues Area-Settings Issues related to settings and customizability, for console or terminal AutoMerge Marked for automatic merge by the bot when requirements are met Issue-Bug It either shouldn't be doing this or needs an investigation. Issue-Task It's a feature request, but it doesn't really need a major design. Priority-2 A description (P2) Product-Terminal The new Windows Terminal. zBugBash-Consider
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Atlas Engine: Way to get back spaces between lines? Add preference to customize vertical line spacing
6 participants