public static void DrawGlyphRun(this DrawingContext drawingContext, Brush foreground, GlyphRun glyphRun, Point position, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment) { var boundingBox = glyphRun.ComputeInkBoundingBox(); switch (horizontalAlignment) { case HorizontalAlignment.Center: position.X -= boundingBox.Width / 2d; break; case HorizontalAlignment.Right: position.X -= boundingBox.Width; break; default: break; } switch (verticalAlignment) { case VerticalAlignment.Center: position.Y -= boundingBox.Height / 2d; break; case VerticalAlignment.Bottom: position.Y -= boundingBox.Height; break; default: break; } drawingContext.PushTransform(new TranslateTransform(position.X - boundingBox.X, position.Y - boundingBox.Y)); drawingContext.DrawGlyphRun(foreground, glyphRun); drawingContext.Pop(); }
public unsafe void DrawGlyphRun(Brush brush, GlyphRun run) { gl.PushMatrix(); Geometry geo = run.GetGeometry(); fixed (TextureCoordinate* texCoords = run.FontCoords) { gl.Enable(gl.GL_BLEND); gl.ActiveTexture(gl.GL_TEXTURE1); gl.ClientActiveTexture(gl.GL_TEXTURE1); gl.EnableClientState(gl.GL_TEXTURE_COORD_ARRAY); gl.Enable(gl.GL_TEXTURE_2D); gl.BindTexture(gl.GL_TEXTURE_2D, run.Font.mySource.myName); gl.TexCoordPointer(2, gl.GL_FLOAT, 0, (IntPtr)texCoords); gl.ActiveTexture(gl.GL_TEXTURE0); gl.ClientActiveTexture(gl.GL_TEXTURE0); DrawGeometry(brush, null, geo); gl.ActiveTexture(gl.GL_TEXTURE1); gl.Disable(gl.GL_TEXTURE_2D); gl.ActiveTexture(gl.GL_TEXTURE0); gl.Disable(gl.GL_BLEND); } gl.PopMatrix(); }
public static ImageSource ToFontAwesomeIcon(this string text, Brush foreBrush, FontStyle fontStyle, FontWeight fontWeight, FontStretch fontStretch) { var fontFamily = new FontFamily("/GitWorkItems;component/Resources/#FontAwesome"); if (fontFamily != null && !String.IsNullOrEmpty(text)) { //premier essai, on charge la police directement Typeface typeface = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch); GlyphTypeface glyphTypeface; if (!typeface.TryGetGlyphTypeface(out glyphTypeface)) { //si ça ne fonctionne pas (et pour le mode design dans certains cas) on ajoute l'uri pack://application typeface = new Typeface(new FontFamily(new Uri("pack://application:,,,"), fontFamily.Source), fontStyle, fontWeight, fontStretch); if (!typeface.TryGetGlyphTypeface(out glyphTypeface)) throw new InvalidOperationException("No glyphtypeface found"); } //détermination des indices/tailles des caractères dans la police ushort[] glyphIndexes = new ushort[text.Length]; double[] advanceWidths = new double[text.Length]; for (int n = 0; n < text.Length; n++) { ushort glyphIndex; try { glyphIndex = glyphTypeface.CharacterToGlyphMap[text[n]]; } catch (Exception) { glyphIndex = 42; } glyphIndexes[n] = glyphIndex; double width = glyphTypeface.AdvanceWidths[glyphIndex] * 1.0; advanceWidths[n] = width; } try { //création de l'objet DrawingImage (compatible avec Imagesource) à partir d'un glyphrun GlyphRun gr = new GlyphRun(glyphTypeface, 0, false, 1.0, glyphIndexes, new Point(0, 0), advanceWidths, null, null, null, null, null, null); GlyphRunDrawing glyphRunDrawing = new GlyphRunDrawing(foreBrush, gr); return new DrawingImage(glyphRunDrawing); } catch (Exception ex) { // ReSharper disable LocalizableElement Console.WriteLine("Error in generating Glyphrun : " + ex.Message); // ReSharper restore LocalizableElement } } return null; }
protected override Size MeasureOverride(Size constraint) { if (Content == null) return Size.Empty; if (myRun == null) myRun = new GlyphRun(Content.ToString(), myFont, myTextAlignment); return new Size(myRun.Width, myRun.Height); }
/// <summary> /// Internal constructor. /// </summary> internal IndexedGlyphRun( int textSourceCharacterIndex, int textSourceCharacterLength, GlyphRun glyphRun ) { _textSourceCharacterIndex = textSourceCharacterIndex; _length = textSourceCharacterLength; _glyphRun = glyphRun; }
public override void Draw(DrawingContext drawingContext, double scale, double x, double y) { // Draw character at given position. var typeface = this.Character.Font; var glyphIndex = typeface.CharacterToGlyphMap[this.Character.Character]; var glyphRun = new GlyphRun(typeface, 0, false, this.Character.Size * scale, new ushort[] { glyphIndex }, new Point(x * scale, y * scale), new double[] { typeface.AdvanceWidths[glyphIndex] }, null, null, null, null, null, null); drawingContext.DrawGlyphRun(this.Foreground ?? Brushes.Black, glyphRun); }
public HexEditorBlock(GeometryCollection hexGeos, GeometryCollection ascciGeos) { m_Run = HexEditor.CreateGlyphRun(new Typeface(FontFamily, FontStyle, FontWeight, FontStretch), "0", FontSize, new Point(0, FontSize)); Unloaded += HexEditorTextBlock_Unloaded; Loaded += HexEditorTextBlock_Loaded; Width = 50; Height = 50; m_HexGeo = hexGeos; m_AsciiGeo = ascciGeos; }
public override IText AddText(string text, double fontSize, SolidColorBrush brush) { if (cachedTypeface == null) { var t = CreateTypeface(); if (!t.TryGetGlyphTypeface(out cachedTypeface)) throw new NotSupportedException(); } ushort[] glyphIndexes = new ushort[text.Length]; double[] advanceWidths = new double[text.Length]; double totalWidth = 0; for (int n = 0; n < text.Length; n++) { ushort glyphIndex; cachedTypeface.CharacterToGlyphMap.TryGetValue(text[n], out glyphIndex); glyphIndexes[n] = glyphIndex; double width = cachedTypeface.AdvanceWidths[glyphIndex] * fontSize; advanceWidths[n] = width; totalWidth += width; } GlyphRun run = new GlyphRun(cachedTypeface, bidiLevel: 0, isSideways: false, renderingEmSize: fontSize, glyphIndices: glyphIndexes, baselineOrigin: new Point(0, Math.Round(cachedTypeface.Baseline * fontSize)), advanceWidths: advanceWidths, glyphOffsets: null, characters: null, deviceFontName: null, clusterMap: null, caretStops: null, language: null); MyText myText = new MyText { run = run, parent = this, brush = brush }; texts.Add(myText); return myText; }
/// <summary> /// /// </summary> /// <param name="glyphRun"></param> public GlyphsSerializer(GlyphRun glyphRun) { if (glyphRun == null) { throw new ArgumentNullException("glyphRun"); } _glyphTypeface = glyphRun.GlyphTypeface; _milToEm = EmScaleFactor / glyphRun.FontRenderingEmSize; _sideways = glyphRun.IsSideways; _characters = glyphRun.Characters; _caretStops = glyphRun.CaretStops; // the first value in the cluster map can be non-zero, in which case it's applied as an offset to all // subsequent entries in the cluster map _clusters = glyphRun.ClusterMap; if (_clusters != null) _glyphClusterInitialOffset = _clusters[0]; _indices = glyphRun.GlyphIndices; _advances = glyphRun.AdvanceWidths; _offsets = glyphRun.GlyphOffsets; // "100,50,,0;".Length is a capacity estimate for an individual glyph _glyphStringBuider = new StringBuilder(10); // string length * _glyphStringBuider.Capacity is an estimate for the whole string _indicesStringBuider = new StringBuilder( Math.Max( (_characters == null ? 0 : _characters.Count), _indices.Count ) * _glyphStringBuider.Capacity ); }
// draws a glyphrun range using the given brush private void _drawGlyphRun(DrawingContext dc, GlyphRun run, Brush brush, int start, int len) { var max = run.GlyphIndices.Count; start = Math.Min(start, max - 1); len = Math.Min(len, max - start); if (start < 0 || len <= 0) return; var indices = new ushort[len]; var widths = new double[len]; for (int i = start, j = 0; i < start + len; i++, j++) { indices[j] = run.GlyphIndices[i]; widths[j] = run.AdvanceWidths[i]; } var origin = run.BaselineOrigin; origin.X += run.AdvanceWidths.Take(start).Sum(); var run2 = new GlyphRun(run.GlyphTypeface, run.BidiLevel, run.IsSideways, run.FontRenderingEmSize, indices, origin, widths, null, null, null, null, null, null); dc.DrawGlyphRun(brush, run2); }
// draws a glyphrun including any defined highlights private void _drawGlyphRun(DrawingContext dc, GlyphRun run, Brush brush) { if (_highlights == null) { dc.DrawGlyphRun(brush, run); return; } var max = run.GlyphIndices.Count; var pos = 0; var k = 0; while (k < _highlights.Count) { var h1 = _highlights[k].Start; var h2 = h1 + _highlights[k].Length; if (h1 > pos) { _drawGlyphRun(dc, run, brush, pos, h1 - pos); } _drawGlyphRun(dc, run, _highlights[k].Foreground, h1, h2 - h1); pos = h2; k++; } if (pos < max) { _drawGlyphRun(dc, run, brush, pos, max - pos); } }
// builds the glyph run for the given text, possibly trimming it to fit the specified max width private BuildGlyphResult _buildGlyph(bool useFallbackFont, double maxWidth) { var font = Font; if (font != null && useFallbackFont) font = Font.CachedFallbackFont; if (VisualText.IsEmpty() || font == null || font.Size <= 0) return null; // get typeface metrics var size = font.Size; var glyphTypeface = font.CachedTypeface; var charmap = glyphTypeface.CharacterToGlyphMap; var widthmap = glyphTypeface.AdvanceWidths; // create arrays for holding the glyph indexes and advance widths of the individual text characters var N = VisualText.Length; var glyphIndexes = new ushort[N]; var advanceWidths = new double[N]; var ellipsisWidth = 0.0; var ellipsisIndex = -1; if (TextOverflow != TextOverflow.Ignore) { ellipsisWidth = 3 * widthmap[charmap['.']] * size; } var height = glyphTypeface.Height * size; var baseline = glyphTypeface.Baseline * size; var origin = new Point(0, baseline); // scan and measure each character until end of text or until overflow var overflowForward = (TextOverflowDirection == LogicalDirection.Forward); var width = 0.0; var index = (overflowForward ? 0 : N - 1); while (true) { if (overflowForward) { if (index >= N) break; } else { if (index < 0) break; } int c = VisualText[index]; ushort g; if (charmap.ContainsKey(c)) { g = charmap[c]; } else { if (!useFallbackFont) { // character cannot be displayed with this font, try building the glyph with the fallback font return _buildGlyph(true, maxWidth); } else { // if no fallback font exists, display a '?' placeholder Log.Warn("Character '{0}' (U+{1:X4}) was not found in font '{2}'", VisualText[index], (int)VisualText[index], font.Family.Source); g = charmap['?']; } } var w = widthmap[g] * size; if (TextOverflow == TextOverflow.Ignore || width + w <= maxWidth - ellipsisWidth) { // in case there is no overflow (or we don't care about overflow), continue to accumulate the characters and their widths glyphIndexes[index] = g; advanceWidths[index] = w; width += w; } else { // in case of overflow, mark the position where the text should be trimmed and ellipsis added ellipsisIndex = index; if (TextOverflow == TextOverflow.WordEllipsis && ellipsisIndex > 0) { // in case of trimming on word boundaries, look for the last whole word Action<Regex> skipChars = pattern => { for (; ellipsisIndex >= 0 && VisualText.At(ellipsisIndex).Matches(pattern); ellipsisIndex--) ; }; skipChars(_nonWhitespace); skipChars(_reWhitespace); ellipsisIndex++; } break; } index += (overflowForward ? +1 : -1); } // handle overflow condition if (ellipsisIndex >= 0) { if (maxWidth < ellipsisWidth) { // not enough room to even display the ellipsis, so return an empty glyph return null; } // truncate the array of characters to display and add the ellipsis var g = charmap['.']; var w = widthmap[g] * size; ushort[] glyphIndexes2 = null; double[] advanceWidths2 = null; if (overflowForward) { glyphIndexes2 = new ushort[ellipsisIndex + 3]; advanceWidths2 = new double[ellipsisIndex + 3]; for (var i = 0; i < ellipsisIndex; i++) { glyphIndexes2[i] = glyphIndexes[i]; advanceWidths2[i] = advanceWidths[i]; } for (var i = ellipsisIndex; i < ellipsisIndex + 3; i++) { glyphIndexes2[i] = g; advanceWidths2[i] = w; width += w; } } else { var K = Math.Max(0, N - ellipsisIndex - 1); glyphIndexes2 = new ushort[K + 3]; advanceWidths2 = new double[K + 3]; for (var i = 0; i < K; i++) { glyphIndexes2[i + 3] = glyphIndexes[i + ellipsisIndex + 1]; advanceWidths2[i + 3] = advanceWidths[i + ellipsisIndex + 1]; } for (var i = 0; i < 3; i++) { glyphIndexes2[i] = g; advanceWidths2[i] = w; width += w; } origin.X += maxWidth - width; } glyphIndexes = glyphIndexes2; advanceWidths = advanceWidths2; } // create the actual glyph run GlyphRun glyphRun = null; try { glyphRun = new GlyphRun(glyphTypeface, 0, false, size, glyphIndexes, origin, advanceWidths, null, null, null, null, null, null); } catch (OverflowException) { // this happens when bounding area of the glyph run exceeds the maximal rendering size _prepareVisualText("Text too long..."); return _buildGlyph(false, maxWidth); } return new BuildGlyphResult { GlyphRun = glyphRun, Width = width, Height = height, Baseline = baseline }; }
/// <summary> /// Draw a GlyphRun. /// </summary> /// <param name="foregroundBrush">Foreground brush to draw GlyphRun with. </param> /// <param name="glyphRun"> The GlyphRun to draw. </param> /// <exception cref="ObjectDisposedException"> /// This call is illegal if this object has already been closed or disposed. /// </exception> public override void DrawGlyphRun(Brush foregroundBrush, GlyphRun glyphRun) { if (glyphRun != null) { // The InkBoundingBox + the Origin produce the true InkBoundingBox. Rect rectangle = glyphRun.ComputeInkBoundingBox(); if (!rectangle.IsEmpty) { rectangle.Offset((Vector)glyphRun.BaselineOrigin); DrawGeometry(Brushes.Black, null /* pen */, new RectangleGeometry(rectangle)); } } }
/// <summary> /// Draw glyph run to the drawing surface /// </summary> internal sealed override void Draw( DrawingContext drawingContext, Brush foregroundBrush, GlyphRun glyphRun ) { if (drawingContext == null) throw new ArgumentNullException("drawingContext"); glyphRun.EmitBackground(drawingContext, _properties.BackgroundBrush); drawingContext.DrawGlyphRun( foregroundBrush != null ? foregroundBrush : _properties.ForegroundBrush, glyphRun ); }
private GlyphRun BuildGlyphRun(int column, int line, char c) { var paddingTop = FontSize / 3; var glyphs = new GlyphRun(); ISupportInitialize isi = glyphs; isi.BeginInit(); glyphs.GlyphTypeface = glyphFace; glyphs.FontRenderingEmSize = FontSize; var chars = new[] { c }; glyphs.Characters = chars; var codePoint = (int)c; var glyphIndex = glyphFace.CharacterToGlyphMap[codePoint]; var glyphWidth = glyphFace.AdvanceWidths[glyphIndex]; glyphs.GlyphIndices = new ushort[] { glyphIndex }; glyphs.AdvanceWidths = new double[] { glyphWidth * FontSize }; _cellWidth = glyphWidth * FontSize; _cellHeight = (glyphFace.Baseline * FontSize) + (paddingTop); glyphs.BaselineOrigin = new Point( glyphWidth * FontSize * column, (glyphFace.Baseline * FontSize * (line + 1)) + (paddingTop * line)); isi.EndInit(); return glyphs; }
//Returns the character offset in a GlyphRun given an X position private int GlyphRunHitTest(GlyphRun run, double xoffset, bool LTR) { bool isInside; double distance = LTR ? xoffset - run.BaselineOrigin.X : run.BaselineOrigin.X - xoffset; CharacterHit hit = run.GetCaretCharacterHitFromDistance(distance, out isInside); return hit.FirstCharacterIndex + hit.TrailingLength; }
/// <summary> /// DrawGlyphRun - /// Draw a GlyphRun /// </summary> /// <param name="foregroundBrush"> /// Foreground brush to draw the GlyphRun with. /// </param> /// <param name="glyphRun"> The GlyphRun to draw. </param> public override void DrawGlyphRun( Brush foregroundBrush, GlyphRun glyphRun) { Debug.Assert(false); }
/// <summary> /// Draw a GlyphRun. /// </summary> /// <param name="foregroundBrush">Foreground brush to draw GlyphRun with. </param> /// <param name="glyphRun"> The GlyphRun to draw. </param> /// <exception cref="ObjectDisposedException"> /// This call is illegal if this object has already been closed or disposed. /// </exception> public override void DrawGlyphRun(Brush foregroundBrush, GlyphRun glyphRun) { if (!IsCurrentLayerNoOp && (glyphRun != null)) { // The InkBoundingBox + the Origin produce the true InkBoundingBox. Rect rectangle = glyphRun.ComputeInkBoundingBox(); if (!rectangle.IsEmpty) { rectangle.Offset((Vector)glyphRun.BaselineOrigin); _contains |= rectangle.Contains(_point); // If we've hit, stop walking. if (_contains) { StopWalking(); } } } }
private double ChangeGlyphOrientation(GlyphRunDrawing glyphDrawing, double baselineShiftX, double baselineShiftY, bool isLatin) { if (glyphDrawing == null) { return 0; } GlyphRun glyphRun = glyphDrawing.GlyphRun; GlyphRun verticalRun = new GlyphRun(); ISupportInitialize glyphInit = verticalRun; glyphInit.BeginInit(); verticalRun.IsSideways = true; List<double> advancedHeights = null; double totalHeight = 0; IList<UInt16> glyphIndices = glyphRun.GlyphIndices; int advancedCount = glyphIndices.Count; //{ // double textHeight = glyphRun.ComputeInkBoundingBox().Height + glyphRun.ComputeAlignmentBox().Height; // textHeight = textHeight / 2.0d; // totalHeight = advancedCount * textHeight; // advancedHeights = new List<double>(advancedCount); // for (int k = 0; k < advancedCount; k++) // { // advancedHeights.Add(textHeight); // } //} advancedHeights = new List<double>(advancedCount); IDictionary<ushort, double> allGlyphHeights = glyphRun.GlyphTypeface.AdvanceHeights; double fontSize = glyphRun.FontRenderingEmSize; for (int k = 0; k < advancedCount; k++) { double tempValue = allGlyphHeights[glyphIndices[k]] * fontSize; advancedHeights.Add(tempValue); totalHeight += tempValue; } Point baselineOrigin = glyphRun.BaselineOrigin; if (isLatin) { baselineOrigin.X += baselineShiftX; baselineOrigin.Y += baselineShiftY; } //verticalRun.AdvanceWidths = glyphRun.AdvanceWidths; verticalRun.AdvanceWidths = advancedHeights; verticalRun.BaselineOrigin = baselineOrigin; verticalRun.BidiLevel = glyphRun.BidiLevel; verticalRun.CaretStops = glyphRun.CaretStops; verticalRun.Characters = glyphRun.Characters; verticalRun.ClusterMap = glyphRun.ClusterMap; verticalRun.DeviceFontName = glyphRun.DeviceFontName; verticalRun.FontRenderingEmSize = glyphRun.FontRenderingEmSize; verticalRun.GlyphIndices = glyphRun.GlyphIndices; verticalRun.GlyphOffsets = glyphRun.GlyphOffsets; verticalRun.GlyphTypeface = glyphRun.GlyphTypeface; verticalRun.Language = glyphRun.Language; glyphInit.EndInit(); glyphDrawing.GlyphRun = verticalRun; return totalHeight; }
/// <summary> /// DrawGlyphRun - /// Draw a GlyphRun /// </summary> /// <param name="foregroundBrush"> /// Foreground brush to draw the GlyphRun with. /// </param> /// <param name="glyphRun"> The GlyphRun to draw. </param> public override void DrawGlyphRun( Brush foregroundBrush, GlyphRun glyphRun) { _drawingContext.DrawGlyphRun( foregroundBrush, glyphRun ); }
//draw related methods: /// <summary> Draws the current glyph run on the specified context at the specified location. </summary> /// <param name="context"> The context to draw on. </param> protected override void OnRender(DrawingContext context) { base.OnRender(context); List<double> advanceWidths = new List<double>(); List<ushort> glyphsToDraw = new List<ushort>(); //this glyph run is set at the correct left, but its height is set at the top of the parent box //to go from that origin to the baseline origin of the box (and hence also of this glyph run), subtract Box.FrombaselineToOrigin. (again, the left coordinate is already correct) //to go from the baseline origin to the top left origin of this glyph run, add layout.Top, which is guaranteed to be at least as high as FontSize * FontConstants.Baseline Point baselineOrigin = Box.FromOriginToBaseline; //relative to coordinates used by the drawingcontext (which have the origin at the top of the parent box and left correct) double top = this.Layout.Top; Point topLeftOrigin = new Point(baselineOrigin.X, baselineOrigin.Y + top); double cumulativeWidth = 0; for (int i = 0; i < viewModel.Glyphs.Count; i++) { Point glyphOrigin = topLeftOrigin + new Vector(cumulativeWidth, 0); var glyphIndex = viewModel.Glyphs[i].Index; var markup = viewModel.Glyphs[i].Markup; double advanceWidth = GlyphRunViewModel.glyphFace.AdvanceWidths[glyphIndex] * viewModel.FontSize; advanceWidths.Add(advanceWidth); glyphsToDraw.Add(glyphIndex); if (markup.Background != null) { Size glyphSize = new Size(advanceWidth, GlyphRunViewModel.glyphFace.Height * viewModel.FontSize); Rect glyphRegion = new Rect(glyphOrigin, glyphSize); context.DrawRectangle(markup.Background, null, glyphRegion); } bool collect = i != viewModel.Glyphs.Count - 1 && markup.Foreground.Equals(viewModel.Glyphs[i + 1].Markup.Foreground); if (!collect) { GlyphRun glyphRun = new GlyphRun(GlyphRunViewModel.glyphFace, 0, false, viewModel.FontSize, glyphsToDraw, baselineOrigin, advanceWidths, null, null, null, null, null, null); context.DrawGlyphRun(markup.Foreground, glyphRun); advanceWidths = new List<double>(); glyphsToDraw = new List<ushort>(); baselineOrigin.X += cumulativeWidth + advanceWidth; } if (markup.Strikethrough != null) this.DrawStrikethrough(context, glyphOrigin, cumulativeWidth, markup.Strikethrough); if (markup.Underline != null) this.DrawUnderline(context, glyphOrigin, cumulativeWidth, markup.Underline); cumulativeWidth += advanceWidth; } Pen testPen = null;//new Pen(Brushes.Black, 1); var selectionRectangle = new Rect(topLeftOrigin, new Size(cumulativeWidth, GlyphRunViewModel.glyphFace.Height * viewModel.FontSize)); context.DrawRectangle(Brushes.Transparent, testPen, selectionRectangle);//for selection }
public override void DrawGlyphRun( Brush foregroundBrush, GlyphRun glyphRun) { VerifyApiNonstructuralChange(); if ((foregroundBrush == null) || (glyphRun == null)) { return; } #if DEBUG MediaTrace.DrawingContextOp.Trace("DrawGlyphRun(const)"); #endif unsafe { EnsureRenderData(); // Always assume visual and drawing brushes need realization updates MILCMD_DRAW_GLYPH_RUN record = new MILCMD_DRAW_GLYPH_RUN ( _renderData.AddDependentResource(foregroundBrush), _renderData.AddDependentResource(glyphRun) ); // Assert that the calculated packet size is the same as the size returned by sizeof(). Debug.Assert(sizeof(MILCMD_DRAW_GLYPH_RUN) == 8); _renderData.WriteDataRecord(MILCMD.MilDrawGlyphRun, (byte*)&record, 8 /* sizeof(MILCMD_DRAW_GLYPH_RUN) */); } }
private bool CheckGlyphRun() { if (glyphRun == null) { if (string.IsNullOrEmpty(Text)) { return false; } var typeface = new Typeface(FontFamily, FontStyle, FontWeight, FontStretch); GlyphTypeface glyphTypeface; if (!typeface.TryGetGlyphTypeface(out glyphTypeface)) { return false; } var glyphIndices = new ushort[Text.Length]; var advanceWidths = new double[Text.Length]; for (int i = 0; i < Text.Length; i++) { var glyphIndex = glyphTypeface.CharacterToGlyphMap[Text[i]]; glyphIndices[i] = glyphIndex; advanceWidths[i] = glyphTypeface.AdvanceWidths[glyphIndex] * FontSize; } glyphRun = new GlyphRun(glyphTypeface, 0, false, FontSize, glyphIndices, new Point(), advanceWidths, null, null, null, null, null, null); outline = glyphRun.BuildGeometry().GetWidenedPathGeometry(new Pen(null, OutlineThickness * 2d)); } return true; }
protected override void OnContentChanged(object oldContent, object newContent) { base.OnContentChanged(oldContent, newContent); myRun = null; InvalidateMeasure(); }
private static ImageSource CreateGlyph(string text, FontFamily fontFamily, FontStyle fontStyle, FontWeight fontWeight, FontStretch fontStretch, Brush foreBrush) { if (fontFamily != null && !string.IsNullOrEmpty(text)) { var typeface = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch); GlyphTypeface glyphTypeface; if (!typeface.TryGetGlyphTypeface(out glyphTypeface)) { throw Log.ErrorAndCreateException<InvalidOperationException>("No glyph type face found"); } var glyphIndexes = new ushort[text.Length]; var advanceWidths = new double[text.Length]; for (var i = 0; i < text.Length; i++) { ushort glyphIndex; try { var key = text[i]; if (!glyphTypeface.CharacterToGlyphMap.TryGetValue(key, out glyphIndex)) { glyphIndex = 42; } } catch (Exception) { glyphIndex = 42; } glyphIndexes[i] = glyphIndex; var width = glyphTypeface.AdvanceWidths[glyphIndex] * 1.0; advanceWidths[i] = width; } try { var glyphRun = new GlyphRun(glyphTypeface, 0, false, RenderingEmSize, glyphIndexes, new Point(0, 0), advanceWidths, null, null, null, null, null, null); var glyphRunDrawing = new GlyphRunDrawing(foreBrush, glyphRun); //TextOptions.SetTextRenderingMode(glyphRunDrawing, TextRenderingMode.Aliased); var drawingImage = new DrawingImage(glyphRunDrawing); //TextOptions.SetTextRenderingMode(drawingImage, TextRenderingMode.Aliased); return drawingImage; } catch (Exception ex) { Log.Error(ex, "Error in generating Glyphrun"); } } return null; }
private Rect DrawIndexedGlyphRun(DrawingContext drawingContext, IndexedGlyphRun indexedrun, Point linePosition, JapaneseTextSource source, bool isVerticalWriting) { GlyphRun run; if (isVerticalWriting) { List<double> advanceWidths = new List<double>(); int[] advance2 = source.Advance; for (int i = 0; i < advance2.Length; i++) { int advance = advance2[i]; advanceWidths.Add((double)advance); } run = new GlyphRun(indexedrun.GlyphRun.GlyphTypeface, indexedrun.GlyphRun.BidiLevel, true, indexedrun.GlyphRun.FontRenderingEmSize, source.Glyphs, linePosition, indexedrun.GlyphRun.AdvanceWidths, indexedrun.GlyphRun.GlyphOffsets, indexedrun.GlyphRun.Characters, indexedrun.GlyphRun.DeviceFontName, indexedrun.GlyphRun.ClusterMap, indexedrun.GlyphRun.CaretStops, indexedrun.GlyphRun.Language); } else { run = new GlyphRun(indexedrun.GlyphRun.GlyphTypeface, indexedrun.GlyphRun.BidiLevel, false, indexedrun.GlyphRun.FontRenderingEmSize, indexedrun.GlyphRun.GlyphIndices, linePosition, indexedrun.GlyphRun.AdvanceWidths, indexedrun.GlyphRun.GlyphOffsets, indexedrun.GlyphRun.Characters, indexedrun.GlyphRun.DeviceFontName, indexedrun.GlyphRun.ClusterMap, indexedrun.GlyphRun.CaretStops, indexedrun.GlyphRun.Language); } drawingContext.DrawGlyphRun(source.JapaneseTextRunProperties.ForegroundBrush, run); return run.ComputeAlignmentBox(); }
protected bool RenderText(String text, DrawingContext dc, ViewUtil.ItemFont itemFont, SolidColorBrush brush, double fontSize, double maxWidth, double maxHeight, double x, double baseline, ref double useHeight, bool nowrap = false) { if (x <= 0 || maxWidth <= 0) { useHeight = 0; return false; } double totalHeight = 0; double fontHeight = fontSize * itemFont.GlyphType.Height; string[] lineText = text.Replace("\r", "").Split('\n'); foreach (string line in lineText) { //高さ確認 if (totalHeight + fontHeight > maxHeight) { //これ以上は無理 useHeight = totalHeight; return false; } // ベースラインの位置の計算 // ビットマップフォントがかすれる問題 とりあえず整数にしておく Point origin = new Point(Math.Round(x), Math.Round(totalHeight + baseline)); //メイリオみたいに行間のあるフォントと MS P ゴシックみたいな行間のないフォントがあるので //なんとなく行間を作ってみる。 totalHeight += Math.Max(fontHeight, fontSize + 2); double totalWidth = 0; List<ushort> glyphIndexes = new List<ushort>(); List<double> advanceWidths = new List<double>(); for (int n = 0; n < line.Length; n++) { // XAML に合わせて、行頭の空白を無視する if (glyphIndexes.Count == 0 && (line[n] == ' ' || line[n] == '\x3000')) continue; //ushort glyphIndex = glyphType.CharacterToGlyphMap[line[n]]; //double width = glyphType.AdvanceWidths[glyphIndex] * fontSize; ushort glyphIndex = itemFont.GlyphIndexCache[line[n]]; if (glyphIndex == 0) { itemFont.GlyphIndexCache[line[n]] = glyphIndex = itemFont.GlyphType.CharacterToGlyphMap[line[n]]; itemFont.GlyphWidthCache[glyphIndex] = (float)itemFont.GlyphType.AdvanceWidths[glyphIndex]; } double width = itemFont.GlyphWidthCache[glyphIndex] * fontSize; if (totalWidth + width > maxWidth) { if (nowrap == true) break;//改行しない場合ここで終り if (totalWidth == 0) return false;//一文字も置けなかった(glyphIndexesなどのCount=0のまま) if (totalHeight + fontHeight > maxHeight) { //次の行無理 //glyphIndex = glyphType.CharacterToGlyphMap['…']; //double widthEllipsis = glyphType.AdvanceWidths[glyphIndex] * fontSize; glyphIndex = itemFont.GlyphType.CharacterToGlyphMap['…']; double widthEllipsis = itemFont.GlyphType.AdvanceWidths[glyphIndex] * fontSize; while (totalWidth - advanceWidths.Last() + widthEllipsis > maxWidth) { totalWidth -= advanceWidths.Last(); glyphIndexes.RemoveAt(glyphIndexes.Count-1); advanceWidths.RemoveAt(advanceWidths.Count - 1); } glyphIndexes[glyphIndexes.Count - 1] = glyphIndex; advanceWidths[advanceWidths.Count - 1] = widthEllipsis; GlyphRun glyphRun = new GlyphRun(itemFont.GlyphType, 0, false, fontSize, glyphIndexes, origin, advanceWidths, null, null, null, null, null, null); dc.DrawGlyphRun(brush, glyphRun); useHeight = totalHeight; return false; } else { //次の行いけるので今までの分出力 GlyphRun glyphRun = new GlyphRun(itemFont.GlyphType, 0, false, fontSize, glyphIndexes, origin, advanceWidths, null, null, null, null, null, null); dc.DrawGlyphRun(brush, glyphRun); origin = new Point(Math.Round(x), Math.Round(totalHeight + baseline)); totalHeight += Math.Max(fontHeight, fontSize + 2); totalWidth = 0; glyphIndexes = new List<ushort>(); advanceWidths = new List<double>(); // XAML に合わせて、行頭の空白を無視する if (line[n] == ' ' || line[n] == '\x3000') continue; } } glyphIndexes.Add(glyphIndex); advanceWidths.Add(width); totalWidth += width; } if (glyphIndexes.Count > 0) { GlyphRun glyphRun = new GlyphRun(itemFont.GlyphType, 0, false, fontSize, glyphIndexes, origin, advanceWidths, null, null, null, null, null, null); dc.DrawGlyphRun(brush, glyphRun); } } useHeight = totalHeight; return true; }
/// <summary> /// DrawGlyphRun - /// Draw a GlyphRun /// </summary> /// <param name="foregroundBrush"> /// Foreground brush to draw the GlyphRun with. /// </param> /// <param name="glyphRun"> The GlyphRun to draw. </param> public abstract void DrawGlyphRun( Brush foregroundBrush, GlyphRun glyphRun);
public static GlyphRun BuildGlyphRun(string text) { double fontSize = 50; GlyphRun glyphs = null; Typeface font = new Typeface("Arial"); GlyphTypeface glyphFace; if (font.TryGetGlyphTypeface(out glyphFace)) { glyphs = new GlyphRun(); System.ComponentModel.ISupportInitialize isi = glyphs; isi.BeginInit(); glyphs.GlyphTypeface = glyphFace; glyphs.FontRenderingEmSize = fontSize; char[] textChars = text.ToCharArray(); glyphs.Characters = textChars; ushort[] glyphIndices = new ushort[textChars.Length]; double[] advanceWidths = new double[textChars.Length]; for (int i = 0; i < textChars.Length; ++i) { int codepoint = textChars[i]; ushort glyphIndex = glyphFace.CharacterToGlyphMap[codepoint]; double glyphWidth = glyphFace.AdvanceWidths[glyphIndex]; glyphIndices[i] = glyphIndex; advanceWidths[i] = glyphWidth * fontSize; } glyphs.GlyphIndices = glyphIndices; glyphs.AdvanceWidths = advanceWidths; glyphs.BaselineOrigin = new Point(0, glyphFace.Baseline * fontSize); isi.EndInit(); } return glyphs; }
private static double _GetDistanceToCharacter(GlyphRun run, int charOffset) { int firstChar = charOffset, trailingLength = 0; int characterCount = (run.Characters == null) ? 0 : run.Characters.Count; if (firstChar == characterCount) { // place carat at end of previous character to make sure it works at end of line firstChar--; trailingLength = 1; } return run.GetDistanceFromCaretCharacterHit(new CharacterHit(firstChar, trailingLength)); }