From cecb4c90ddc73d564c3fbad6167faa9d5635534c Mon Sep 17 00:00:00 2001
From: "13.beta2" <temp.13.beta2@mail.ru>
Date: Mon, 11 Jan 2016 00:23:48 +0300
Subject: [PATCH] Implement basic font rendering tuning for code editor. (1/2:
 Main+AddIns part)

Ability to disable anti-aliasing for 'pixel-perfect' fonts like Courier New.
Ability to disable hinting to forget about jagged default WPF rendering.
---
 data/resources/StringResources.resx           |   6 +
 .../Src/Options/GeneralEditorOptions.xaml     |  10 +-
 .../Project/ZoomScrollViewer.cs               | 120 ++++++++++++++++++
 .../Project/ZoomScrollViewer.xaml             |  21 +++
 4 files changed, 156 insertions(+), 1 deletion(-)

diff --git a/data/resources/StringResources.resx b/data/resources/StringResources.resx
index d9f7fd02b7..214ba99511 100644
--- a/data/resources/StringResources.resx
+++ b/data/resources/StringResources.resx
@@ -8445,5 +8445,11 @@ Press Esc to cancel this operation.</value>
   </data>
   <data name="ICSharpCode.WpfDesign.AddIn.Options.EnableAppXamlParsing" xml:space="preserve">
     <value>Enable App.xaml parsing</value>
+  </data>
+	<data name="Dialog.Options.IDEOptions.TextEditor.General.EnableTextAntialiasing" xml:space="preserve">
+    <value>Enable anti-aliasing</value>
+  </data>
+	<data name="Dialog.Options.IDEOptions.TextEditor.General.EnableTextHinting" xml:space="preserve">
+    <value>Enable hinting</value>
   </data>
 </root>
\ No newline at end of file
diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/GeneralEditorOptions.xaml b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/GeneralEditorOptions.xaml
index 576ec15bef..0720da5ae0 100644
--- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/GeneralEditorOptions.xaml
+++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/Options/GeneralEditorOptions.xaml
@@ -4,7 +4,15 @@
 	<StackPanel>
 		<GroupBox
 			Header="{core:Localize Dialog.Options.IDEOptions.TextEditor.General.FontGroupBox}">
-			<gui:FontSelector x:Name="fontSelectionPanel" />
+			<widgets:StackPanelWithSpacing SpaceBetweenItems="5">
+				<gui:FontSelector x:Name="fontSelectionPanel" />
+				<CheckBox
+					IsChecked="{core:OptionBinding local:CodeEditorOptions.EnableTextAntialiasing}"
+					Content="{core:Localize Dialog.Options.IDEOptions.TextEditor.General.EnableTextAntialiasing}" />
+				<CheckBox
+					IsChecked="{core:OptionBinding local:CodeEditorOptions.EnableTextHinting}"
+					Content="{core:Localize Dialog.Options.IDEOptions.TextEditor.General.EnableTextHinting}" />
+			</widgets:StackPanelWithSpacing>
 		</GroupBox>
 		<GroupBox
 			Header="{core:Localize Dialog.Options.IDEOptions.TextEditor.General.GeneralOptionsGroupBox}">
diff --git a/src/Main/ICSharpCode.SharpDevelop.Widgets/Project/ZoomScrollViewer.cs b/src/Main/ICSharpCode.SharpDevelop.Widgets/Project/ZoomScrollViewer.cs
index 969c4812f7..bafd6a0e74 100644
--- a/src/Main/ICSharpCode.SharpDevelop.Widgets/Project/ZoomScrollViewer.cs
+++ b/src/Main/ICSharpCode.SharpDevelop.Widgets/Project/ZoomScrollViewer.cs
@@ -186,4 +186,124 @@ namespace ICSharpCode.SharpDevelop.Widgets
 			throw new NotImplementedException();
 		}
 	}
