Repository: microsoft/terminal (language: cpp)

Issue:
[Settings] An option to disable colour font emoji
Is there any merit to having an option to disable colour font emoji?

So any emoji used will be single colour using the font colour settings?

_Originally posted by @mdtauk in https://github.com/microsoft/terminal/issues/190#issuecomment-495192220_


Discussion / hints:
There's some discussion about getting options into the renderer in #817.
From @francogp

> # Environment
> ```
> Windows build number: Win32NT 10.0.19041.0 Microsoft Windows NT 10.0.19041.0
> Windows Terminal version (if applicable): 1.0.1402.0
> 
> Using WSL Ubuntu LTS version 20.04
> ```
> 
> I'm using this font, but can reproduced with others too: [JetBrainsMono](https://github.com/ryanoasis/nerd-fonts/blob/master/patched-fonts/JetBrainsMono/Regular/complete/JetBrains%20Mono%20Regular%20Nerd%20Font%20Complete%20Mono%20Windows%20Compatible.ttf?rgh-link-date=2020-06-20T18%3A47%3A05Z)
> 
> # Expected behavior
> image taken by using other windows terminal emulators, like Terminus on windows, and Tilix or Terminator on Ubuntu. All the same results
> ![image](https://user-images.githubusercontent.com/2739706/85209354-94c35f00-b30d-11ea-8d77-e6779d68df98.png)
> 
> # Actual behavior
> ![image](https://user-images.githubusercontent.com/2739706/85209296-1961ad80-b30d-11ea-86d7-4b95fd9bbc5a.png)
> Lots of characters/emoticons have a wrong size at render. This is just an example. Look up the check emoticon ✔
> It seems that its ignoring my font.

I believe DirectWrite _prefers_ a color glyph for this.

I wonder if we should like to add emoji "range" settings for fine-grained control of this. Maybe I want to disable emoji WHITE SMILING FACE only?
Curious if this is a font feature that we added by happenstance back in #10433
> Is there any merit to having an option to disable colour font emoji?

Yes! For example, [some CLI libraries](https://github.com/console-rs/dialoguer) may use colored text emojis in order to display a "selected" (green) / "not selected" (gray) state in a multi-select list.

For applications using such CLI approaches to work, it is important to be able to prefer text emoji over colored emoji.

Fix patch:
diff --git a/src/cascadia/TerminalControl/ControlCore.cpp b/src/cascadia/TerminalControl/ControlCore.cpp
index b873a7c4dd2..b9eb79ac3a6 100644
--- a/src/cascadia/TerminalControl/ControlCore.cpp
+++ b/src/cascadia/TerminalControl/ControlCore.cpp
@@ -862,6 +862,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         const auto lock = _terminal->LockForWriting();
 
         _builtinGlyphs = _settings->EnableBuiltinGlyphs();
+        _colorGlyphs = _settings->EnableColorGlyphs();
         _cellWidth = CSSLengthPercentage::FromString(_settings->CellWidth().c_str());
         _cellHeight = CSSLengthPercentage::FromString(_settings->CellHeight().c_str());
         _runtimeOpacity = std::nullopt;
@@ -1042,6 +1043,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         _actualFontFaceName = { fontFace };
 
         _desiredFont.SetEnableBuiltinGlyphs(_builtinGlyphs);
+        _desiredFont.SetEnableColorGlyphs(_colorGlyphs);
         _desiredFont.SetCellSize(_cellWidth, _cellHeight);
 
         const auto before = _actualFont.GetSize();
diff --git a/src/cascadia/TerminalControl/ControlCore.h b/src/cascadia/TerminalControl/ControlCore.h
index 6ab42cdbddb..681858a398c 100644
--- a/src/cascadia/TerminalControl/ControlCore.h
+++ b/src/cascadia/TerminalControl/ControlCore.h
@@ -317,6 +317,7 @@ namespace winrt::Microsoft::Terminal::Control::implementation
         FontInfo _actualFont;
         winrt::hstring _actualFontFaceName;
         bool _builtinGlyphs = true;
+        bool _colorGlyphs = true;
         CSSLengthPercentage _cellWidth;
         CSSLengthPercentage _cellHeight;
 
diff --git a/src/cascadia/TerminalControl/IControlSettings.idl b/src/cascadia/TerminalControl/IControlSettings.idl
index 8a680f1488e..63c35d8a952 100644
--- a/src/cascadia/TerminalControl/IControlSettings.idl
+++ b/src/cascadia/TerminalControl/IControlSettings.idl
@@ -42,6 +42,7 @@ namespace Microsoft.Terminal.Control
         Windows.Foundation.Collections.IMap<String, UInt32> FontFeatures { get; };
         Windows.Foundation.Collections.IMap<String, Single> FontAxes { get; };
         Boolean EnableBuiltinGlyphs { get; };
+        Boolean EnableColorGlyphs { get; };
         String CellWidth { get; };
         String CellHeight { get; };
 
diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.h b/src/cascadia/TerminalSettingsEditor/Appearances.h
index 651523b7a69..2080a4740db 100644
--- a/src/cascadia/TerminalSettingsEditor/Appearances.h
+++ b/src/cascadia/TerminalSettingsEditor/Appearances.h
@@ -151,6 +151,7 @@ namespace winrt::Microsoft::Terminal::Settings::Editor::implementation
         OBSERVABLE_PROJECTED_SETTING(_appearance.SourceProfile().FontInfo(), FontAxes);
         OBSERVABLE_PROJECTED_SETTING(_appearance.SourceProfile().FontInfo(), FontFeatures);
         OBSERVABLE_PROJECTED_SETTING(_appearance.SourceProfile().FontInfo(), EnableBuiltinGlyphs);
+        OBSERVABLE_PROJECTED_SETTING(_appearance.SourceProfile().FontInfo(), EnableColorGlyphs);
 
         OBSERVABLE_PROJECTED_SETTING(_appearance, RetroTerminalEffect);
         OBSERVABLE_PROJECTED_SETTING(_appearance, CursorShape);
diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.idl b/src/cascadia/TerminalSettingsEditor/Appearances.idl
index 17ef8a1867a..0859e00349d 100644
--- a/src/cascadia/TerminalSettingsEditor/Appearances.idl
+++ b/src/cascadia/TerminalSettingsEditor/Appearances.idl
@@ -80,6 +80,7 @@ namespace Microsoft.Terminal.Settings.Editor
         OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Double, LineHeight);
         OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Windows.UI.Text.FontWeight, FontWeight);
         OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Boolean, EnableBuiltinGlyphs);
