private void RenderTextPath(SvgTextPathElement textPath, ref Point ctp, double rotate, WpfTextPlacement placement) { if (textPath.ChildNodes == null || textPath.ChildNodes.Count == 0) { return; } SvgElement targetPath = textPath.ReferencedElement as SvgElement; if (targetPath == null) { return; } PathGeometry pathGeometry = WpfRendering.CreateGeometry(targetPath, true) as PathGeometry; if (pathGeometry == null) { return; } this.IsTextPath = true; WpfTextOnPathDrawing pathDrawing = new WpfTextOnPathDrawing(); pathDrawing.BeginTextPath(); XmlNodeType nodeType = XmlNodeType.None; foreach (XmlNode child in textPath.ChildNodes) { nodeType = child.NodeType; if (nodeType == XmlNodeType.Text) { RenderTextPath(textPath, pathDrawing, GetText(textPath, child), new Point(ctp.X, ctp.Y), rotate, placement); } else if (nodeType == XmlNodeType.Element) { string nodeName = child.Name; if (String.Equals(nodeName, "tref")) { RenderTRefPath((SvgTRefElement)child, pathDrawing, ref ctp); } else if (String.Equals(nodeName, "tspan")) { RenderTSpanPath((SvgTSpanElement)child, pathDrawing, ref ctp); } } } WpfTextStringFormat stringFormat = GetTextStringFormat(_textElement); ISvgAnimatedLength pathOffset = textPath.StartOffset; SvgTextPathMethod pathMethod = (SvgTextPathMethod)textPath.Method.BaseVal; SvgTextPathSpacing pathSpacing = (SvgTextPathSpacing)textPath.Spacing.BaseVal; pathDrawing.DrawTextPath(_textContext, pathGeometry, pathOffset, stringFormat.Alignment, pathMethod, pathSpacing); pathDrawing.EndTextPath(); }
public override void RenderText(SvgTextContentElement element, ref Point ctp, string text, double rotate, WpfTextPlacement placement) { this.IsTextPath = true; this.RenderTextPath((SvgTextPathElement)element, ref ctp, rotate, placement); }
private void RenderTSpanPath(SvgTSpanElement element, WpfPathTextBuilder pathBuilder, ref Point ctp) { WpfTextPlacement placement = WpfTextPlacement.Create(element, ctp, true); ctp = placement.Location; double rotate = placement.Rotation; if (!placement.HasPositions) { placement = null; // Render it useless. } string sBaselineShift = element.GetPropertyValue("baseline-shift").Trim(); double shiftBy = 0; var comparer = StringComparison.OrdinalIgnoreCase; if (sBaselineShift.Length > 0) { SvgTextBaseElement textElement = (SvgTextBaseElement)element.SelectSingleNode("ancestor::svg:text", element.OwnerDocument.NamespaceManager); double textFontSize = GetComputedFontSize(textElement); if (sBaselineShift.EndsWith("%", comparer)) { shiftBy = SvgNumber.ParseNumber(sBaselineShift.Substring(0, sBaselineShift.Length - 1)) / 100f * textFontSize; } else if (string.Equals(sBaselineShift, "sub", comparer)) { shiftBy = -0.6F * textFontSize; } else if (string.Equals(sBaselineShift, "super", comparer)) { shiftBy = 0.6F * textFontSize; } else if (string.Equals(sBaselineShift, "baseline", comparer)) { shiftBy = 0; } else { shiftBy = SvgNumber.ParseNumber(sBaselineShift); } } foreach (XmlNode child in element.ChildNodes) { if (child.NodeType == XmlNodeType.Text) { ctp.Y -= shiftBy; RenderTextPath(element, pathBuilder, GetText(element, child), new Point(ctp.X, ctp.Y), rotate, placement); ctp.Y += shiftBy; } } }
private void RenderTSpanPath(SvgTSpanElement element, WpfTextOnPathDrawing pathDrawing, ref Point ctp) { WpfTextPlacement placement = GetCurrentTextPosition(element, ctp); ctp = placement.Location; double rotate = placement.Rotation; if (!placement.HasPositions) { placement = null; // Render it useless. } string sBaselineShift = element.GetPropertyValue("baseline-shift").Trim(); double shiftBy = 0; if (sBaselineShift.Length > 0) { SvgTextElement textElement = (SvgTextElement)element.SelectSingleNode("ancestor::svg:text", element.OwnerDocument.NamespaceManager); double textFontSize = GetComputedFontSize(textElement); if (sBaselineShift.EndsWith("%")) { shiftBy = SvgNumber.ParseNumber(sBaselineShift.Substring(0, sBaselineShift.Length - 1)) / 100f * textFontSize; } else if (sBaselineShift == "sub") { shiftBy = -0.6F * textFontSize; } else if (sBaselineShift == "super") { shiftBy = 0.6F * textFontSize; } else if (sBaselineShift == "baseline") { shiftBy = 0; } else { shiftBy = SvgNumber.ParseNumber(sBaselineShift); } } foreach (XmlNode child in element.ChildNodes) { if (child.NodeType == XmlNodeType.Text) { ctp.Y -= shiftBy; RenderTextPath(element, pathDrawing, GetText(element, child), new Point(ctp.X, ctp.Y), rotate, placement); ctp.Y += shiftBy; } } }
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); }
private void RenderTRefPath(SvgTRefElement element, WpfPathTextBuilder pathBuilder, ref Point ctp) { WpfTextPlacement placement = WpfTextPlacement.Create(element, ctp, true); ctp = placement.Location; double rotate = placement.Rotation; if (!placement.HasPositions) { placement = null; // Render it useless. } this.RenderTextPath(element, pathBuilder, GetText(element), new Point(ctp.X, ctp.Y), rotate, placement); }
private void RenderTRefPath(SvgTRefElement element, WpfTextOnPathDrawing pathDrawing, ref Point ctp) { WpfTextPlacement placement = GetCurrentTextPosition(element, ctp); ctp = placement.Location; double rotate = placement.Rotation; if (!placement.HasPositions) { placement = null; // Render it useless. } this.RenderTextPath(element, pathDrawing, GetTRefText(element), new Point(ctp.X, ctp.Y), rotate, placement); }
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(); } } }
public override void RenderText(SvgTextContentElement element, ref Point ctp, string text, double rotate, WpfTextPlacement placement) { if (string.IsNullOrWhiteSpace(text)) { return; } int vertOrientation = -1; int horzOrientation = -1; string orientationText = element.GetPropertyValue("glyph-orientation-vertical"); if (!string.IsNullOrWhiteSpace(orientationText)) { double orientationValue = 0; if (double.TryParse(orientationText, out orientationValue)) { vertOrientation = (int)orientationValue; } } orientationText = element.GetPropertyValue("glyph-orientation-horizontal"); if (!string.IsNullOrWhiteSpace(orientationText)) { double orientationValue = 0; if (double.TryParse(orientationText, out orientationValue)) { horzOrientation = (int)orientationValue; } } Point startPoint = ctp; IList <WpfTextRun> textRunList = WpfTextRun.BreakWords(text, vertOrientation, horzOrientation); for (int tr = 0; tr < textRunList.Count; tr++) { // For unknown reasons, FormattedText will split a text like "-70%" into two parts "-" // and "70%". We provide a shift to account for the split... double baselineShiftX = 0; double baselineShiftY = 0; WpfTextRun textRun = textRunList[tr]; DrawingGroup verticalGroup = new DrawingGroup(); DrawingContext verticalContext = verticalGroup.Open(); DrawingContext currentContext = _drawContext; _drawContext = verticalContext; this.DrawSingleLineText(element, ref ctp, textRun, rotate, placement); verticalContext.Close(); _drawContext = currentContext; if (verticalGroup.Children.Count == 1) { DrawingGroup textGroup = verticalGroup.Children[0] as DrawingGroup; if (textGroup != null) { verticalGroup = textGroup; } } string runText = textRun.Text; int charCount = runText.Length; double totalHeight = 0; DrawingCollection drawings = verticalGroup.Children; int itemCount = drawings != null ? drawings.Count : 0; for (int i = 0; i < itemCount; i++) { Drawing textDrawing = drawings[i]; DrawingGroup textGroup = textDrawing as DrawingGroup; if (vertOrientation == -1) { if (textGroup != null) { for (int j = 0; j < textGroup.Children.Count; j++) { GlyphRunDrawing glyphDrawing = textGroup.Children[j] as GlyphRunDrawing; if (glyphDrawing != null) { if (textRun.IsLatin) { GlyphRun glyphRun = glyphDrawing.GlyphRun; IList <ushort> glyphIndices = glyphRun.GlyphIndices; IDictionary <ushort, double> allGlyphWeights = glyphRun.GlyphTypeface.AdvanceWidths; double lastAdvanceWeight = allGlyphWeights[glyphIndices[glyphIndices.Count - 1]] * glyphRun.FontRenderingEmSize; totalHeight += glyphRun.ComputeAlignmentBox().Width + lastAdvanceWeight / 2d; } else { totalHeight += ChangeGlyphOrientation(glyphDrawing, baselineShiftX, baselineShiftY, false); } } } } else { GlyphRunDrawing glyphDrawing = textDrawing as GlyphRunDrawing; if (glyphDrawing != null) { if (textRun.IsLatin) { GlyphRun glyphRun = glyphDrawing.GlyphRun; IList <UInt16> glyphIndices = glyphRun.GlyphIndices; IDictionary <ushort, double> allGlyphWeights = glyphRun.GlyphTypeface.AdvanceWidths; double lastAdvanceWeight = allGlyphWeights[glyphIndices[glyphIndices.Count - 1]] * glyphRun.FontRenderingEmSize; totalHeight += glyphRun.ComputeAlignmentBox().Width + lastAdvanceWeight / 2d; } else { totalHeight += ChangeGlyphOrientation(glyphDrawing, baselineShiftX, baselineShiftY, false); } } } } else if (vertOrientation == 0) { if (textGroup != null) { for (int j = 0; j < textGroup.Children.Count; j++) { GlyphRunDrawing glyphDrawing = textGroup.Children[j] as GlyphRunDrawing; if (glyphDrawing != null) { baselineShiftX = ChangeGlyphOrientation(glyphDrawing, baselineShiftX, baselineShiftY, textRun.IsLatin); totalHeight += baselineShiftX; } } } else { GlyphRunDrawing glyphDrawing = textDrawing as GlyphRunDrawing; if (textDrawing != null) { totalHeight += ChangeGlyphOrientation(glyphDrawing, baselineShiftX, baselineShiftY, textRun.IsLatin); } } } else { throw new NotImplementedException(); } } if (!this.IsMeasuring) { _drawContext.DrawDrawing(verticalGroup); } if (tr < textRunList.Count) { ctp.X = startPoint.X; ctp.Y = startPoint.Y + totalHeight; startPoint.Y += totalHeight; } } }
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 RenderSingleLineText(SvgTextContentElement element, ref Point ctp, string text, double rotate, WpfTextPlacement placement) { if (String.IsNullOrEmpty(text)) return; int vertOrientation = -1; int horzOrientation = -1; string orientationText = element.GetPropertyValue("glyph-orientation-vertical"); if (!String.IsNullOrEmpty(orientationText)) { double orientationValue = 0; if (Double.TryParse(orientationText, out orientationValue)) { vertOrientation = (int)orientationValue; } } orientationText = element.GetPropertyValue("glyph-orientation-horizontal"); if (!String.IsNullOrEmpty(orientationText)) { double orientationValue = 0; if (Double.TryParse(orientationText, out orientationValue)) { horzOrientation = (int)orientationValue; } } Point startPoint = ctp; IList<WpfTextRun> textRunList = WpfTextRun.BreakWords(text, vertOrientation, horzOrientation); for (int tr = 0; tr < textRunList.Count; tr++) { // For unknown reasons, FormattedText will split a text like "-70%" into two parts "-" // and "70%". We provide a shift to account for the split... double baselineShiftX = 0; double baselineShiftY = 0; WpfTextRun textRun = textRunList[tr]; DrawingGroup verticalGroup = new DrawingGroup(); DrawingContext verticalContext = verticalGroup.Open(); DrawingContext currentContext = _textContext; _textContext = verticalContext; this.DrawSingleLineText(element, ref ctp, textRun, rotate, placement); verticalContext.Close(); _textContext = currentContext; if (verticalGroup.Children.Count == 1) { DrawingGroup textGroup = verticalGroup.Children[0] as DrawingGroup; if (textGroup != null) { verticalGroup = textGroup; } } string runText = textRun.Text; int charCount = runText.Length; double totalHeight = 0; DrawingCollection drawings = verticalGroup.Children; int itemCount = drawings != null ? drawings.Count : 0; for (int i = 0; i < itemCount; i++) { Drawing textDrawing = drawings[i]; DrawingGroup textGroup = textDrawing as DrawingGroup; if (vertOrientation == -1) { if (textGroup != null) { for (int j = 0; j < textGroup.Children.Count; j++) { GlyphRunDrawing glyphDrawing = textGroup.Children[j] as GlyphRunDrawing; if (glyphDrawing != null) { if (textRun.IsLatin) { GlyphRun glyphRun = glyphDrawing.GlyphRun; IList<UInt16> glyphIndices = glyphRun.GlyphIndices; IDictionary<ushort, double> allGlyphWeights = glyphRun.GlyphTypeface.AdvanceWidths; double lastAdvanceWeight = allGlyphWeights[glyphIndices[glyphIndices.Count - 1]] * glyphRun.FontRenderingEmSize; totalHeight += glyphRun.ComputeAlignmentBox().Width + lastAdvanceWeight / 2d; } else { totalHeight += ChangeGlyphOrientation(glyphDrawing, baselineShiftX, baselineShiftY, false); } } } } else { GlyphRunDrawing glyphDrawing = textDrawing as GlyphRunDrawing; if (glyphDrawing != null) { if (textRun.IsLatin) { GlyphRun glyphRun = glyphDrawing.GlyphRun; IList<UInt16> glyphIndices = glyphRun.GlyphIndices; IDictionary<ushort, double> allGlyphWeights = glyphRun.GlyphTypeface.AdvanceWidths; double lastAdvanceWeight = allGlyphWeights[glyphIndices[glyphIndices.Count - 1]] * glyphRun.FontRenderingEmSize; totalHeight += glyphRun.ComputeAlignmentBox().Width + lastAdvanceWeight / 2d; } else { totalHeight += ChangeGlyphOrientation(glyphDrawing, baselineShiftX, baselineShiftY, false); } } } } else if (vertOrientation == 0) { if (textGroup != null) { for (int j = 0; j < textGroup.Children.Count; j++) { GlyphRunDrawing glyphDrawing = textGroup.Children[j] as GlyphRunDrawing; if (glyphDrawing != null) { baselineShiftX = ChangeGlyphOrientation(glyphDrawing, baselineShiftX, baselineShiftY, textRun.IsLatin); totalHeight += baselineShiftX; } } } else { GlyphRunDrawing glyphDrawing = textDrawing as GlyphRunDrawing; if (textDrawing != null) { totalHeight += ChangeGlyphOrientation(glyphDrawing, baselineShiftX, baselineShiftY, textRun.IsLatin); } } } else { throw new NotImplementedException(); } } if (!this.IsMeasuring) { _textContext.DrawDrawing(verticalGroup); } if (tr < textRunList.Count) { ctp.X = startPoint.X; ctp.Y = startPoint.Y + totalHeight; startPoint.Y += totalHeight; } } }
public override void RenderTextRun(SvgTextContentElement element, ref Point ctp, string text, double rotate, WpfTextPlacement placement) { }
public override void RenderSingleLineText(SvgTextContentElement element, ref Point ctp, string text, double rotate, WpfTextPlacement placement) { this.RenderTextPath((SvgTextPathElement)element, ref ctp, rotate, placement); }
public override void RenderTextRun(SvgTextContentElement element, ref Point ctp, string text, double rotate, WpfTextPlacement placement) { throw new NotImplementedException(); }
public static WpfTextPlacement GetCurrentTextPosition(SvgTextPositioningElement posElement, Point p) { ISvgLengthList xValues = posElement.X.AnimVal; ISvgLengthList yValues = posElement.Y.AnimVal; ISvgLengthList dxValues = posElement.Dx.AnimVal; ISvgLengthList dyValues = posElement.Dy.AnimVal; ISvgNumberList rValues = posElement.Rotate.AnimVal; bool requiresGlyphPositioning = false; bool isXYGlyphPositioning = false; bool isDxyGlyphPositioning = false; bool isRotateGlyphPositioning = false; double xValue = p.X; double yValue = p.Y; double rValue = 0; double dxValue = 0; double dyValue = 0; WpfTextPlacement textPlacement = null; if (xValues.NumberOfItems > 0) { if (xValues.NumberOfItems > 1) { isXYGlyphPositioning = true; requiresGlyphPositioning = true; } xValue = xValues.GetItem(0).Value; p.X = xValue; } if (yValues.NumberOfItems > 0) { if (yValues.NumberOfItems > 1) { isXYGlyphPositioning = true; requiresGlyphPositioning = true; } yValue = yValues.GetItem(0).Value; p.Y = yValue; } if (dxValues.NumberOfItems > 0) { if (dxValues.NumberOfItems > 1) { isDxyGlyphPositioning = true; requiresGlyphPositioning = true; } dxValue = dxValues.GetItem(0).Value; p.X += dxValue; } if (dyValues.NumberOfItems > 0) { if (dyValues.NumberOfItems > 1) { isDxyGlyphPositioning = true; requiresGlyphPositioning = true; } dyValue = dyValues.GetItem(0).Value; p.Y += dyValue; } if (rValues.NumberOfItems > 0) { if (rValues.NumberOfItems > 1) { isRotateGlyphPositioning = true; requiresGlyphPositioning = true; } rValue = rValues.GetItem(0).Value; } if (requiresGlyphPositioning) { uint xCount = xValues.NumberOfItems; uint yCount = yValues.NumberOfItems; uint dxCount = dxValues.NumberOfItems; uint dyCount = dyValues.NumberOfItems; uint rCount = rValues.NumberOfItems; List <WpfTextPosition> textPositions = null; bool isRotateOnly = false; if (isXYGlyphPositioning) { uint itemCount = Math.Max(Math.Max(xCount, yCount), Math.Max(dxCount, dyCount)); itemCount = Math.Max(itemCount, rCount); textPositions = new List <WpfTextPosition>((int)itemCount); double xLast = 0; double yLast = 0; for (uint i = 0; i < itemCount; i++) { double xNext = i < xCount?xValues.GetItem(i).Value : xValue; double yNext = i < yCount?yValues.GetItem(i).Value : yValue; double rNext = i < rCount?rValues.GetItem(i).Value : rValue; double dxNext = i < dxCount?dxValues.GetItem(i).Value : dxValue; double dyNext = i < dyCount?dyValues.GetItem(i).Value : dyValue; if (i < xCount) { xLast = xNext; } else { xNext = xLast; } if (i < yCount) { yLast = yNext; } else { yNext = yLast; } WpfTextPosition textPosition = new WpfTextPosition( new Point(xNext + dxNext, yNext + dyNext), rNext); textPositions.Add(textPosition); } } else if (isDxyGlyphPositioning) { } else if (isRotateGlyphPositioning) { isRotateOnly = true; uint itemCount = Math.Max(Math.Max(xCount, yCount), Math.Max(dxCount, dyCount)); itemCount = Math.Max(itemCount, rCount); textPositions = new List <WpfTextPosition>((int)itemCount); for (uint i = 0; i < itemCount; i++) { double rNext = i < rCount?rValues.GetItem(i).Value : rValue; WpfTextPosition textPosition = new WpfTextPosition(p, rNext); textPositions.Add(textPosition); } } if (textPositions != null && textPositions.Count != 0) { textPlacement = new WpfTextPlacement(p, rValue, textPositions, isRotateOnly); } else { textPlacement = new WpfTextPlacement(p, rValue); } } else { textPlacement = new WpfTextPlacement(p, rValue); } return(textPlacement); }
public abstract void RenderTextRun(SvgTextContentElement element, ref Point startPos, string text, double rotate, WpfTextPlacement placement);
private void RenderTextPath(SvgTextContentElement element, WpfTextOnPathDrawing pathDrawing, string text, Point origin, 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 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); }
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(); } } }
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 static WpfTextPlacement GetCurrentTextPosition(SvgTextPositioningElement posElement, Point p) { ISvgLengthList xValues = posElement.X.AnimVal; ISvgLengthList yValues = posElement.Y.AnimVal; ISvgLengthList dxValues = posElement.Dx.AnimVal; ISvgLengthList dyValues = posElement.Dy.AnimVal; ISvgNumberList rValues = posElement.Rotate.AnimVal; bool requiresGlyphPositioning = false; bool isXYGlyphPositioning = false; bool isDxyGlyphPositioning = false; bool isRotateGlyphPositioning = false; double xValue = p.X; double yValue = p.Y; double rValue = 0; double dxValue = 0; double dyValue = 0; WpfTextPlacement textPlacement = null; if (xValues.NumberOfItems > 0) { if (xValues.NumberOfItems > 1) { isXYGlyphPositioning = true; requiresGlyphPositioning = true; } xValue = xValues.GetItem(0).Value; p.X = xValue; } if (yValues.NumberOfItems > 0) { if (yValues.NumberOfItems > 1) { isXYGlyphPositioning = true; requiresGlyphPositioning = true; } yValue = yValues.GetItem(0).Value; p.Y = yValue; } if (dxValues.NumberOfItems > 0) { if (dxValues.NumberOfItems > 1) { isDxyGlyphPositioning = true; requiresGlyphPositioning = true; } dxValue = dxValues.GetItem(0).Value; p.X += dxValue; } if (dyValues.NumberOfItems > 0) { if (dyValues.NumberOfItems > 1) { isDxyGlyphPositioning = true; requiresGlyphPositioning = true; } dyValue = dyValues.GetItem(0).Value; p.Y += dyValue; } if (rValues.NumberOfItems > 0) { if (rValues.NumberOfItems > 1) { isRotateGlyphPositioning = true; requiresGlyphPositioning = true; } rValue = rValues.GetItem(0).Value; } if (requiresGlyphPositioning) { uint xCount = xValues.NumberOfItems; uint yCount = yValues.NumberOfItems; uint dxCount = dxValues.NumberOfItems; uint dyCount = dyValues.NumberOfItems; uint rCount = rValues.NumberOfItems; List<WpfTextPosition> textPositions = null; bool isRotateOnly = false; if (isXYGlyphPositioning) { uint itemCount = Math.Max(Math.Max(xCount, yCount), Math.Max(dxCount, dyCount)); itemCount = Math.Max(itemCount, rCount); textPositions = new List<WpfTextPosition>((int)itemCount); double xLast = 0; double yLast = 0; for (uint i = 0; i < itemCount; i++) { double xNext = i < xCount ? xValues.GetItem(i).Value : xValue; double yNext = i < yCount ? yValues.GetItem(i).Value : yValue; double rNext = i < rCount ? rValues.GetItem(i).Value : rValue; double dxNext = i < dxCount ? dxValues.GetItem(i).Value : dxValue; double dyNext = i < dyCount ? dyValues.GetItem(i).Value : dyValue; if (i < xCount) { xLast = xNext; } else { xNext = xLast; } if (i < yCount) { yLast = yNext; } else { yNext = yLast; } WpfTextPosition textPosition = new WpfTextPosition( new Point(xNext + dxNext, yNext + dyNext), rNext); textPositions.Add(textPosition); } } else if (isDxyGlyphPositioning) { } else if (isRotateGlyphPositioning) { isRotateOnly = true; uint itemCount = Math.Max(Math.Max(xCount, yCount), Math.Max(dxCount, dyCount)); itemCount = Math.Max(itemCount, rCount); textPositions = new List<WpfTextPosition>((int)itemCount); for (uint i = 0; i < itemCount; i++) { double rNext = i < rCount ? rValues.GetItem(i).Value : rValue; WpfTextPosition textPosition = new WpfTextPosition(p, rNext); textPositions.Add(textPosition); } } if (textPositions != null && textPositions.Count != 0) { textPlacement = new WpfTextPlacement(p, rValue, textPositions, isRotateOnly); } else { textPlacement = new WpfTextPlacement(p, rValue); } } else { textPlacement = new WpfTextPlacement(p, rValue); } return textPlacement; }
public static WpfTextPlacement Create(SvgTextPositioningElement posElement, Point p, bool isTextPath = false) { ISvgLengthList xValues = posElement.X.AnimVal; ISvgLengthList yValues = posElement.Y.AnimVal; ISvgLengthList dxValues = posElement.Dx.AnimVal; ISvgLengthList dyValues = posElement.Dy.AnimVal; ISvgNumberList rValues = posElement.Rotate.AnimVal; bool requiresGlyphPositioning = false; bool isXYGlyphPositioning = false; bool isDxyGlyphPositioning = false; bool isRotateGlyphPositioning = false; double xValue = p.X; double yValue = p.Y; double rValue = 0; double dxValue = 0; double dyValue = 0; WpfTextPlacement textPlacement = null; if (xValues.NumberOfItems > 0 && isTextPath == false) { if (xValues.NumberOfItems > 1) { isXYGlyphPositioning = true; requiresGlyphPositioning = true; } xValue = xValues.GetItem(xValues.NumberOfItems - 1).Value; p.X = xValue; } if (yValues.NumberOfItems > 0) { if (yValues.NumberOfItems > 1) { isXYGlyphPositioning = true; requiresGlyphPositioning = true; } yValue = yValues.GetItem(yValues.NumberOfItems - 1).Value; p.Y = yValue; } if (dxValues.NumberOfItems > 0 && isTextPath == false) { if (dxValues.NumberOfItems > 1) { isDxyGlyphPositioning = true; requiresGlyphPositioning = true; } dxValue = dxValues.GetItem(dxValues.NumberOfItems - 1).Value; p.X += dxValue; } if (dyValues.NumberOfItems > 0) { if (dyValues.NumberOfItems > 1) { isDxyGlyphPositioning = true; requiresGlyphPositioning = true; } dyValue = dyValues.GetItem(dyValues.NumberOfItems - 1).Value; p.Y += dyValue; } if (rValues.NumberOfItems > 0) { if (rValues.NumberOfItems > 1) { isRotateGlyphPositioning = true; requiresGlyphPositioning = true; } // If the element contains more characters than the number of values specified // in the "rotate" attribute. In this case the last value specified in the "rotate" // attribute of the "tspan" must be applied to the remaining characters in the string. rValue = rValues.GetItem(rValues.NumberOfItems - 1).Value; } if (requiresGlyphPositioning) { uint xCount = xValues.NumberOfItems; uint yCount = yValues.NumberOfItems; uint dxCount = dxValues.NumberOfItems; uint dyCount = dyValues.NumberOfItems; uint rCount = rValues.NumberOfItems; List <WpfTextPosition> textPositions = null; bool isRotateOnly = false; if (isXYGlyphPositioning) { uint itemCount = Math.Max(Math.Max(xCount, yCount), Math.Max(dxCount, dyCount)); itemCount = Math.Max(itemCount, rCount); textPositions = new List <WpfTextPosition>((int)itemCount); double xLast = 0; double yLast = 0; for (uint i = 0; i < itemCount; i++) { double xNext = i < xCount?xValues.GetItem(i).Value : xValue; double yNext = i < yCount?yValues.GetItem(i).Value : yValue; double rNext = i < rCount?rValues.GetItem(i).Value : rValue; double dxNext = i < dxCount?dxValues.GetItem(i).Value : dxValue; double dyNext = i < dyCount?dyValues.GetItem(i).Value : dyValue; if (i < xCount) { xLast = xNext; } else { xNext = xLast; } if (i < yCount) { yLast = yNext; } else { yNext = yLast; } WpfTextPosition textPosition = new WpfTextPosition( new Point(xNext + dxNext, yNext + dyNext), rNext); textPositions.Add(textPosition); } } else if (isDxyGlyphPositioning) { } else if (isRotateGlyphPositioning) { isRotateOnly = true; uint itemCount = Math.Max(Math.Max(xCount, yCount), Math.Max(dxCount, dyCount)); itemCount = Math.Max(itemCount, rCount); textPositions = new List <WpfTextPosition>((int)itemCount); for (uint i = 0; i < itemCount; i++) { double rNext = i < rCount?rValues.GetItem(i).Value : rValue; WpfTextPosition textPosition = new WpfTextPosition(p, rNext); textPositions.Add(textPosition); } } if (textPositions != null && textPositions.Count != 0) { textPlacement = new WpfTextPlacement(p, rValue, textPositions, isRotateOnly); } else { textPlacement = new WpfTextPlacement(p, rValue); } } else { textPlacement = new WpfTextPlacement(p, rValue); } return(textPlacement); }
private void RenderTextPath(SvgTextPathElement textPath, ref Point ctp, double rotate, WpfTextPlacement placement) { if (textPath.ChildNodes == null || textPath.ChildNodes.Count == 0) { return; } SvgElement targetPath = textPath.ReferencedElement as SvgElement; if (targetPath == null) { return; } Geometry textGeometry = CreateGeometry(targetPath, true); if (textGeometry == null) { return; } PathGeometry pathGeometry = textGeometry as PathGeometry; if (pathGeometry == null) { pathGeometry = textGeometry.GetFlattenedPathGeometry(); } // If the path has a transform, apply it to get a transformed path... if (targetPath.HasAttribute("transform")) { var svgTransform = new SvgTransform(targetPath.GetAttribute("transform")); var svgMatrix = svgTransform.Matrix; if (!svgMatrix.IsIdentity) { pathGeometry.Transform = new MatrixTransform(svgMatrix.A, svgMatrix.B, svgMatrix.C, svgMatrix.D, svgMatrix.E, svgMatrix.F); var transformPath = new PathGeometry(); transformPath.AddGeometry(pathGeometry); pathGeometry = transformPath; } } WpfPathTextBuilder pathBuilder = new WpfPathTextBuilder(_textElement); pathBuilder.BeginTextPath(textPath); var comparer = StringComparison.OrdinalIgnoreCase; XmlNodeType nodeType = XmlNodeType.None; int nodeCount = textPath.ChildNodes.Count; for (int i = 0; i < nodeCount; i++) { XmlNode child = textPath.ChildNodes[i]; nodeType = child.NodeType; if (nodeType == XmlNodeType.Text) { var nodeText = GetText(textPath, child); if (i == (nodeCount - 1)) { // No need to render the last white space... if (nodeCount == 1) { if (nodeText.StartsWith(NonBreaking, StringComparison.OrdinalIgnoreCase)) { if (!nodeText.EndsWith(NonBreaking, StringComparison.OrdinalIgnoreCase)) { nodeText = nodeText.TrimEnd(); } } else if (nodeText.EndsWith(NonBreaking, StringComparison.OrdinalIgnoreCase)) { nodeText = nodeText.TrimStart(); } else { nodeText = nodeText.Trim(); } } else { if (!nodeText.EndsWith(NonBreaking, StringComparison.OrdinalIgnoreCase)) { nodeText = nodeText.TrimEnd(); } } } else if (i == 0) { nodeText = nodeText.Trim(); } RenderTextPath(textPath, pathBuilder, nodeText, new Point(ctp.X, ctp.Y), rotate, placement); } else if (nodeType == XmlNodeType.Element) { string nodeName = child.Name; if (string.Equals(nodeName, "tref", comparer)) { RenderTRefPath((SvgTRefElement)child, pathBuilder, ref ctp); } else if (string.Equals(nodeName, "tspan", comparer)) { RenderTSpanPath((SvgTSpanElement)child, pathBuilder, ref ctp); } } } WpfTextStringFormat stringFormat = GetTextStringFormat(textPath); //ISvgAnimatedLength pathOffset = textPath.StartOffset; //SvgTextPathMethod pathMethod = (SvgTextPathMethod)textPath.Method.BaseVal; //SvgTextPathSpacing pathSpacing = (SvgTextPathSpacing)textPath.Spacing.BaseVal; pathBuilder.RenderTextPath(_drawContext, pathGeometry, stringFormat.Alignment); pathBuilder.EndTextPath(); }
public override void RenderTextRun(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); 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.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) { double spacing = Convert.ToDouble(letterSpacing); 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); 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 && 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(ctp.X, ctp.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); 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 != 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 RenderSingleLineTextV(SvgTextContentElement element, ref Point ctp, string text, double rotate, WpfTextPlacement placement) { if (String.IsNullOrEmpty(text) || _vertRenderer == null) return; string targetText = text.Trim(); if (placement != null) { placement.UpdatePositions(targetText); } _vertRenderer.RenderSingleLineText(element, ref ctp, targetText, rotate, placement); }
private void RenderTextPath(SvgTextElement element, SvgTextPathElement textPath, ref Point ctp, double rotate, WpfTextPlacement placement) { if (_pathRenderer == null) { return; } _pathRenderer.RenderSingleLineText(textPath, ref ctp, String.Empty, rotate, placement); }
private void RenderTextRunV(SvgTextContentElement element, ref Point ctp, string text, double rotate, WpfTextPlacement placement) { if (String.IsNullOrEmpty(text) || _vertRenderer == null) return; if (placement != null) { placement.UpdatePositions(text); } _vertRenderer.RenderTextRun(element, ref ctp, text, rotate, placement); }
private void RenderTextPath(SvgTextPathElement textPath, ref Point ctp, double rotate, WpfTextPlacement placement) { if (textPath.ChildNodes == null || textPath.ChildNodes.Count == 0) { return; } SvgElement targetPath = textPath.ReferencedElement as SvgElement; if (targetPath == null) { return; } PathGeometry pathGeometry = CreateGeometry(targetPath, true) as PathGeometry; if (pathGeometry == null) { return; } this.IsTextPath = true; WpfTextOnPathDrawing pathDrawing = new WpfTextOnPathDrawing(); pathDrawing.BeginTextPath(); XmlNodeType nodeType = XmlNodeType.None; foreach (XmlNode child in textPath.ChildNodes) { nodeType = child.NodeType; if (nodeType == XmlNodeType.Text) { RenderTextPath(textPath, pathDrawing, GetText(textPath, child), new Point(ctp.X, ctp.Y), rotate, placement); } else if (nodeType == XmlNodeType.Element) { string nodeName = child.Name; if (string.Equals(nodeName, "tref")) { RenderTRefPath((SvgTRefElement)child, pathDrawing, ref ctp); } else if (string.Equals(nodeName, "tspan")) { RenderTSpanPath((SvgTSpanElement)child, pathDrawing, ref ctp); } } } WpfTextStringFormat stringFormat = GetTextStringFormat(_textElement); ISvgAnimatedLength pathOffset = textPath.StartOffset; SvgTextPathMethod pathMethod = (SvgTextPathMethod)textPath.Method.BaseVal; SvgTextPathSpacing pathSpacing = (SvgTextPathSpacing)textPath.Spacing.BaseVal; pathDrawing.DrawTextPath(_textContext, pathGeometry, pathOffset, stringFormat.Alignment, pathMethod, pathSpacing); pathDrawing.EndTextPath(); }
public abstract void RenderSingleLineText(SvgTextContentElement element, ref Point ctp, string text, double rotate, WpfTextPlacement placement);
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); 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; string letterSpacing = element.GetAttribute("letter-spacing"); if (String.IsNullOrEmpty(letterSpacing)) { FormattedText formattedText = new FormattedText(text, textRun.IsLatin ? _drawContext.EnglishCultureInfo : _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; Point textPoint = new Point(ctp.X, ctp.Y - yCorrection); RotateTransform rotateAt = new RotateTransform(90, ctp.X, ctp.Y); _textContext.PushTransform(rotateAt); _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(); } } else { RotateTransform rotateAt = new RotateTransform(90, ctp.X, ctp.Y); _textContext.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 ? _drawContext.EnglishCultureInfo : _drawContext.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); _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; ctp.X += bboxWidth + spacing; } if (rotateAt != null) { _textContext.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(); } } }