Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GrammaticalOptimization/SharpVectorRenderingWpf/Texts/WpfTextRenderer.cs @ 14040

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

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

File size: 26.7 KB
Line 
1using System;
2using System.Xml;
3using System.Linq;
4using System.Text;
5using System.Text.RegularExpressions;
6using System.Diagnostics;
7using System.Collections.Generic;
8
9using System.Windows;
10using System.Windows.Media;
11
12using SharpVectors.Runtime;
13
14using SharpVectors.Dom.Css;
15using SharpVectors.Dom.Svg;
16
17using SharpVectors.Renderers.Wpf;
18
19namespace SharpVectors.Renderers.Texts
20{
21    public abstract class WpfTextRenderer
22    {
23        #region Protected Fields
24
25        protected const string Whitespace = " ";
26
27        protected readonly static Regex _tabNewline = new Regex(@"[\n\f\t]");
28        protected readonly static Regex _decimalNumber = new Regex(@"^\d");
29
30        protected string _actualFontName;
31
32        protected DrawingContext    _textContext;
33        protected SvgTextElement    _textElement;
34
35        protected WpfDrawingContext _drawContext;
36        protected WpfTextRendering  _textRendering;
37
38        #endregion
39
40        #region Constructors and Destructor
41
42        protected WpfTextRenderer(SvgTextElement textElement, WpfTextRendering textRendering)
43        {
44            if (textElement == null)
45            {
46                throw new ArgumentNullException("textElement",
47                    "The SVG text element is required, and cannot be null (or Nothing).");
48            }
49            if (textRendering == null)
50            {
51                throw new ArgumentNullException("textRendering",
52                    "The text rendering object is required, and cannot be null (or Nothing).");
53            }
54
55            _textElement   = textElement;
56            _textRendering = textRendering;
57        }
58
59        #endregion
60
61        #region Public Properties
62
63        public bool IsInitialized
64        {
65            get
66            {
67                return (_textContext != null && _drawContext != null);
68            }
69        }
70
71        public DrawingContext TextContext
72        {
73            get
74            {
75                return _textContext;
76            }
77        }
78
79        public SvgTextElement TextElement
80        {
81            get
82            {
83                return _textElement;
84            }
85        }
86
87        public WpfDrawingContext DrawContext
88        {
89            get
90            {
91                return _drawContext;
92            }
93        }
94
95
96        #endregion
97
98        #region Protected Properties
99
100        protected bool IsMeasuring
101        {
102            get
103            {
104                if (_textRendering != null)
105                {
106                    return _textRendering.IsMeasuring;
107                }
108
109                return false;
110            }
111        }
112
113        protected bool IsTextPath
114        {
115            get
116            {
117                if (_textRendering != null)
118                {
119                    return _textRendering.IsTextPath;
120                }
121
122                return false;
123            }
124            set
125            {
126                if (_textRendering != null)
127                {
128                    _textRendering.IsTextPath = value;
129                }
130            }
131        }
132
133        protected double TextWidth
134        {
135            get
136            {
137                if (_textRendering != null)
138                {
139                    return _textRendering.TextWidth;
140                }
141
142                return 0;
143            }
144        }
145
146        #endregion
147
148        #region Public Methods
149
150        public virtual void Initialize(DrawingContext textContext, WpfDrawingContext drawContext)
151        {
152            if (textContext == null)
153            {
154                throw new ArgumentNullException("textContext",
155                    "The text context is required, and cannot be null (or Nothing).");
156            }
157            if (drawContext == null)
158            {
159                throw new ArgumentNullException("drawContext",
160                    "The drawing context is required, and cannot be null (or Nothing).");
161            }
162
163            _textContext = textContext;
164            _drawContext = drawContext;
165        }
166
167        public virtual void Uninitialize()
168        {
169            _textContext = null;
170            _drawContext = null;
171        }
172
173        public abstract void RenderSingleLineText(SvgTextContentElement element,
174            ref Point startPos, string text, double rotate, WpfTextPlacement placement);
175
176        public abstract void RenderTextRun(SvgTextContentElement element,
177            ref Point startPos, string text, double rotate, WpfTextPlacement placement);
178
179        #region TRef/TSpan Methods
180
181        public static string TrimText(SvgTextContentElement element, string val)
182        {
183            if (element.XmlSpace != "preserve")
184                val = val.Replace("\n", String.Empty);
185            val = _tabNewline.Replace(val, " ");
186
187            if (element.XmlSpace == "preserve" || element.XmlSpace == "default")
188            {
189                return val;
190            }
191            else
192            {
193                return val.Trim();
194            }
195        }
196
197        public static string GetText(SvgTextContentElement element, XmlNode child)
198        {
199            return TrimText(element, child.Value);
200        }
201
202        public static string GetTRefText(SvgTRefElement element)
203        {
204            XmlElement refElement = element.ReferencedElement;
205            if (refElement != null)
206            {
207                return TrimText(element, refElement.InnerText);
208            }
209            else
210            {
211                return String.Empty;
212            }
213        }
214
215        #endregion
216
217        #region TextPosition/Size Methods
218
219        public static WpfTextPlacement GetCurrentTextPosition(SvgTextPositioningElement posElement, Point p)
220        {
221            ISvgLengthList xValues  = posElement.X.AnimVal;
222            ISvgLengthList yValues  = posElement.Y.AnimVal;
223            ISvgLengthList dxValues = posElement.Dx.AnimVal;
224            ISvgLengthList dyValues = posElement.Dy.AnimVal;
225            ISvgNumberList rValues  = posElement.Rotate.AnimVal;
226
227            bool requiresGlyphPositioning = false;
228            bool isXYGlyphPositioning     = false;
229            bool isDxyGlyphPositioning    = false;
230            bool isRotateGlyphPositioning = false;
231
232            double xValue  = p.X;
233            double yValue  = p.Y;
234            double rValue  = 0;
235            double dxValue = 0;
236            double dyValue = 0;
237
238            WpfTextPlacement textPlacement = null;
239
240            if (xValues.NumberOfItems > 0)
241            {
242                if (xValues.NumberOfItems > 1)
243                {
244                    isXYGlyphPositioning     = true;
245                    requiresGlyphPositioning = true;
246                }
247
248                xValue = xValues.GetItem(0).Value;
249                p.X = xValue;
250            }
251            if (yValues.NumberOfItems > 0)
252            {
253                if (yValues.NumberOfItems > 1)
254                {
255                    isXYGlyphPositioning     = true;
256                    requiresGlyphPositioning = true;
257                }
258
259                yValue = yValues.GetItem(0).Value;
260                p.Y = yValue;
261            }
262            if (dxValues.NumberOfItems > 0)
263            {
264                if (dxValues.NumberOfItems > 1)
265                {
266                    isDxyGlyphPositioning    = true;
267                    requiresGlyphPositioning = true;
268                }
269
270                dxValue = dxValues.GetItem(0).Value;
271                p.X += dxValue;
272            }
273            if (dyValues.NumberOfItems > 0)
274            {
275                if (dyValues.NumberOfItems > 1)
276                {
277                    isDxyGlyphPositioning    = true;
278                    requiresGlyphPositioning = true;
279                }
280
281                dyValue = dyValues.GetItem(0).Value;
282                p.Y += dyValue;
283            }
284            if (rValues.NumberOfItems > 0)
285            {
286                if (rValues.NumberOfItems > 1)
287                {
288                    isRotateGlyphPositioning = true;
289                    requiresGlyphPositioning = true;
290                }
291
292                rValue = rValues.GetItem(0).Value;
293            }
294
295            if (requiresGlyphPositioning)
296            {
297                uint xCount  = xValues.NumberOfItems;
298                uint yCount  = yValues.NumberOfItems;
299                uint dxCount = dxValues.NumberOfItems;
300                uint dyCount = dyValues.NumberOfItems;
301                uint rCount  = rValues.NumberOfItems;
302
303                List<WpfTextPosition> textPositions = null;
304
305                bool isRotateOnly = false;
306
307                if (isXYGlyphPositioning)
308                {
309                    uint itemCount = Math.Max(Math.Max(xCount, yCount), Math.Max(dxCount, dyCount));
310                    itemCount      = Math.Max(itemCount, rCount);
311                    textPositions  = new List<WpfTextPosition>((int)itemCount);
312
313                    double xLast = 0;
314                    double yLast = 0;
315
316                    for (uint i = 0; i < itemCount; i++)
317                    {
318                        double xNext  = i < xCount  ? xValues.GetItem(i).Value  : xValue;
319                        double yNext  = i < yCount  ? yValues.GetItem(i).Value  : yValue;
320                        double rNext  = i < rCount  ? rValues.GetItem(i).Value  : rValue;
321                        double dxNext = i < dxCount ? dxValues.GetItem(i).Value : dxValue;
322                        double dyNext = i < dyCount ? dyValues.GetItem(i).Value : dyValue;
323
324                        if (i < xCount)
325                        {
326                            xLast = xNext;
327                        }
328                        else
329                        {
330                            xNext = xLast;
331                        }
332                        if (i < yCount)
333                        {
334                            yLast = yNext;
335                        }
336                        else
337                        {
338                            yNext = yLast;
339                        }
340
341                        WpfTextPosition textPosition = new WpfTextPosition(
342                            new Point(xNext + dxNext, yNext + dyNext), rNext);
343
344                        textPositions.Add(textPosition);
345                    }                     
346                }
347                else if (isDxyGlyphPositioning)
348                {   
349                }
350                else if (isRotateGlyphPositioning)
351                {
352                    isRotateOnly   = true;
353                    uint itemCount = Math.Max(Math.Max(xCount, yCount), Math.Max(dxCount, dyCount));
354                    itemCount      = Math.Max(itemCount, rCount);
355                    textPositions  = new List<WpfTextPosition>((int)itemCount);
356
357                    for (uint i = 0; i < itemCount; i++)
358                    {
359                        double rNext  = i < rCount  ? rValues.GetItem(i).Value  : rValue;
360
361                        WpfTextPosition textPosition = new WpfTextPosition(p, rNext);
362
363                        textPositions.Add(textPosition);
364                    }                     
365                }
366
367                if (textPositions != null && textPositions.Count != 0)
368                {
369                    textPlacement = new WpfTextPlacement(p, rValue, textPositions, isRotateOnly);
370                }
371                else
372                {
373                    textPlacement = new WpfTextPlacement(p, rValue);
374                }
375            }
376            else
377            {
378                textPlacement = new WpfTextPlacement(p, rValue);
379            }
380
381            return textPlacement;
382        }
383
384        public static double GetComputedFontSize(SvgTextContentElement element)
385        {
386            string str = element.GetPropertyValue("font-size");
387            double fontSize = 12;
388            if (str.EndsWith("%"))
389            {
390                // percentage of inherited value
391            }
392            else if (_decimalNumber.IsMatch(str))
393            {
394                // svg length
395                fontSize = new SvgLength(element, "font-size",
396                    SvgLengthDirection.Viewport, str, "10px").Value;
397            }
398            else if (str == "larger")
399            {
400            }
401            else if (str == "smaller")
402            {
403
404            }
405            else
406            {
407                // check for absolute value
408            }
409
410            return fontSize;
411        }
412
413        #endregion
414   
415        #endregion
416
417        #region Protected Methods
418
419        #region Helper Methods
420
421        protected void SetTextWidth(double textWidth)
422        {
423            if (_textRendering != null && textWidth != 0)
424            {
425                _textRendering.SetTextWidth(textWidth);
426            }
427        }
428
429        protected void AddTextWidth(double textWidth)
430        {
431            if (_textRendering != null && textWidth != 0)
432            {
433                _textRendering.AddTextWidth(textWidth);
434            }
435        }
436
437        protected Brush GetBrush()
438        {
439            WpfSvgPaint paint = new WpfSvgPaint(_drawContext, _textElement, "fill");
440
441            return paint.GetBrush();
442        }
443
444        protected Pen GetPen()
445        {
446            WpfSvgPaint paint = new WpfSvgPaint(_drawContext, _textElement, "stroke");
447
448            return paint.GetPen();
449        }
450
451        /// <summary>
452        /// This will extract a <see cref="PathGeometry"/> that is nested into GeometryGroup, which
453        /// is normally created by the FormattedText.BuildGeometry() method.
454        /// </summary>
455        /// <param name="sourceGeometry"></param>
456        /// <returns></returns>
457        protected static Geometry ExtractTextPathGeometry(Geometry sourceGeometry)
458        {
459            GeometryGroup outerGroup = sourceGeometry as GeometryGroup;
460            if (outerGroup != null && outerGroup.Children.Count == 1)
461            {
462                GeometryGroup innerGroup = outerGroup.Children[0] as GeometryGroup;
463                if (innerGroup != null && innerGroup.Children.Count == 1)
464                {
465                    return innerGroup.Children[0];
466                }
467
468                return innerGroup;
469            }
470
471            return sourceGeometry;
472        }
473
474        #endregion
475
476        #region FontWeight Methods
477
478        protected FontWeight GetTextFontWeight(SvgTextContentElement element)
479        {
480            string fontWeight = element.GetPropertyValue("font-weight");
481            if (String.IsNullOrEmpty(fontWeight))
482            {
483                return FontWeights.Normal;
484            }
485
486            switch (fontWeight)
487            {
488                case "normal":
489                    return FontWeights.Normal;
490                case "bold":
491                    return FontWeights.Bold;
492                case "100":
493                    return FontWeights.Thin;
494                case "200":
495                    return FontWeights.ExtraLight;
496                case "300":
497                    return FontWeights.Light;
498                case "400":
499                    return FontWeights.Normal;
500                case "500":
501                    return FontWeights.Medium;
502                case "600":
503                    return FontWeights.SemiBold;
504                case "700":
505                    return FontWeights.Bold;
506                case "800":
507                    return FontWeights.ExtraBold;
508                case "900":
509                    return FontWeights.Black;
510                case "950":
511                    return FontWeights.UltraBlack;
512            }
513
514            if (String.Equals(fontWeight, "bolder", StringComparison.OrdinalIgnoreCase))
515            {
516                SvgTransformableElement parentElement = element.ParentNode as SvgTransformableElement;
517                if (parentElement != null)
518                {
519                    fontWeight = parentElement.GetPropertyValue("font-weight");
520                    if (!String.IsNullOrEmpty(fontWeight))
521                    {
522                        return this.GetBolderFontWeight(fontWeight);
523                    }
524                }
525                return FontWeights.ExtraBold;
526            }
527            if (String.Equals(fontWeight, "lighter", StringComparison.OrdinalIgnoreCase))
528            {
529                SvgTransformableElement parentElement = element.ParentNode as SvgTransformableElement;
530                if (parentElement != null)
531                {
532                    fontWeight = parentElement.GetPropertyValue("font-weight");
533                    if (!String.IsNullOrEmpty(fontWeight))
534                    {
535                        return this.GetLighterFontWeight(fontWeight);
536                    }
537                }
538                return FontWeights.Light;
539            }
540
541            return FontWeights.Normal;
542        }
543
544        protected FontWeight GetBolderFontWeight(string fontWeight)
545        {
546            if (String.IsNullOrEmpty(fontWeight))
547            {
548                return FontWeights.Normal;
549            }
550
551            switch (fontWeight)
552            {
553                case "normal":
554                    return FontWeights.Bold;
555                case "bold":
556                    return FontWeights.ExtraBold;
557                case "100":
558                    return FontWeights.ExtraLight;
559                case "200":
560                    return FontWeights.Light;
561                case "300":
562                    return FontWeights.Normal;
563                case "400":
564                    return FontWeights.Bold;
565                case "500":
566                    return FontWeights.SemiBold;
567                case "600":
568                    return FontWeights.Bold;
569                case "700":
570                    return FontWeights.ExtraBold;
571                case "800":
572                    return FontWeights.Black;
573                case "900":
574                    return FontWeights.UltraBlack;
575                case "950":
576                    return FontWeights.UltraBlack;
577            }
578
579            return FontWeights.Normal;
580        }
581
582        protected FontWeight GetLighterFontWeight(string fontWeight)
583        {
584            if (String.IsNullOrEmpty(fontWeight))
585            {
586                return FontWeights.Normal;
587            }
588
589            switch (fontWeight)
590            {
591                case "normal":
592                    return FontWeights.Light;
593                case "bold":
594                    return FontWeights.Normal;
595
596                case "100":
597                    return FontWeights.Thin;
598                case "200":
599                    return FontWeights.Thin;
600                case "300":
601                    return FontWeights.ExtraLight;
602                case "400":
603                    return FontWeights.Light;
604                case "500":
605                    return FontWeights.Normal;
606                case "600":
607                    return FontWeights.Medium;
608                case "700":
609                    return FontWeights.SemiBold;
610                case "800":
611                    return FontWeights.Bold;
612                case "900":
613                    return FontWeights.ExtraBold;
614                case "950":
615                    return FontWeights.Black;
616            }
617
618            return FontWeights.Normal;
619        }
620
621        #endregion
622
623        #region FontStyle/Stretch Methods
624
625        protected FontStyle GetTextFontStyle(SvgTextContentElement element)
626        {
627            string fontStyle = element.GetPropertyValue("font-style");
628            if (String.IsNullOrEmpty(fontStyle))
629            {
630                return FontStyles.Normal;
631            }
632
633            if (fontStyle == "normal")
634            {
635                return FontStyles.Normal;
636            }
637            if (fontStyle == "italic")
638            {
639                return FontStyles.Italic;
640            }
641            if (fontStyle == "oblique")
642            {
643                return FontStyles.Oblique;
644            }
645
646            return FontStyles.Normal;
647        }
648
649        protected FontStretch GetTextFontStretch(SvgTextContentElement element)
650        {
651            string fontStretch = element.GetPropertyValue("font-stretch");
652            if (String.IsNullOrEmpty(fontStretch))
653            {
654                return FontStretches.Normal;
655            }
656
657            switch (fontStretch)
658            {
659                case "normal":
660                    return FontStretches.Normal;
661                case "ultra-condensed":
662                    return FontStretches.UltraCondensed;
663                case "extra-condensed":
664                    return FontStretches.ExtraCondensed;
665                case "condensed":
666                    return FontStretches.Condensed;
667                case "semi-condensed":
668                    return FontStretches.SemiCondensed;
669                case "semi-expanded":
670                    return FontStretches.SemiExpanded;
671                case "expanded":
672                    return FontStretches.Expanded;
673                case "extra-expanded":
674                    return FontStretches.ExtraExpanded;
675                case "ultra-expanded":
676                    return FontStretches.UltraExpanded;
677            }
678
679            return FontStretches.Normal;
680        }
681
682        #endregion
683
684        #region Other Text/Font Attributes
685
686        protected TextDecorationCollection GetTextDecoration(SvgTextContentElement element)
687        {
688            string textDeco = element.GetPropertyValue("text-decoration");
689            if (textDeco == "line-through")
690            {
691                return TextDecorations.Strikethrough;
692            }
693            if (textDeco == "underline")
694            {
695                return TextDecorations.Underline;
696            }
697            if (textDeco == "overline")
698            {
699                return TextDecorations.OverLine;
700            }
701
702            return null;
703        }
704
705        protected FontFamily GetTextFontFamily(SvgTextContentElement element, double fontSize)
706        {
707            _actualFontName = null;
708
709            string fontFamily = element.GetPropertyValue("font-family");
710            string[] fontNames = fontNames = fontFamily.Split(new char[1] { ',' });
711
712            FontFamily family;
713
714            foreach (string fn in fontNames)
715            {
716                try
717                {
718                    string fontName = fn.Trim(new char[] { ' ', '\'', '"' });
719
720                    if (String.Equals(fontName, "serif", StringComparison.OrdinalIgnoreCase))
721                    {
722                        family = WpfDrawingSettings.GenericSerif;
723                    }
724                    else if (String.Equals(fontName, "sans-serif", StringComparison.OrdinalIgnoreCase))
725                    {
726                        family = WpfDrawingSettings.GenericSansSerif;
727                    }
728                    else if (String.Equals(fontName, "monospace", StringComparison.OrdinalIgnoreCase))
729                    {
730                        family = WpfDrawingSettings.GenericMonospace;
731                    }
732                    else
733                    {
734                        family = new FontFamily(fontName);
735                        _actualFontName = fontName;
736                    }
737
738                    return family;
739                }
740                catch
741                {
742                }
743            }
744
745            // no known font-family was found => default to Arial
746            return WpfDrawingSettings.DefaultFontFamily;
747        }
748
749        protected WpfTextStringFormat GetTextStringFormat(SvgTextContentElement element)
750        {
751            WpfTextStringFormat sf = WpfTextStringFormat.Default;
752
753            bool doAlign = true;
754            if (element is SvgTSpanElement || element is SvgTRefElement)
755            {
756                SvgTextPositioningElement posElement = (SvgTextPositioningElement)element;
757                if (posElement.X.AnimVal.NumberOfItems == 0)
758                    doAlign = false;
759            }
760
761            string dir = element.GetPropertyValue("direction");
762            bool isRightToLeft = (dir == "rtl");
763            sf.Direction = isRightToLeft ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;
764
765            if (doAlign)
766            {
767                string anchor = element.GetPropertyValue("text-anchor");
768
769                if (isRightToLeft)
770                {
771                    if (anchor == "middle")
772                        sf.Anchor = WpfTextAnchor.Middle;
773                    else if (anchor == "end")
774                        sf.Anchor = WpfTextAnchor.Start;
775                    else
776                        sf.Anchor = WpfTextAnchor.End;
777                }
778                else
779                {
780                    if (anchor == "middle")
781                        sf.Anchor = WpfTextAnchor.Middle;
782                    else if (anchor == "end")
783                        sf.Anchor = WpfTextAnchor.End;
784                }
785            }
786            else
787            {
788                SvgTextElement textElement = element.ParentNode as SvgTextElement;
789                if (textElement != null)
790                {
791                    string anchor = textElement.GetPropertyValue("text-anchor");
792                    if (isRightToLeft)
793                    {
794                        if (anchor == "middle")
795                            sf.Anchor = WpfTextAnchor.Middle;
796                        else if (anchor == "end")
797                            sf.Anchor = WpfTextAnchor.Start;
798                        else
799                            sf.Anchor = WpfTextAnchor.End;
800                    }
801                    else
802                    {
803                        if (anchor == "middle")
804                            sf.Anchor = WpfTextAnchor.Middle;
805                        else if (anchor == "end")
806                            sf.Anchor = WpfTextAnchor.End;
807                    }
808                }
809            }
810
811            //if (isRightToLeft)
812            //{
813            //    if (sf.Alignment == TextAlignment.Right)
814            //        sf.Alignment = TextAlignment.Left;
815            //    else if (sf.Alignment == TextAlignment.Left)
816            //        sf.Alignment = TextAlignment.Right;
817
818            //    //sf.FormatFlags = StringFormatFlags.DirectionRightToLeft;
819            //}
820
821            //dir = element.GetPropertyValue("writing-mode");
822            //if (dir == "tb")
823            //{
824            //    sf.FormatFlags = sf.FormatFlags | StringFormatFlags.DirectionVertical;
825            //}
826
827            //sf.FormatFlags = sf.FormatFlags | StringFormatFlags.MeasureTrailingSpaces;
828
829            return sf;
830        }
831
832        #endregion
833
834        #endregion
835    }
836}
Note: See TracBrowser for help on using the repository browser.