+
+	sealed class ZoomToTextFormattingModeConverter : IMultiValueConverter
+	{
+		public static readonly ZoomToTextFormattingModeConverter Instance = new ZoomToTextFormattingModeConverter();
+		
+		public object Convert(object[] value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+		{
+			var zoom			= value[0] != null ? (double) value[0] : 1.0;
+			var antialiasing	= value[1] != DependencyProperty.UnsetValue ? (bool) value[1] : true;
+			var hinting			= value[2] != DependencyProperty.UnsetValue ? (bool) value[2] : true;
+
+			if (antialiasing)
+			{
+				if (hinting)
+				{
+					if (zoom == 1.0)
+					{
+						return TextFormattingMode.Display;
+					}
+					else
+					{
+						return TextFormattingMode.Ideal;
+					}
+				}
+				else
+				{
+					return TextFormattingMode.Ideal;
+				}
+			}
+			else
+			{
+				return TextFormattingMode.Display;
+			}
+		}
+		
+		public object[] ConvertBack(object value, Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
+		{
+			throw new NotImplementedException();
+		}
+	}
+
+	sealed class ZoomToTextRenderingModeConverter : IMultiValueConverter
+	{
+		public static readonly ZoomToTextRenderingModeConverter Instance = new ZoomToTextRenderingModeConverter();
+		
+		public object Convert(object[] value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+		{
+			var zoom			= value[0] != null ? (double) value[0] : 1.0;
+			var antialiasing	= value[1] != DependencyProperty.UnsetValue ? (bool) value[1] : true;
+			var hinting			= value[2] != DependencyProperty.UnsetValue ? (bool) value[2] : true;
+
+			if (antialiasing)
+			{
+				if (hinting)
+				{
+					if (zoom == 1.0)
+					{
+						return TextRenderingMode.ClearType;
+					}
+					else
+					{
+						return TextRenderingMode.Grayscale;
+					}
+				}
+				else
+				{
+					return TextRenderingMode.Grayscale;
+				}
+			}
+			else
+			{
+				return TextRenderingMode.Aliased;
+			}
+		}
+
+		public object[] ConvertBack(object value, Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
+		{
+			throw new NotImplementedException();
+		}
+	}
+
+	sealed class ZoomToTextHintingModeConverter : IMultiValueConverter
+	{
+		public static readonly ZoomToTextHintingModeConverter Instance = new ZoomToTextHintingModeConverter();
+		
+		public object Convert(object[] value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+		{
+			var zoom			= value[0] != null ? (double) value[0] : 1.0;
+			var antialiasing	= value[1] != DependencyProperty.UnsetValue ? (bool) value[1] : true;
+			var hinting			= value[2] != DependencyProperty.UnsetValue ? (bool) value[2] : true;
+
+			if (antialiasing)
+			{
+				if (hinting)
+				{
+					if (zoom == 1.0)
+					{
+						return TextHintingMode.Fixed;
+					}
+					else
+					{
+						return TextHintingMode.Fixed;
+					}
+				}
+				else
+				{
+					return TextHintingMode.Animated;
+				}
+			}
+			else
+			{
+				return TextHintingMode.Fixed;
+			}
+		}
+
+		public object[] ConvertBack(object value, Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
+		{
+			throw new NotImplementedException();
+		}
+	}
 }
diff --git a/src/Main/ICSharpCode.SharpDevelop.Widgets/Project/ZoomScrollViewer.xaml b/src/Main/ICSharpCode.SharpDevelop.Widgets/Project/ZoomScrollViewer.xaml
index 6034140ef0..674e076538 100644
--- a/src/Main/ICSharpCode.SharpDevelop.Widgets/Project/ZoomScrollViewer.xaml
+++ b/src/Main/ICSharpCode.SharpDevelop.Widgets/Project/ZoomScrollViewer.xaml
@@ -24,6 +24,27 @@
 							<ScrollContentPresenter.LayoutTransform>
 								<ScaleTransform ScaleX="{Binding Path=CurrentZoom, RelativeSource={RelativeSource Mode=TemplatedParent}}" ScaleY="{Binding Path=CurrentZoom, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
 							</ScrollContentPresenter.LayoutTransform>
+							<TextOptions.TextFormattingMode>
+								<MultiBinding Converter="{x:Static Controls:ZoomToTextFormattingModeConverter.Instance}">
+									<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="CurrentZoom" />
+									<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="Content.Options.EnableTextAntialiasing" />
+									<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="Content.Options.EnableTextHinting" />
+								</MultiBinding>
+							</TextOptions.TextFormattingMode>
+							<TextOptions.TextRenderingMode>
+								<MultiBinding Converter="{x:Static Controls:ZoomToTextRenderingModeConverter.Instance}">
+									<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="CurrentZoom" />
+									<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="Content.Options.EnableTextAntialiasing" />
+									<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="Content.Options.EnableTextHinting" />
+								</MultiBinding>
+							</TextOptions.TextRenderingMode>
+							<TextOptions.TextHintingMode>
+								<MultiBinding Converter="{x:Static Controls:ZoomToTextHintingModeConverter.Instance}">
+									<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="CurrentZoom"  />
+									<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="Content.Options.EnableTextAntialiasing" />
+									<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="Content.Options.EnableTextHinting" />
+								</MultiBinding>
+							</TextOptions.TextHintingMode>
 						</ScrollContentPresenter>
 						<ScrollBar Name="PART_VerticalScrollBar" Grid.Column="2" Grid.Row="0" Minimum="0" Maximum="{TemplateBinding ScrollableHeight}" ViewportSize="{TemplateBinding ViewportHeight}" Value="{TemplateBinding VerticalOffset}" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
 						<ScrollBar Name="PART_HorizontalScrollBar" Orientation="Horizontal" Grid.Column="1" Grid.Row="1" Minimum="0" Maximum="{TemplateBinding ScrollableWidth}" ViewportSize="{TemplateBinding ViewportWidth}" Value="{TemplateBinding HorizontalOffset}" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />