1 | using System;
|
---|
2 | using System.Xml;
|
---|
3 | using System.Linq;
|
---|
4 | using System.Text;
|
---|
5 | using System.Collections.Generic;
|
---|
6 |
|
---|
7 | using System.Windows;
|
---|
8 | using System.Windows.Media;
|
---|
9 |
|
---|
10 | using SharpVectors.Dom.Css;
|
---|
11 | using SharpVectors.Dom.Svg;
|
---|
12 |
|
---|
13 | using SharpVectors.Renderers.Wpf;
|
---|
14 |
|
---|
15 | namespace SharpVectors.Renderers.Texts
|
---|
16 | {
|
---|
17 | public sealed class WpfPathTextRenderer : WpfTextRenderer
|
---|
18 | {
|
---|
19 | #region Private Fields
|
---|
20 |
|
---|
21 | #endregion
|
---|
22 |
|
---|
23 | #region Constructors and Destructor
|
---|
24 |
|
---|
25 | public WpfPathTextRenderer(SvgTextElement textElement, WpfTextRendering textRendering)
|
---|
26 | : base(textElement, textRendering)
|
---|
27 | {
|
---|
28 | }
|
---|
29 |
|
---|
30 | #endregion
|
---|
31 |
|
---|
32 | #region Public Methods
|
---|
33 |
|
---|
34 | public override void RenderSingleLineText(SvgTextContentElement element,
|
---|
35 | ref Point ctp, string text, double rotate, WpfTextPlacement placement)
|
---|
36 | {
|
---|
37 | this.RenderTextPath((SvgTextPathElement)element, ref ctp, rotate, placement);
|
---|
38 | }
|
---|
39 |
|
---|
40 | public override void RenderTextRun(SvgTextContentElement element,
|
---|
41 | ref Point ctp, string text, double rotate, WpfTextPlacement placement)
|
---|
42 | {
|
---|
43 | }
|
---|
44 |
|
---|
45 | #endregion
|
---|
46 |
|
---|
47 | #region Private Methods
|
---|
48 |
|
---|
49 | private void RenderTextPath(SvgTextPathElement textPath, ref Point ctp,
|
---|
50 | double rotate, WpfTextPlacement placement)
|
---|
51 | {
|
---|
52 | if (textPath.ChildNodes == null || textPath.ChildNodes.Count == 0)
|
---|
53 | {
|
---|
54 | return;
|
---|
55 | }
|
---|
56 |
|
---|
57 | SvgElement targetPath = textPath.ReferencedElement as SvgElement;
|
---|
58 | if (targetPath == null)
|
---|
59 | {
|
---|
60 | return;
|
---|
61 | }
|
---|
62 |
|
---|
63 | PathGeometry pathGeometry = WpfRendering.CreateGeometry(targetPath, true) as PathGeometry;
|
---|
64 | if (pathGeometry == null)
|
---|
65 | {
|
---|
66 | return;
|
---|
67 | }
|
---|
68 |
|
---|
69 | this.IsTextPath = true;
|
---|
70 |
|
---|
71 | WpfTextOnPathDrawing pathDrawing = new WpfTextOnPathDrawing();
|
---|
72 |
|
---|
73 | pathDrawing.BeginTextPath();
|
---|
74 |
|
---|
75 | XmlNodeType nodeType = XmlNodeType.None;
|
---|
76 |
|
---|
77 | foreach (XmlNode child in textPath.ChildNodes)
|
---|
78 | {
|
---|
79 | nodeType = child.NodeType;
|
---|
80 | if (nodeType == XmlNodeType.Text)
|
---|
81 | {
|
---|
82 | RenderTextPath(textPath, pathDrawing, GetText(textPath, child),
|
---|
83 | new Point(ctp.X, ctp.Y), rotate, placement);
|
---|
84 | }
|
---|
85 | else if (nodeType == XmlNodeType.Element)
|
---|
86 | {
|
---|
87 | string nodeName = child.Name;
|
---|
88 | if (String.Equals(nodeName, "tref"))
|
---|
89 | {
|
---|
90 | RenderTRefPath((SvgTRefElement)child, pathDrawing, ref ctp);
|
---|
91 | }
|
---|
92 | else if (String.Equals(nodeName, "tspan"))
|
---|
93 | {
|
---|
94 | RenderTSpanPath((SvgTSpanElement)child, pathDrawing, ref ctp);
|
---|
95 | }
|
---|
96 | }
|
---|
97 | }
|
---|
98 |
|
---|
99 | WpfTextStringFormat stringFormat = GetTextStringFormat(_textElement);
|
---|
100 |
|
---|
101 | ISvgAnimatedLength pathOffset = textPath.StartOffset;
|
---|
102 | SvgTextPathMethod pathMethod = (SvgTextPathMethod)textPath.Method.BaseVal;
|
---|
103 | SvgTextPathSpacing pathSpacing = (SvgTextPathSpacing)textPath.Spacing.BaseVal;
|
---|
104 | pathDrawing.DrawTextPath(_textContext, pathGeometry, pathOffset,
|
---|
105 | stringFormat.Alignment, pathMethod, pathSpacing);
|
---|
106 |
|
---|
107 | pathDrawing.EndTextPath();
|
---|
108 | }
|
---|
109 |
|
---|
110 | private void RenderTRefPath(SvgTRefElement element, WpfTextOnPathDrawing pathDrawing,
|
---|
111 | ref Point ctp)
|
---|
112 | {
|
---|
113 | WpfTextPlacement placement = GetCurrentTextPosition(element, ctp);
|
---|
114 | ctp = placement.Location;
|
---|
115 | double rotate = placement.Rotation;
|
---|
116 | if (!placement.HasPositions)
|
---|
117 | {
|
---|
118 | placement = null; // Render it useless.
|
---|
119 | }
|
---|
120 |
|
---|
121 | this.RenderTextPath(element, pathDrawing, GetTRefText(element),
|
---|
122 | new Point(ctp.X, ctp.Y), rotate, placement);
|
---|
123 | }
|
---|
124 |
|
---|
125 | private void RenderTSpanPath(SvgTSpanElement element, WpfTextOnPathDrawing pathDrawing,
|
---|
126 | ref Point ctp)
|
---|
127 | {
|
---|
128 | WpfTextPlacement placement = GetCurrentTextPosition(element, ctp);
|
---|
129 | ctp = placement.Location;
|
---|
130 | double rotate = placement.Rotation;
|
---|
131 | if (!placement.HasPositions)
|
---|
132 | {
|
---|
133 | placement = null; // Render it useless.
|
---|
134 | }
|
---|
135 |
|
---|
136 | string sBaselineShift = element.GetPropertyValue("baseline-shift").Trim();
|
---|
137 | double shiftBy = 0;
|
---|
138 |
|
---|
139 | if (sBaselineShift.Length > 0)
|
---|
140 | {
|
---|
141 | SvgTextElement textElement = (SvgTextElement)element.SelectSingleNode("ancestor::svg:text",
|
---|
142 | element.OwnerDocument.NamespaceManager);
|
---|
143 |
|
---|
144 | double textFontSize = GetComputedFontSize(textElement);
|
---|
145 | if (sBaselineShift.EndsWith("%"))
|
---|
146 | {
|
---|
147 | shiftBy = SvgNumber.ParseNumber(sBaselineShift.Substring(0,
|
---|
148 | sBaselineShift.Length - 1)) / 100f * textFontSize;
|
---|
149 | }
|
---|
150 | else if (sBaselineShift == "sub")
|
---|
151 | {
|
---|
152 | shiftBy = -0.6F * textFontSize;
|
---|
153 | }
|
---|
154 | else if (sBaselineShift == "super")
|
---|
155 | {
|
---|
156 | shiftBy = 0.6F * textFontSize;
|
---|
157 | }
|
---|
158 | else if (sBaselineShift == "baseline")
|
---|
159 | {
|
---|
160 | shiftBy = 0;
|
---|
161 | }
|
---|
162 | else
|
---|
163 | {
|
---|
164 | shiftBy = SvgNumber.ParseNumber(sBaselineShift);
|
---|
165 | }
|
---|
166 | }
|
---|
167 |
|
---|
168 | foreach (XmlNode child in element.ChildNodes)
|
---|
169 | {
|
---|
170 | if (child.NodeType == XmlNodeType.Text)
|
---|
171 | {
|
---|
172 | ctp.Y -= shiftBy;
|
---|
173 | RenderTextPath(element, pathDrawing, GetText(element, child),
|
---|
174 | new Point(ctp.X, ctp.Y), rotate, placement);
|
---|
175 | ctp.Y += shiftBy;
|
---|
176 | }
|
---|
177 | }
|
---|
178 | }
|
---|
179 |
|
---|
180 | private void RenderTextPath(SvgTextContentElement element, WpfTextOnPathDrawing pathDrawing,
|
---|
181 | string text, Point origin, double rotate, WpfTextPlacement placement)
|
---|
182 | {
|
---|
183 | if (String.IsNullOrEmpty(text))
|
---|
184 | {
|
---|
185 | return;
|
---|
186 | }
|
---|
187 |
|
---|
188 | double emSize = GetComputedFontSize(element);
|
---|
189 | FontFamily fontFamily = GetTextFontFamily(element, emSize);
|
---|
190 |
|
---|
191 | FontStyle fontStyle = GetTextFontStyle(element);
|
---|
192 | FontWeight fontWeight = GetTextFontWeight(element);
|
---|
193 |
|
---|
194 | FontStretch fontStretch = GetTextFontStretch(element);
|
---|
195 |
|
---|
196 | WpfTextStringFormat stringFormat = GetTextStringFormat(element);
|
---|
197 |
|
---|
198 | // Fix the use of Postscript fonts...
|
---|
199 | WpfFontFamilyVisitor fontFamilyVisitor = _drawContext.FontFamilyVisitor;
|
---|
200 | if (!String.IsNullOrEmpty(_actualFontName) && fontFamilyVisitor != null)
|
---|
201 | {
|
---|
202 | WpfFontFamilyInfo currentFamily = new WpfFontFamilyInfo(fontFamily, fontWeight,
|
---|
203 | fontStyle, fontStretch);
|
---|
204 | WpfFontFamilyInfo familyInfo = fontFamilyVisitor.Visit(_actualFontName,
|
---|
205 | currentFamily, _drawContext);
|
---|
206 | if (familyInfo != null && !familyInfo.IsEmpty)
|
---|
207 | {
|
---|
208 | fontFamily = familyInfo.Family;
|
---|
209 | fontWeight = familyInfo.Weight;
|
---|
210 | fontStyle = familyInfo.Style;
|
---|
211 | fontStretch = familyInfo.Stretch;
|
---|
212 | }
|
---|
213 | }
|
---|
214 |
|
---|
215 | WpfSvgPaint fillPaint = new WpfSvgPaint(_drawContext, element, "fill");
|
---|
216 | Brush textBrush = fillPaint.GetBrush();
|
---|
217 |
|
---|
218 | WpfSvgPaint strokePaint = new WpfSvgPaint(_drawContext, element, "stroke");
|
---|
219 | Pen pen = strokePaint.GetPen();
|
---|
220 |
|
---|
221 | TextDecorationCollection textDecors = GetTextDecoration(element);
|
---|
222 | TextAlignment alignment = stringFormat.Alignment;
|
---|
223 |
|
---|
224 | pathDrawing.FontSize = emSize;
|
---|
225 |
|
---|
226 | pathDrawing.FontFamily = fontFamily;
|
---|
227 | pathDrawing.FontWeight = fontWeight;
|
---|
228 | pathDrawing.FontStretch = fontStretch;
|
---|
229 |
|
---|
230 | pathDrawing.Foreground = textBrush;
|
---|
231 |
|
---|
232 | pathDrawing.AddTextPath(text, origin);
|
---|
233 | }
|
---|
234 |
|
---|
235 | #endregion
|
---|
236 | }
|
---|
237 | }
|
---|