Add support for cleartype text antialiasing (#4711)

## Summary of the Pull Request

I needed to do something to keep sane so today I day of learned about antialiasing. This PR adds the ability to specify the `"antialiasingMode"` as a setting.
* "antialiasingMode": "grayscale": the current behavior, `D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE`
* "antialiasingMode": "cleartype": use `D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE` instead


## PR Checklist
* [x] Closes #1298
* [x] I work here
* [ ] I didn't add tests 
* [x] Requires documentation to be updated

## Detailed Description of the Pull Request / Additional comments
Grayscale:
 
![image](https://user-images.githubusercontent.com/18356694/75173847-2373f680-56f5-11ea-8896-c1cf04c61d41.png)



Cleartype:
![image](https://user-images.githubusercontent.com/18356694/75173854-25d65080-56f5-11ea-9de1-e2d1c343cae5.png)

 


Side-by-side (can you tell which is which?) <!-- grayscale, cleartype -->
 
![image](https://user-images.githubusercontent.com/18356694/75173864-28d14100-56f5-11ea-8bdd-d47a60fbbe4d.png)
This commit is contained in:
Mike Griese 2020-02-25 16:19:57 -06:00 committed by GitHub
parent 4def49c45e
commit 8a5407c13a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 147 additions and 7 deletions

View file

@ -29,6 +29,7 @@ Properties listed below are specific to each unique profile.
| `guid` | _Required_ | String | | Unique identifier of the profile. Written in registry format: `"{00000000-0000-0000-0000-000000000000}"`. |
| `name` | _Required_ | String | | Name of the profile. Displays in the dropdown menu. <br>Additionally, this value will be used as the "title" to pass to the shell on startup. Some shells (like `bash`) may choose to ignore this initial value, while others (`cmd`, `powershell`) may use this value over the lifetime of the application. This "title" behavior can be overridden by using `tabTitle`. |
| `acrylicOpacity` | Optional | Number | `0.5` | When `useAcrylic` is set to `true`, it sets the transparency of the window for the profile. Accepts floating point values from 0-1. |
| `antialiasingMode` | Optional | String | `"grayscale"` | Controls how text is antialiased in the renderer. Possible values are "grayscale", "cleartype" and "aliased". Note that changing this setting will require starting a new terminal instance. |
| `background` | Optional | String | | Sets the background color of the profile. Overrides `background` set in color scheme if `colorscheme` is set. Uses hex color format: `"#rrggbb"`. |
| `backgroundImage` | Optional | String | | Sets the file location of the Image to draw over the window background. |
| `backgroundImageAlignment` | Optional | String | `center` | Sets how the background image aligns to the boundaries of the window. Possible values: `"center"`, `"left"`, `"top"`, `"right"`, `"bottom"`, `"topLeft"`, `"topRight"`, `"bottomLeft"`, `"bottomRight"` |

View file

@ -378,6 +378,16 @@
"minimum": 0,
"type": "number"
},
"antialiasingMode": {
"default": "grayscale",
"description": "Controls how text is antialiased in the renderer. Possible values are \"grayscale\", \"cleartype\" and \"aliased\". Note that changing this setting will require starting a new terminal instance.",
"enum": [
"grayscale",
"cleartype",
"aliased"
],
"type": "string"
},
"background": {
"$ref": "#/definitions/Color",
"default": "#0c0c0c",

View file

@ -49,6 +49,8 @@ static constexpr std::string_view BackgroundImageKey{ "backgroundImage" };
static constexpr std::string_view BackgroundImageOpacityKey{ "backgroundImageOpacity" };
static constexpr std::string_view BackgroundImageStretchModeKey{ "backgroundImageStretchMode" };
static constexpr std::string_view BackgroundImageAlignmentKey{ "backgroundImageAlignment" };
static constexpr std::string_view RetroTerminalEffectKey{ "experimental.retroTerminalEffect" };
static constexpr std::string_view AntialiasingModeKey{ "antialiasingMode" };
// Possible values for closeOnExit
static constexpr std::string_view CloseOnExitAlways{ "always" };
@ -83,8 +85,10 @@ static constexpr std::string_view ImageAlignmentTopRight{ "topRight" };
static constexpr std::string_view ImageAlignmentBottomLeft{ "bottomLeft" };
static constexpr std::string_view ImageAlignmentBottomRight{ "bottomRight" };
// Terminal effects
static constexpr std::string_view RetroTerminalEffectKey{ "experimental.retroTerminalEffect" };
// Possible values for TextAntialiasingMode
static constexpr std::wstring_view AntialiasingModeGrayscale{ L"grayscale" };
static constexpr std::wstring_view AntialiasingModeCleartype{ L"cleartype" };
static constexpr std::wstring_view AntialiasingModeAliased{ L"aliased" };
Profile::Profile() :
Profile(std::nullopt)
@ -124,7 +128,8 @@ Profile::Profile(const std::optional<GUID>& guid) :
_backgroundImageOpacity{},
_backgroundImageStretchMode{},
_backgroundImageAlignment{},
_retroTerminalEffect{}
_retroTerminalEffect{},
_antialiasingMode{ TextAntialiasingMode::Grayscale }
{
}
@ -257,6 +262,8 @@ TerminalSettings Profile::CreateTerminalSettings(const std::unordered_map<std::w
terminalSettings.RetroTerminalEffect(_retroTerminalEffect.value());
}
terminalSettings.AntialiasingMode(_antialiasingMode);
return terminalSettings;
}
@ -377,6 +384,8 @@ Json::Value Profile::ToJson() const
root[JsonKey(RetroTerminalEffectKey)] = _retroTerminalEffect.value();
}
root[JsonKey(AntialiasingModeKey)] = SerializeTextAntialiasingMode(_antialiasingMode).data();
return root;
}
@ -742,6 +751,12 @@ void Profile::LayerJson(const Json::Value& json)
JsonUtils::GetOptionalValue(json, BackgroundImageAlignmentKey, _backgroundImageAlignment, &Profile::_ConvertJsonToAlignment);
JsonUtils::GetOptionalValue(json, RetroTerminalEffectKey, _retroTerminalEffect, Profile::_ConvertJsonToBool);
if (json.isMember(JsonKey(AntialiasingModeKey)))
{
auto antialiasingMode{ json[JsonKey(AntialiasingModeKey)] };
_antialiasingMode = ParseTextAntialiasingMode(GetWstringFromJson(antialiasingMode));
}
}
void Profile::SetFontFace(std::wstring fontFace) noexcept
@ -1349,3 +1364,49 @@ void Profile::SetRetroTerminalEffect(bool value) noexcept
{
_retroTerminalEffect = value;
}
// Method Description:
// - Helper function for converting a user-specified antialiasing mode
// corresponding TextAntialiasingMode enum value
// Arguments:
// - antialiasingMode: The string value from the settings file to parse
// Return Value:
// - The corresponding enum value which maps to the string provided by the user
TextAntialiasingMode Profile::ParseTextAntialiasingMode(const std::wstring& antialiasingMode)
{
if (antialiasingMode == AntialiasingModeCleartype)
{
return TextAntialiasingMode::Cleartype;
}
else if (antialiasingMode == AntialiasingModeAliased)
{
return TextAntialiasingMode::Aliased;
}
else if (antialiasingMode == AntialiasingModeGrayscale)
{
return TextAntialiasingMode::Grayscale;
}
// default behavior for invalid data
return TextAntialiasingMode::Grayscale;
}
// Method Description:
// - Helper function for converting a TextAntialiasingMode to its corresponding
// string value.
// Arguments:
// - antialiasingMode: The enum value to convert to a string.
// Return Value:
// - The string value for the given TextAntialiasingMode
std::wstring_view Profile::SerializeTextAntialiasingMode(const TextAntialiasingMode antialiasingMode)
{
switch (antialiasingMode)
{
case TextAntialiasingMode::Cleartype:
return AntialiasingModeCleartype;
case TextAntialiasingMode::Aliased:
return AntialiasingModeAliased;
default:
case TextAntialiasingMode::Grayscale:
return AntialiasingModeGrayscale;
}
}