+        OBSERVABLE_PROJECTED_APPEARANCE_SETTING(Boolean, EnableColorGlyphs);
 
         OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, DarkColorSchemeName);
         OBSERVABLE_PROJECTED_APPEARANCE_SETTING(String, LightColorSchemeName);
diff --git a/src/cascadia/TerminalSettingsEditor/Appearances.xaml b/src/cascadia/TerminalSettingsEditor/Appearances.xaml
index 98e062e5f30..1c6dc506052 100644
--- a/src/cascadia/TerminalSettingsEditor/Appearances.xaml
+++ b/src/cascadia/TerminalSettingsEditor/Appearances.xaml
@@ -423,6 +423,15 @@
                               Style="{StaticResource ToggleSwitchInExpanderStyle}" />
             </local:SettingContainer>
 
+            <!--  Color Glyphs  -->
+            <local:SettingContainer x:Uid="Profile_EnableColorGlyphs"
+                                    ClearSettingValue="{x:Bind Appearance.ClearEnableColorGlyphs}"
+                                    HasSettingValue="{x:Bind Appearance.HasEnableColorGlyphs, Mode=OneWay}"
+                                    SettingOverrideSource="{x:Bind Appearance.EnableColorGlyphsOverrideSource, Mode=OneWay}">
+                <ToggleSwitch IsOn="{x:Bind Appearance.EnableColorGlyphs, Mode=TwoWay}"
+                              Style="{StaticResource ToggleSwitchInExpanderStyle}" />
+            </local:SettingContainer>
+
             <!--  Retro Terminal Effect  -->
             <local:SettingContainer x:Uid="Profile_RetroTerminalEffect"
                                     ClearSettingValue="{x:Bind Appearance.ClearRetroTerminalEffect}"
