diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretLayer.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretLayer.cs
index caaf11bebf..bcee2206ef 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretLayer.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Editing/CaretLayer.cs
@@ -79,7 +79,7 @@ namespace ICSharpCode.AvalonEdit.Editing
caretRectangle.Y - textView.VerticalOffset,
caretRectangle.Width,
caretRectangle.Height);
- drawingContext.DrawRectangle(caretBrush, null, PixelSnapHelpers.ToPixels(r));
+ drawingContext.DrawRectangle(caretBrush, null, PixelSnapHelpers.PixelAlign(r));
}
}
}
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMargin.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMargin.cs
index f2ee1b7947..e041441574 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMargin.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMargin.cs
@@ -37,7 +37,8 @@ namespace ICSharpCode.AvalonEdit.Folding
foreach (FoldingMarginMarker m in markers) {
m.Measure(availableSize);
}
- return new Size(SizeFactor * (double)GetValue(TextBlock.FontSizeProperty), 0);
+ double width = SizeFactor * (double)GetValue(TextBlock.FontSizeProperty);
+ return new Size(PixelSnapHelpers.RoundToOdd(width), 0);
}
///
@@ -49,7 +50,7 @@ namespace ICSharpCode.AvalonEdit.Folding
double yPos = m.VisualLine.GetTextLineVisualYPosition(textLine, VisualYPosition.LineTop) - TextView.VerticalOffset;
yPos += (textLine.Height - m.DesiredSize.Height) / 2;
double xPos = (finalSize.Width - m.DesiredSize.Width) / 2;
- m.Arrange(new Rect(new Point(xPos, yPos), m.DesiredSize));
+ m.Arrange(new Rect(PixelSnapHelpers.Round(new Point(xPos, yPos)), m.DesiredSize));
}
return base.ArrangeOverride(finalSize);
}
@@ -84,7 +85,6 @@ namespace ICSharpCode.AvalonEdit.Folding
if (fs.StartOffset <= line.LastDocumentLine.Offset + line.LastDocumentLine.Length) {
FoldingMarginMarker m = new FoldingMarginMarker {
IsExpanded = !fs.IsFolded,
- SnapsToDevicePixels = true,
VisualLine = line,
FoldingSection = fs
};
@@ -208,6 +208,10 @@ namespace ICSharpCode.AvalonEdit.Folding
///
void DrawFoldLines(DrawingContext drawingContext, Pen[] colors, Pen[] endMarker)
{
+ // Because we are using PenLineCap.Flat (the default), for vertical lines,
+ // Y coordinates must be on pixel boundaries, whereas the X coordinate must be in the
+ // middle of a pixel. (and the other way round for horizontal lines)
+ Size pixelSize = PixelSnapHelpers.GetPixelSize();
double markerXPos = PixelSnapHelpers.PixelAlign(RenderSize.Width / 2);
double startY = 0;
Pen currentPen = colors[0];
@@ -216,12 +220,12 @@ namespace ICSharpCode.AvalonEdit.Folding
foreach (TextLine tl in vl.TextLines) {
if (endMarker[tlNumber] != null) {
double visualPos = GetVisualPos(vl, tl);
- drawingContext.DrawLine(endMarker[tlNumber], new Point(markerXPos, visualPos), new Point(RenderSize.Width, visualPos));
+ drawingContext.DrawLine(endMarker[tlNumber], new Point(markerXPos - pixelSize.Width / 2, visualPos), new Point(RenderSize.Width, visualPos));
}
if (colors[tlNumber + 1] != currentPen) {
double visualPos = GetVisualPos(vl, tl);
if (currentPen != null) {
- drawingContext.DrawLine(currentPen, new Point(markerXPos, startY), new Point(markerXPos, visualPos));
+ drawingContext.DrawLine(currentPen, new Point(markerXPos, startY + pixelSize.Height / 2), new Point(markerXPos, visualPos - pixelSize.Height / 2));
}
currentPen = colors[tlNumber + 1];
startY = visualPos;
@@ -230,14 +234,14 @@ namespace ICSharpCode.AvalonEdit.Folding
}
}
if (currentPen != null) {
- drawingContext.DrawLine(currentPen, new Point(markerXPos, startY), new Point(markerXPos, RenderSize.Height));
+ drawingContext.DrawLine(currentPen, new Point(markerXPos, startY + pixelSize.Height / 2), new Point(markerXPos, RenderSize.Height));
}
}
double GetVisualPos(VisualLine vl, TextLine tl)
{
double pos = vl.GetTextLineVisualYPosition(tl, VisualYPosition.LineTop) + tl.Height / 2 - TextView.VerticalOffset;
- return Math.Round(pos) + 0.5;
+ return PixelSnapHelpers.PixelAlign(pos);
}
int GetTextLineIndexFromOffset(List textLines, int offset)
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMarginMarker.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMarginMarker.cs
index ab3bf6c065..1154a495e0 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMarginMarker.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Folding/FoldingMarginMarker.cs
@@ -12,6 +12,7 @@ using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.AvalonEdit.Rendering;
+using ICSharpCode.AvalonEdit.Utils;
namespace ICSharpCode.AvalonEdit.Folding
{
@@ -40,7 +41,7 @@ namespace ICSharpCode.AvalonEdit.Folding
if (!e.Handled) {
if (e.ChangedButton == MouseButton.Left) {
IsExpanded = !IsExpanded;
- e.Handled = true;
+ e.Handled = true;
}
}
}
@@ -50,23 +51,26 @@ namespace ICSharpCode.AvalonEdit.Folding
protected override Size MeasureCore(Size availableSize)
{
double size = MarginSizeFactor * FoldingMargin.SizeFactor * (double)GetValue(TextBlock.FontSizeProperty);
- size = Math.Round(size);
- if (Math.Abs((size % 2) - 1) < 0.001) {
- size -= 1;
- }
+ size = PixelSnapHelpers.RoundToOdd(size);
return new Size(size, size);
}
protected override void OnRender(DrawingContext drawingContext)
{
Pen blackPen = new Pen(Brushes.Black, 1);
- Rect rect = new Rect(new Point(0.5, 0.5), this.RenderSize);
+ blackPen.StartLineCap = PenLineCap.Square;
+ blackPen.EndLineCap = PenLineCap.Square;
+ Size pixelSize = PixelSnapHelpers.GetPixelSize();
+ Rect rect = new Rect(pixelSize.Width / 2,
+ pixelSize.Height / 2,
+ this.RenderSize.Width - pixelSize.Width,
+ this.RenderSize.Height - pixelSize.Height);
drawingContext.DrawRectangle(Brushes.White,
IsMouseDirectlyOver ? blackPen : new Pen(Brushes.Gray, 1),
rect);
double middleX = rect.Left + rect.Width / 2;
double middleY = rect.Top + rect.Height / 2;
- double space = Math.Round(rect.Width / 8) + 1;
+ double space = PixelSnapHelpers.Round(rect.Width / 8) + pixelSize.Width;
drawingContext.DrawLine(blackPen,
new Point(rect.Left + space, middleY),
new Point(rect.Right - space, middleY));
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs
index cc9e3d8071..4a9bcdc215 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Rendering/BackgroundGeometryBuilder.cs
@@ -44,8 +44,10 @@ namespace ICSharpCode.AvalonEdit.Rendering
///
public void AddSegment(TextView textView, ISegment segment)
{
- foreach (Rect r in GetRectsForSegment(textView, segment))
- AddRectangle(r.Left, r.Top, r.Right, r.Bottom);
+ foreach (Rect r in GetRectsForSegment(textView, segment)) {
+ Rect roundedRect = PixelSnapHelpers.PixelAlign(r);
+ AddRectangle(roundedRect.Left, roundedRect.Top, roundedRect.Right, roundedRect.Bottom);
+ }
}
///
diff --git a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/PixelSnapHelpers.cs b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/PixelSnapHelpers.cs
index 1db689938c..36ba025bc9 100644
--- a/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/PixelSnapHelpers.cs
+++ b/src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Utils/PixelSnapHelpers.cs
@@ -12,18 +12,67 @@ namespace ICSharpCode.AvalonEdit.Utils
{
static class PixelSnapHelpers
{
+ public static Size GetPixelSize()
+ {
+ return new Size(1, 1);
+ }
+
+ ///
+ /// Aligns val on the next middle of a pixel.
+ ///
public static double PixelAlign(double val)
{
+ // 0 -> 0.5
+ // 0.1 -> 0.5
+ // 0.5 -> 0.5
+ // 0.9 -> 0.5
+ // 1 -> 1.5
return Math.Round(val + 0.5) - 0.5;
}
- public static Rect ToPixels(Rect rect)
+ ///
+ /// Aligns the borders of rect on the middles of pixels.
+ ///
+ public static Rect PixelAlign(Rect rect)
{
rect.X = PixelAlign(rect.X);
rect.Y = PixelAlign(rect.Y);
- rect.Width = Math.Round(rect.Width);
- rect.Height = Math.Round(rect.Height);
+ rect.Width = Round(rect.Width);
+ rect.Height = Round(rect.Height);
return rect;
}
+
+ public static Point Round(Point val)
+ {
+ return new Point(Round(val.X), Round(val.Y));
+ }
+
+ ///
+ /// Rounds val to a whole number of pixels.
+ ///
+ public static double Round(double val)
+ {
+ return Math.Round(val);
+ }
+
+ ///
+ /// Rounds val to an even number of pixels.
+ ///
+ public static double RoundToEven(double val)
+ {
+ // 0 -> 0
+ // 1 -> 2
+ // 2 -> 2
+ // 3 -> 4
+ return Math.Round(val / 2) * 2;
+ }
+
+ ///
+ /// Rounds val to an odd number of pixels.
+ ///
+ public static double RoundToOdd(double val)
+ {
+ return RoundToEven(val - 1) + 1;
+ }
}
}