View file

@ -123,6 +123,9 @@ private:
static winrt::Microsoft::Terminal::Settings::CursorStyle _ParseCursorShape(const std::wstring& cursorShapeString);
static std::wstring_view _SerializeCursorStyle(const winrt::Microsoft::Terminal::Settings::CursorStyle cursorShape);
static winrt::Microsoft::Terminal::Settings::TextAntialiasingMode ParseTextAntialiasingMode(const std::wstring& antialiasingMode);
static std::wstring_view SerializeTextAntialiasingMode(const winrt::Microsoft::Terminal::Settings::TextAntialiasingMode antialiasingMode);
static GUID _GenerateGuidForProfile(const std::wstring& name, const std::optional<std::wstring>& source) noexcept;
static bool _ConvertJsonToBool(const Json::Value& json);
@ -166,6 +169,8 @@ private:
std::optional<std::wstring> _icon;
winrt::Microsoft::Terminal::Settings::TextAntialiasingMode _antialiasingMode;
friend class TerminalAppLocalTests::SettingsTests;
friend class TerminalAppLocalTests::ProfileTests;
friend class TerminalAppUnitTests::JsonTests;

View file

@ -30,7 +30,8 @@
"icon": "ms-appx:///ProfileIcons/{61c54bbd-c2c6-5271-96e7-009a87ff44bf}.png",
"padding": "8, 8, 8, 8",
"snapOnInput": true,
"useAcrylic": false
"useAcrylic": false,
"antialiasingMode": "grayscale"
},
{
"guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
@ -48,7 +49,8 @@
"icon": "ms-appx:///ProfileIcons/{0caa0dad-35be-5f56-a8ff-afceeeaa6101}.png",
"padding": "8, 8, 8, 8",
"snapOnInput": true,
"useAcrylic": false
"useAcrylic": false,
"antialiasingMode": "grayscale"
}
],
"schemes":

View file

@ -638,6 +638,22 @@ namespace winrt::Microsoft::Terminal::TerminalControl::implementation
// here, the setting will only be used when the Terminal is initialized.
dxEngine->SetRetroTerminalEffects(_settings.RetroTerminalEffect());
// TODO:GH#3927 - hot-reload this one too
// Update DxEngine's AntialiasingMode
switch (_settings.AntialiasingMode())
{
case TextAntialiasingMode::Cleartype:
dxEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE);
break;
case TextAntialiasingMode::Aliased:
dxEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED);
break;
case TextAntialiasingMode::Grayscale:
default:
dxEngine->SetAntialiasingMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
break;
}
THROW_IF_FAILED(dxEngine->Enable());
_renderEngine = std::move(dxEngine);

View file

@ -12,6 +12,13 @@ namespace Microsoft.Terminal.Settings
Hidden
};
enum TextAntialiasingMode
{
Grayscale = 0,
Cleartype,
Aliased
};
// Class Description:
// TerminalSettings encapsulates all settings that control the
// TermControl's behavior. In these settings there is both the entirety
@ -41,5 +48,7 @@ namespace Microsoft.Terminal.Settings
UInt32 SelectionBackground;
Boolean RetroTerminalEffect;
TextAntialiasingMode AntialiasingMode;
};
}

View file