diff --git a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
index 1aa417d74d5..ac4e14d1170 100644
--- a/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
+++ b/src/cascadia/TerminalSettingsEditor/Resources/en-US/Resources.resw
@@ -914,6 +914,14 @@
     <value>When enabled, the terminal draws custom glyphs for block element and box drawing characters instead of using the font. This feature only works when GPU Acceleration is available.</value>
     <comment>A longer description of the "Profile_EnableBuiltinGlyphs" toggle. "glyphs", "block element" and "box drawing characters" are technical terms from the Unicode specification.</comment>
   </data>
+  <data name="Profile_EnableColorGlyphs.Header" xml:space="preserve">
+    <value>Full-color Emoji</value>
+    <comment>The main label of a toggle. When enabled, certain characters (emoji in this case) are displayed with multiple colors.</comment>
+  </data>
+  <data name="Profile_EnableColorGlyphs.HelpText" xml:space="preserve">
+    <value>When enabled, Emoji are displayed in full color.</value>
+    <comment>A longer description of the "Profile_EnableColorGlyphs" toggle.</comment>
+  </data>
   <data name="Profile_FontWeightComboBox.[using:Windows.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
     <value>Font weight</value>
     <comment>Name for a control to select the weight (i.e. bold, thin, etc.) of the text in the app.</comment>
diff --git a/src/cascadia/TerminalSettingsModel/FontConfig.idl b/src/cascadia/TerminalSettingsModel/FontConfig.idl
index 995e7c6a651..9145919c438 100644
--- a/src/cascadia/TerminalSettingsModel/FontConfig.idl
+++ b/src/cascadia/TerminalSettingsModel/FontConfig.idl
@@ -21,6 +21,7 @@ namespace Microsoft.Terminal.Settings.Model
         INHERITABLE_FONT_SETTING(Windows.Foundation.Collections.IMap<String COMMA UInt32>, FontFeatures);
         INHERITABLE_FONT_SETTING(Windows.Foundation.Collections.IMap<String COMMA Single>, FontAxes);
         INHERITABLE_FONT_SETTING(Boolean, EnableBuiltinGlyphs);
+        INHERITABLE_FONT_SETTING(Boolean, EnableColorGlyphs);
         INHERITABLE_FONT_SETTING(String, CellWidth);
         INHERITABLE_FONT_SETTING(String, CellHeight);
     }
diff --git a/src/cascadia/TerminalSettingsModel/MTSMSettings.h b/src/cascadia/TerminalSettingsModel/MTSMSettings.h
index 9ff95eaf114..cb8eb8bcdff 100644
--- a/src/cascadia/TerminalSettingsModel/MTSMSettings.h
+++ b/src/cascadia/TerminalSettingsModel/MTSMSettings.h
@@ -114,6 +114,7 @@ Author(s):
     X(IFontAxesMap, FontAxes, "axes")                                                  \
     X(IFontFeatureMap, FontFeatures, "features")                                       \
     X(bool, EnableBuiltinGlyphs, "builtinGlyphs", true)                                \
+    X(bool, EnableColorGlyphs, "colorGlyphs", true)                                    \
     X(winrt::hstring, CellWidth, "cellWidth")                                          \
     X(winrt::hstring, CellHeight, "cellHeight")
 
diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp
index dc3a420ec23..e5c07a71103 100644
--- a/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp
+++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.cpp
@@ -291,6 +291,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
         _FontFeatures = fontInfo.FontFeatures();
         _FontAxes = fontInfo.FontAxes();
         _EnableBuiltinGlyphs = fontInfo.EnableBuiltinGlyphs();
+        _EnableColorGlyphs = fontInfo.EnableColorGlyphs();
         _CellWidth = fontInfo.CellWidth();
         _CellHeight = fontInfo.CellHeight();
         _Padding = profile.Padding();
diff --git a/src/cascadia/TerminalSettingsModel/TerminalSettings.h b/src/cascadia/TerminalSettingsModel/TerminalSettings.h
index a6c19b267e3..184e05ac8f9 100644
--- a/src/cascadia/TerminalSettingsModel/TerminalSettings.h
+++ b/src/cascadia/TerminalSettingsModel/TerminalSettings.h
@@ -130,6 +130,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
         INHERITABLE_SETTING(Model::TerminalSettings, IFontAxesMap, FontAxes);
         INHERITABLE_SETTING(Model::TerminalSettings, IFontFeatureMap, FontFeatures);
         INHERITABLE_SETTING(Model::TerminalSettings, bool, EnableBuiltinGlyphs, true);
+        INHERITABLE_SETTING(Model::TerminalSettings, bool, EnableColorGlyphs, true);
         INHERITABLE_SETTING(Model::TerminalSettings, hstring, CellWidth);
         INHERITABLE_SETTING(Model::TerminalSettings, hstring, CellHeight);
 
diff --git a/src/cascadia/inc/ControlProperties.h b/src/cascadia/inc/ControlProperties.h
index fc62147a239..a7700b04958 100644
--- a/src/cascadia/inc/ControlProperties.h
+++ b/src/cascadia/inc/ControlProperties.h
@@ -65,6 +65,7 @@
     X(IFontFeatureMap, FontFeatures)                                                                                                                     \
     X(IFontAxesMap, FontAxes)                                                                                                                            \
     X(bool, EnableBuiltinGlyphs, true)                                                                                                                   \
+    X(bool, EnableColorGlyphs, true)                                                                                                                     \
     X(winrt::hstring, CellWidth)                                                                                                                         \
     X(winrt::hstring, CellHeight)                                                                                                                        \
     X(winrt::Microsoft::Terminal::Control::IKeyBindings, KeyBindings, nullptr)                                                                           \
diff --git a/src/renderer/atlas/AtlasEngine.api.cpp b/src/renderer/atlas/AtlasEngine.api.cpp
index e60baab59d4..a29c5e7779a 100644
--- a/src/renderer/atlas/AtlasEngine.api.cpp
+++ b/src/renderer/atlas/AtlasEngine.api.cpp
@@ -794,5 +794,6 @@ void AtlasEngine::_resolveFontMetrics(const wchar_t* requestedFaceName, const Fo
         fontMetrics->overline = { 0, underlineWidthU16 };
 
         fontMetrics->builtinGlyphs = fontInfoDesired.GetEnableBuiltinGlyphs();
+        fontMetrics->colorGlyphs = fontInfoDesired.GetEnableColorGlyphs();
     }
 }
