Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GrammaticalOptimization/SharpVectorRenderingWpf/Wpf/WpfRendering.cs @ 12762

Last change on this file since 12762 was 12762, checked in by aballeit, 9 years ago

#2283 GUI updates, Tree-chart, MCTS Version 2 (prune leaves)

File size: 50.4 KB
Line 
1using System;
2using System.Xml;
3using System.Linq;
4using System.Text;
5using System.Collections.Generic;
6using System.Text.RegularExpressions;
7
8using System.Windows;
9using System.Windows.Media;
10using System.Windows.Media.Imaging;
11
12using SharpVectors.Dom.Css;
13using SharpVectors.Dom.Svg;
14using SharpVectors.Renderers.Utils;
15
16namespace 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}
Note: See TracBrowser for help on using the repository browser.