/* * Copyright (C) 2013 FooProject * * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ using System; using SharpDX; using D2D = SharpDX.Direct2D1; using DW = SharpDX.DirectWrite; namespace FooEditEngine { sealed class CustomTextRenderer : CallbackBase, DW.TextRenderer { D2D.RenderTarget render; ColorBrushCollection brushes; StrokeCollection strokes; public CustomTextRenderer(D2D.RenderTarget render, ColorBrushCollection brushes,StrokeCollection strokes,Color4 defalut) { this.render = render; this.DefaultFore = defalut; this.brushes = brushes; this.strokes = strokes; } public Color4 DefaultFore { get; set; } #region TextRenderer Members public Result DrawGlyphRun(object clientDrawingContext, float baselineOriginX, float baselineOriginY, D2D.MeasuringMode measuringMode, DW.GlyphRun glyphRun, DW.GlyphRunDescription glyphRunDescription, ComObject clientDrawingEffect) { D2D.SolidColorBrush foreBrush = this.brushes.Get(this.DefaultFore); if (clientDrawingEffect != null) { if (clientDrawingEffect is D2D.SolidColorBrush) { D2D.SolidColorBrush effect; effect = clientDrawingEffect as D2D.SolidColorBrush; foreBrush = effect; } else if (clientDrawingEffect is DrawingEffect) { DrawingEffect effect = clientDrawingEffect as DrawingEffect; RectangleF rect; if (effect.Stroke == HilightType.Select) { D2D.SolidColorBrush backBrush = this.brushes.Get(effect.Fore); rect = this.GetGlyphBound(glyphRun, baselineOriginX, baselineOriginY); render.FillRectangle(rect, backBrush); } if (effect.Stroke == HilightType.Url) foreBrush = this.brushes.Get(effect.Fore); } } render.DrawGlyphRun(new Vector2(baselineOriginX, baselineOriginY), glyphRun, foreBrush, measuringMode); return SharpDX.Result.Ok; } RectangleF GetGlyphBound(DW.GlyphRun myGlyphRun, float baselineOriginX, float baselineOriginY,bool underline = false) { RectangleF bounds = new RectangleF(); DW.FontMetrics fontMetrics = myGlyphRun.FontFace.Metrics; float ascentPixel = myGlyphRun.FontSize * fontMetrics.Ascent / fontMetrics.DesignUnitsPerEm; float dscentPixel = underline ? myGlyphRun.FontSize * (fontMetrics.Descent + fontMetrics.LineGap + fontMetrics.UnderlinePosition) / fontMetrics.DesignUnitsPerEm : myGlyphRun.FontSize * (fontMetrics.Descent + fontMetrics.LineGap) / fontMetrics.DesignUnitsPerEm; float right = baselineOriginX; int glyphCount = myGlyphRun.Advances.Length; for (int i = 0; i < glyphCount; i++) { if (myGlyphRun.BidiLevel % 2 == 1) right -= myGlyphRun.Advances[i]; else right += myGlyphRun.Advances[i]; } bounds.Left = baselineOriginX; if (glyphCount > 0) bounds.Right = right; else bounds.Right = baselineOriginX + myGlyphRun.Advances[0]; bounds.Top = baselineOriginY - ascentPixel; bounds.Bottom = baselineOriginY + dscentPixel; return bounds; } public Result DrawInlineObject(object clientDrawingContext, float originX, float originY, DW.InlineObject inlineObject, bool isSideways, bool isRightToLeft, ComObject clientDrawingEffect) { inlineObject.Draw(this.render, this, originX, originY, isSideways, isRightToLeft, clientDrawingEffect); return Result.Ok; } public Result DrawStrikethrough(object clientDrawingContext, float baselineOriginX, float baselineOriginY, ref DW.Strikethrough strikethrough, ComObject clientDrawingEffect) { D2D.SolidColorBrush foreBrush = this.brushes.Get(this.DefaultFore); DrawingEffect effect = null; if (clientDrawingEffect != null && clientDrawingEffect is DrawingEffect) { effect = clientDrawingEffect as DrawingEffect; foreBrush = this.brushes.Get(effect.Fore); } if (effect == null) { render.DrawLine(new Vector2(baselineOriginX, baselineOriginY + strikethrough.Offset), new Vector2(baselineOriginX + strikethrough.Width - 1, baselineOriginY + strikethrough.Offset), foreBrush, GetThickness(strikethrough.Thickness)); } return Result.Ok; } public Result DrawUnderline(object clientDrawingContext, float baselineOriginX, float baselineOriginY, ref DW.Underline underline, ComObject clientDrawingEffect) { D2D.SolidColorBrush foreBrush = this.brushes.Get(this.DefaultFore); DrawingEffect effect = null; if (clientDrawingEffect != null && clientDrawingEffect is DrawingEffect) { effect = clientDrawingEffect as DrawingEffect; foreBrush = this.brushes.Get(effect.Fore); float thickness = effect.isBoldLine ? D2DRenderCommon.BoldThickness : D2DRenderCommon.NormalThickness; if (effect.Stroke == HilightType.Squiggle) { SquilleLineMarker marker = new D2DSquilleLineMarker(this.render, this.brushes.Get(effect.Fore), this.strokes.Get(effect.Stroke), 1); marker.Draw( baselineOriginX, baselineOriginY + underline.Offset, underline.Width, underline.RunHeight ); } else { LineMarker marker = new LineMarker(this.render, this.brushes.Get(effect.Fore), this.strokes.Get(effect.Stroke), GetThickness(thickness)); marker.Draw( baselineOriginX, baselineOriginY + underline.Offset, underline.Width, 0 ); } } if (effect == null) { render.DrawLine(new Vector2(baselineOriginX, baselineOriginY + underline.Offset), new Vector2(baselineOriginX + underline.Width - 1, baselineOriginY + underline.Offset), foreBrush, GetThickness(underline.Thickness)); } return SharpDX.Result.Ok; } #endregion #region PixelSnapping Members public SharpDX.Mathematics.Interop.RawMatrix3x2 GetCurrentTransform(object clientDrawingContext) { SharpDX.Mathematics.Interop.RawMatrix3x2 d2Dmatrix = render.Transform; return d2Dmatrix; } public float GetPixelsPerDip(object clientDrawingContext) { return render.PixelSize.Width / 96f; } public bool IsPixelSnappingDisabled(object clientDrawingContext) { return false; } #endregion float GetThickness(float thickness) { if (this.render.AntialiasMode == D2D.AntialiasMode.Aliased) return (int)(thickness + 0.5); else return thickness; } } }