diff --git a/src/renderer/atlas/BackendD2D.cpp b/src/renderer/atlas/BackendD2D.cpp
index 05f79c78c20..4310bed3f89 100644
--- a/src/renderer/atlas/BackendD2D.cpp
+++ b/src/renderer/atlas/BackendD2D.cpp
@@ -221,8 +221,14 @@ void BackendD2D::_drawText(RenderingPayload& p)
                 if (glyphRun.fontFace)
                 {
                     D2D1_RECT_F bounds = GlyphRunEmptyBounds;
+                    wil::com_ptr<IDWriteColorGlyphRunEnumerator1> enumerator;
 
-                    if (const auto enumerator = TranslateColorGlyphRun(p.dwriteFactory4.get(), baselineOrigin, &glyphRun))
+                    if (p.s->font->colorGlyphs)
+                    {
+                        enumerator = TranslateColorGlyphRun(p.dwriteFactory4.get(), baselineOrigin, &glyphRun);
+                    }
+
+                    if (enumerator)
                     {
                         while (ColorGlyphRunMoveNext(enumerator.get()))
                         {
diff --git a/src/renderer/atlas/BackendD3D.cpp b/src/renderer/atlas/BackendD3D.cpp
index fe9df2e13cd..6a3b7e4ea41 100644
--- a/src/renderer/atlas/BackendD3D.cpp
+++ b/src/renderer/atlas/BackendD3D.cpp
@@ -1316,7 +1316,12 @@ BackendD3D::AtlasGlyphEntry* BackendD3D::_drawGlyph(const RenderingPayload& p, c
     });
 
     {
-        const auto enumerator = TranslateColorGlyphRun(p.dwriteFactory4.get(), {}, &glyphRun);
+        wil::com_ptr<IDWriteColorGlyphRunEnumerator1> enumerator;
+
+        if (p.s->font->colorGlyphs)
+        {
+            enumerator = TranslateColorGlyphRun(p.dwriteFactory4.get(), {}, &glyphRun);
+        }
 
         if (!enumerator)
         {
diff --git a/src/renderer/atlas/common.h b/src/renderer/atlas/common.h
index 9ab279fc78c..967191bdfbe 100644
--- a/src/renderer/atlas/common.h
+++ b/src/renderer/atlas/common.h
@@ -361,6 +361,7 @@ namespace Microsoft::Console::Render::Atlas
         u16 dpi = 96;
         AntialiasingMode antialiasingMode = DefaultAntialiasingMode;
         bool builtinGlyphs = false;
+        bool colorGlyphs = true;
 
         std::vector<uint16_t> softFontPattern;
         til::size softFontCellSize;
diff --git a/src/renderer/base/FontInfoDesired.cpp b/src/renderer/base/FontInfoDesired.cpp
index b578960c812..592da9df2bc 100644
--- a/src/renderer/base/FontInfoDesired.cpp
+++ b/src/renderer/base/FontInfoDesired.cpp
@@ -34,6 +34,11 @@ void FontInfoDesired::SetEnableBuiltinGlyphs(bool builtinGlyphs) noexcept
     _builtinGlyphs = builtinGlyphs;
 }
 
+void FontInfoDesired::SetEnableColorGlyphs(bool colorGlyphs) noexcept
+{
+    _colorGlyphs = colorGlyphs;
+}
+
 const CSSLengthPercentage& FontInfoDesired::GetCellWidth() const noexcept
 {
     return _cellWidth;
@@ -49,6 +54,11 @@ bool FontInfoDesired::GetEnableBuiltinGlyphs() const noexcept
     return _builtinGlyphs;
 }
 
+bool FontInfoDesired::GetEnableColorGlyphs() const noexcept
+{
+    return _colorGlyphs;
+}
+
 float FontInfoDesired::GetFontSize() const noexcept
 {
     return _fontSize;
diff --git a/src/renderer/inc/FontInfoDesired.hpp b/src/renderer/inc/FontInfoDesired.hpp
index a58425b4118..f7e598761cc 100644
--- a/src/renderer/inc/FontInfoDesired.hpp
+++ b/src/renderer/inc/FontInfoDesired.hpp
@@ -36,10 +36,12 @@ class FontInfoDesired : public FontInfoBase
 
     void SetCellSize(const CSSLengthPercentage& cellWidth, const CSSLengthPercentage& cellHeight) noexcept;
     void SetEnableBuiltinGlyphs(bool builtinGlyphs) noexcept;
+    void SetEnableColorGlyphs(bool colorGlyphs) noexcept;
 
     const CSSLengthPercentage& GetCellWidth() const noexcept;
     const CSSLengthPercentage& GetCellHeight() const noexcept;
     bool GetEnableBuiltinGlyphs() const noexcept;
+    bool GetEnableColorGlyphs() const noexcept;
     float GetFontSize() const noexcept;
     til::size GetEngineSize() const noexcept;
     bool IsDefaultRasterFont() const noexcept;
@@ -50,4 +52,5 @@ class FontInfoDesired : public FontInfoBase
     CSSLengthPercentage _cellWidth;
     CSSLengthPercentage _cellHeight;
     bool _builtinGlyphs = false;
+    bool _colorGlyphs = true;
 };


Test patch: