public WpfGlyphTextBuilder(WpfFontFamilyInfo familyInfo, CultureInfo culture, double fontSize) : base(culture, familyInfo.Name, fontSize, null) { _typeface = new Typeface(familyInfo.Family, familyInfo.Style, familyInfo.Weight, familyInfo.Stretch); if (!_typeface.TryGetGlyphTypeface(out _glyphTypeface)) { throw new ArgumentException(); } }
private void RenderTextPath(SvgTextContentElement element, WpfTextOnPathDrawing pathDrawing, string text, Point origin, double rotate, WpfTextPlacement placement) { if (string.IsNullOrWhiteSpace(text)) { return; } double emSize = GetComputedFontSize(element); FontFamily fontFamily = GetTextFontFamily(element, emSize); FontStyle fontStyle = GetTextFontStyle(element); FontWeight fontWeight = GetTextFontWeight(element); FontStretch fontStretch = GetTextFontStretch(element); WpfTextStringFormat stringFormat = GetTextStringFormat(element); // Fix the use of Postscript fonts... WpfFontFamilyVisitor fontFamilyVisitor = _context.FontFamilyVisitor; if (!string.IsNullOrWhiteSpace(_actualFontName) && fontFamilyVisitor != null) { WpfFontFamilyInfo currentFamily = new WpfFontFamilyInfo(fontFamily, fontWeight, fontStyle, fontStretch); WpfFontFamilyInfo familyInfo = fontFamilyVisitor.Visit(_actualFontName, currentFamily, _context); if (familyInfo != null && !familyInfo.IsEmpty) { fontFamily = familyInfo.Family; fontWeight = familyInfo.Weight; fontStyle = familyInfo.Style; fontStretch = familyInfo.Stretch; } } WpfSvgPaint fillPaint = new WpfSvgPaint(_context, element, "fill"); Brush textBrush = fillPaint.GetBrush(); WpfSvgPaint strokePaint = new WpfSvgPaint(_context, element, "stroke"); Pen pen = strokePaint.GetPen(); TextDecorationCollection textDecors = GetTextDecoration(element); TextAlignment alignment = stringFormat.Alignment; pathDrawing.FontSize = emSize; pathDrawing.FontFamily = fontFamily; pathDrawing.FontWeight = fontWeight; pathDrawing.FontStretch = fontStretch; pathDrawing.Foreground = textBrush; pathDrawing.AddTextPath(text, origin); }
private void RenderTextPath(SvgTextContentElement element, WpfPathTextBuilder pathBuilder, string text, Point origin, double rotate, WpfTextPlacement placement) { if (string.IsNullOrWhiteSpace(text)) { return; } WpfSvgPaint fillPaint = new WpfSvgPaint(_context, element, "fill"); WpfSvgPaint strokePaint = new WpfSvgPaint(_context, element, "stroke"); Brush textBrush = fillPaint.GetBrush(); Pen textPen = strokePaint.GetPen(); if (textBrush == null && textPen == null) { return; } double emSize = GetComputedFontSize(element); var fontFamilyInfo = GetTextFontFamilyInfo(element); WpfTextStringFormat stringFormat = GetTextStringFormat(element); // Fix the use of Postscript fonts... WpfFontFamilyVisitor fontFamilyVisitor = _context.FontFamilyVisitor; if (!string.IsNullOrWhiteSpace(_actualFontName) && fontFamilyVisitor != null) { WpfFontFamilyInfo familyInfo = fontFamilyVisitor.Visit(_actualFontName, fontFamilyInfo, _context); if (familyInfo != null && !familyInfo.IsEmpty) { fontFamilyInfo = familyInfo; } } // Create the text builder object defined by the font family information WpfTextBuilder textBuilder = WpfTextBuilder.Create(fontFamilyInfo, this.TextCulture, emSize); textBuilder.TextDecorations = GetTextDecoration(element); textBuilder.TextAlignment = stringFormat.Alignment; // This is character-by-character placement, text-alignment will distort the view... textBuilder.TextAlignment = TextAlignment.Left; // Create the path-run information holder for this render request... WpfPathTextRun textPathRun = new WpfPathTextRun(element, textBuilder); // Finally, register the path-run with path builder... pathBuilder.AddTextRun(textPathRun, text, origin, textBrush, textPen); }
public static WpfTextBuilder Create(WpfFontFamilyInfo familyInfo, CultureInfo culture, double fontSize) { if (familyInfo == null) { return(new WpfGlyphTextBuilder(culture, fontSize)); } if (familyInfo.FontFamilyType == WpfFontFamilyType.Svg) { WpfSvgTextBuilder textBuilder = new WpfSvgTextBuilder(familyInfo.FontElement, culture, familyInfo.Name, fontSize); textBuilder.FontVariant = familyInfo.Variant; return(textBuilder); } return(new WpfGlyphTextBuilder(familyInfo, culture, fontSize)); }
public override WpfFontFamilyInfo Visit(string fontName, WpfFontFamilyInfo familyInfo, WpfDrawingContext context) { if (string.IsNullOrWhiteSpace(fontName)) { return(null); } if (fontName.StartsWith("Arial", StringComparison.OrdinalIgnoreCase) && fontName.Length > 5) { if (string.Equals(fontName, "ArialMT", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, familyInfo.Weight, familyInfo.Style, familyInfo.Stretch)); } else if (string.Equals(fontName, "Arial-BoldMT", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, FontWeights.Bold, familyInfo.Style, familyInfo.Stretch)); } else if (string.Equals(fontName, "Arial-ItalicMT", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, familyInfo.Weight, FontStyles.Italic, familyInfo.Stretch)); } else if (string.Equals(fontName, "Arial-BoldItalicMT", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, FontWeights.Bold, FontStyles.Italic, familyInfo.Stretch)); } else if (string.Equals(fontName, "Arial Unicode MS", StringComparison.OrdinalIgnoreCase)) { return(null); } return(new WpfFontFamilyInfo(_arialFamily, familyInfo.Weight, familyInfo.Style, familyInfo.Stretch)); } else if (fontName.StartsWith("Helvetica", StringComparison.OrdinalIgnoreCase)) { if (string.Equals(fontName, "Helvetica", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, familyInfo.Weight, familyInfo.Style, familyInfo.Stretch)); } else if (string.Equals(fontName, "Helvetica-Bold", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, FontWeights.Bold, familyInfo.Style, familyInfo.Stretch)); } else if (string.Equals(fontName, "Helvetica-Oblique", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, familyInfo.Weight, FontStyles.Italic, familyInfo.Stretch)); } else if (string.Equals(fontName, "Helvetica-BoldOblique", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, FontWeights.Bold, FontStyles.Italic, familyInfo.Stretch)); } return(new WpfFontFamilyInfo(_arialFamily, familyInfo.Weight, familyInfo.Style, familyInfo.Stretch)); } else if (fontName.StartsWith("TimesNewRomanPS", StringComparison.OrdinalIgnoreCase)) { if (string.Equals(fontName, "TimesNewRomanPSMT", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, familyInfo.Weight, familyInfo.Style, familyInfo.Stretch)); } else if (string.Equals(fontName, "TimesNewRomanPS-BoldMT", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, FontWeights.Bold, familyInfo.Style, familyInfo.Stretch)); } else if (string.Equals(fontName, "TimesNewRomanPS-ItalicMT", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, familyInfo.Weight, FontStyles.Italic, familyInfo.Stretch)); } else if (string.Equals(fontName, "TimesNewRomanPS-BoldItalicMT", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, FontWeights.Bold, FontStyles.Italic, familyInfo.Stretch)); } return(new WpfFontFamilyInfo(_arialFamily, familyInfo.Weight, familyInfo.Style, familyInfo.Stretch)); } else if (fontName.StartsWith("CourierNewPS", StringComparison.OrdinalIgnoreCase)) { if (string.Equals(fontName, "CourierNewPSMT", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, familyInfo.Weight, familyInfo.Style, familyInfo.Stretch)); } else if (string.Equals(fontName, "CourierNewPS-BoldMT", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, FontWeights.Bold, familyInfo.Style, familyInfo.Stretch)); } else if (string.Equals(fontName, "CourierNewPS-ItalicMT", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, familyInfo.Weight, FontStyles.Italic, familyInfo.Stretch)); } else if (string.Equals(fontName, "CourierNewPS-BoldItalicMT", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(_arialFamily, FontWeights.Bold, FontStyles.Italic, familyInfo.Stretch)); } return(new WpfFontFamilyInfo(_arialFamily, familyInfo.Weight, familyInfo.Style, familyInfo.Stretch)); } else if (fontName.Equals("MS-Gothic", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(new FontFamily("MS Gothic"), familyInfo.Weight, familyInfo.Style, familyInfo.Stretch)); //return new WpfFontFamilyInfo(_arialFamily, familyInfo.Weight, // familyInfo.Style, familyInfo.Stretch); } else if (fontName.Equals("MS-PGothic", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(new FontFamily("MS PGothic"), familyInfo.Weight, familyInfo.Style, familyInfo.Stretch)); } else if (fontName.Equals("MS Pゴシック", StringComparison.OrdinalIgnoreCase)) { return(new WpfFontFamilyInfo(new FontFamily("MS PGothic"), familyInfo.Weight, familyInfo.Style, familyInfo.Stretch)); } return(null); //return new WpfFontFamilyInfo(_arialFamily, familyInfo.Weight, // familyInfo.Style, familyInfo.Stretch); }
public override void RenderTextRun(SvgTextContentElement element, ref Point ctp, string text, double rotate, WpfTextPlacement placement) { if (string.IsNullOrWhiteSpace(text)) { return; } double emSize = GetComputedFontSize(element); var fontFamilyInfo = GetTextFontFamilyInfo(element); FontFamily fontFamily = fontFamilyInfo.Family; FontStyle fontStyle = fontFamilyInfo.Style; FontWeight fontWeight = fontFamilyInfo.Weight; FontStretch fontStretch = fontFamilyInfo.Stretch; WpfTextStringFormat stringFormat = GetTextStringFormat(element); // Fix the use of Postscript fonts... WpfFontFamilyVisitor fontFamilyVisitor = _context.FontFamilyVisitor; if (!string.IsNullOrWhiteSpace(_actualFontName) && fontFamilyVisitor != null) { //WpfFontFamilyInfo currentFamily = new WpfFontFamilyInfo(fontFamily, fontWeight, // fontStyle, fontStretch); WpfFontFamilyInfo familyInfo = fontFamilyVisitor.Visit(_actualFontName, fontFamilyInfo, _context); if (familyInfo != null && !familyInfo.IsEmpty) { fontFamily = familyInfo.Family; fontWeight = familyInfo.Weight; fontStyle = familyInfo.Style; fontStretch = familyInfo.Stretch; } } WpfSvgPaint fillPaint = new WpfSvgPaint(_context, element, "fill"); Brush textBrush = fillPaint.GetBrush(); WpfSvgPaint strokePaint = new WpfSvgPaint(_context, element, "stroke"); Pen textPen = strokePaint.GetPen(); if (textBrush == null && textPen == null) { return; } else if (textBrush == null) { // If here, then the pen is not null, and so the fill cannot be null. // We set this to transparent for stroke only text path... textBrush = Brushes.Transparent; } TextDecorationCollection textDecors = GetTextDecoration(element); if (textDecors == null) { SvgTextElement textElement = element.ParentNode as SvgTextElement; if (textElement != null) { textDecors = GetTextDecoration(textElement); } } TextAlignment alignment = stringFormat.Alignment; bool hasWordSpacing = false; string wordSpaceText = element.GetAttribute("word-spacing"); double wordSpacing = 0; if (!string.IsNullOrWhiteSpace(wordSpaceText) && double.TryParse(wordSpaceText, out wordSpacing) && !wordSpacing.Equals(0)) { hasWordSpacing = true; } bool hasLetterSpacing = false; string letterSpaceText = element.GetAttribute("letter-spacing"); double letterSpacing = 0; if (!string.IsNullOrWhiteSpace(letterSpaceText) && double.TryParse(letterSpaceText, out letterSpacing) && !letterSpacing.Equals(0)) { hasLetterSpacing = true; } bool isRotatePosOnly = false; IList <WpfTextPosition> textPositions = null; int textPosCount = 0; if ((placement != null && placement.HasPositions)) { textPositions = placement.Positions; textPosCount = textPositions.Count; isRotatePosOnly = placement.IsRotateOnly; } var typeFace = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch); if (textPositions != null && textPositions.Count != 0) { if (textPositions.Count == text.Trim().Length) //TODO: Best way to handle this... { text = text.Trim(); } } if (hasLetterSpacing || hasWordSpacing || textPositions != null) { double spacing = Convert.ToDouble(letterSpacing); int startSpaces = 0; for (int i = 0; i < text.Length; i++) { if (char.IsWhiteSpace(text[i])) { startSpaces++; } else { break; } } int j = 0; string inputText = string.Empty; for (int i = 0; i < text.Length; i++) { // Avoid rendering only spaces at the start of text run... if (i == 0 && startSpaces != 0) { inputText = text.Substring(0, startSpaces + 1); i += startSpaces; } else { inputText = new string(text[i], 1); } FormattedText formattedText = new FormattedText(inputText, _context.CultureInfo, stringFormat.Direction, typeFace, emSize, textBrush); if (this.IsMeasuring) { this.AddTextWidth(formattedText.WidthIncludingTrailingWhitespace); continue; } formattedText.Trimming = stringFormat.Trimming; formattedText.TextAlignment = stringFormat.Alignment; if (textDecors != null && textDecors.Count != 0) { formattedText.SetTextDecorations(textDecors); } WpfTextPosition?textPosition = null; if (textPositions != null && j < textPosCount) { textPosition = textPositions[j]; } //float xCorrection = 0; //if (alignment == TextAlignment.Left) // xCorrection = emSize * 1f / 6f; //else if (alignment == TextAlignment.Right) // xCorrection = -emSize * 1f / 6f; double yCorrection = formattedText.Baseline; float rotateAngle = (float)rotate; if (textPosition != null) { if (!isRotatePosOnly) { Point pt = textPosition.Value.Location; ctp.X = pt.X; ctp.Y = pt.Y; } rotateAngle = (float)textPosition.Value.Rotation; } Point textStart = ctp; RotateTransform rotateAt = null; if (!rotateAngle.Equals(0)) { rotateAt = new RotateTransform(rotateAngle, textStart.X, textStart.Y); _textContext.PushTransform(rotateAt); } Point textPoint = new Point(ctp.X, ctp.Y - yCorrection); if (textPen != null || _context.TextAsGeometry) { Geometry textGeometry = formattedText.BuildGeometry(textPoint); if (textGeometry != null && !textGeometry.IsEmpty()) { _textContext.DrawGeometry(textBrush, textPen, ExtractTextPathGeometry(textGeometry)); this.IsTextPath = true; } else { _textContext.DrawText(formattedText, textPoint); } } else { _textContext.DrawText(formattedText, textPoint); } //float bboxWidth = (float)formattedText.Width; double bboxWidth = formattedText.WidthIncludingTrailingWhitespace; if (alignment == TextAlignment.Center) { bboxWidth /= 2f; } else if (alignment == TextAlignment.Right) { bboxWidth = 0; } //ctp.X += bboxWidth + emSize / 4 + spacing; if (hasLetterSpacing) { ctp.X += bboxWidth + letterSpacing; } if (hasWordSpacing && char.IsWhiteSpace(text[i])) { if (hasLetterSpacing) { ctp.X += wordSpacing; } else { ctp.X += bboxWidth + wordSpacing; } } else { if (!hasLetterSpacing) { ctp.X += bboxWidth; } } if (rotateAt != null) { _textContext.Pop(); } j++; } } else { FormattedText formattedText = new FormattedText(text, _context.CultureInfo, stringFormat.Direction, typeFace, emSize, textBrush); if (this.IsMeasuring) { this.AddTextWidth(formattedText.WidthIncludingTrailingWhitespace); return; } if (alignment == TextAlignment.Center && this.TextWidth > 0) { alignment = TextAlignment.Left; } formattedText.TextAlignment = alignment; formattedText.Trimming = stringFormat.Trimming; if (textDecors != null && textDecors.Count != 0) { formattedText.SetTextDecorations(textDecors); } //float xCorrection = 0; //if (alignment == TextAlignment.Left) // xCorrection = emSize * 1f / 6f; //else if (alignment == TextAlignment.Right) // xCorrection = -emSize * 1f / 6f; double yCorrection = formattedText.Baseline; float rotateAngle = (float)rotate; Point textPoint = new Point(ctp.X, ctp.Y - yCorrection); RotateTransform rotateAt = null; if (!rotateAngle.Equals(0)) { rotateAt = new RotateTransform(rotateAngle, ctp.X, ctp.Y); _textContext.PushTransform(rotateAt); } if (textPen != null || _context.TextAsGeometry) { Geometry textGeometry = formattedText.BuildGeometry(textPoint); if (textGeometry != null && !textGeometry.IsEmpty()) { _textContext.DrawGeometry(textBrush, textPen, ExtractTextPathGeometry(textGeometry)); this.IsTextPath = true; } else { _textContext.DrawText(formattedText, textPoint); } } else { _textContext.DrawText(formattedText, textPoint); } //float bboxWidth = (float)formattedText.Width; double bboxWidth = formattedText.WidthIncludingTrailingWhitespace; if (alignment == TextAlignment.Center) { bboxWidth /= 2f; } else if (alignment == TextAlignment.Right) { bboxWidth = 0; } //ctp.X += bboxWidth + emSize / 4; ctp.X += bboxWidth; if (rotateAt != null) { _textContext.Pop(); } } }
public WpfFontTextBuilder(WpfFontFamilyInfo familyInfo, CultureInfo culture, double fontSize) : base(culture, familyInfo.Name, fontSize, null) { _typeface = new Typeface(familyInfo.Family, familyInfo.Style, familyInfo.Weight, familyInfo.Stretch); }
private void DrawTextRun(SvgTextContentElement element, ref Point ctp, WpfTextRun textRun, double rotate, WpfTextPlacement placement) { if (textRun == null || textRun.IsEmpty) { return; } string text = textRun.Text; double emSize = GetComputedFontSize(element); var fontFamilyInfo = GetTextFontFamilyInfo(element); FontFamily fontFamily = fontFamilyInfo.Family; FontStyle fontStyle = fontFamilyInfo.Style; FontWeight fontWeight = fontFamilyInfo.Weight; FontStretch fontStretch = fontFamilyInfo.Stretch; WpfTextStringFormat stringFormat = GetTextStringFormat(element); // Fix the use of Postscript fonts... WpfFontFamilyVisitor fontFamilyVisitor = _context.FontFamilyVisitor; if (!string.IsNullOrWhiteSpace(_actualFontName) && fontFamilyVisitor != null) { //WpfFontFamilyInfo currentFamily = new WpfFontFamilyInfo(fontFamily, fontWeight, // fontStyle, fontStretch); WpfFontFamilyInfo familyInfo = fontFamilyVisitor.Visit(_actualFontName, fontFamilyInfo, _context); if (familyInfo != null && !familyInfo.IsEmpty) { fontFamily = familyInfo.Family; fontWeight = familyInfo.Weight; fontStyle = familyInfo.Style; fontStretch = familyInfo.Stretch; } } WpfSvgPaint fillPaint = new WpfSvgPaint(_context, element, "fill"); Brush textBrush = fillPaint.GetBrush(); WpfSvgPaint strokePaint = new WpfSvgPaint(_context, element, "stroke"); Pen textPen = strokePaint.GetPen(); if (textBrush == null && textPen == null) { return; } else if (textBrush == null) { // If here, then the pen is not null, and so the fill cannot be null. // We set this to transparent for stroke only text path... textBrush = Brushes.Transparent; } TextDecorationCollection textDecors = GetTextDecoration(element); TextAlignment alignment = stringFormat.Alignment; string letterSpacing = element.GetAttribute("letter-spacing"); if (string.IsNullOrWhiteSpace(letterSpacing)) { FormattedText formattedText = new FormattedText(text, textRun.IsLatin ? _context.EnglishCultureInfo : _context.CultureInfo, stringFormat.Direction, new Typeface(fontFamily, fontStyle, fontWeight, fontStretch), emSize, textBrush); formattedText.TextAlignment = stringFormat.Alignment; formattedText.Trimming = stringFormat.Trimming; if (textDecors != null && textDecors.Count != 0) { formattedText.SetTextDecorations(textDecors); } //float xCorrection = 0; //if (alignment == TextAlignment.Left) // xCorrection = emSize * 1f / 6f; //else if (alignment == TextAlignment.Right) // xCorrection = -emSize * 1f / 6f; double yCorrection = formattedText.Baseline; Point textPoint = new Point(ctp.X, ctp.Y - yCorrection); RotateTransform rotateAt = new RotateTransform(90, ctp.X, ctp.Y); _drawContext.PushTransform(rotateAt); _drawContext.DrawText(formattedText, textPoint); //float bboxWidth = (float)formattedText.Width; double bboxWidth = formattedText.WidthIncludingTrailingWhitespace; if (alignment == TextAlignment.Center) { bboxWidth /= 2f; } else if (alignment == TextAlignment.Right) { bboxWidth = 0; } //ctp.X += bboxWidth + emSize / 4; ctp.X += bboxWidth; if (rotateAt != null) { _drawContext.Pop(); } } else { RotateTransform rotateAt = new RotateTransform(90, ctp.X, ctp.Y); _drawContext.PushTransform(rotateAt); float spacing = Convert.ToSingle(letterSpacing); for (int i = 0; i < text.Length; i++) { FormattedText formattedText = new FormattedText(new string(text[i], 1), textRun.IsLatin ? _context.EnglishCultureInfo : _context.CultureInfo, stringFormat.Direction, new Typeface(fontFamily, fontStyle, fontWeight, fontStretch), emSize, textBrush); formattedText.Trimming = stringFormat.Trimming; formattedText.TextAlignment = stringFormat.Alignment; if (textDecors != null && textDecors.Count != 0) { formattedText.SetTextDecorations(textDecors); } //float xCorrection = 0; //if (alignment == TextAlignment.Left) // xCorrection = emSize * 1f / 6f; //else if (alignment == TextAlignment.Right) // xCorrection = -emSize * 1f / 6f; double yCorrection = formattedText.Baseline; Point textPoint = new Point(ctp.X, ctp.Y - yCorrection); _drawContext.DrawText(formattedText, textPoint); //float bboxWidth = (float)formattedText.Width; double bboxWidth = formattedText.WidthIncludingTrailingWhitespace; if (alignment == TextAlignment.Center) { bboxWidth /= 2f; } else if (alignment == TextAlignment.Right) { bboxWidth = 0; } //ctp.X += bboxWidth + emSize / 4 + spacing; ctp.X += bboxWidth + spacing; } if (rotateAt != null) { _drawContext.Pop(); } } }
protected WpfFontFamilyInfo GetTextFontFamilyInfo(SvgTextContentElement element) { _actualFontName = null; string fontFamily = element.GetPropertyValue("font-family"); string[] fontNames = fontFamily.Split(new char[1] { ',' }); FontStyle fontStyle = GetTextFontStyle(element); FontWeight fontWeight = GetTextFontWeight(element); FontStretch fontStretch = GetTextFontStretch(element); var comparer = StringComparison.OrdinalIgnoreCase; var docElement = element.OwnerDocument; ISet <string> svgFontFamilies = docElement.SvgFontFamilies; IDictionary <string, string> styledFontIds = docElement.StyledFontIds; IList <string> svgFontNames = null; if (svgFontFamilies != null && svgFontFamilies.Count != 0) { svgFontNames = new List <string>(); } //var systemFontFamilies = Fonts.SystemFontFamilies; var wpfSettings = _context.Settings; var fontFamilyNames = wpfSettings.FontFamilyNames; var privateFontFamilies = wpfSettings.HasFontFamilies; FontFamily family = null; // using separate pointer to give less priority to generic font names FontFamily genericFamily = null; WpfFontFamilyType familyType = WpfFontFamilyType.None; foreach (string fn in fontNames) { try { string fontName = fn.Trim(new char[] { ' ', '\'', '"' }); if (svgFontFamilies != null && svgFontFamilies.Count != 0) { if (svgFontFamilies.Contains(fontName)) { svgFontNames.Add(fontName); continue; } if (styledFontIds.ContainsKey(fontName)) { string mappedFontName = styledFontIds[fontName]; if (svgFontFamilies.Contains(mappedFontName)) { svgFontNames.Add(mappedFontName); continue; } } } if (string.Equals(fontName, "serif", comparer)) { genericFamily = WpfDrawingSettings.GenericSerif; } else if (string.Equals(fontName, "sans-serif", comparer) || string.Equals(fontName, "sans serif", comparer)) { genericFamily = WpfDrawingSettings.GenericSansSerif; } else if (string.Equals(fontName, "monospace", comparer)) { genericFamily = WpfDrawingSettings.GenericMonospace; } else if (styledFontIds.ContainsKey(fontName)) { string mappedFontName = styledFontIds[fontName]; family = LookupFontFamily(mappedFontName, fontFamilyNames); if (family != null) { _actualFontName = mappedFontName; familyType = WpfFontFamilyType.System; } } else { // Try looking up fonts in the system font registry... family = LookupFontFamily(fontName, fontFamilyNames); if (family != null) { _actualFontName = fontName; familyType = WpfFontFamilyType.System; } // If not found, look through private fonts if available.. if (family == null && privateFontFamilies) { family = wpfSettings.LookupFontFamily(fontName); if (family != null) { _actualFontName = fontName; familyType = WpfFontFamilyType.Private; } } } if (family != null) { return(new WpfFontFamilyInfo(familyType, _actualFontName, family, fontWeight, fontStyle, fontStretch)); } } catch (Exception ex) { Trace.TraceError(ex.ToString()); } } // If set, use the SVG-Font... if (svgFontNames != null && svgFontNames.Count != 0) { FontFamily altFamily = (genericFamily != null) ? genericFamily : WpfDrawingSettings.DefaultFontFamily; IList <SvgFontElement> svgFonts = docElement.GetFonts(svgFontNames); if (svgFonts != null && svgFonts.Count != 0) { string fontVariant = element.GetPropertyValue("font-variant"); // For a single match... if (svgFonts.Count == 1) { var fontFamilyInfo = new WpfFontFamilyInfo(svgFonts[0].FontFamily, svgFonts[0], fontWeight, fontStyle, fontStretch); fontFamilyInfo.Variant = fontVariant; // For rendering that do not support the SVG Fonts... fontFamilyInfo.Family = altFamily; return(fontFamilyInfo); } // For the defined font style... if (fontStyle != FontStyles.Normal) { // Then it is either oblique or italic SvgFontElement closeFont = null; SvgFontElement closestFont = null; bool isItalic = fontStyle.Equals(FontStyles.Italic); foreach (var svgFont in svgFonts) { var fontFace = svgFont.FontFace; if (fontFace == null) { continue; } var typefaceStyle = GetTextFontStyle(fontFace.FontStyle); if (fontStyle.Equals(typefaceStyle)) { closeFont = svgFont; if (closestFont == null) { closestFont = svgFont; } var typefaceWeight = GetTextFontWeight(fontFace.FontWeight); if (fontVariant.Equals(fontFace.FontVariant, comparer)) { closestFont = svgFont; if (fontWeight.Equals(typefaceWeight)) { var fontFamilyInfo = new WpfFontFamilyInfo(svgFont.FontFamily, svgFont, fontWeight, fontStyle, fontStretch); fontFamilyInfo.Variant = fontVariant; // For rendering that do not support the SVG Fonts... fontFamilyInfo.Family = altFamily; return(fontFamilyInfo); } } } if (closeFont == null) { if (isItalic && typefaceStyle == FontStyles.Oblique) { closeFont = svgFont; } if (!isItalic && typefaceStyle == FontStyles.Italic) { closeFont = svgFont; } } } if (closestFont != null) { closeFont = closestFont; } if (closeFont != null) { var fontFamilyInfo = new WpfFontFamilyInfo(closeFont.FontFamily, closeFont, fontWeight, fontStyle, fontStretch); fontFamilyInfo.Variant = fontVariant; // For rendering that do not support the SVG Fonts... fontFamilyInfo.Family = altFamily; return(fontFamilyInfo); } } SvgFontElement variantFont = null; // For multiple matches, we will test the variants... if (!string.IsNullOrWhiteSpace(fontVariant)) { foreach (var svgFont in svgFonts) { var fontFace = svgFont.FontFace; if (fontFace == null) { continue; } if (fontVariant.Equals(fontFace.FontVariant, comparer)) { variantFont = svgFont; // Check for more perfect match... var typefaceWeight = GetTextFontWeight(fontFace.FontWeight); var typefaceStyle = GetTextFontStyle(fontFace.FontStyle); if (fontStyle.Equals(typefaceStyle) && fontWeight.Equals(typefaceWeight)) { var fontFamilyInfo = new WpfFontFamilyInfo(svgFont.FontFamily, svgFont, fontWeight, fontStyle, fontStretch); fontFamilyInfo.Variant = fontVariant; // For rendering that do not support the SVG Fonts... fontFamilyInfo.Family = altFamily; return(fontFamilyInfo); } } } //if (variantFont != null) //{ // // If there was a matching variant but either style or weight not matched... // var fontFamilyInfo = new WpfFontFamilyInfo(variantFont.FontFamily, variantFont, // fontWeight, fontStyle, fontStretch); // fontFamilyInfo.Variant = fontVariant; // // For rendering that do not support the SVG Fonts... // fontFamilyInfo.Family = altFamily; // return fontFamilyInfo; //} } // For the defined font weights... if (fontWeight != FontWeights.Normal && fontWeight != FontWeights.Regular) { int weightValue = fontWeight.ToOpenTypeWeight(); int selectedValue = int.MaxValue; SvgFontElement sameWeightFont = null; SvgFontElement closestFont = null; foreach (var svgFont in svgFonts) { var fontFace = svgFont.FontFace; if (fontFace == null) { continue; } var typefaceWeight = GetTextFontWeight(fontFace.FontWeight); if (fontWeight.Equals(typefaceWeight)) { sameWeightFont = svgFont; var typefaceStyle = GetTextFontStyle(fontFace.FontStyle); if (fontStyle.Equals(typefaceStyle)) { var fontFamilyInfo = new WpfFontFamilyInfo(svgFont.FontFamily, svgFont, fontWeight, fontStyle, fontStretch); fontFamilyInfo.Variant = fontVariant; // For rendering that do not support the SVG Fonts... fontFamilyInfo.Family = altFamily; return(fontFamilyInfo); } } int weightDiff = Math.Abs(weightValue - typefaceWeight.ToOpenTypeWeight()); if (weightDiff < selectedValue) { closestFont = svgFont; selectedValue = weightDiff; } } // If the weights matched, but not the style if (sameWeightFont != null) { var fontFamilyInfo = new WpfFontFamilyInfo(sameWeightFont.FontFamily, sameWeightFont, fontWeight, fontStyle, fontStretch); fontFamilyInfo.Variant = fontVariant; // For rendering that do not support the SVG Fonts... fontFamilyInfo.Family = altFamily; return(fontFamilyInfo); } if (closestFont != null) { var fontFamilyInfo = new WpfFontFamilyInfo(closestFont.FontFamily, closestFont, fontWeight, fontStyle, fontStretch); fontFamilyInfo.Variant = fontVariant; // For rendering that do not support the SVG Fonts... fontFamilyInfo.Family = altFamily; return(fontFamilyInfo); } } if (variantFont != null) { // If there was a matching variant but either style or weight not matched... var fontFamilyInfo = new WpfFontFamilyInfo(variantFont.FontFamily, variantFont, fontWeight, fontStyle, fontStretch); fontFamilyInfo.Variant = fontVariant; // For rendering that do not support the SVG Fonts... fontFamilyInfo.Family = altFamily; return(fontFamilyInfo); } else // If the variant is not found, return the first match... { var fontFamilyInfo = new WpfFontFamilyInfo(svgFonts[0].FontFamily, svgFonts[0], fontWeight, fontStyle, fontStretch); fontFamilyInfo.Variant = fontVariant; // For rendering that do not support the SVG Fonts... fontFamilyInfo.Family = altFamily; return(fontFamilyInfo); } //// For multiple matches, we will test the variants... //if (string.IsNullOrWhiteSpace(fontVariant)) //{ // // Not found, return the first match... // var fontFamilyInfo = new WpfFontFamilyInfo(svgFonts[0].FontFamily, svgFonts[0], // fontWeight, fontStyle, fontStretch); // fontFamilyInfo.Variant = fontVariant; // // For rendering that do not support the SVG Fonts... // fontFamilyInfo.Family = altFamily; // return fontFamilyInfo; //} } } if (genericFamily != null) { return(new WpfFontFamilyInfo(WpfFontFamilyType.Generic, _actualFontName, genericFamily, fontWeight, fontStyle, fontStretch)); } // No known font-family was found => default to "Arial" return(new WpfFontFamilyInfo(familyType, _actualFontName, WpfDrawingSettings.DefaultFontFamily, fontWeight, fontStyle, fontStretch)); }
public override void RenderSingleLineText(SvgTextContentElement element, ref Point ctp, string text, double rotate, WpfTextPlacement placement) { if (String.IsNullOrEmpty(text)) { return; } double emSize = GetComputedFontSize(element); FontFamily fontFamily = GetTextFontFamily(element, emSize); FontStyle fontStyle = GetTextFontStyle(element); FontWeight fontWeight = GetTextFontWeight(element); FontStretch fontStretch = GetTextFontStretch(element); WpfTextStringFormat stringFormat = GetTextStringFormat(element); // Fix the use of Postscript fonts... WpfFontFamilyVisitor fontFamilyVisitor = _drawContext.FontFamilyVisitor; if (!String.IsNullOrEmpty(_actualFontName) && fontFamilyVisitor != null) { WpfFontFamilyInfo currentFamily = new WpfFontFamilyInfo(fontFamily, fontWeight, fontStyle, fontStretch); WpfFontFamilyInfo familyInfo = fontFamilyVisitor.Visit(_actualFontName, currentFamily, _drawContext); if (familyInfo != null && !familyInfo.IsEmpty) { fontFamily = familyInfo.Family; fontWeight = familyInfo.Weight; fontStyle = familyInfo.Style; fontStretch = familyInfo.Stretch; } } WpfSvgPaint fillPaint = new WpfSvgPaint(_drawContext, element, "fill"); Brush textBrush = fillPaint.GetBrush(); WpfSvgPaint strokePaint = new WpfSvgPaint(_drawContext, element, "stroke"); Pen textPen = strokePaint.GetPen(); if (textBrush == null && textPen == null) { return; } else if (textBrush == null) { // If here, then the pen is not null, and so the fill cannot be null. // We set this to transparent for stroke only text path... textBrush = Brushes.Transparent; } TextDecorationCollection textDecors = GetTextDecoration(element); TextAlignment alignment = stringFormat.Alignment; bool hasWordSpacing = false; string wordSpaceText = element.GetAttribute("word-spacing"); double wordSpacing = 0; if (!String.IsNullOrEmpty(wordSpaceText) && Double.TryParse(wordSpaceText, out wordSpacing) && (float)wordSpacing != 0) { hasWordSpacing = true; } bool hasLetterSpacing = false; string letterSpaceText = element.GetAttribute("letter-spacing"); double letterSpacing = 0; if (!String.IsNullOrEmpty(letterSpaceText) && Double.TryParse(letterSpaceText, out letterSpacing) && (float)letterSpacing != 0) { hasLetterSpacing = true; } bool isRotatePosOnly = false; IList <WpfTextPosition> textPositions = null; int textPosCount = 0; if ((placement != null && placement.HasPositions)) { textPositions = placement.Positions; textPosCount = textPositions.Count; isRotatePosOnly = placement.IsRotateOnly; } if (hasLetterSpacing || hasWordSpacing || textPositions != null) { for (int i = 0; i < text.Length; i++) { FormattedText formattedText = new FormattedText(new string(text[i], 1), _drawContext.CultureInfo, stringFormat.Direction, new Typeface(fontFamily, fontStyle, fontWeight, fontStretch), emSize, textBrush); formattedText.TextAlignment = stringFormat.Alignment; formattedText.Trimming = stringFormat.Trimming; if (textDecors != null && textDecors.Count != 0) { formattedText.SetTextDecorations(textDecors); } WpfTextPosition?textPosition = null; if (textPositions != null && i < textPosCount) { textPosition = textPositions[i]; } //float xCorrection = 0; //if (alignment == TextAlignment.Left) // xCorrection = emSize * 1f / 6f; //else if (alignment == TextAlignment.Right) // xCorrection = -emSize * 1f / 6f; double yCorrection = formattedText.Baseline; float rotateAngle = (float)rotate; if (textPosition != null) { if (!isRotatePosOnly) { Point pt = textPosition.Value.Location; ctp.X = pt.X; ctp.Y = pt.Y; } rotateAngle = (float)textPosition.Value.Rotation; } Point textStart = ctp; RotateTransform rotateAt = null; if (rotateAngle != 0) { rotateAt = new RotateTransform(rotateAngle, textStart.X, textStart.Y); _textContext.PushTransform(rotateAt); } Point textPoint = new Point(textStart.X, textStart.Y - yCorrection); if (textPen != null || _drawContext.TextAsGeometry) { Geometry textGeometry = formattedText.BuildGeometry(textPoint); if (textGeometry != null && !textGeometry.IsEmpty()) { _textContext.DrawGeometry(textBrush, textPen, ExtractTextPathGeometry(textGeometry)); this.IsTextPath = true; } else { _textContext.DrawText(formattedText, textPoint); } } else { _textContext.DrawText(formattedText, textPoint); } //float bboxWidth = (float)formattedText.Width; double bboxWidth = formattedText.WidthIncludingTrailingWhitespace; if (alignment == TextAlignment.Center) { bboxWidth /= 2f; } else if (alignment == TextAlignment.Right) { bboxWidth = 0; } //ctp.X += bboxWidth + emSize / 4 + spacing; if (hasLetterSpacing) { ctp.X += bboxWidth + letterSpacing; } if (hasWordSpacing && Char.IsWhiteSpace(text[i])) { if (hasLetterSpacing) { ctp.X += wordSpacing; } else { ctp.X += bboxWidth + wordSpacing; } } else { if (!hasLetterSpacing) { ctp.X += bboxWidth; } } if (rotateAt != null) { _textContext.Pop(); } } } else { FormattedText formattedText = new FormattedText(text, _drawContext.CultureInfo, stringFormat.Direction, new Typeface(fontFamily, fontStyle, fontWeight, fontStretch), emSize, textBrush); formattedText.TextAlignment = stringFormat.Alignment; formattedText.Trimming = stringFormat.Trimming; if (textDecors != null && textDecors.Count != 0) { formattedText.SetTextDecorations(textDecors); } //float xCorrection = 0; //if (alignment == TextAlignment.Left) // xCorrection = emSize * 1f / 6f; //else if (alignment == TextAlignment.Right) // xCorrection = -emSize * 1f / 6f; double yCorrection = formattedText.Baseline; float rotateAngle = (float)rotate; Point textPoint = new Point(ctp.X, ctp.Y - yCorrection); RotateTransform rotateAt = null; if (rotateAngle != 0) { rotateAt = new RotateTransform(rotateAngle, ctp.X, ctp.Y); _textContext.PushTransform(rotateAt); } if (textPen != null || _drawContext.TextAsGeometry) { Geometry textGeometry = formattedText.BuildGeometry(textPoint); if (textGeometry != null && !textGeometry.IsEmpty()) { _textContext.DrawGeometry(textBrush, textPen, ExtractTextPathGeometry(textGeometry)); this.IsTextPath = true; } else { _textContext.DrawText(formattedText, textPoint); } } else { _textContext.DrawText(formattedText, textPoint); } //float bboxWidth = (float)formattedText.Width; double bboxWidth = formattedText.WidthIncludingTrailingWhitespace; if (alignment == TextAlignment.Center) { bboxWidth /= 2f; } else if (alignment == TextAlignment.Right) { bboxWidth = 0; } //ctp.X += bboxWidth + emSize / 4; ctp.X += bboxWidth; if (rotateAt != null) { _textContext.Pop(); } } }
private void DrawSingleLineText(SvgTextContentElement element, ref Point ctp, WpfTextRun textRun, double rotate, WpfTextPlacement placement) { if (textRun == null || textRun.IsEmpty) { return; } string text = textRun.Text; double emSize = GetComputedFontSize(element); var fontFamilyInfo = GetTextFontFamilyInfo(element); FontFamily fontFamily = fontFamilyInfo.Family; FontStyle fontStyle = fontFamilyInfo.Style; FontWeight fontWeight = fontFamilyInfo.Weight; FontStretch fontStretch = fontFamilyInfo.Stretch; WpfTextStringFormat stringFormat = GetTextStringFormat(element); // Fix the use of Postscript fonts... WpfFontFamilyVisitor fontFamilyVisitor = _context.FontFamilyVisitor; if (!string.IsNullOrWhiteSpace(_actualFontName) && fontFamilyVisitor != null) { WpfFontFamilyInfo familyInfo = fontFamilyVisitor.Visit(_actualFontName, fontFamilyInfo, _context); if (familyInfo != null && !familyInfo.IsEmpty) { fontFamily = familyInfo.Family; fontWeight = familyInfo.Weight; fontStyle = familyInfo.Style; fontStretch = familyInfo.Stretch; } } WpfSvgPaint fillPaint = new WpfSvgPaint(_context, element, "fill"); Brush textBrush = fillPaint.GetBrush(); WpfSvgPaint strokePaint = new WpfSvgPaint(_context, element, "stroke"); Pen textPen = strokePaint.GetPen(); if (textBrush == null && textPen == null) { return; } if (textBrush == null) { // If here, then the pen is not null, and so the fill cannot be null. // We set this to transparent for stroke only text path... textBrush = Brushes.Transparent; } TextDecorationCollection textDecors = GetTextDecoration(element); TextAlignment alignment = stringFormat.Alignment; var typeface = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch); string letterSpacing = element.GetAttribute("letter-spacing"); if (string.IsNullOrWhiteSpace(letterSpacing)) { #if DOTNET40 || DOTNET45 || DOTNET46 FormattedText formattedText = new FormattedText(text, textRun.IsLatin ? _context.EnglishCultureInfo : _context.CultureInfo, stringFormat.Direction, typeface, emSize, textBrush); #else FormattedText formattedText = new FormattedText(text, textRun.IsLatin ? _context.EnglishCultureInfo : _context.CultureInfo, stringFormat.Direction, typeface, emSize, textBrush, _context.PixelsPerDip); #endif if (this.IsMeasuring) { this.AddTextWidth(ctp, formattedText.WidthIncludingTrailingWhitespace); return; } // formattedText.TextAlignment = stringFormat.Alignment; formattedText.TextAlignment = TextAlignment.Left; formattedText.Trimming = stringFormat.Trimming; if (textDecors != null && textDecors.Count != 0) { formattedText.SetTextDecorations(textDecors); } //float xCorrection = 0; //if (alignment == TextAlignment.Left) // xCorrection = emSize * 1f / 6f; //else if (alignment == TextAlignment.Right) // xCorrection = -emSize * 1f / 6f; double yCorrection = formattedText.Baseline; //float yCorrection = 0; if (textRun.IsLatin && textRun.VerticalOrientation == -1) { yCorrection = yCorrection + formattedText.OverhangAfter * 1.5; } Point textPoint = new Point(ctp.X, ctp.Y - yCorrection); var textSize = this.MeasureString(text, emSize, typeface); //float bboxWidth1 = (float)formattedText.Width; double bboxWidth = formattedText.WidthIncludingTrailingWhitespace; TranslateTransform translateAt = null; RotateTransform rotateAt = new RotateTransform(90, ctp.X, ctp.Y); if (alignment == TextAlignment.Center) { // translateAt = new TranslateTransform(0, -(textSize.Height - textSize.Width/2) / 2); translateAt = new TranslateTransform(0, -(textSize.Height - yCorrection / 2) / 2); } else if (alignment == TextAlignment.Right) { // translateAt = new TranslateTransform(0, -(textSize.Height + textSize.Width / 2)); translateAt = new TranslateTransform(0, -(textSize.Height + yCorrection / 2)); } if (translateAt != null) { TransformGroup group = new TransformGroup(); group.Children.Add(rotateAt); group.Children.Add(translateAt); _drawContext.PushTransform(group); } else { _drawContext.PushTransform(rotateAt); } _drawContext.DrawText(formattedText, textPoint); if (alignment == TextAlignment.Center) { bboxWidth /= 2f; } else if (alignment == TextAlignment.Right) { bboxWidth = 0; } //ctp.X += bboxWidth + emSize / 4; ctp.X += bboxWidth; //if (translateAt != null) //{ // _textContext.Pop(); //} if (rotateAt != null) { _drawContext.Pop(); } } else { RotateTransform rotateAt = new RotateTransform(90, ctp.X, ctp.Y); _drawContext.PushTransform(rotateAt); double spacing = Convert.ToDouble(letterSpacing); for (int i = 0; i < text.Length; i++) { #if DOTNET40 || DOTNET45 || DOTNET46 FormattedText formattedText = new FormattedText(new string(text[i], 1), textRun.IsLatin ? _context.EnglishCultureInfo : _context.CultureInfo, stringFormat.Direction, typeface, emSize, textBrush); #else FormattedText formattedText = new FormattedText(new string(text[i], 1), textRun.IsLatin ? _context.EnglishCultureInfo : _context.CultureInfo, stringFormat.Direction, typeface, emSize, textBrush, _context.PixelsPerDip); #endif if (this.IsMeasuring) { this.AddTextWidth(ctp, formattedText.WidthIncludingTrailingWhitespace); continue; } formattedText.TextAlignment = stringFormat.Alignment; formattedText.Trimming = stringFormat.Trimming; if (textDecors != null && textDecors.Count != 0) { formattedText.SetTextDecorations(textDecors); } //float xCorrection = 0; //if (alignment == TextAlignment.Left) // xCorrection = emSize * 1f / 6f; //else if (alignment == TextAlignment.Right) // xCorrection = -emSize * 1f / 6f; double yCorrection = formattedText.Baseline; Point textPoint = new Point(ctp.X, ctp.Y - yCorrection); _drawContext.DrawText(formattedText, textPoint); //float bboxWidth = (float)formattedText.Width; double bboxWidth = formattedText.WidthIncludingTrailingWhitespace; if (alignment == TextAlignment.Center) { bboxWidth /= 2f; } else if (alignment == TextAlignment.Right) { bboxWidth = 0; } //ctp.X += bboxWidth + emSize / 4 + spacing; ctp.X += bboxWidth + spacing; } if (rotateAt != null) { _drawContext.Pop(); } } }
private void RenderTextRun(WpfTextTuple textInfo, ref Point ctp, string text, double rotate, WpfTextPlacement placement) { if (string.IsNullOrWhiteSpace(text)) { return; } WpfFontFamilyInfo familyInfo = textInfo.Item1; double emSize = textInfo.Item2; WpfTextStringFormat stringFormat = textInfo.Item3; SvgTextContentElement element = textInfo.Item4; FontFamily fontFamily = familyInfo.Family; FontWeight fontWeight = familyInfo.Weight; FontStyle fontStyle = familyInfo.Style; FontStretch fontStretch = familyInfo.Stretch; WpfSvgPaint fillPaint = new WpfSvgPaint(_context, element, "fill"); Brush textBrush = fillPaint.GetBrush(); WpfSvgPaint strokePaint = new WpfSvgPaint(_context, element, "stroke"); Pen textPen = strokePaint.GetPen(); if (textBrush == null && textPen == null) { return; } if (textBrush == null) { // If here, then the pen is not null, and so the fill cannot be null. // We set this to transparent for stroke only text path... textBrush = Brushes.Transparent; } if (textPen != null) { textPen.LineJoin = PenLineJoin.Miter; // Better for text rendering textPen.MiterLimit = 1; } TextDecorationCollection textDecors = GetTextDecoration(element); if (textDecors == null) { SvgTextElement textElement = element.ParentNode as SvgTextElement; if (textElement != null) { textDecors = GetTextDecoration(textElement); } } TextAlignment alignment = stringFormat.Alignment; bool hasWordSpacing = false; string wordSpaceText = element.GetAttribute("word-spacing"); double wordSpacing = 0; if (!string.IsNullOrWhiteSpace(wordSpaceText) && double.TryParse(wordSpaceText, out wordSpacing) && !wordSpacing.Equals(0)) { hasWordSpacing = true; } bool hasLetterSpacing = false; string letterSpaceText = element.GetAttribute("letter-spacing"); double letterSpacing = 0; if (!string.IsNullOrWhiteSpace(letterSpaceText) && double.TryParse(letterSpaceText, out letterSpacing) && !letterSpacing.Equals(0)) { hasLetterSpacing = true; } bool isRotatePosOnly = false; IList <WpfTextPosition> textPositions = null; int textPosCount = 0; if ((placement != null && placement.HasPositions)) { textPositions = placement.Positions; textPosCount = textPositions.Count; isRotatePosOnly = placement.IsRotateOnly; } WpfTextBuilder textBuilder = WpfTextBuilder.Create(familyInfo, this.TextCulture, emSize); this.IsTextPath = true; if (textPositions != null && textPositions.Count != 0) { if (textPositions.Count == text.Trim().Length) //TODO: Best way to handle this... { text = text.Trim(); } } if (hasLetterSpacing || hasWordSpacing || textPositions != null) { double spacing = Convert.ToDouble(letterSpacing); int startSpaces = 0; for (int i = 0; i < text.Length; i++) { if (char.IsWhiteSpace(text[i])) { startSpaces++; } else { break; } } int j = 0; string inputText = string.Empty; for (int i = 0; i < text.Length; i++) { // Avoid rendering only spaces at the start of text run... if (i == 0 && startSpaces != 0) { inputText = text.Substring(0, startSpaces + 1); i += startSpaces; } else { inputText = new string(text[i], 1); } if (this.IsMeasuring) { var textSize = textBuilder.MeasureText(element, inputText); this.AddTextWidth(ctp, textSize.Width); continue; } textBuilder.Trimming = stringFormat.Trimming; textBuilder.TextAlignment = stringFormat.Alignment; if (textDecors != null && textDecors.Count != 0) { textBuilder.SetTextDecorations(textDecors); } WpfTextPosition?textPosition = null; if (textPositions != null && j < textPosCount) { textPosition = textPositions[j]; } //float xCorrection = 0; //if (alignment == TextAlignment.Left) // xCorrection = emSize * 1f / 6f; //else if (alignment == TextAlignment.Right) // xCorrection = -emSize * 1f / 6f; double yCorrection = textBuilder.Baseline; float rotateAngle = (float)rotate; if (textPosition != null) { if (!isRotatePosOnly) { Point pt = textPosition.Value.Location; ctp.X = pt.X; ctp.Y = pt.Y; } rotateAngle = (float)textPosition.Value.Rotation; } Point textStart = ctp; RotateTransform rotateAt = null; if (!rotateAngle.Equals(0)) { rotateAt = new RotateTransform(rotateAngle, textStart.X, textStart.Y); _drawContext.PushTransform(rotateAt); } Point textPoint = new Point(ctp.X, ctp.Y - yCorrection); Geometry textGeometry = textBuilder.Build(element, inputText, textPoint.X, textPoint.Y); if (textGeometry != null && !textGeometry.IsEmpty()) { _drawContext.DrawGeometry(textBrush, textPen, ExtractTextPathGeometry(textGeometry)); this.IsTextPath = true; } //float bboxWidth = (float)formattedText.Width; double bboxWidth = textGeometry.Bounds.Width; if (alignment == TextAlignment.Center) { bboxWidth /= 2f; } else if (alignment == TextAlignment.Right) { bboxWidth = 0; } //ctp.X += bboxWidth + emSize / 4 + spacing; if (hasLetterSpacing) { ctp.X += bboxWidth + letterSpacing; } if (hasWordSpacing && char.IsWhiteSpace(text[i])) { if (hasLetterSpacing) { ctp.X += wordSpacing; } else { ctp.X += bboxWidth + wordSpacing; } } else { if (!hasLetterSpacing) { ctp.X += bboxWidth; } } if (rotateAt != null) { _drawContext.Pop(); } j++; } } else { if (this.IsMeasuring) { var textSize = textBuilder.MeasureText(element, text); this.AddTextWidth(ctp, textSize.Width); return; } var textContext = this.TextContext; if (textContext != null && textContext.IsPositionChanged(element) == false) { if (alignment == TextAlignment.Center && this.TextWidth > 0) { alignment = TextAlignment.Left; } } textBuilder.TextAlignment = alignment; textBuilder.Trimming = stringFormat.Trimming; if (textDecors != null && textDecors.Count != 0) { textBuilder.SetTextDecorations(textDecors); } //float xCorrection = 0; //if (alignment == TextAlignment.Left) // xCorrection = emSize * 1f / 6f; //else if (alignment == TextAlignment.Right) // xCorrection = -emSize * 1f / 6f; double yCorrection = textBuilder.Baseline; float rotateAngle = (float)rotate; Point textPoint = new Point(ctp.X, ctp.Y - yCorrection); RotateTransform rotateAt = null; if (!rotateAngle.Equals(0)) { rotateAt = new RotateTransform(rotateAngle, ctp.X, ctp.Y); _drawContext.PushTransform(rotateAt); } Geometry textGeometry = textBuilder.Build(element, text, textPoint.X, textPoint.Y); if (textGeometry != null && !textGeometry.IsEmpty()) { _drawContext.DrawGeometry(textBrush, textPen, ExtractTextPathGeometry(textGeometry)); } //float bboxWidth = (float)formattedText.Width; // double bboxWidth = textGeometry.Bounds.Width; double bboxWidth = textBuilder.Width; if (alignment == TextAlignment.Center) { bboxWidth /= 2f; } else if (alignment == TextAlignment.Right) { bboxWidth = 0; } //ctp.X += bboxWidth + emSize / 4; ctp.X += bboxWidth; if (rotateAt != null) { _drawContext.Pop(); } } }
public override void RenderText(SvgTextContentElement element, ref Point ctp, string text, double rotate, WpfTextPlacement placement) { if (string.IsNullOrWhiteSpace(text)) { return; } double emSize = GetComputedFontSize(element); var fontFamilyInfo = GetTextFontFamilyInfo(element); WpfTextStringFormat stringFormat = GetTextStringFormat(element); if (fontFamilyInfo.FontFamilyType == WpfFontFamilyType.Svg || fontFamilyInfo.FontFamilyType == WpfFontFamilyType.Private) { WpfTextTuple textInfo = new WpfTextTuple(fontFamilyInfo, emSize, stringFormat, element); this.RenderText(textInfo, ref ctp, text, rotate, placement); return; } FontFamily fontFamily = fontFamilyInfo.Family; FontStyle fontStyle = fontFamilyInfo.Style; FontWeight fontWeight = fontFamilyInfo.Weight; FontStretch fontStretch = fontFamilyInfo.Stretch; // Fix the use of Postscript fonts... WpfFontFamilyVisitor fontFamilyVisitor = _context.FontFamilyVisitor; if (!string.IsNullOrWhiteSpace(_actualFontName) && fontFamilyVisitor != null) { WpfFontFamilyInfo familyInfo = fontFamilyVisitor.Visit(_actualFontName, fontFamilyInfo, _context); if (familyInfo != null && !familyInfo.IsEmpty) { fontFamily = familyInfo.Family; fontWeight = familyInfo.Weight; fontStyle = familyInfo.Style; fontStretch = familyInfo.Stretch; } } WpfSvgPaint fillPaint = new WpfSvgPaint(_context, element, "fill"); Brush textBrush = fillPaint.GetBrush(); WpfSvgPaint strokePaint = new WpfSvgPaint(_context, element, "stroke"); Pen textPen = strokePaint.GetPen(); if (textBrush == null && textPen == null) { return; } bool isForcedPathMode = false; if (textBrush == null) { // If here, then the pen is not null, and so the fill cannot be null. // We set this to transparent for stroke only text path... textBrush = Brushes.Transparent; } else { // WPF gradient fill does not work well on text, use geometry to render it isForcedPathMode = (fillPaint.FillType == WpfFillType.Gradient); } if (textPen != null) { textPen.LineJoin = PenLineJoin.Round; // Better for text rendering isForcedPathMode = true; } TextDecorationCollection textDecors = GetTextDecoration(element); TextAlignment alignment = stringFormat.Alignment; bool hasWordSpacing = false; string wordSpaceText = element.GetAttribute("word-spacing"); double wordSpacing = 0; if (!string.IsNullOrWhiteSpace(wordSpaceText) && double.TryParse(wordSpaceText, out wordSpacing) && !wordSpacing.Equals(0)) { hasWordSpacing = true; } bool hasLetterSpacing = false; string letterSpaceText = element.GetAttribute("letter-spacing"); double letterSpacing = 0; if (!string.IsNullOrWhiteSpace(letterSpaceText) && double.TryParse(letterSpaceText, out letterSpacing) && !letterSpacing.Equals(0)) { hasLetterSpacing = true; } bool isRotatePosOnly = false; IList <WpfTextPosition> textPositions = null; int textPosCount = 0; if ((placement != null && placement.HasPositions)) { textPositions = placement.Positions; textPosCount = textPositions.Count; isRotatePosOnly = placement.IsRotateOnly; } var typeFace = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch); bool isRightToLeft = false; var xmlLang = _textElement.XmlLang; if (!string.IsNullOrWhiteSpace(xmlLang)) { if (string.Equals(xmlLang, "ar", StringComparison.OrdinalIgnoreCase) || // Arabic language string.Equals(xmlLang, "he", StringComparison.OrdinalIgnoreCase)) // Hebrew language { isRightToLeft = true; } } if (hasLetterSpacing || hasWordSpacing || textPositions != null) { for (int i = 0; i < text.Length; i++) { var nextText = new string(text[i], 1); FormattedText formattedText = new FormattedText(nextText, _context.CultureInfo, stringFormat.Direction, typeFace, emSize, textBrush); // formattedText.FlowDirection = isRightToLeft ? FlowDirection.RightToLeft : FlowDirection.LeftToRight; formattedText.TextAlignment = stringFormat.Alignment; formattedText.Trimming = stringFormat.Trimming; if (textDecors != null && textDecors.Count != 0) { formattedText.SetTextDecorations(textDecors); } WpfTextPosition?textPosition = null; if (textPositions != null && i < textPosCount) { textPosition = textPositions[i]; } //float xCorrection = 0; //if (alignment == TextAlignment.Left) // xCorrection = emSize * 1f / 6f; //else if (alignment == TextAlignment.Right) // xCorrection = -emSize * 1f / 6f; double yCorrection = formattedText.Baseline; float rotateAngle = (float)rotate; if (textPosition != null) { if (!isRotatePosOnly) { Point pt = textPosition.Value.Location; ctp.X = pt.X; ctp.Y = pt.Y; } rotateAngle = (float)textPosition.Value.Rotation; } Point textStart = ctp; RotateTransform rotateAt = null; if (!rotateAngle.Equals(0)) { rotateAt = new RotateTransform(rotateAngle, textStart.X, textStart.Y); _drawContext.PushTransform(rotateAt); } Point textPoint = new Point(textStart.X, textStart.Y - yCorrection); if (_context.TextAsGeometry || isForcedPathMode) { Geometry textGeometry = formattedText.BuildGeometry(textPoint); if (textGeometry != null && !textGeometry.IsEmpty()) { _drawContext.DrawGeometry(textBrush, textPen, ExtractTextPathGeometry(textGeometry)); this.IsTextPath = true; } else { _drawContext.DrawText(formattedText, textPoint); } } else { _drawContext.DrawText(formattedText, textPoint); } //float bboxWidth = (float)formattedText.Width; double bboxWidth = formattedText.WidthIncludingTrailingWhitespace; if (alignment == TextAlignment.Center) { bboxWidth /= 2f; } else if (alignment == TextAlignment.Right) { bboxWidth = 0; } //ctp.X += bboxWidth + emSize / 4 + spacing; if (hasLetterSpacing) { ctp.X += bboxWidth + letterSpacing; } if (hasWordSpacing && char.IsWhiteSpace(text[i])) { if (hasLetterSpacing) { ctp.X += wordSpacing; } else { ctp.X += bboxWidth + wordSpacing; } } else { if (!hasLetterSpacing) { ctp.X += bboxWidth; } } if (rotateAt != null) { _drawContext.Pop(); } } } else { FormattedText formattedText = new FormattedText(text, _context.CultureInfo, stringFormat.Direction, typeFace, emSize, textBrush); formattedText.TextAlignment = stringFormat.Alignment; formattedText.Trimming = stringFormat.Trimming; // formattedText.FlowDirection = isRightToLeft ? FlowDirection.RightToLeft : FlowDirection.LeftToRight; if (textDecors != null && textDecors.Count != 0) { formattedText.SetTextDecorations(textDecors); } //float xCorrection = 0; //if (alignment == TextAlignment.Left) // xCorrection = emSize * 1f / 6f; //else if (alignment == TextAlignment.Right) // xCorrection = -emSize * 1f / 6f; double yCorrection = formattedText.Baseline; float rotateAngle = (float)rotate; Point textPoint = new Point(ctp.X, ctp.Y - yCorrection); RotateTransform rotateAt = null; if (!rotateAngle.Equals(0)) { rotateAt = new RotateTransform(rotateAngle, ctp.X, ctp.Y); _drawContext.PushTransform(rotateAt); } if (_context.TextAsGeometry || isForcedPathMode) { Geometry textGeometry = formattedText.BuildGeometry(textPoint); if (textGeometry != null && !textGeometry.IsEmpty()) { _drawContext.DrawGeometry(textBrush, textPen, ExtractTextPathGeometry(textGeometry)); this.IsTextPath = true; } else { _drawContext.DrawText(formattedText, textPoint); } } else { _drawContext.DrawText(formattedText, textPoint); } //float bboxWidth = (float)formattedText.Width; double bboxWidth = formattedText.WidthIncludingTrailingWhitespace; if (alignment == TextAlignment.Center) { bboxWidth /= 2f; } else if (alignment == TextAlignment.Right) { bboxWidth = 0; } //ctp.X += bboxWidth + emSize / 4; ctp.X += bboxWidth; if (rotateAt != null) { _drawContext.Pop(); } } }
protected WpfFontFamilyInfo GetTextFontFamilyInfo(SvgTextContentElement element) { _actualFontName = null; string fontFamily = element.GetPropertyValue("font-family"); string[] fontNames = fontNames = fontFamily.Split(new char[1] { ',' }); FontStyle fontStyle = GetTextFontStyle(element); FontWeight fontWeight = GetTextFontWeight(element); FontStretch fontStretch = GetTextFontStretch(element); var comparer = StringComparison.OrdinalIgnoreCase; var docElement = element.OwnerDocument; ISet <string> svgFontFamilies = docElement.SvgFontFamilies; IDictionary <string, string> styledFontIds = docElement.StyledFontIds; IList <string> svgFontNames = null; if (svgFontFamilies != null && svgFontFamilies.Count != 0) { svgFontNames = new List <string>(); } var systemFontFamilies = Fonts.SystemFontFamilies; FontFamily family = null; WpfFontFamilyType familyType = WpfFontFamilyType.None; foreach (string fn in fontNames) { try { string fontName = fn.Trim(new char[] { ' ', '\'', '"' }); if (svgFontFamilies != null && svgFontFamilies.Count != 0) { if (svgFontFamilies.Contains(fontName)) { svgFontNames.Add(fontName); continue; } else if (styledFontIds.ContainsKey(fontName)) { string mappedFontName = styledFontIds[fontName]; if (svgFontFamilies.Contains(mappedFontName)) { svgFontNames.Add(mappedFontName); continue; } } } if (string.Equals(fontName, "serif", comparer)) { family = WpfDrawingSettings.GenericSerif; familyType = WpfFontFamilyType.Generic; } else if (string.Equals(fontName, "sans-serif", comparer)) { family = WpfDrawingSettings.GenericSansSerif; familyType = WpfFontFamilyType.Generic; } else if (string.Equals(fontName, "monospace", comparer)) { family = WpfDrawingSettings.GenericMonospace; familyType = WpfFontFamilyType.Generic; } else if (styledFontIds.ContainsKey(fontName)) { string mappedFontName = styledFontIds[fontName]; var funcFamily = new Func <FontFamily, bool>(ff => string.Equals(ff.Source, mappedFontName, comparer)); family = systemFontFamilies.FirstOrDefault(funcFamily); if (family != null) { _actualFontName = mappedFontName; familyType = WpfFontFamilyType.System; } } else { string normalizedFontName; var funcFamily = new Func <FontFamily, bool>(ff => string.Equals(ff.Source, fontName, comparer)); family = systemFontFamilies.FirstOrDefault(funcFamily); if (family != null) { _actualFontName = fontName; familyType = WpfFontFamilyType.System; } else if (fontName.IndexOf('-') > 0) { normalizedFontName = fontName.Replace("-", " "); funcFamily = new Func <FontFamily, bool>(ff => string.Equals(ff.Source, normalizedFontName, comparer)); family = systemFontFamilies.FirstOrDefault(funcFamily); if (family != null) { _actualFontName = normalizedFontName; familyType = WpfFontFamilyType.System; } } else if (SplitByCaps(fontName, out normalizedFontName)) { funcFamily = new Func <FontFamily, bool>(ff => string.Equals(ff.Source, normalizedFontName, comparer)); family = systemFontFamilies.FirstOrDefault(funcFamily); if (family != null) { _actualFontName = normalizedFontName; familyType = WpfFontFamilyType.System; } } } if (family != null) { return(new WpfFontFamilyInfo(familyType, _actualFontName, family, fontWeight, fontStyle, fontStretch)); } } catch (Exception ex) { Trace.TraceError(ex.ToString()); } } // If set, use the SVG-Font... if (svgFontNames != null && svgFontNames.Count != 0) { IList <SvgFontElement> svgFonts = docElement.GetFonts(svgFontNames); if (svgFonts != null && svgFonts.Count != 0) { string fontVariant = element.GetPropertyValue("font-variant"); // For a single match... if (svgFonts.Count == 1) { var fontFamilyInfo = new WpfFontFamilyInfo(svgFonts[0].FontFamily, svgFonts[0], fontWeight, fontStyle, fontStretch); fontFamilyInfo.Variant = fontVariant; return(fontFamilyInfo); } // For multiple matches, we will test the variants... if (string.IsNullOrWhiteSpace(fontVariant)) { // Not found, return the first match... var fontFamilyInfo = new WpfFontFamilyInfo(svgFonts[0].FontFamily, svgFonts[0], fontWeight, fontStyle, fontStretch); fontFamilyInfo.Variant = fontVariant; return(fontFamilyInfo); } foreach (var svgFont in svgFonts) { var fontFace = svgFont.FontFace; if (fontFace == null) { continue; } if (fontVariant.Equals(fontFace.FontVariant, comparer)) { var fontFamilyInfo = new WpfFontFamilyInfo(svgFont.FontFamily, svgFont, fontWeight, fontStyle, fontStretch); fontFamilyInfo.Variant = fontVariant; return(fontFamilyInfo); } } // If the variant is not found, return the first match... { var fontFamilyInfo = new WpfFontFamilyInfo(svgFonts[0].FontFamily, svgFonts[0], fontWeight, fontStyle, fontStretch); fontFamilyInfo.Variant = fontVariant; return(fontFamilyInfo); } } } // No known font-family was found => default to "Arial Unicode MS" return(new WpfFontFamilyInfo(familyType, _actualFontName, WpfDrawingSettings.DefaultFontFamily, fontWeight, fontStyle, fontStretch)); }