1 | using System;
|
---|
2 | using System.Xml;
|
---|
3 | using System.Linq;
|
---|
4 | using System.Text;
|
---|
5 | using System.Collections.Generic;
|
---|
6 | using System.Text.RegularExpressions;
|
---|
7 |
|
---|
8 | using System.Windows;
|
---|
9 | using System.Windows.Media;
|
---|
10 | using System.Windows.Media.Imaging;
|
---|
11 |
|
---|
12 | using SharpVectors.Dom.Css;
|
---|
13 | using SharpVectors.Dom.Svg;
|
---|
14 | using SharpVectors.Renderers.Utils;
|
---|
15 |
|
---|
16 | namespace SharpVectors.Renderers.Wpf
|
---|
17 | {
|
---|
18 | public class WpfRendering : WpfRenderingBase
|
---|
19 | {
|
---|
20 | #region Private Fields
|
---|
21 |
|
---|
22 | private static Regex _reUrl = new Regex(@"^url\((?<uri>.+)\)$", RegexOptions.Compiled);
|
---|
23 |
|
---|
24 | private Geometry _clipGeometry;
|
---|
25 | private Transform _transformMatrix;
|
---|
26 | private Brush _maskBrush;
|
---|
27 |
|
---|
28 | private SvgUnitType _clipPathUnits;
|
---|
29 |
|
---|
30 | private SvgUnitType _maskUnits;
|
---|
31 |
|
---|
32 | private SvgUnitType _maskContentUnits;
|
---|
33 |
|
---|
34 | #endregion
|
---|
35 |
|
---|
36 | #region Constructor and Destructor
|
---|
37 |
|
---|
38 | public WpfRendering(SvgElement element)
|
---|
39 | : base(element)
|
---|
40 | {
|
---|
41 | _maskUnits = SvgUnitType.UserSpaceOnUse;
|
---|
42 | _clipPathUnits = SvgUnitType.UserSpaceOnUse;
|
---|
43 | _maskContentUnits = SvgUnitType.UserSpaceOnUse;
|
---|
44 | }
|
---|
45 |
|
---|
46 | #endregion
|
---|
47 |
|
---|
48 | #region Public Properties
|
---|
49 |
|
---|
50 | public Transform Transform
|
---|
51 | {
|
---|
52 | get
|
---|
53 | {
|
---|
54 | return _transformMatrix;
|
---|
55 | }
|
---|
56 | set
|
---|
57 | {
|
---|
58 | _transformMatrix = value;
|
---|
59 | }
|
---|
60 | }
|
---|
61 |
|
---|
62 | public Geometry ClipGeometry
|
---|
63 | {
|
---|
64 | get
|
---|
65 | {
|
---|
66 | return _clipGeometry;
|
---|
67 | }
|
---|
68 | set
|
---|
69 | {
|
---|
70 | _clipGeometry = value;
|
---|
71 | }
|
---|
72 | }
|
---|
73 |
|
---|
74 | public SvgUnitType ClipUnits
|
---|
75 | {
|
---|
76 | get
|
---|
77 | {
|
---|
78 | return _clipPathUnits;
|
---|
79 | }
|
---|
80 | }
|
---|
81 |
|
---|
82 | public Brush Masking
|
---|
83 | {
|
---|
84 | get
|
---|
85 | {
|
---|
86 | return _maskBrush;
|
---|
87 | }
|
---|
88 | set
|
---|
89 | {
|
---|
90 | _maskBrush = value;
|
---|
91 | }
|
---|
92 | }
|
---|
93 |
|
---|
94 | public SvgUnitType MaskUnits
|
---|
95 | {
|
---|
96 | get
|
---|
97 | {
|
---|
98 | return _maskUnits;
|
---|
99 | }
|
---|
100 | }
|
---|
101 |
|
---|
102 | public SvgUnitType MaskContentUnits
|
---|
103 | {
|
---|
104 | get
|
---|
105 | {
|
---|
106 | return _maskContentUnits;
|
---|
107 | }
|
---|
108 | }
|
---|
109 |
|
---|
110 | #endregion
|
---|
111 |
|
---|
112 | #region Public Methods
|
---|
113 |
|
---|
114 | public override void BeforeRender(WpfDrawingRenderer renderer)
|
---|
115 | {
|
---|
116 | if (renderer == null)
|
---|
117 | {
|
---|
118 | return;
|
---|
119 | }
|
---|
120 |
|
---|
121 | _maskUnits = SvgUnitType.UserSpaceOnUse;
|
---|
122 | _clipPathUnits = SvgUnitType.UserSpaceOnUse;
|
---|
123 | _maskContentUnits = SvgUnitType.UserSpaceOnUse;
|
---|
124 |
|
---|
125 | WpfDrawingContext context = renderer.Context;
|
---|
126 |
|
---|
127 | SetQuality(context);
|
---|
128 | SetTransform(context);
|
---|
129 | SetClip(context);
|
---|
130 | SetMask(context);
|
---|
131 | }
|
---|
132 |
|
---|
133 | public override void AfterRender(WpfDrawingRenderer renderer)
|
---|
134 | {
|
---|
135 | _clipGeometry = null;
|
---|
136 | _transformMatrix = null;
|
---|
137 | _maskBrush = null;
|
---|
138 |
|
---|
139 | _maskUnits = SvgUnitType.UserSpaceOnUse;
|
---|
140 | _clipPathUnits = SvgUnitType.UserSpaceOnUse;
|
---|
141 | _maskContentUnits = SvgUnitType.UserSpaceOnUse;
|
---|
142 | }
|
---|
143 |
|
---|
144 | #endregion
|
---|
145 |
|
---|
146 | #region Public Static Methods
|
---|
147 |
|
---|
148 | public static WpfRendering Create(ISvgElement element)
|
---|
149 | {
|
---|
150 | if (element == null)
|
---|
151 | {
|
---|
152 | return null;
|
---|
153 | }
|
---|
154 |
|
---|
155 | SvgRenderingHint hint = element.RenderingHint;
|
---|
156 | // For the shapes and text contents...
|
---|
157 | if (hint == SvgRenderingHint.Shape)
|
---|
158 | {
|
---|
159 | return new WpfPathRendering((SvgElement)element);
|
---|
160 | }
|
---|
161 | if (hint == SvgRenderingHint.Text)
|
---|
162 | {
|
---|
163 | return new WpfTextRendering((SvgElement)element);
|
---|
164 | }
|
---|
165 |
|
---|
166 | string localName = element.LocalName;
|
---|
167 | if (String.IsNullOrEmpty(localName))
|
---|
168 | {
|
---|
169 | return new WpfRendering((SvgElement)element);
|
---|
170 | }
|
---|
171 |
|
---|
172 | switch (localName)
|
---|
173 | {
|
---|
174 | case "svg":
|
---|
175 | return new WpfSvgRendering((SvgElement)element);
|
---|
176 | case "g":
|
---|
177 | return new WpfGroupRendering((SvgElement)element);
|
---|
178 | case "a":
|
---|
179 | return new WpfARendering((SvgElement)element);
|
---|
180 | case "use":
|
---|
181 | return new WpfUseRendering((SvgElement)element);
|
---|
182 | case "switch":
|
---|
183 | return new WpfSwitchRendering((SvgElement)element);
|
---|
184 | case "image":
|
---|
185 | return new WpfImageRendering((SvgElement)element);
|
---|
186 | case "marker":
|
---|
187 | return new WpfMarkerRendering((SvgElement)element);
|
---|
188 | }
|
---|
189 |
|
---|
190 | return new WpfRendering((SvgElement)element);
|
---|
191 | }
|
---|
192 |
|
---|
193 | /// <summary>
|
---|
194 | /// Generates a new <see cref="RenderingNode">RenderingNode</see> that
|
---|
195 | /// corresponds to the given Uri.
|
---|
196 | /// </summary>
|
---|
197 | /// <param name="baseUri">
|
---|
198 | /// The base Uri.
|
---|
199 | /// </param>
|
---|
200 | /// <param name="url">
|
---|
201 | /// The url.
|
---|
202 | /// </param>
|
---|
203 | /// <returns>
|
---|
204 | /// The generated <see cref="RenderingNode">RenderingNode</see> that
|
---|
205 | /// corresponds to the given Uri.
|
---|
206 | /// </returns>
|
---|
207 | public static WpfRendering CreateByUri(SvgDocument document, string baseUri, string url)
|
---|
208 | {
|
---|
209 | if (url.StartsWith("#"))
|
---|
210 | {
|
---|
211 | // do nothing
|
---|
212 | }
|
---|
213 | else if (baseUri != "")
|
---|
214 | {
|
---|
215 | Uri absoluteUri = new Uri(new Uri(baseUri), url);
|
---|
216 | url = absoluteUri.AbsoluteUri;
|
---|
217 | }
|
---|
218 | else
|
---|
219 | {
|
---|
220 | // TODO: Handle xml:base here?
|
---|
221 | // Right now just skip this... it can't be resolved, must assume it is absolute
|
---|
222 | }
|
---|
223 | ISvgElement elm = document.GetNodeByUri(url) as ISvgElement;
|
---|
224 |
|
---|
225 | if (elm != null)
|
---|
226 | {
|
---|
227 | return WpfRendering.Create(elm);
|
---|
228 | }
|
---|
229 | else
|
---|
230 | {
|
---|
231 | return null;
|
---|
232 | }
|
---|
233 | }
|
---|
234 |
|
---|
235 | #endregion
|
---|
236 |
|
---|
237 | #region Protected Methods
|
---|
238 |
|
---|
239 | protected SvgTitleElement GetTitleElement()
|
---|
240 | {
|
---|
241 | if (_svgElement == null)
|
---|
242 | {
|
---|
243 | return null;
|
---|
244 | }
|
---|
245 |
|
---|
246 | SvgTitleElement titleElement = null;
|
---|
247 | foreach (XmlNode node in _svgElement.ChildNodes)
|
---|
248 | {
|
---|
249 | if (node.NodeType == XmlNodeType.Element &&
|
---|
250 | String.Equals(node.LocalName, "title", StringComparison.OrdinalIgnoreCase))
|
---|
251 | {
|
---|
252 | titleElement = node as SvgTitleElement;
|
---|
253 | break;
|
---|
254 | }
|
---|
255 | }
|
---|
256 |
|
---|
257 | return titleElement;
|
---|
258 | }
|
---|
259 |
|
---|
260 | protected void SetClip(WpfDrawingContext context)
|
---|
261 | {
|
---|
262 | _clipPathUnits = SvgUnitType.UserSpaceOnUse;
|
---|
263 |
|
---|
264 | if (_svgElement == null)
|
---|
265 | {
|
---|
266 | return;
|
---|
267 | }
|
---|
268 |
|
---|
269 | #region Clip with clip
|
---|
270 |
|
---|
271 | // see http://www.w3.org/TR/SVG/masking.html#OverflowAndClipProperties
|
---|
272 | if (_svgElement is ISvgSvgElement || _svgElement is ISvgMarkerElement ||
|
---|
273 | _svgElement is ISvgSymbolElement || _svgElement is ISvgPatternElement)
|
---|
274 | {
|
---|
275 | // check overflow property
|
---|
276 | CssValue overflow = _svgElement.GetComputedCssValue("overflow", String.Empty) as CssValue;
|
---|
277 | // TODO: clip can have "rect(10 10 auto 10)"
|
---|
278 | CssPrimitiveValue clip = _svgElement.GetComputedCssValue("clip", String.Empty) as CssPrimitiveValue;
|
---|
279 |
|
---|
280 | string sOverflow = null;
|
---|
281 |
|
---|
282 | if (overflow != null || overflow.CssText == "")
|
---|
283 | {
|
---|
284 | sOverflow = overflow.CssText;
|
---|
285 | }
|
---|
286 | else
|
---|
287 | {
|
---|
288 | if (this is ISvgSvgElement)
|
---|
289 | sOverflow = "hidden";
|
---|
290 | }
|
---|
291 |
|
---|
292 | if (sOverflow != null)
|
---|
293 | {
|
---|
294 | // "If the 'overflow' property has a value other than hidden or scroll, the property has no effect (i.e., a clipping rectangle is not created)."
|
---|
295 | if (sOverflow == "hidden" || sOverflow == "scroll")
|
---|
296 | {
|
---|
297 | Rect clipRect = Rect.Empty;
|
---|
298 | if (clip != null && clip.PrimitiveType == CssPrimitiveType.Rect)
|
---|
299 | {
|
---|
300 | if (_svgElement is ISvgSvgElement)
|
---|
301 | {
|
---|
302 | ISvgSvgElement svgElement = (ISvgSvgElement)_svgElement;
|
---|
303 | SvgRect viewPort = svgElement.Viewport as SvgRect;
|
---|
304 | clipRect = WpfConvert.ToRect(viewPort);
|
---|
305 | ICssRect clipShape = (CssRect)clip.GetRectValue();
|
---|
306 | if (clipShape.Top.PrimitiveType != CssPrimitiveType.Ident)
|
---|
307 | clipRect.Y += clipShape.Top.GetFloatValue(CssPrimitiveType.Number);
|
---|
308 | if (clipShape.Left.PrimitiveType != CssPrimitiveType.Ident)
|
---|
309 | clipRect.X += clipShape.Left.GetFloatValue(CssPrimitiveType.Number);
|
---|
310 | if (clipShape.Right.PrimitiveType != CssPrimitiveType.Ident)
|
---|
311 | clipRect.Width = (clipRect.Right - clipRect.X) - clipShape.Right.GetFloatValue(CssPrimitiveType.Number);
|
---|
312 | if (clipShape.Bottom.PrimitiveType != CssPrimitiveType.Ident)
|
---|
313 | clipRect.Height = (clipRect.Bottom - clipRect.Y) - clipShape.Bottom.GetFloatValue(CssPrimitiveType.Number);
|
---|
314 | }
|
---|
315 | }
|
---|
316 | else if (clip == null || (clip.PrimitiveType == CssPrimitiveType.Ident && clip.GetStringValue() == "auto"))
|
---|
317 | {
|
---|
318 | if (_svgElement is ISvgSvgElement)
|
---|
319 | {
|
---|
320 | ISvgSvgElement svgElement = (ISvgSvgElement)_svgElement;
|
---|
321 | SvgRect viewPort = svgElement.Viewport as SvgRect;
|
---|
322 | clipRect = WpfConvert.ToRect(viewPort);
|
---|
323 | }
|
---|
324 | else if (_svgElement is ISvgMarkerElement ||
|
---|
325 | _svgElement is ISvgSymbolElement ||
|
---|
326 | _svgElement is ISvgPatternElement)
|
---|
327 | {
|
---|
328 | // TODO: what to do here?
|
---|
329 | }
|
---|
330 | }
|
---|
331 | if (clipRect != Rect.Empty)
|
---|
332 | {
|
---|
333 | _clipGeometry = new RectangleGeometry(clipRect);
|
---|
334 | //gr.SetClip(clipRect);
|
---|
335 | }
|
---|
336 | }
|
---|
337 | }
|
---|
338 | }
|
---|
339 | #endregion
|
---|
340 |
|
---|
341 | #region Clip with clip-path
|
---|
342 |
|
---|
343 | SvgRenderingHint hint = _svgElement.RenderingHint;
|
---|
344 |
|
---|
345 | if (hint == SvgRenderingHint.Image)
|
---|
346 | {
|
---|
347 | }
|
---|
348 |
|
---|
349 | // see: http://www.w3.org/TR/SVG/masking.html#EstablishingANewClippingPath
|
---|
350 |
|
---|
351 | if (hint == SvgRenderingHint.Shape || hint == SvgRenderingHint.Text ||
|
---|
352 | hint == SvgRenderingHint.Clipping || hint == SvgRenderingHint.Masking ||
|
---|
353 | hint == SvgRenderingHint.Containment || hint == SvgRenderingHint.Image)
|
---|
354 | {
|
---|
355 | CssPrimitiveValue clipPath = _svgElement.GetComputedCssValue("clip-path", String.Empty) as CssPrimitiveValue;
|
---|
356 |
|
---|
357 | if (clipPath != null && clipPath.PrimitiveType == CssPrimitiveType.Uri)
|
---|
358 | {
|
---|
359 | string absoluteUri = _svgElement.ResolveUri(clipPath.GetStringValue());
|
---|
360 |
|
---|
361 | SvgClipPathElement eClipPath = _svgElement.OwnerDocument.GetNodeByUri(absoluteUri) as SvgClipPathElement;
|
---|
362 |
|
---|
363 | if (eClipPath != null)
|
---|
364 | {
|
---|
365 | GeometryCollection geomColl = CreateClippingRegion(eClipPath, context);
|
---|
366 | if (geomColl == null || geomColl.Count == 0)
|
---|
367 | {
|
---|
368 | return;
|
---|
369 | }
|
---|
370 | Geometry gpClip = geomColl[0];
|
---|
371 | int geomCount = geomColl.Count;
|
---|
372 | if (geomCount > 1)
|
---|
373 | {
|
---|
374 | //GeometryGroup clipGroup = new GeometryGroup();
|
---|
375 | //clipGroup.Children.Add(gpClip);
|
---|
376 | for (int k = 1; k < geomCount; k++)
|
---|
377 | {
|
---|
378 | gpClip = CombinedGeometry.Combine(gpClip, geomColl[k],
|
---|
379 | GeometryCombineMode.Union, null);
|
---|
380 | //clipGroup.Children.Add(geomColl[k]);
|
---|
381 | }
|
---|
382 |
|
---|
383 | //clipGroup.Children.Reverse();
|
---|
384 |
|
---|
385 | //gpClip = clipGroup;
|
---|
386 | }
|
---|
387 |
|
---|
388 | if (gpClip == null || gpClip.IsEmpty())
|
---|
389 | {
|
---|
390 | return;
|
---|
391 | }
|
---|
392 |
|
---|
393 | _clipPathUnits = (SvgUnitType)eClipPath.ClipPathUnits.AnimVal;
|
---|
394 |
|
---|
395 | //if (_clipPathUnits == SvgUnitType.ObjectBoundingBox)
|
---|
396 | //{
|
---|
397 | // SvgTransformableElement transElement = _svgElement as SvgTransformableElement;
|
---|
398 |
|
---|
399 | // if (transElement != null)
|
---|
400 | // {
|
---|
401 | // ISvgRect bbox = transElement.GetBBox();
|
---|
402 |
|
---|
403 | // // scale clipping path
|
---|
404 | // gpClip.Transform = new ScaleTransform(bbox.Width, bbox.Height);
|
---|
405 | // //gr.SetClip(gpClip);
|
---|
406 |
|
---|
407 | // // offset clip
|
---|
408 | // //TODO--PAUL gr.TranslateClip((float)bbox.X, (float)bbox.Y);
|
---|
409 |
|
---|
410 | // _clipGeometry = gpClip;
|
---|
411 | // }
|
---|
412 | // else
|
---|
413 | // {
|
---|
414 | // throw new NotImplementedException("clip-path with SvgUnitType.ObjectBoundingBox "
|
---|
415 | // + "not supported for this type of element: " + _svgElement.GetType());
|
---|
416 | // }
|
---|
417 | //}
|
---|
418 | //else
|
---|
419 | {
|
---|
420 | //gr.SetClip(gpClip);
|
---|
421 |
|
---|
422 | _clipGeometry = gpClip;
|
---|
423 | }
|
---|
424 | }
|
---|
425 | }
|
---|
426 | }
|
---|
427 |
|
---|
428 | #endregion
|
---|
429 | }
|
---|
430 |
|
---|
431 | protected void SetMask(WpfDrawingContext context)
|
---|
432 | {
|
---|
433 | _maskUnits = SvgUnitType.UserSpaceOnUse;
|
---|
434 | _maskContentUnits = SvgUnitType.UserSpaceOnUse;
|
---|
435 |
|
---|
436 | CssPrimitiveValue maskPath = _svgElement.GetComputedCssValue(
|
---|
437 | "mask", String.Empty) as CssPrimitiveValue;
|
---|
438 |
|
---|
439 | if (maskPath != null && maskPath.PrimitiveType == CssPrimitiveType.Uri)
|
---|
440 | {
|
---|
441 | string absoluteUri = _svgElement.ResolveUri(maskPath.GetStringValue());
|
---|
442 |
|
---|
443 | SvgMaskElement maskElement =
|
---|
444 | _svgElement.OwnerDocument.GetNodeByUri(absoluteUri) as SvgMaskElement;
|
---|
445 |
|
---|
446 | if (maskElement != null)
|
---|
447 | {
|
---|
448 | WpfDrawingRenderer renderer = new WpfDrawingRenderer();
|
---|
449 | renderer.Window = _svgElement.OwnerDocument.Window as SvgWindow;
|
---|
450 |
|
---|
451 | WpfDrawingSettings settings = context.Settings.Clone();
|
---|
452 | settings.TextAsGeometry = true;
|
---|
453 | WpfDrawingContext maskContext = new WpfDrawingContext(true,
|
---|
454 | settings);
|
---|
455 |
|
---|
456 | maskContext.Initialize(null, context.FontFamilyVisitor, null);
|
---|
457 |
|
---|
458 | renderer.RenderMask(maskElement, maskContext);
|
---|
459 | Drawing image = renderer.Drawing;
|
---|
460 |
|
---|
461 | Rect bounds = new Rect(0, 0, 1, 1);
|
---|
462 | //Rect destRect = GetMaskDestRect(maskElement, bounds);
|
---|
463 |
|
---|
464 | //destRect = bounds;
|
---|
465 |
|
---|
466 | //DrawingImage drawImage = new DrawingImage(image);
|
---|
467 |
|
---|
468 | //DrawingVisual drawingVisual = new DrawingVisual();
|
---|
469 | //DrawingContext drawingContext = drawingVisual.RenderOpen();
|
---|
470 | //drawingContext.DrawDrawing(image);
|
---|
471 | //drawingContext.Close();
|
---|
472 |
|
---|
473 | //RenderTargetBitmap drawImage = new RenderTargetBitmap((int)200,
|
---|
474 | // (int)200, 96, 96, PixelFormats.Pbgra32);
|
---|
475 | //drawImage.Render(drawingVisual);
|
---|
476 |
|
---|
477 | //ImageBrush imageBrush = new ImageBrush(drawImage);
|
---|
478 | //imageBrush.Viewbox = image.Bounds;
|
---|
479 | //imageBrush.Viewport = image.Bounds;
|
---|
480 | //imageBrush.ViewboxUnits = BrushMappingMode.Absolute;
|
---|
481 | //imageBrush.ViewportUnits = BrushMappingMode.Absolute;
|
---|
482 | //imageBrush.TileMode = TileMode.None;
|
---|
483 | //imageBrush.Stretch = Stretch.None;
|
---|
484 |
|
---|
485 | //this.Masking = imageBrush;
|
---|
486 |
|
---|
487 | DrawingBrush maskBrush = new DrawingBrush(image);
|
---|
488 | //tb.Viewbox = new Rect(0, 0, destRect.Width, destRect.Height);
|
---|
489 | //tb.Viewport = new Rect(0, 0, destRect.Width, destRect.Height);
|
---|
490 | maskBrush.Viewbox = image.Bounds;
|
---|
491 | maskBrush.Viewport = image.Bounds;
|
---|
492 | maskBrush.ViewboxUnits = BrushMappingMode.Absolute;
|
---|
493 | maskBrush.ViewportUnits = BrushMappingMode.Absolute;
|
---|
494 | maskBrush.TileMode = TileMode.None;
|
---|
495 | maskBrush.Stretch = Stretch.Uniform;
|
---|
496 |
|
---|
497 | ////maskBrush.AlignmentX = AlignmentX.Center;
|
---|
498 | ////maskBrush.AlignmentY = AlignmentY.Center;
|
---|
499 |
|
---|
500 | this.Masking = maskBrush;
|
---|
501 |
|
---|
502 | _maskUnits = (SvgUnitType)maskElement.MaskUnits.AnimVal;
|
---|
503 | _maskContentUnits = (SvgUnitType)maskElement.MaskContentUnits.AnimVal;
|
---|
504 |
|
---|
505 | }
|
---|
506 | }
|
---|
507 | }
|
---|
508 |
|
---|
509 | private static double CalcPatternUnit(SvgMaskElement maskElement, SvgLength length,
|
---|
510 | SvgLengthDirection dir, Rect bounds)
|
---|
511 | {
|
---|
512 | if (maskElement.MaskUnits.AnimVal.Equals(SvgUnitType.UserSpaceOnUse))
|
---|
513 | {
|
---|
514 | return length.Value;
|
---|
515 | }
|
---|
516 | else
|
---|
517 | {
|
---|
518 | double calcValue = length.ValueInSpecifiedUnits;
|
---|
519 | if (dir == SvgLengthDirection.Horizontal)
|
---|
520 | {
|
---|
521 | calcValue *= bounds.Width;
|
---|
522 | }
|
---|
523 | else
|
---|
524 | {
|
---|
525 | calcValue *= bounds.Height;
|
---|
526 | }
|
---|
527 | if (length.UnitType == SvgLengthType.Percentage)
|
---|
528 | {
|
---|
529 | calcValue /= 100F;
|
---|
530 | }
|
---|
531 |
|
---|
532 | return calcValue;
|
---|
533 | }
|
---|
534 | }
|
---|
535 |
|
---|
536 | private static Rect GetMaskDestRect(SvgMaskElement maskElement, Rect bounds)
|
---|
537 | {
|
---|
538 | Rect result = new Rect(0, 0, 0, 0);
|
---|
539 |
|
---|
540 | result.X = CalcPatternUnit(maskElement, maskElement.X.AnimVal as SvgLength,
|
---|
541 | SvgLengthDirection.Horizontal, bounds);
|
---|
542 | result.Y = CalcPatternUnit(maskElement, maskElement.Y.AnimVal as SvgLength,
|
---|
543 | SvgLengthDirection.Vertical, bounds);
|
---|
544 |
|
---|
545 | result.Width = CalcPatternUnit(maskElement, maskElement.Width.AnimVal as SvgLength,
|
---|
546 | SvgLengthDirection.Horizontal, bounds);
|
---|
547 | result.Height = CalcPatternUnit(maskElement, maskElement.Height.AnimVal as SvgLength,
|
---|
548 | SvgLengthDirection.Vertical, bounds);
|
---|
549 |
|
---|
550 | return result;
|
---|
551 | }
|
---|
552 |
|
---|
553 | protected void SetQuality(WpfDrawingContext context)
|
---|
554 | {
|
---|
555 | //Graphics graphics = gr.Graphics;
|
---|
556 |
|
---|
557 | //string colorRendering = _svgElement.GetComputedStringValue("color-rendering", String.Empty);
|
---|
558 | //switch (colorRendering)
|
---|
559 | //{
|
---|
560 | // case "optimizeSpeed":
|
---|
561 | // graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
|
---|
562 | // break;
|
---|
563 | // case "optimizeQuality":
|
---|
564 | // graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
|
---|
565 | // break;
|
---|
566 | // default:
|
---|
567 | // // "auto"
|
---|
568 | // // todo: could use AssumeLinear for slightly better
|
---|
569 | // graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.Default;
|
---|
570 | // break;
|
---|
571 | //}
|
---|
572 |
|
---|
573 | //if (element is SvgTextContentElement)
|
---|
574 | //{
|
---|
575 | // // Unfortunately the text rendering hints are not applied because the
|
---|
576 | // // text path is recorded and painted to the Graphics object as a path
|
---|
577 | // // not as text.
|
---|
578 | // string textRendering = _svgElement.GetComputedStringValue("text-rendering", String.Empty);
|
---|
579 | // switch (textRendering)
|
---|
580 | // {
|
---|
581 | // case "optimizeSpeed":
|
---|
582 | // graphics.SmoothingMode = SmoothingMode.HighSpeed;
|
---|
583 | // //graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel;
|
---|
584 | // break;
|
---|
585 | // case "optimizeLegibility":
|
---|
586 | // graphics.SmoothingMode = SmoothingMode.HighQuality;
|
---|
587 | // //graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
|
---|
588 | // break;
|
---|
589 | // case "geometricPrecision":
|
---|
590 | // graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
---|
591 | // //graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
|
---|
592 | // break;
|
---|
593 | // default:
|
---|
594 | // // "auto"
|
---|
595 | // graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
---|
596 | // //graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault;
|
---|
597 | // break;
|
---|
598 | // }
|
---|
599 | //}
|
---|
600 | //else
|
---|
601 | //{
|
---|
602 | // string shapeRendering = _svgElement.GetComputedStringValue("shape-rendering", String.Empty);
|
---|
603 | // switch (shapeRendering)
|
---|
604 | // {
|
---|
605 | // case "optimizeSpeed":
|
---|
606 | // graphics.SmoothingMode = SmoothingMode.HighSpeed;
|
---|
607 | // break;
|
---|
608 | // case "crispEdges":
|
---|
609 | // graphics.SmoothingMode = SmoothingMode.None;
|
---|
610 | // break;
|
---|
611 | // case "geometricPrecision":
|
---|
612 | // graphics.SmoothingMode = SmoothingMode.HighQuality;
|
---|
613 | // break;
|
---|
614 | // default:
|
---|
615 | // // "auto"
|
---|
616 | // graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
---|
617 | // break;
|
---|
618 | // }
|
---|
619 | //}
|
---|
620 | }
|
---|
621 |
|
---|
622 | protected void SetTransform(WpfDrawingContext context)
|
---|
623 | {
|
---|
624 | _transformMatrix = null;
|
---|
625 |
|
---|
626 | ISvgTransformable transElm = _svgElement as ISvgTransformable;
|
---|
627 | if (transElm != null)
|
---|
628 | {
|
---|
629 | SvgTransformList svgTList = (SvgTransformList)transElm.Transform.AnimVal;
|
---|
630 | SvgMatrix svgMatrix = ((SvgTransformList)transElm.Transform.AnimVal).TotalMatrix;
|
---|
631 |
|
---|
632 | if (svgMatrix.IsIdentity)
|
---|
633 | {
|
---|
634 | return;
|
---|
635 | }
|
---|
636 |
|
---|
637 | _transformMatrix = new MatrixTransform(svgMatrix.A, svgMatrix.B, svgMatrix.C,
|
---|
638 | svgMatrix.D, svgMatrix.E, svgMatrix.F);
|
---|
639 | }
|
---|
640 | }
|
---|
641 |
|
---|
642 | protected void FitToViewbox(WpfDrawingContext context, Rect elementBounds)
|
---|
643 | {
|
---|
644 | ISvgFitToViewBox fitToView = _svgElement as ISvgFitToViewBox;
|
---|
645 | if (fitToView == null)
|
---|
646 | {
|
---|
647 | return;
|
---|
648 | }
|
---|
649 |
|
---|
650 | SvgPreserveAspectRatio spar = (SvgPreserveAspectRatio)fitToView.PreserveAspectRatio.AnimVal;
|
---|
651 |
|
---|
652 | double[] transformArray = spar.FitToViewBox((SvgRect)fitToView.ViewBox.AnimVal,
|
---|
653 | new SvgRect(elementBounds.X, elementBounds.Y, elementBounds.Width, elementBounds.Height));
|
---|
654 |
|
---|
655 | double translateX = transformArray[0];
|
---|
656 | double translateY = transformArray[1];
|
---|
657 | double scaleX = transformArray[2];
|
---|
658 | double scaleY = transformArray[3];
|
---|
659 |
|
---|
660 | Transform translateMatrix = null;
|
---|
661 | Transform scaleMatrix = null;
|
---|
662 | //if (translateX >= 0 && translateY >= 0)
|
---|
663 | {
|
---|
664 | translateMatrix = new TranslateTransform(translateX, translateY);
|
---|
665 | }
|
---|
666 | if ((float)scaleX != 1.0f && (float)scaleY != 1.0f)
|
---|
667 | {
|
---|
668 | scaleMatrix = new ScaleTransform(scaleX, scaleY);
|
---|
669 | }
|
---|
670 |
|
---|
671 | if (translateMatrix != null && scaleMatrix != null)
|
---|
672 | {
|
---|
673 | // Create a TransformGroup to contain the transforms
|
---|
674 | // and add the transforms to it.
|
---|
675 | TransformGroup transformGroup = new TransformGroup();
|
---|
676 | transformGroup.Children.Add(scaleMatrix);
|
---|
677 | transformGroup.Children.Add(translateMatrix);
|
---|
678 |
|
---|
679 | this.Transform = transformGroup;
|
---|
680 | }
|
---|
681 | else if (translateMatrix != null)
|
---|
682 | {
|
---|
683 | this.Transform = translateMatrix;
|
---|
684 | }
|
---|
685 | else if (scaleMatrix != null)
|
---|
686 | {
|
---|
687 | this.Transform = scaleMatrix;
|
---|
688 | }
|
---|
689 | }
|
---|
690 |
|
---|
691 | protected void FitToViewbox(WpfDrawingContext context, SvgElement svgElement, Rect elementBounds)
|
---|
692 | {
|
---|
693 | if (svgElement == null)
|
---|
694 | {
|
---|
695 | return;
|
---|
696 | }
|
---|
697 | ISvgFitToViewBox fitToView = svgElement as ISvgFitToViewBox;
|
---|
698 | if (fitToView == null)
|
---|
699 | {
|
---|
700 | return;
|
---|
701 | }
|
---|
702 |
|
---|
703 | SvgPreserveAspectRatio spar = (SvgPreserveAspectRatio)fitToView.PreserveAspectRatio.AnimVal;
|
---|
704 |
|
---|
705 | double[] transformArray = spar.FitToViewBox((SvgRect)fitToView.ViewBox.AnimVal,
|
---|
706 | new SvgRect(elementBounds.X, elementBounds.Y, elementBounds.Width, elementBounds.Height));
|
---|
707 |
|
---|
708 | double translateX = transformArray[0];
|
---|
709 | double translateY = transformArray[1];
|
---|
710 | double scaleX = transformArray[2];
|
---|
711 | double scaleY = transformArray[3];
|
---|
712 |
|
---|
713 | Transform translateMatrix = null;
|
---|
714 | Transform scaleMatrix = null;
|
---|
715 | //if (translateX > 0 && translateY > 0)
|
---|
716 | {
|
---|
717 | translateMatrix = new TranslateTransform(translateX, translateY);
|
---|
718 | }
|
---|
719 | if ((float)scaleX != 1.0f && (float)scaleY != 1.0f)
|
---|
720 | {
|
---|
721 | scaleMatrix = new ScaleTransform(scaleX, scaleY);
|
---|
722 | }
|
---|
723 |
|
---|
724 | if (translateMatrix != null && scaleMatrix != null)
|
---|
725 | {
|
---|
726 | // Create a TransformGroup to contain the transforms
|
---|
727 | // and add the transforms to it.
|
---|
728 | TransformGroup transformGroup = new TransformGroup();
|
---|
729 | transformGroup.Children.Add(scaleMatrix);
|
---|
730 | transformGroup.Children.Add(translateMatrix);
|
---|
731 |
|
---|
732 | this.Transform = transformGroup;
|
---|
733 | }
|
---|
734 | else if (translateMatrix != null)
|
---|
735 | {
|
---|
736 | this.Transform = translateMatrix;
|
---|
737 | }
|
---|
738 | else if (scaleMatrix != null)
|
---|
739 | {
|
---|
740 | this.Transform = scaleMatrix;
|
---|
741 | }
|
---|
742 | }
|
---|
743 |
|
---|
744 | #endregion
|
---|
745 |
|
---|
746 | #region Private Methods
|
---|
747 |
|
---|
748 | private GeometryCollection CreateClippingRegion(SvgClipPathElement clipPath,
|
---|
749 | WpfDrawingContext context)
|
---|
750 | {
|
---|
751 | GeometryCollection geomColl = new GeometryCollection();
|
---|
752 |
|
---|
753 | foreach (XmlNode node in clipPath.ChildNodes)
|
---|
754 | {
|
---|
755 | if (node.NodeType != XmlNodeType.Element)
|
---|
756 | {
|
---|
757 | continue;
|
---|
758 | }
|
---|
759 |
|
---|
760 | // Handle a case where the clip element has "use" element as a child...
|
---|
761 | if (String.Equals(node.LocalName, "use"))
|
---|
762 | {
|
---|
763 | SvgUseElement useElement = (SvgUseElement)node;
|
---|
764 |
|
---|
765 | XmlElement refEl = useElement.ReferencedElement;
|
---|
766 | if (refEl != null)
|
---|
767 | {
|
---|
768 | XmlElement refElParent = (XmlElement)refEl.ParentNode;
|
---|
769 | useElement.OwnerDocument.Static = true;
|
---|
770 | useElement.CopyToReferencedElement(refEl);
|
---|
771 | refElParent.RemoveChild(refEl);
|
---|
772 | useElement.AppendChild(refEl);
|
---|
773 |
|
---|
774 | foreach (XmlNode useChild in useElement.ChildNodes)
|
---|
775 | {
|
---|
776 | if (useChild.NodeType != XmlNodeType.Element)
|
---|
777 | {
|
---|
778 | continue;
|
---|
779 | }
|
---|
780 |
|
---|
781 | SvgStyleableElement element = useChild as SvgStyleableElement;
|
---|
782 | if (element != null && element.RenderingHint == SvgRenderingHint.Shape)
|
---|
783 | {
|
---|
784 | Geometry childPath = CreateGeometry(element, context.OptimizePath);
|
---|
785 |
|
---|
786 | if (childPath != null)
|
---|
787 | {
|
---|
788 | geomColl.Add(childPath);
|
---|
789 | }
|
---|
790 | }
|
---|
791 | }
|
---|
792 |
|
---|
793 | useElement.RemoveChild(refEl);
|
---|
794 | useElement.RestoreReferencedElement(refEl);
|
---|
795 | refElParent.AppendChild(refEl);
|
---|
796 | useElement.OwnerDocument.Static = false;
|
---|
797 | }
|
---|
798 | }
|
---|
799 | else
|
---|
800 | {
|
---|
801 | SvgStyleableElement element = node as SvgStyleableElement;
|
---|
802 | if (element != null)
|
---|
803 | {
|
---|
804 | if (element.RenderingHint == SvgRenderingHint.Shape)
|
---|
805 | {
|
---|
806 | Geometry childPath = CreateGeometry(element, context.OptimizePath);
|
---|
807 |
|
---|
808 | if (childPath != null)
|
---|
809 | {
|
---|
810 | geomColl.Add(childPath);
|
---|
811 | }
|
---|
812 | }
|
---|
813 | else if (element.RenderingHint == SvgRenderingHint.Text)
|
---|
814 | {
|
---|
815 | GeometryCollection textGeomColl = GetTextClippingRegion(element, context);
|
---|
816 | if (textGeomColl != null)
|
---|
817 | {
|
---|
818 | for (int i = 0; i < textGeomColl.Count; i++)
|
---|
819 | {
|
---|
820 | geomColl.Add(textGeomColl[i]);
|
---|
821 | }
|
---|
822 | }
|
---|
823 | }
|
---|
824 | }
|
---|
825 | }
|
---|
826 | }
|
---|
827 |
|
---|
828 | return geomColl;
|
---|
829 | }
|
---|
830 |
|
---|
831 | private GeometryCollection GetTextClippingRegion(SvgStyleableElement element,
|
---|
832 | WpfDrawingContext context)
|
---|
833 | {
|
---|
834 | GeometryCollection geomColl = new GeometryCollection();
|
---|
835 |
|
---|
836 | WpfDrawingRenderer renderer = new WpfDrawingRenderer();
|
---|
837 | renderer.Window = _svgElement.OwnerDocument.Window as SvgWindow;
|
---|
838 |
|
---|
839 | WpfDrawingSettings settings = context.Settings.Clone();
|
---|
840 | settings.TextAsGeometry = true;
|
---|
841 | WpfDrawingContext clipContext = new WpfDrawingContext(true,
|
---|
842 | settings);
|
---|
843 | clipContext.RenderingClipRegion = true;
|
---|
844 |
|
---|
845 | clipContext.Initialize(null, context.FontFamilyVisitor, null);
|
---|
846 |
|
---|
847 | renderer.Render(element, clipContext);
|
---|
848 |
|
---|
849 | DrawingGroup rootGroup = renderer.Drawing as DrawingGroup;
|
---|
850 | if (rootGroup != null && rootGroup.Children.Count == 1)
|
---|
851 | {
|
---|
852 | DrawingGroup textGroup = rootGroup.Children[0] as DrawingGroup;
|
---|
853 | if (textGroup != null)
|
---|
854 | {
|
---|
855 | ExtractGeometry(textGroup, geomColl);
|
---|
856 | }
|
---|
857 | }
|
---|
858 |
|
---|
859 | return geomColl;
|
---|
860 | }
|
---|
861 |
|
---|
862 | private static void ExtractGeometry(DrawingGroup group, GeometryCollection geomColl)
|
---|
863 | {
|
---|
864 | if (geomColl == null)
|
---|
865 | {
|
---|
866 | return;
|
---|
867 | }
|
---|
868 |
|
---|
869 | DrawingCollection drawings = group.Children;
|
---|
870 | int textItem = drawings.Count;
|
---|
871 | for (int i = 0; i < textItem; i++)
|
---|
872 | {
|
---|
873 | Drawing drawing = drawings[i];
|
---|
874 | GeometryDrawing aDrawing = drawing as GeometryDrawing;
|
---|
875 | if (aDrawing != null)
|
---|
876 | {
|
---|
877 | Geometry aGeometry = aDrawing.Geometry;
|
---|
878 | if (aGeometry != null)
|
---|
879 | {
|
---|
880 | GeometryGroup geomGroup = aGeometry as GeometryGroup;
|
---|
881 | if (geomGroup != null)
|
---|
882 | {
|
---|
883 | GeometryCollection children = geomGroup.Children;
|
---|
884 | for (int j = 0; j < children.Count; j++)
|
---|
885 | {
|
---|
886 | geomColl.Add(children[j]);
|
---|
887 | }
|
---|
888 | }
|
---|
889 | else
|
---|
890 | {
|
---|
891 | geomColl.Add(aGeometry);
|
---|
892 | }
|
---|
893 | }
|
---|
894 | }
|
---|
895 | else
|
---|
896 | {
|
---|
897 | DrawingGroup innerGroup = drawing as DrawingGroup;
|
---|
898 | if (innerGroup != null)
|
---|
899 | {
|
---|
900 | ExtractGeometry(innerGroup, geomColl);
|
---|
901 | }
|
---|
902 | }
|
---|
903 | }
|
---|
904 | }
|
---|
905 |
|
---|
906 |
|
---|
907 | #endregion
|
---|
908 |
|
---|
909 | #region Geometry Methods
|
---|
910 |
|
---|
911 | public static Geometry CreateGeometry(ISvgElement element, bool optimizePath)
|
---|
912 | {
|
---|
913 | if (element == null || element.RenderingHint != SvgRenderingHint.Shape)
|
---|
914 | {
|
---|
915 | return null;
|
---|
916 | }
|
---|
917 |
|
---|
918 | string localName = element.LocalName;
|
---|
919 | switch (localName)
|
---|
920 | {
|
---|
921 | case "ellipse":
|
---|
922 | return CreateGeometry((SvgEllipseElement)element);
|
---|
923 | case "rect":
|
---|
924 | return CreateGeometry((SvgRectElement)element);
|
---|
925 | case "line":
|
---|
926 | return CreateGeometry((SvgLineElement)element);
|
---|
927 | case "path":
|
---|
928 | if (optimizePath)
|
---|
929 | {
|
---|
930 | return CreateGeometryEx((SvgPathElement)element);
|
---|
931 | }
|
---|
932 | else
|
---|
933 | {
|
---|
934 | return CreateGeometry((SvgPathElement)element);
|
---|
935 | }
|
---|
936 | case "circle":
|
---|
937 | return CreateGeometry((SvgCircleElement)element);
|
---|
938 | case "polyline":
|
---|
939 | return CreateGeometry((SvgPolylineElement)element);
|
---|
940 | case "polygon":
|
---|
941 | return CreateGeometry((SvgPolygonElement)element);
|
---|
942 | }
|
---|
943 |
|
---|
944 | return null;
|
---|
945 | }
|
---|
946 |
|
---|
947 | #region SvgEllipseElement Geometry
|
---|
948 |
|
---|
949 | public static Geometry CreateGeometry(SvgEllipseElement element)
|
---|
950 | {
|
---|
951 | double _cx = Math.Round(element.Cx.AnimVal.Value, 4);
|
---|
952 | double _cy = Math.Round(element.Cy.AnimVal.Value, 4);
|
---|
953 | double _rx = Math.Round(element.Rx.AnimVal.Value, 4);
|
---|
954 | double _ry = Math.Round(element.Ry.AnimVal.Value, 4);
|
---|
955 |
|
---|
956 | if (_rx <= 0 || _ry <= 0)
|
---|
957 | {
|
---|
958 | return null;
|
---|
959 | }
|
---|
960 |
|
---|
961 | /*if (_cx <= 1 && _cy <= 1 && _rx <= 1 && _ry <= 1)
|
---|
962 | {
|
---|
963 | gp.AddEllipse(_cx-_rx, _cy-_ry, _rx*2, _ry*2);
|
---|
964 | }
|
---|
965 | else
|
---|
966 | {
|
---|
967 | gp.AddEllipse(_cx-_rx, _cy-_ry, _rx*2 - 1, _ry*2 - 1);
|
---|
968 | }*/
|
---|
969 | //gp.AddEllipse(_cx - _rx, _cy - _ry, _rx * 2, _ry * 2);
|
---|
970 |
|
---|
971 | EllipseGeometry geometry = new EllipseGeometry(new Point(_cx, _cy),
|
---|
972 | _rx, _ry);
|
---|
973 |
|
---|
974 | return geometry;
|
---|
975 | }
|
---|
976 |
|
---|
977 | #endregion
|
---|
978 |
|
---|
979 | #region SvgRectElement Geometry
|
---|
980 |
|
---|
981 | public static Geometry CreateGeometry(SvgRectElement element)
|
---|
982 | {
|
---|
983 | double dx = Math.Round(element.X.AnimVal.Value, 4);
|
---|
984 | double dy = Math.Round(element.Y.AnimVal.Value, 4);
|
---|
985 | double width = Math.Round(element.Width.AnimVal.Value, 4);
|
---|
986 | double height = Math.Round(element.Height.AnimVal.Value, 4);
|
---|
987 | double rx = Math.Round(element.Rx.AnimVal.Value, 4);
|
---|
988 | double ry = Math.Round(element.Ry.AnimVal.Value, 4);
|
---|
989 |
|
---|
990 | if (width <= 0 || height <= 0)
|
---|
991 | {
|
---|
992 | return null;
|
---|
993 | }
|
---|
994 | if (rx <= 0 && ry > 0)
|
---|
995 | {
|
---|
996 | rx = ry;
|
---|
997 | }
|
---|
998 | else if (rx > 0 && ry <= 0)
|
---|
999 | {
|
---|
1000 | ry = rx;
|
---|
1001 | }
|
---|
1002 |
|
---|
1003 | return new RectangleGeometry(new Rect(dx, dy, width, height), rx, ry);
|
---|
1004 | }
|
---|
1005 |
|
---|
1006 | #endregion
|
---|
1007 |
|
---|
1008 | #region SvgLineElement Geometry
|
---|
1009 |
|
---|
1010 | public static Geometry CreateGeometry(SvgLineElement element)
|
---|
1011 | {
|
---|
1012 | return new LineGeometry(new Point(Math.Round(element.X1.AnimVal.Value, 4),
|
---|
1013 | Math.Round(element.Y1.AnimVal.Value, 4)),
|
---|
1014 | new Point(Math.Round(element.X2.AnimVal.Value, 4), Math.Round(element.Y2.AnimVal.Value, 4)));
|
---|
1015 | }
|
---|
1016 |
|
---|
1017 | #endregion
|
---|
1018 |
|
---|
1019 | #region SvgPathElement Geometry
|
---|
1020 |
|
---|
1021 | public static Geometry CreateGeometryEx(SvgPathElement element)
|
---|
1022 | {
|
---|
1023 | PathGeometry geometry = new PathGeometry();
|
---|
1024 |
|
---|
1025 | string pathScript = element.PathScript;
|
---|
1026 | if (String.IsNullOrEmpty(pathScript))
|
---|
1027 | {
|
---|
1028 | return geometry;
|
---|
1029 | }
|
---|
1030 |
|
---|
1031 | string fillRule = element.GetPropertyValue("fill-rule");
|
---|
1032 | string clipRule = element.GetAttribute("clip-rule");
|
---|
1033 | if (!String.IsNullOrEmpty(clipRule) &&
|
---|
1034 | String.Equals(clipRule, "evenodd") || String.Equals(clipRule, "nonzero"))
|
---|
1035 | {
|
---|
1036 | fillRule = clipRule;
|
---|
1037 | }
|
---|
1038 | if (fillRule == "evenodd")
|
---|
1039 | geometry.FillRule = FillRule.EvenOdd;
|
---|
1040 | else if (fillRule == "nonzero")
|
---|
1041 | geometry.FillRule = FillRule.Nonzero;
|
---|
1042 |
|
---|
1043 | try
|
---|
1044 | {
|
---|
1045 | geometry.Figures = PathFigureCollection.Parse(pathScript);
|
---|
1046 | }
|
---|
1047 | catch
|
---|
1048 | {
|
---|
1049 | }
|
---|
1050 |
|
---|
1051 | return geometry;
|
---|
1052 | }
|
---|
1053 |
|
---|
1054 | public static Geometry CreateGeometry(SvgPathElement element)
|
---|
1055 | {
|
---|
1056 | PathGeometry geometry = new PathGeometry();
|
---|
1057 |
|
---|
1058 | string fillRule = element.GetPropertyValue("fill-rule");
|
---|
1059 | string clipRule = element.GetAttribute("clip-rule");
|
---|
1060 | if (!String.IsNullOrEmpty(clipRule) &&
|
---|
1061 | String.Equals(clipRule, "evenodd") || String.Equals(clipRule, "nonzero"))
|
---|
1062 | {
|
---|
1063 | fillRule = clipRule;
|
---|
1064 | }
|
---|
1065 | if (fillRule == "evenodd")
|
---|
1066 | geometry.FillRule = FillRule.EvenOdd;
|
---|
1067 | else if (fillRule == "nonzero")
|
---|
1068 | geometry.FillRule = FillRule.Nonzero;
|
---|
1069 |
|
---|
1070 | SvgPointF initPoint = new SvgPointF(0, 0);
|
---|
1071 | SvgPointF lastPoint = new SvgPointF(0, 0);
|
---|
1072 |
|
---|
1073 | ISvgPathSeg segment = null;
|
---|
1074 | SvgPathSegMoveto pathMoveTo = null;
|
---|
1075 | SvgPathSegLineto pathLineTo = null;
|
---|
1076 | SvgPathSegCurveto pathCurveTo = null;
|
---|
1077 | SvgPathSegArc pathArc = null;
|
---|
1078 |
|
---|
1079 | ISvgPathSegList segments = element.PathSegList;
|
---|
1080 | int nElems = segments.NumberOfItems;
|
---|
1081 |
|
---|
1082 | PathFigure pathFigure = null;
|
---|
1083 |
|
---|
1084 | for (int i = 0; i < nElems; i++)
|
---|
1085 | {
|
---|
1086 | segment = segments.GetItem(i);
|
---|
1087 |
|
---|
1088 | if (DynamicCast.Cast(segment, out pathMoveTo))
|
---|
1089 | {
|
---|
1090 | if (pathFigure != null)
|
---|
1091 | {
|
---|
1092 | pathFigure.IsClosed = false;
|
---|
1093 | pathFigure.IsFilled = true;
|
---|
1094 | geometry.Figures.Add(pathFigure);
|
---|
1095 | pathFigure = null;
|
---|
1096 | }
|
---|
1097 |
|
---|
1098 | lastPoint = initPoint = pathMoveTo.AbsXY;
|
---|
1099 |
|
---|
1100 | pathFigure = new PathFigure();
|
---|
1101 | pathFigure.StartPoint = new Point(initPoint.ValueX, initPoint.ValueY);
|
---|
1102 | }
|
---|
1103 | else if (DynamicCast.Cast(segment, out pathLineTo))
|
---|
1104 | {
|
---|
1105 | SvgPointF p = pathLineTo.AbsXY;
|
---|
1106 | pathFigure.Segments.Add(new LineSegment(new Point(p.ValueX, p.ValueY), true));
|
---|
1107 |
|
---|
1108 | lastPoint = p;
|
---|
1109 | }
|
---|
1110 | else if (DynamicCast.Cast(segment, out pathCurveTo))
|
---|
1111 | {
|
---|
1112 | SvgPointF xy = pathCurveTo.AbsXY;
|
---|
1113 | SvgPointF x1y1 = pathCurveTo.CubicX1Y1;
|
---|
1114 | SvgPointF x2y2 = pathCurveTo.CubicX2Y2;
|
---|
1115 | pathFigure.Segments.Add(new BezierSegment(new Point(x1y1.ValueX, x1y1.ValueY),
|
---|
1116 | new Point(x2y2.ValueX, x2y2.ValueY), new Point(xy.ValueX, xy.ValueY), true));
|
---|
1117 |
|
---|
1118 | lastPoint = xy;
|
---|
1119 | }
|
---|
1120 | else if (DynamicCast.Cast(segment, out pathArc))
|
---|
1121 | {
|
---|
1122 | SvgPointF p = pathArc.AbsXY;
|
---|
1123 | if (lastPoint.Equals(p))
|
---|
1124 | {
|
---|
1125 | // If the endpoints (x, y) and (x0, y0) are identical, then this
|
---|
1126 | // is equivalent to omitting the elliptical arc segment entirely.
|
---|
1127 | }
|
---|
1128 | else if (pathArc.R1 == 0 || pathArc.R2 == 0)
|
---|
1129 | {
|
---|
1130 | // Ensure radii are valid
|
---|
1131 | pathFigure.Segments.Add(new LineSegment(new Point(p.ValueX, p.ValueY), true));
|
---|
1132 | }
|
---|
1133 | else
|
---|
1134 | {
|
---|
1135 | CalculatedArcValues calcValues = pathArc.GetCalculatedArcValues();
|
---|
1136 |
|
---|
1137 | pathFigure.Segments.Add(new ArcSegment(new Point(p.ValueX, p.ValueY),
|
---|
1138 | new Size(pathArc.R1, pathArc.R2), pathArc.Angle, pathArc.LargeArcFlag,
|
---|
1139 | pathArc.SweepFlag ? SweepDirection.Clockwise : SweepDirection.Counterclockwise,
|
---|
1140 | true));
|
---|
1141 | }
|
---|
1142 |
|
---|
1143 | lastPoint = p;
|
---|
1144 | }
|
---|
1145 | else if (segment is SvgPathSegClosePath)
|
---|
1146 | {
|
---|
1147 | if (pathFigure != null)
|
---|
1148 | {
|
---|
1149 | pathFigure.IsClosed = true;
|
---|
1150 | pathFigure.IsFilled = true;
|
---|
1151 | geometry.Figures.Add(pathFigure);
|
---|
1152 | pathFigure = null;
|
---|
1153 | }
|
---|
1154 |
|
---|
1155 | lastPoint = initPoint;
|
---|
1156 | }
|
---|
1157 | }
|
---|
1158 |
|
---|
1159 | if (pathFigure != null)
|
---|
1160 | {
|
---|
1161 | pathFigure.IsClosed = false;
|
---|
1162 | pathFigure.IsFilled = true;
|
---|
1163 | geometry.Figures.Add(pathFigure);
|
---|
1164 | }
|
---|
1165 |
|
---|
1166 | return geometry;
|
---|
1167 | }
|
---|
1168 |
|
---|
1169 | #endregion
|
---|
1170 |
|
---|
1171 | #region SvgCircleElement Geometry
|
---|
1172 |
|
---|
1173 | public static Geometry CreateGeometry(SvgCircleElement element)
|
---|
1174 | {
|
---|
1175 | double _cx = Math.Round(element.Cx.AnimVal.Value, 4);
|
---|
1176 | double _cy = Math.Round(element.Cy.AnimVal.Value, 4);
|
---|
1177 | double _r = Math.Round(element.R.AnimVal.Value, 4);
|
---|
1178 |
|
---|
1179 | if (_r <= 0)
|
---|
1180 | {
|
---|
1181 | return null;
|
---|
1182 | }
|
---|
1183 |
|
---|
1184 | EllipseGeometry geometry = new EllipseGeometry(new Point(_cx, _cy), _r, _r);
|
---|
1185 |
|
---|
1186 | return geometry;
|
---|
1187 | }
|
---|
1188 |
|
---|
1189 | #endregion
|
---|
1190 |
|
---|
1191 | #region SvgPolylineElement Geometry
|
---|
1192 |
|
---|
1193 | public static Geometry CreateGeometry(SvgPolylineElement element)
|
---|
1194 | {
|
---|
1195 | ISvgPointList list = element.AnimatedPoints;
|
---|
1196 | ulong nElems = list.NumberOfItems;
|
---|
1197 | if (nElems == 0)
|
---|
1198 | {
|
---|
1199 | return null;
|
---|
1200 | }
|
---|
1201 |
|
---|
1202 | PointCollection points = new PointCollection((int)nElems);
|
---|
1203 |
|
---|
1204 | for (uint i = 0; i < nElems; i++)
|
---|
1205 | {
|
---|
1206 | ISvgPoint point = list.GetItem(i);
|
---|
1207 | points.Add(new Point(Math.Round(point.X, 4), Math.Round(point.Y, 4)));
|
---|
1208 | }
|
---|
1209 | PolyLineSegment polyline = new PolyLineSegment();
|
---|
1210 | polyline.Points = points;
|
---|
1211 |
|
---|
1212 | PathFigure polylineFigure = new PathFigure();
|
---|
1213 | polylineFigure.StartPoint = points[0];
|
---|
1214 | polylineFigure.IsClosed = false;
|
---|
1215 | polylineFigure.IsFilled = true;
|
---|
1216 |
|
---|
1217 | polylineFigure.Segments.Add(polyline);
|
---|
1218 |
|
---|
1219 | PathGeometry geometry = new PathGeometry();
|
---|
1220 |
|
---|
1221 | string fillRule = element.GetPropertyValue("fill-rule");
|
---|
1222 | string clipRule = element.GetAttribute("clip-rule");
|
---|
1223 | if (!String.IsNullOrEmpty(clipRule) &&
|
---|
1224 | String.Equals(clipRule, "evenodd") || String.Equals(clipRule, "nonzero"))
|
---|
1225 | {
|
---|
1226 | fillRule = clipRule;
|
---|
1227 | }
|
---|
1228 | if (fillRule == "evenodd")
|
---|
1229 | geometry.FillRule = FillRule.EvenOdd;
|
---|
1230 | else if (fillRule == "nonzero")
|
---|
1231 | geometry.FillRule = FillRule.Nonzero;
|
---|
1232 |
|
---|
1233 | geometry.Figures.Add(polylineFigure);
|
---|
1234 |
|
---|
1235 | return geometry;
|
---|
1236 | }
|
---|
1237 |
|
---|
1238 | #endregion
|
---|
1239 |
|
---|
1240 | #region SvgPolygonElement Geometry
|
---|
1241 |
|
---|
1242 | public static Geometry CreateGeometry(SvgPolygonElement element)
|
---|
1243 | {
|
---|
1244 | ISvgPointList list = element.AnimatedPoints;
|
---|
1245 | ulong nElems = list.NumberOfItems;
|
---|
1246 | if (nElems == 0)
|
---|
1247 | {
|
---|
1248 | return null;
|
---|
1249 | }
|
---|
1250 |
|
---|
1251 | PointCollection points = new PointCollection((int)nElems);
|
---|
1252 |
|
---|
1253 | for (uint i = 0; i < nElems; i++)
|
---|
1254 | {
|
---|
1255 | ISvgPoint point = list.GetItem(i);
|
---|
1256 | points.Add(new Point(Math.Round(point.X, 4), Math.Round(point.Y, 4)));
|
---|
1257 | }
|
---|
1258 |
|
---|
1259 | PolyLineSegment polyline = new PolyLineSegment();
|
---|
1260 | polyline.Points = points;
|
---|
1261 |
|
---|
1262 | PathFigure polylineFigure = new PathFigure();
|
---|
1263 | polylineFigure.StartPoint = points[0];
|
---|
1264 | polylineFigure.IsClosed = true;
|
---|
1265 | polylineFigure.IsFilled = true;
|
---|
1266 |
|
---|
1267 | polylineFigure.Segments.Add(polyline);
|
---|
1268 |
|
---|
1269 | PathGeometry geometry = new PathGeometry();
|
---|
1270 |
|
---|
1271 | string fillRule = element.GetPropertyValue("fill-rule");
|
---|
1272 | string clipRule = element.GetAttribute("clip-rule");
|
---|
1273 | if (!String.IsNullOrEmpty(clipRule) &&
|
---|
1274 | String.Equals(clipRule, "evenodd") || String.Equals(clipRule, "nonzero"))
|
---|
1275 | {
|
---|
1276 | fillRule = clipRule;
|
---|
1277 | }
|
---|
1278 | if (fillRule == "evenodd")
|
---|
1279 | geometry.FillRule = FillRule.EvenOdd;
|
---|
1280 | else if (fillRule == "nonzero")
|
---|
1281 | geometry.FillRule = FillRule.Nonzero;
|
---|
1282 |
|
---|
1283 | geometry.Figures.Add(polylineFigure);
|
---|
1284 |
|
---|
1285 | return geometry;
|
---|
1286 | }
|
---|
1287 |
|
---|
1288 | #endregion
|
---|
1289 |
|
---|
1290 | #endregion
|
---|
1291 |
|
---|
1292 | #region Marker Methods
|
---|
1293 |
|
---|
1294 | protected static string ExtractMarkerUrl(string propValue)
|
---|
1295 | {
|
---|
1296 | Match match = _reUrl.Match(propValue);
|
---|
1297 | if (match.Success)
|
---|
1298 | {
|
---|
1299 | return match.Groups["uri"].Value;
|
---|
1300 | }
|
---|
1301 | else
|
---|
1302 | {
|
---|
1303 | return String.Empty;
|
---|
1304 | }
|
---|
1305 | }
|
---|
1306 |
|
---|
1307 | protected static void RenderMarkers(WpfDrawingRenderer renderer,
|
---|
1308 | SvgStyleableElement styleElm, WpfDrawingContext gr)
|
---|
1309 | {
|
---|
1310 | // OPTIMIZE
|
---|
1311 |
|
---|
1312 | if (styleElm is ISharpMarkerHost)
|
---|
1313 | {
|
---|
1314 | string markerStartUrl = ExtractMarkerUrl(styleElm.GetPropertyValue("marker-start", "marker"));
|
---|
1315 | string markerMiddleUrl = ExtractMarkerUrl(styleElm.GetPropertyValue("marker-mid", "marker"));
|
---|
1316 | string markerEndUrl = ExtractMarkerUrl(styleElm.GetPropertyValue("marker-end", "marker"));
|
---|
1317 |
|
---|
1318 | if (markerStartUrl.Length > 0)
|
---|
1319 | {
|
---|
1320 | WpfMarkerRendering markerRenderer = CreateByUri(styleElm.OwnerDocument,
|
---|
1321 | styleElm.BaseURI, markerStartUrl) as WpfMarkerRendering;
|
---|
1322 | if (markerRenderer != null)
|
---|
1323 | {
|
---|
1324 | markerRenderer.RenderMarker(renderer, gr, SvgMarkerPosition.Start, styleElm);
|
---|
1325 | }
|
---|
1326 | }
|
---|
1327 |
|
---|
1328 | if (markerMiddleUrl.Length > 0)
|
---|
1329 | {
|
---|
1330 | // TODO markerMiddleUrl != markerStartUrl
|
---|
1331 | WpfMarkerRendering markerRenderer = CreateByUri(styleElm.OwnerDocument,
|
---|
1332 | styleElm.BaseURI, markerMiddleUrl) as WpfMarkerRendering;
|
---|
1333 | if (markerRenderer != null)
|
---|
1334 | {
|
---|
1335 | markerRenderer.RenderMarker(renderer, gr, SvgMarkerPosition.Mid, styleElm);
|
---|
1336 | }
|
---|
1337 | }
|
---|
1338 |
|
---|
1339 | if (markerEndUrl.Length > 0)
|
---|
1340 | {
|
---|
1341 | // TODO: markerEndUrl != markerMiddleUrl
|
---|
1342 | WpfMarkerRendering markerRenderer = CreateByUri(styleElm.OwnerDocument,
|
---|
1343 | styleElm.BaseURI, markerEndUrl) as WpfMarkerRendering;
|
---|
1344 | if (markerRenderer != null)
|
---|
1345 | {
|
---|
1346 | markerRenderer.RenderMarker(renderer, gr, SvgMarkerPosition.End, styleElm);
|
---|
1347 | }
|
---|
1348 | }
|
---|
1349 | }
|
---|
1350 | }
|
---|
1351 |
|
---|
1352 | #endregion
|
---|
1353 |
|
---|
1354 | #region IDisposable Members
|
---|
1355 |
|
---|
1356 | protected override void Dispose(bool disposing)
|
---|
1357 | {
|
---|
1358 | base.Dispose(disposing);
|
---|
1359 | }
|
---|
1360 |
|
---|
1361 | #endregion
|
---|
1362 | }
|
---|
1363 | }
|
---|