@ -39,7 +39,9 @@ namespace winrt::Microsoft::Terminal::Settings::implementation
_backgroundImageHorizontalAlignment{ winrt::Windows::UI::Xaml::HorizontalAlignment::Center },
_backgroundImageVerticalAlignment{ winrt::Windows::UI::Xaml::VerticalAlignment::Center },
_keyBindings{ nullptr },
_scrollbarState{ ScrollbarState::Visible }
_scrollbarState{ ScrollbarState::Visible },
_antialiasingMode{ TextAntialiasingMode::Grayscale }
{
}
@ -374,4 +376,14 @@ namespace winrt::Microsoft::Terminal::Settings::implementation
_retroTerminalEffect = value;
}
Settings::TextAntialiasingMode TerminalSettings::AntialiasingMode() const noexcept
{
return _antialiasingMode;
}
void TerminalSettings::AntialiasingMode(const Settings::TextAntialiasingMode& value) noexcept
{
_antialiasingMode = value;
}
}

View file

@ -102,6 +102,9 @@ namespace winrt::Microsoft::Terminal::Settings::implementation
bool RetroTerminalEffect() noexcept;
void RetroTerminalEffect(bool value) noexcept;
TextAntialiasingMode AntialiasingMode() const noexcept;
void AntialiasingMode(winrt::Microsoft::Terminal::Settings::TextAntialiasingMode const& value) noexcept;
private:
uint32_t _defaultForeground;
uint32_t _defaultBackground;
@ -137,6 +140,8 @@ namespace winrt::Microsoft::Terminal::Settings::implementation
Settings::ScrollbarState _scrollbarState;
bool _retroTerminalEffect;
Settings::TextAntialiasingMode _antialiasingMode;
};
}

View file

@ -82,6 +82,7 @@ DxEngine::DxEngine() :
_glyphCell{ 0 },
_haveDeviceResources{ false },
_retroTerminalEffects{ false },
_antialiasingMode{ D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE },
_hwndTarget{ static_cast<HWND>(INVALID_HANDLE_VALUE) },
_sizeTarget{ 0 },
_dpi{ USER_DEFAULT_SCREEN_DPI },
@ -504,7 +505,8 @@ HRESULT DxEngine::_SetupTerminalEffects()
&props,
&_d2dRenderTarget));
_d2dRenderTarget->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE);
_d2dRenderTarget->SetTextAntialiasMode(_antialiasingMode);
RETURN_IF_FAILED(_d2dRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::DarkRed),
&_d2dBrushBackground));
@ -2115,3 +2117,17 @@ void DxEngine::SetSelectionBackground(const COLORREF color) noexcept
GetBValue(color) / 255.0f,
0.5f);
}
// Routine Description:
// - Changes the antialiasing mode of the renderer. This must be called before
// _PrepareRenderTarget, otherwise the renderer will default to
// D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE.
// Arguments:
// - antialiasingMode: a value from the D2D1_TEXT_ANTIALIAS_MODE enum. See:
// https://docs.microsoft.com/en-us/windows/win32/api/d2d1/ne-d2d1-d2d1_text_antialias_mode
// Return Value:
// - N/A
void DxEngine::SetAntialiasingMode(const D2D1_TEXT_ANTIALIAS_MODE antialiasingMode) noexcept
{
_antialiasingMode = antialiasingMode;
}

View file

@ -104,6 +104,7 @@ namespace Microsoft::Console::Render
float GetScaling() const noexcept;
void SetSelectionBackground(const COLORREF color) noexcept;
void SetAntialiasingMode(const D2D1_TEXT_ANTIALIAS_MODE antialiasingMode) noexcept;
protected:
[[nodiscard]] HRESULT _DoUpdateTitle(_In_ const std::wstring& newTitle) noexcept override;
@ -190,6 +191,8 @@ namespace Microsoft::Console::Render
::Microsoft::WRL::ComPtr<ID3D11SamplerState> _samplerState;
::Microsoft::WRL::ComPtr<ID3D11Texture2D> _framebufferCapture;
D2D1_TEXT_ANTIALIAS_MODE _antialiasingMode;
[[nodiscard]] HRESULT _CreateDeviceResources(const bool createSwapChain) noexcept;
HRESULT _SetupTerminalEffects();