public Result DrawGlyphRun( object clientDrawingContext, float baselineOriginX, float baselineOriginY, MeasuringMode measuringMode, GlyphRun glyphRun, GlyphRunDescription glyphRunDescription, ComObject clientDrawingEffect) { var wrapper = clientDrawingEffect as BrushWrapper; var brush = (wrapper == null) ? this.foreground : wrapper.Brush.ToDirect2D(this.renderTarget); this.renderTarget.DrawGlyphRun( new Vector2(baselineOriginX, baselineOriginY), glyphRun, brush, measuringMode); if (wrapper != null) { brush.Dispose(); } return Result.Ok; }
public Result DrawGlyphRun( object clientDrawingContext, float baselineOriginX, float baselineOriginY, MeasuringMode measuringMode, GlyphRun glyphRun, GlyphRunDescription glyphRunDescription, ComObject clientDrawingEffect) { var wrapper = clientDrawingEffect as BrushWrapper; // TODO: Work out how to get the size below rather than passing new Size(). var brush = (wrapper == null) ? _foreground : _context.CreateBrush(wrapper.Brush, new Size()).PlatformBrush; _renderTarget.DrawGlyphRun( new RawVector2 { X = baselineOriginX, Y = baselineOriginY }, glyphRun, brush, measuringMode); if (wrapper != null) { brush.Dispose(); } return Result.Ok; }
private static int DrawGlyphRunImpl(IntPtr thisObject, IntPtr clientDrawingContextPtr, float baselineOriginX, float baselineOriginY, MeasuringMode measuringMode, IntPtr glyphRunPtr, IntPtr glyphRunDescriptionPtr, IntPtr clientDrawingEffectPtr) { unsafe { var shadow = ToShadow<TextRendererShadow>(thisObject); var callback = (TextRenderer) shadow.Callback; // Read GlyphRun var glyphRunData = default(GlyphRun.__Native); Utilities.Read(glyphRunPtr, ref glyphRunData); using (var glyphRun = new GlyphRun()) { glyphRun.__MarshalFrom(ref glyphRunData); // Read GlyphRunDescription var glyphRunDescriptionData = default(GlyphRunDescription.__Native); Utilities.Read(glyphRunDescriptionPtr, ref glyphRunDescriptionData); var glyphRunDescription = new GlyphRunDescription(); glyphRunDescription.__MarshalFrom(ref glyphRunDescriptionData); return callback.DrawGlyphRun(GCHandle.FromIntPtr(clientDrawingContextPtr).Target, baselineOriginX, baselineOriginY, measuringMode, glyphRun, glyphRunDescription, (ComObject) Utilities.GetObjectForIUnknown(clientDrawingEffectPtr)).Code; } } }
public override Result DrawGlyphRun(object clientDrawingContext, float baselineOriginX, float baselineOriginY, D2D1.MeasuringMode measuringMode, DW.GlyphRun glyphRun, DW.GlyphRunDescription glyphRunDescription, ComObject clientDrawingEffect) { using (var pathGeometry = new D2D1.PathGeometry(_renderTarget.Factory)) { using (var geometrySink = pathGeometry.Open()) using (var fontFace = glyphRun.FontFace) { if (glyphRun.Indices.Length > 0) { fontFace.GetGlyphRunOutline( glyphRun.FontSize, glyphRun.Indices, glyphRun.Advances, glyphRun.Offsets, glyphRun.Indices.Length, glyphRun.IsSideways, glyphRun.BidiLevel % 2 != 0, geometrySink ); } geometrySink.Close(); } var matrix = new Matrix3x2() { M11 = 1, M12 = 0, M21 = 0, M22 = 1, M31 = baselineOriginX, M32 = baselineOriginY }; var sw = _renderTarget.StrokeWidth; using (var transformedGeometry = new D2D1.TransformedGeometry(_renderTarget.Factory, pathGeometry, matrix)) { _renderTarget.StrokeWidth = _strokeWidth; _renderTarget.DrawGeometry(transformedGeometry, _strokeBrush); _renderTarget.FillGeometry(transformedGeometry, _fillBrush); } _renderTarget.StrokeWidth = sw; } 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 if (myGlyphRun.Advances.Length == 1) { bounds.Right = baselineOriginX + myGlyphRun.Advances[0]; } else { bounds.Right = bounds.Left; } bounds.Top = baselineOriginY - ascentPixel; bounds.Bottom = baselineOriginY + dscentPixel; return(bounds); }
public override Result DrawGlyphRun(object clientDrawingContext, float baselineOriginX, float baselineOriginY, MeasuringMode measuringMode, GlyphRun glyphRun, GlyphRunDescription glyphRunDescription, ComObject clientDrawingEffect) { SolidColorBrush sb = defaultBrush; if (clientDrawingEffect != null && clientDrawingEffect is SolidColorBrush) { sb = (SolidColorBrush)clientDrawingEffect; } try { this.renderTarget.DrawGlyphRun(new Vector2(baselineOriginX, baselineOriginY), glyphRun, sb, measuringMode); return Result.Ok; } catch { return Result.Fail; } }
public override SharpDX.Result DrawGlyphRun(object clientDrawingContext, float baselineOriginX, float baselineOriginY, D2D1.MeasuringMode measuringMode, DW.GlyphRun glyphRun, DW.GlyphRunDescription glyphRunDescription, ComObject effect) { var sb = _defaultBrush; if (effect != null && effect is D2D1.SolidColorBrush solidColorBrush) { sb = solidColorBrush; } try { _renderTarget.DrawGlyphRun(new Vector2(baselineOriginX, baselineOriginY), glyphRun, sb, measuringMode); return(SharpDX.Result.Ok); } catch { return(SharpDX.Result.Fail); } }
public Result DrawGlyphRun(object clientDrawingContext, float baselineOriginX, float baselineOriginY, MeasuringMode measuringMode, GlyphRun glyphRun, GlyphRunDescription glyphRunDescription, ComObject clientDrawingEffect) { var pathGeometry = new PathGeometry(_d2DFactory); var geometrySink = pathGeometry.Open(); var fontFace = glyphRun.FontFace; if (glyphRun.Indices.Length > 0) fontFace.GetGlyphRunOutline(glyphRun.FontSize, glyphRun.Indices, glyphRun.Advances, glyphRun.Offsets, glyphRun.IsSideways, glyphRun.BidiLevel % 2 != 0, geometrySink); geometrySink.Close(); geometrySink.Dispose(); fontFace.Dispose(); var matrix = new Matrix3x2() { M11 = 1, M12 = 0, M21 = 0, M22 = 1, M31 = baselineOriginX, M32 = baselineOriginY }; var transformedGeometry = new TransformedGeometry(_d2DFactory, pathGeometry, matrix); var brushColor = (Color4)Color.Black; if (clientDrawingEffect != null && clientDrawingEffect is ColorDrawingEffect) brushColor = (clientDrawingEffect as ColorDrawingEffect).Color; var brush = new SolidColorBrush(_renderTarget, brushColor); _renderTarget.DrawGeometry(transformedGeometry, brush); _renderTarget.FillGeometry(transformedGeometry, brush); pathGeometry.Dispose(); transformedGeometry.Dispose(); brush.Dispose(); return SharpDX.Result.Ok; }
internal GlyphRun Convert(List<short> glyphIndices, List<float> glyphAdvances, List<GlyphOffset> glyphOffsets) { try { GlyphRun gr = new GlyphRun(); gr.Items = new GlyphRunItem[glyphCount]; for (int i = 0; i < glyphCount; i++) { gr.Items[i].Index = glyphIndices[glyphStart + i]; gr.Items[i].Advance = glyphAdvances[glyphStart + i]; gr.Items[i].Offset = glyphOffsets[glyphStart + i]; } gr.FontSize = fontEmSize; gr.FontFace = fontFace; gr.BidiLevel = bidiLevel; gr.IsSideways = isSideways; return gr; } catch { return null; } }
public override SharpDX.Result DrawGlyphRun(object clientDrawingContext, float baselineOriginX, float baselineOriginY, MeasuringMode measuringMode, GlyphRun glyphRun, GlyphRunDescription glyphRunDescription, SharpDX.ComObject clientDrawingEffect) { Color4 c = Color4.White; if (clientDrawingEffect != null) { if (clientDrawingEffect is SharpDX.Direct2D1.SolidColorBrush) { var sb = (SharpDX.Direct2D1.SolidColorBrush)clientDrawingEffect; c = sb.Color; } } if (glyphRun.Indices.Length > 0) { PathGeometry pg = new PathGeometry(this.factory); GeometrySink sink = pg.Open(); glyphRun.FontFace.GetGlyphRunOutline(glyphRun.FontSize, glyphRun.Indices, glyphRun.Advances, glyphRun.Offsets, glyphRun.IsSideways, glyphRun.BidiLevel % 2 == 1, sink as SimplifiedGeometrySink); sink.Close(); TransformedGeometry tg = new TransformedGeometry(this.factory, pg, Matrix3x2.Translation(baselineOriginX, baselineOriginY) * Matrix3x2.Scaling(1.0f, -1.0f)); pg.Dispose(); //Transform from baseline this.AddGeometry(tg); return SharpDX.Result.Ok; } else { return SharpDX.Result.Ok; } }
public Result DrawGlyphRun(object clientDrawingContext, float baselineOriginX, float baselineOriginY, D2D.MeasuringMode measuringMode, DW.GlyphRun glyphRun, DW.GlyphRunDescription glyphRunDescription, ComObject clientDrawingEffect) { D2D.RenderTarget render = clientDrawingContext as D2D.RenderTarget; if (render == null) { return(SharpDX.Result.Ok); } D2D.SolidColorBrush foreBrush = this.factory.GetSolidColorBrush(this.DefaultFore); bool isDrawGlyphRun = true; if (clientDrawingEffect != null) { var drawingForeBrush = clientDrawingEffect as D2D.SolidColorBrush; var selectedEffect = clientDrawingEffect as SelectedEffect; var drawingEffect = clientDrawingEffect as DrawingEffect; if (drawingForeBrush != null) { foreBrush = drawingForeBrush; } else if (selectedEffect != null) { foreBrush = this.factory.GetSolidColorBrush(selectedEffect.Fore); } else if (drawingEffect != null) { if (drawingEffect.Stroke == HilightType.Url) { foreBrush = this.factory.GetSolidColorBrush(drawingEffect.Fore); } } } if (isDrawGlyphRun) { render.DrawGlyphRun(new Vector2(baselineOriginX, baselineOriginY), glyphRun, foreBrush, measuringMode); } return(SharpDX.Result.Ok); }
/// <summary> /// IDWriteTextLayout::Draw calls this function to instruct the client to render a run of glyphs. /// </summary> /// <remarks> /// The <see cref="SharpDX.DirectWrite.TextLayout.Draw_"/> function calls this callback function with all the information about glyphs to render. The application implements this callback by mostly delegating the call to the underlying platform's graphics API such as {{Direct2D}} to draw glyphs on the drawing context. An application that uses GDI can implement this callback in terms of the <see cref="BitmapRenderTarget.DrawGlyphRun(float,float,MeasuringMode,SharpDX.DirectWrite.GlyphRun,SharpDX.DirectWrite.RenderingParams,SharpDX.Color4)"/> method. /// </remarks> /// <param name="clientDrawingContext">The application-defined drawing context passed to <see cref="SharpDX.DirectWrite.TextLayout.Draw_"/>.</param> /// <param name="baselineOriginX">The pixel location (X-coordinate) at the baseline origin of the glyph run.</param> /// <param name="baselineOriginY">The pixel location (Y-coordinate) at the baseline origin of the glyph run.</param> /// <param name="measuringMode"> The measuring method for glyphs in the run, used with the other properties to determine the rendering mode.</param> /// <param name="glyphRun">Pointer to the glyph run instance to render. </param> /// <param name="glyphRunDescription">A pointer to the optional glyph run description instance which contains properties of the characters associated with this run.</param> /// <param name="clientDrawingEffect">Application-defined drawing effects for the glyphs to render. Usually this argument represents effects such as the foreground brush filling the interior of text.</param> /// <returns>If the method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code.</returns> /// <unmanaged>HRESULT DrawGlyphRun([None] void* clientDrawingContext,[None] FLOAT baselineOriginX,[None] FLOAT baselineOriginY,[None] DWRITE_MEASURING_MODE measuringMode,[In] const DWRITE_GLYPH_RUN* glyphRun,[In] const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription,[None] IUnknown* clientDrawingEffect)</unmanaged> public virtual Result DrawGlyphRun(object clientDrawingContext, float baselineOriginX, float baselineOriginY, MeasuringMode measuringMode, GlyphRun glyphRun, GlyphRunDescription glyphRunDescription, ComObject clientDrawingEffect) { return Result.NotImplemented; }
internal GlyphRun Convert(List<short> glyphIndices, List<float> glyphAdvances, List<GlyphOffset> glyphOffsets) { try { var gr = new GlyphRun(); gr.Indices = new short[glyphCount]; glyphIndices.CopyTo(glyphStart, gr.Indices, 0, glyphCount); gr.Advances = new float[glyphCount]; glyphAdvances.CopyTo(glyphStart, gr.Advances, 0, glyphCount); gr.Offsets= new GlyphOffset[glyphCount]; glyphOffsets.CopyTo(glyphStart, gr.Offsets, 0, glyphCount); gr.FontSize = fontEmSize; gr.FontFace = fontFace; gr.BidiLevel = bidiLevel; gr.IsSideways = isSideways; return gr; } catch { return null; } }
/// <summary> /// Creates a glyph run analysis object, which encapsulates information used to render a glyph run. /// </summary> /// <param name="factory">The factory.</param> /// <param name="glyphRun">A structure that contains the properties of the glyph run (font face, advances, and so on).</param> /// <param name="pixelsPerDip">Number of physical pixels per DIP (device independent pixel). For example, if rendering onto a 96 DPI bitmap then pixelsPerDip is 1. If rendering onto a 120 DPI bitmap then pixelsPerDip is 1.25.</param> /// <param name="renderingMode">A value that specifies the rendering mode, which must be one of the raster rendering modes (that is, not default and not outline).</param> /// <param name="measuringMode">Specifies the measuring mode to use with glyphs.</param> /// <param name="baselineOriginX">The horizontal position (X-coordinate) of the baseline origin, in DIPs.</param> /// <param name="baselineOriginY">Vertical position (Y-coordinate) of the baseline origin, in DIPs.</param> /// <remarks> /// The glyph run analysis object contains the results of analyzing the glyph run, including the positions of all the glyphs and references to all of the rasterized glyphs in the font cache. /// </remarks> /// <unmanaged>HRESULT IDWriteFactory::CreateGlyphRunAnalysis([In] const DWRITE_GLYPH_RUN* glyphRun,[None] float pixelsPerDip,[In, Optional] const DWRITE_MATRIX* transform,[None] DWRITE_RENDERING_MODE renderingMode,[None] DWRITE_MEASURING_MODE measuringMode,[None] float baselineOriginX,[None] float baselineOriginY,[Out] IDWriteGlyphRunAnalysis** glyphRunAnalysis)</unmanaged> public GlyphRunAnalysis(Factory factory, GlyphRun glyphRun, float pixelsPerDip, RenderingMode renderingMode, MeasuringMode measuringMode, float baselineOriginX, float baselineOriginY) : this(factory, glyphRun, pixelsPerDip, null, renderingMode, measuringMode, baselineOriginX, baselineOriginY) { }
private static void GetKerningInfo(CCRawList<char> charset) { _abcValues.Clear(); var fontFace = new FontFace(_currentFont); var value = new ABCFloat[1]; var glyphRun = new GlyphRun(); glyphRun.FontFace = fontFace; glyphRun.FontSize = _currentDIP; var BrushColor = SharpDX.Color.White; /* SharpDX.DirectWrite.Matrix mtrx = new SharpDX.DirectWrite.Matrix(); mtrx.M11 = 1F; mtrx.M12 = 0; mtrx.M21 = 0; mtrx.M22 = 1F; mtrx.Dx = 0; mtrx.Dy = 0; */ //GlyphMetrics[] metrics = fontFace.GetGdiCompatibleGlyphMetrics(23, 1, mtrx, false, glyphIndices, false); //FontMetrics metr = fontFace.GetGdiCompatibleMetrics(23, 1, new SharpDX.DirectWrite.Matrix()); //_pRenderTarget.DrawGlyphRun(new SharpDX.DrawingPointF(left, top), glyphRun, new SharpDX.Direct2D1.SolidColorBrush(_pRenderTarget, BrushColor), MeasuringMode.GdiClassic); int[] codePoints = new int[1]; var unitsPerEm = fontFace.Metrics.DesignUnitsPerEm; var familyName = _currentFont.ToString(); for (int i = 0; i < charset.Count; i++) { var ch = charset[i]; if (!_abcValues.ContainsKey(ch)) { var textLayout = new TextLayout(FactoryDWrite, ch.ToString(), textFormat, unitsPerEm, unitsPerEm); var tlMetrics = textLayout.Metrics; var tlmWidth = tlMetrics.Width; var tllWidth = tlMetrics.LayoutWidth; codePoints[0] = (int)ch; short[] glyphIndices = fontFace.GetGlyphIndices(codePoints); glyphRun.Indices = glyphIndices; var metrics = fontFace.GetDesignGlyphMetrics(glyphIndices, false); //var width = metrics[0].AdvanceWidth + metrics[0].LeftSideBearing + metrics[0].RightSideBearing; //var glyphWidth = _currentFontSizeEm * (float)metrics[0].AdvanceWidth / unitsPerEm; //var abcWidth = _currentDIP * (float)width / unitsPerEm; //value[0].abcfA = _currentFontSizeEm * (float)metrics[0].LeftSideBearing / unitsPerEm; //value[0].abcfB = _currentFontSizeEm * (float)metrics[0].AdvanceWidth / unitsPerEm; //value[0].abcfC = _currentFontSizeEm * (float)metrics[0].RightSideBearing / unitsPerEm; // The A and C values are throwing the spacing off //value[0].abcfA = _currentDIP * (float)metrics[0].LeftSideBearing / unitsPerEm; value[0].abcfB = _currentDIP * (float)metrics[0].AdvanceWidth / unitsPerEm; //value[0].abcfC = _currentDIP * (float)metrics[0].RightSideBearing / unitsPerEm; _abcValues.Add( ch, new KerningInfo() { A = value[0].abcfA, B = value[0].abcfB, C = value[0].abcfC }); } } }
private Glyph ImportGlyph(Factory factory, FontFace fontFace, char character, FontMetrics fontMetrics, float fontSize, FontAntiAliasMode antiAliasMode) { var indices = fontFace.GetGlyphIndices(new int[] { character }); var metrics = fontFace.GetDesignGlyphMetrics(indices, false); var metric = metrics[0]; var width = (float)(metric.AdvanceWidth - metric.LeftSideBearing - metric.RightSideBearing) / fontMetrics.DesignUnitsPerEm * fontSize; var height = (float)(metric.AdvanceHeight - metric.TopSideBearing - metric.BottomSideBearing) / fontMetrics.DesignUnitsPerEm * fontSize; var xOffset = (float)metric.LeftSideBearing / fontMetrics.DesignUnitsPerEm * fontSize; var yOffset = (float)(metric.TopSideBearing - metric.VerticalOriginY) / fontMetrics.DesignUnitsPerEm * fontSize; var advanceWidth = (float)metric.AdvanceWidth / fontMetrics.DesignUnitsPerEm * fontSize; //var advanceHeight = (float)metric.AdvanceHeight / fontMetrics.DesignUnitsPerEm * fontSize; var pixelWidth = (int)Math.Ceiling(width + 4); var pixelHeight = (int)Math.Ceiling(height + 4); var matrix = new RawMatrix3x2 { M11 = 1, M22 = 1, M31 = -(float)Math.Floor(xOffset) + 1, M32 = -(float)Math.Floor(yOffset) + 1 }; Bitmap bitmap; if (char.IsWhiteSpace(character)) { bitmap = new Bitmap(1, 1, PixelFormat.Format32bppArgb); } else { var glyphRun = new GlyphRun { FontFace = fontFace, Advances = new[] { (float)Math.Ceiling(advanceWidth) }, FontSize = fontSize, BidiLevel = 0, Indices = indices, IsSideways = false, Offsets = new[] { new GlyphOffset() } }; RenderingMode renderingMode; if (antiAliasMode != FontAntiAliasMode.Aliased) { var rtParams = new RenderingParams(factory); renderingMode = fontFace.GetRecommendedRenderingMode(fontSize, 1.0f, MeasuringMode.Natural, rtParams); rtParams.Dispose(); } else { renderingMode = RenderingMode.Aliased; } using (var runAnalysis = new GlyphRunAnalysis(factory, glyphRun, 1.0f, matrix, renderingMode, MeasuringMode.Natural, 0.0f, 0.0f)) { var bounds = new RawRectangle(0, 0, pixelWidth, pixelHeight); bitmap = new Bitmap(pixelWidth, pixelHeight, PixelFormat.Format32bppArgb); if (renderingMode == RenderingMode.Aliased) { var texture = new byte[pixelWidth * pixelHeight]; runAnalysis.CreateAlphaTexture(TextureType.Aliased1x1, bounds, texture, texture.Length); for (int y = 0; y < pixelHeight; y++) { for (int x = 0; x < pixelWidth; x++) { int pixelX = y * pixelWidth + x; var grey = texture[pixelX]; var color = Color.FromArgb(grey, grey, grey); bitmap.SetPixel(x, y, color); } } } else { var texture = new byte[pixelWidth * pixelHeight * 3]; runAnalysis.CreateAlphaTexture(TextureType.Cleartype3x1, bounds, texture, texture.Length); for (int y = 0; y < pixelHeight; y++) { for (int x = 0; x < pixelWidth; x++) { int pixelX = (y * pixelWidth + x) * 3; var red = LinearToGamma(texture[pixelX]); var green = LinearToGamma(texture[pixelX + 1]); var blue = LinearToGamma(texture[pixelX + 2]); var color = Color.FromArgb(red, green, blue); bitmap.SetPixel(x, y, color); } } } } } var glyph = new Glyph(character, bitmap) { XOffset = -matrix.M31, XAdvance = advanceWidth, YOffset = -matrix.M32, }; return glyph; }
/// <summary> /// Creates a glyph run analysis object, which encapsulates information used to render a glyph run. /// </summary> /// <param name="factory">The factory.</param> /// <param name="glyphRun">A structure that contains the properties of the glyph run (font face, advances, and so on).</param> /// <param name="pixelsPerDip">Number of physical pixels per DIP (device independent pixel). For example, if rendering onto a 96 DPI bitmap then pixelsPerDip is 1. If rendering onto a 120 DPI bitmap then pixelsPerDip is 1.25.</param> /// <param name="transform">Optional transform applied to the glyphs and their positions. This transform is applied after the scaling specified the emSize and pixelsPerDip.</param> /// <param name="renderingMode">A value that specifies the rendering mode, which must be one of the raster rendering modes (that is, not default and not outline).</param> /// <param name="measuringMode">Specifies the measuring mode to use with glyphs.</param> /// <param name="baselineOriginX">The horizontal position (X-coordinate) of the baseline origin, in DIPs.</param> /// <param name="baselineOriginY">Vertical position (Y-coordinate) of the baseline origin, in DIPs.</param> /// <remarks> /// The glyph run analysis object contains the results of analyzing the glyph run, including the positions of all the glyphs and references to all of the rasterized glyphs in the font cache. /// </remarks> /// <unmanaged>HRESULT IDWriteFactory::CreateGlyphRunAnalysis([In] const DWRITE_GLYPH_RUN* glyphRun,[None] float pixelsPerDip,[In, Optional] const DWRITE_MATRIX* transform,[None] DWRITE_RENDERING_MODE renderingMode,[None] DWRITE_MEASURING_MODE measuringMode,[None] float baselineOriginX,[None] float baselineOriginY,[Out] IDWriteGlyphRunAnalysis** glyphRunAnalysis)</unmanaged> public GlyphRunAnalysis(Factory factory, GlyphRun glyphRun, float pixelsPerDip, RawMatrix3x2? transform, RenderingMode renderingMode, MeasuringMode measuringMode, float baselineOriginX, float baselineOriginY) { factory.CreateGlyphRunAnalysis(glyphRun, pixelsPerDip, transform, renderingMode, measuringMode, baselineOriginX, baselineOriginY, this); }
public override Result DrawGlyphRun(object clientDrawingContext, float baselineOriginX, float baselineOriginY, MeasuringMode measuringMode, DW.GlyphRun glyphRun, DW.GlyphRunDescription glyphRunDescription, ComObject clientDrawingEffect) { try { TextBrush textBrush = _textBrush; if (clientDrawingEffect != null && clientDrawingEffect is TextBrush) { textBrush = (TextBrush)clientDrawingEffect; } using (textBrush) { _renderTarget.DrawGlyphRun(new Vector2(baselineOriginX - 1, baselineOriginY - 1), glyphRun, textBrush.BGBrush, measuringMode); _renderTarget.DrawGlyphRun(new Vector2(baselineOriginX + 1, baselineOriginY + 1), glyphRun, textBrush.BGBrush, measuringMode); _renderTarget.DrawGlyphRun(new Vector2(baselineOriginX, baselineOriginY), glyphRun, textBrush.FGBrush, measuringMode); } return(Result.Ok); } catch { return(Result.Fail); } }
private Glyph ImportGlyph(Factory factory, FontFace fontFace, char character, FontMetrics fontMetrics, float fontSize, bool activateAntiAliasDetection) { var indices = fontFace.GetGlyphIndices(new int[] {character}); var metrics = fontFace.GetDesignGlyphMetrics(indices, false); var metric = metrics[0]; var width = (float)(metric.AdvanceWidth - metric.LeftSideBearing - metric.RightSideBearing) / fontMetrics.DesignUnitsPerEm * fontSize; var height = (float)(metric.AdvanceHeight - metric.TopSideBearing - metric.BottomSideBearing) / fontMetrics.DesignUnitsPerEm * fontSize; var xOffset = (float)metric.LeftSideBearing / fontMetrics.DesignUnitsPerEm * fontSize; var yOffset = (float)(metric.TopSideBearing - metric.VerticalOriginY) / fontMetrics.DesignUnitsPerEm * fontSize; var advanceWidth = (float)(metric.AdvanceWidth) / fontMetrics.DesignUnitsPerEm * fontSize; var advanceHeight = (float)(metric.AdvanceHeight) / fontMetrics.DesignUnitsPerEm * fontSize; var pixelWidth = (int)Math.Ceiling(width + 2); var pixelHeight = (int)Math.Ceiling(height + 2); Bitmap bitmap; if(char.IsWhiteSpace(character)) { bitmap = new Bitmap(1, 1, PixelFormat.Format32bppArgb); } else { var glyphRun = new GlyphRun() { FontFace = fontFace, Advances = new[] { (float)Math.Round(advanceWidth) }, FontSize = fontSize, BidiLevel = 0, Indices = indices, IsSideways = false, Offsets = new[] {new GlyphOffset()} }; var matrix = SharpDX.Matrix.Identity; matrix.M41 = -(float)Math.Floor(xOffset - 1); matrix.M42 = -(float)Math.Floor(yOffset - 1); RenderingMode renderingMode; if (activateAntiAliasDetection) { var rtParams = new RenderingParams(factory); renderingMode = fontFace.GetRecommendedRenderingMode(fontSize, 1.0f, MeasuringMode.Natural, rtParams); rtParams.Dispose(); } else { renderingMode = RenderingMode.Aliased; } using(var runAnalysis = new GlyphRunAnalysis(factory, glyphRun, 1.0f, matrix, renderingMode, MeasuringMode.Natural, 0.0f, 0.0f)) { var bounds = new SharpDX.Rectangle(0, 0, pixelWidth, pixelHeight); bitmap = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb); if(renderingMode == RenderingMode.Aliased) { var texture = new byte[bounds.Width * bounds.Height]; runAnalysis.CreateAlphaTexture(TextureType.Aliased1x1, bounds, texture, texture.Length); bitmap = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb); for (int y = 0; y < bounds.Height; y++) { for (int x = 0; x < bounds.Width; x++) { int pixelX = y * bounds.Width + x; var grey = texture[pixelX]; var color = Color.FromArgb(grey, grey, grey); bitmap.SetPixel(x, y, color); } } } else { var texture = new byte[bounds.Width * bounds.Height * 3]; runAnalysis.CreateAlphaTexture(TextureType.Cleartype3x1, bounds, texture, texture.Length); for (int y = 0; y < bounds.Height; y++) { for (int x = 0; x < bounds.Width; x++) { int pixelX = (y * bounds.Width + x) * 3; var red = texture[pixelX]; var green = texture[pixelX + 1]; var blue = texture[pixelX + 2]; var color = Color.FromArgb(red, green, blue); bitmap.SetPixel(x, y, color); } } } //var positionUnderline = (float)fontMetrics.UnderlinePosition / fontMetrics.DesignUnitsPerEm * fontSize; //var positionUnderlineSize = (float)fontMetrics.UnderlineThickness / fontMetrics.DesignUnitsPerEm * fontSize; } } var glyph = new Glyph(character, bitmap) { XOffset = (float)Math.Floor(xOffset-1), XAdvance = (float)Math.Round(advanceWidth), YOffset = (float)Math.Floor(yOffset-1), }; return glyph; }
/// <inheritdoc /> protected override void Draw() { while (this.pendingActions.TryDequeue(out var action)) { action(); } var args = this.neovimClient.GetScreen(); if (args == null) { return; } this.scriptAnalysesCache.StartNewFrame(); this.DeviceContext.BeginDraw(); this.DeviceContext.Clear(Helpers.GetColor(args.BackgroundColor, 0)); // Paint the background for (int i = 0; i < args.Cells.GetLength(0); i++) { for (int j = 0; j < args.Cells.GetLength(1); j++) { if (args.Cells[i, j].BackgroundColor != args.BackgroundColor || args.Cells[i, j].Reverse) { var x = j * this.textParam.CharWidth; var y = i * this.textParam.LineHeight; var rect = new RawRectangleF(x, y, x + this.textParam.CharWidth, y + this.textParam.LineHeight); int color = args.Cells[i, j].Reverse ? args.Cells[i, j].ForegroundColor : args.Cells[i, j].BackgroundColor; var brush = this.brushCache.GetBrush(this.DeviceContext, color); this.DeviceContext.FillRectangle(rect, brush); } } } // Paint the foreground for (int i = 0; i < args.Cells.GetLength(0); i++) { int j = 0; while (j < args.Cells.GetLength(1)) { // Cells with the same style should be analyzed together. // This prevents the inproper ligature in <html>= // Of course, it relies on enabling the syntax. int cellRangeStart = j; int cellRangeEnd = j; Cell startCell = args.Cells[i, cellRangeStart]; while (true) { if (cellRangeEnd == args.Cells.GetLength(1)) { break; } Cell cell = args.Cells[i, cellRangeEnd]; if (cell.Character != null && (cell.ForegroundColor != startCell.ForegroundColor || cell.BackgroundColor != startCell.BackgroundColor || cell.SpecialColor != startCell.SpecialColor || cell.Italic != startCell.Italic || cell.Bold != startCell.Bold || cell.Reverse != startCell.Reverse || cell.Undercurl != startCell.Undercurl || cell.Underline != startCell.Underline)) { break; } cellRangeEnd++; } j = cellRangeEnd; var fontWeight = args.Cells[i, cellRangeStart].Bold ? DWrite.FontWeight.Bold : this.textParam.Weight; var fontStyle = args.Cells[i, cellRangeStart].Italic ? DWrite.FontStyle.Italic : this.textParam.Style; int cellIndex = cellRangeStart; using (var textSource = new RowTextSource(this.factoryDWrite, args.Cells, i, cellRangeStart, cellRangeEnd)) { var scriptAnalyses = this.scriptAnalysesCache.GetOrAddAnalysisResult( textSource.GetTextAtPosition(0), (_) => { using (var textSink = new TextAnalysisSink()) { this.textAnalyzer.AnalyzeScript(textSource, 0, textSource.Length, textSink); return(textSink.ScriptAnalyses); } }); // The result of AalyzeScript may cut the text into several ranges, // and in each range the text's scripts are different. foreach (var(codePointStart, codePointLength, scriptAnalysis) in scriptAnalyses) { var glyphBufferLength = (codePointLength * 3 / 2) + 16; var clusterMap = new short[codePointLength]; var textProperties = new DWrite.ShapingTextProperties[codePointLength]; short[] indices; DWrite.ShapingGlyphProperties[] shapingProperties; var fontFace = this.fontCache.GetPrimaryFontFace(fontWeight, fontStyle); int actualGlyphCount; // We don't know how many glyphs the text have. TextLength * 3 / 2 + 16 // is an empirical estimation suggested by MSDN. So using a loop to detect // the actual glyph count. while (true) { indices = new short[glyphBufferLength]; shapingProperties = new DWrite.ShapingGlyphProperties[glyphBufferLength]; try { var str = textSource.GetSubString(codePointStart, codePointLength); DWrite.FontFeature[][] fontFeatures = null; int[] featureLength = null; if (!this.EnableLigature) { fontFeatures = new DWrite.FontFeature[][] { new DWrite.FontFeature[] { new DWrite.FontFeature(DWrite.FontFeatureTag.StandardLigatures, 0), }, }; featureLength = new int[] { str.Length, }; } this.textAnalyzer.GetGlyphs( str, str.Length, fontFace, false, false, scriptAnalysis, null, null, fontFeatures, featureLength, glyphBufferLength, clusterMap, textProperties, indices, shapingProperties, out actualGlyphCount); break; } catch (SharpDX.SharpDXException e) { const int ERROR_INSUFFICIENT_BUFFER = 122; if (e.ResultCode == SharpDX.Result.GetResultFromWin32Error(ERROR_INSUFFICIENT_BUFFER)) { glyphBufferLength *= 2; } } } for (int codePointIndex = 0, glyphIndex = 0; codePointIndex < codePointLength;) { // var fontWeight = args.Screen[i, cellIndex].Bold ? DWrite.FontWeight.Bold : DWrite.FontWeight.Normal; // var fontStyle = args.Screen[i, cellIndex].Italic ? DWrite.FontStyle.Italic : DWrite.FontStyle.Normal; var foregroundColor = args.Cells[i, cellIndex].Reverse ? args.Cells[i, cellIndex].BackgroundColor : args.Cells[i, cellIndex].ForegroundColor; var foregroundBrush = this.brushCache.GetBrush(this.DeviceContext, foregroundColor); var fontFace2 = fontFace; short[] indices2; int cellWidth = 0; int codePointCount = 0; int glyphCount = 0; if (indices[glyphIndex] == 0) { // If the primary font doesn't have the glyph, get a font from system font fallback. // Ligatures for fallback fonts are not supported yet. int codePoint = args.Cells[i, cellIndex].Character.Value; fontFace2 = this.fontCache.GetFontFace(codePoint, fontWeight, fontStyle); indices2 = fontFace2.GetGlyphIndices(new int[] { codePoint }); glyphCount = indices2.Length; // NativeInterop.Methods.wcwidth(textSource.GetCodePoint(codePointStart + codePointIndex)); cellWidth = this.GetCharWidth(args.Cells, i, cellIndex); codePointCount = 1; } else { // The cluster map stores the information about the codepoint-glyph mapping. // If several codepoints share the same glyph (e.g. ligature), then they will // have the same value in clusterMap. // If one code point has several corresponding glyphs, then for the next codepoint, // the value in clusterMap will bump higher. // Example: CodePointLength = 5, GlyphCount = 5, clusterMap = [0, 1, 1, 2, 4] means: // Codepoint Index Glyph Index // 0 ----------- 0 // 1 ----------- 1 // 2 ----------/ // 3 ----------- 2 // \---------- 3 // 4 ----------- 4 var cluster = clusterMap[codePointIndex]; int nextCluster = cluster; while (true) { if (codePointIndex + codePointCount == clusterMap.Length) { nextCluster++; break; } nextCluster = clusterMap[codePointIndex + codePointCount]; if (cluster != nextCluster) { break; } // NativeInterop.Methods.wcwidth(textSource.GetCodePoint(codePointStart + codePointIndex + codePointCount)); cellWidth += this.GetCharWidth(args.Cells, i, cellIndex + cellWidth); codePointCount++; } glyphCount = nextCluster - cluster; indices2 = new short[glyphCount]; for (int c = 0; c < glyphCount; c++) { indices2[c] = indices[glyphIndex]; } } using (var glyphrun = new DWrite.GlyphRun { FontFace = fontFace2, Advances = null, BidiLevel = 0, FontSize = this.textParam.DipSize, Indices = indices2, IsSideways = false, Offsets = null, }) { var origin = new RawVector2(this.textParam.CharWidth * cellIndex, this.textParam.LineHeight * (i + 0.8f)); this.DeviceContext.DrawGlyphRun(origin, glyphrun, foregroundBrush, D2D.MeasuringMode.GdiNatural); glyphrun.FontFace = null; } cellIndex += cellWidth; codePointIndex += codePointCount; glyphIndex += glyphCount; } } } } } this.DeviceContext.EndDraw(); this.DrawCursor(args); }
/// <summary> /// Draws a run of glyphs to a bitmap target at the specified position. /// </summary> /// <remarks> /// You can use the IDWriteBitmapRenderTarget::DrawGlyphRun to render to a bitmap from a custom text renderer that you implement. The custom text renderer should call this method from within the <see cref="M:SharpDX.DirectWrite.TextRenderer.DrawGlyphRun(System.IntPtr,System.Single,System.Single,SharpDX.DirectWrite.MeasuringMode,SharpDX.DirectWrite.GlyphRun,SharpDX.DirectWrite.GlyphRunDescription,SharpDX.ComObject)" /> callback method as shown in the following code. /// <code> STDMETHODIMP GdiTextRenderer::DrawGlyphRun( __maybenull void* clientDrawingContext, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode, __in DWRITE_GLYPH_RUN const* glyphRun, __in DWRITE_GLYPH_RUN_DESCRIPTION const* glyphRunDescription, IUnknown* clientDrawingEffect ) /// { HRESULT hr = S_OK; // Pass on the drawing call to the render target to do the real work. RECT dirtyRect = {0}; hr = pRenderTarget_->DrawGlyphRun( baselineOriginX, baselineOriginY, measuringMode, glyphRun, pRenderingParams_, RGB(0,200,255), &dirtyRect ); return hr; /// } </code> /// /// The baselineOriginX, baslineOriginY, measuringMethod, and glyphRun parameters are provided (as arguments) when the callback method is invoked. The renderingParams, textColor and blackBoxRect are not. Default rendering params can be retrieved by using the <see cref="M:SharpDX.DirectWrite.Factory.CreateMonitorRenderingParams(System.IntPtr,SharpDX.DirectWrite.RenderingParams@)" /> method. /// </remarks> /// <param name="baselineOriginX">The horizontal position of the baseline origin, in DIPs, relative to the upper-left corner of the DIB. </param> /// <param name="baselineOriginY">The vertical position of the baseline origin, in DIPs, relative to the upper-left corner of the DIB. </param> /// <param name="measuringMode">The measuring method for glyphs in the run, used with the other properties to determine the rendering mode. </param> /// <param name="glyphRun">The structure containing the properties of the glyph run. </param> /// <param name="renderingParams">The object that controls rendering behavior. </param> /// <param name="textColor">The foreground color of the text. </param> /// <returns>If the method succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. </returns> /// <unmanaged>HRESULT IDWriteBitmapRenderTarget::DrawGlyphRun([None] float baselineOriginX,[None] float baselineOriginY,[None] DWRITE_MEASURING_MODE measuringMode,[In] const DWRITE_GLYPH_RUN* glyphRun,[None] IDWriteRenderingParams* renderingParams,[None] COLORREF textColor,[Out, Optional] RECT* blackBoxRect)</unmanaged> public void DrawGlyphRun(float baselineOriginX, float baselineOriginY, MeasuringMode measuringMode, GlyphRun glyphRun, RenderingParams renderingParams, RawColor4 textColor) { RawRectangle temp; DrawGlyphRun(baselineOriginX, baselineOriginY, measuringMode, glyphRun, renderingParams, textColor, out temp); }