Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GrammaticalOptimization/SharpVectorRenderingGdi/Gdi/GdiTextRendering.cs @ 13777

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

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

File size: 16.4 KB
Line 
1using System;
2using System.Xml;
3using System.Drawing;
4using System.Drawing.Drawing2D;
5using System.Text;
6using System.Text.RegularExpressions;
7
8using SharpVectors.Dom.Css;
9using SharpVectors.Dom.Svg;
10
11namespace SharpVectors.Renderers.Gdi
12{
13    public sealed class GdiTextRendering : GdiRendering
14    {
15        #region Private Fields
16
17        private GdiGraphicsWrapper _graphics;
18
19        #endregion
20
21        #region Constructor and Destructor
22
23        public GdiTextRendering(SvgElement element)
24            : base(element)
25        {
26        }
27
28        #endregion
29
30        #region Public Properties
31
32        public override bool IsRecursive
33        {
34            get
35            {
36                return true;
37            }
38        }
39
40        #endregion
41
42        #region Public Methods
43
44        public override void BeforeRender(GdiGraphicsRenderer renderer)
45        {
46            if (_uniqueColor.IsEmpty)
47                _uniqueColor = renderer.GetNextColor(element);
48
49            GdiGraphicsWrapper graphics = renderer.GraphicsWrapper;
50
51            _graphicsContainer = graphics.BeginContainer();
52            SetQuality(graphics);
53            Transform(graphics);
54        }
55
56        public override void Render(GdiGraphicsRenderer renderer)
57        {
58            _graphics = renderer.GraphicsWrapper;
59
60            SvgRenderingHint hint = element.RenderingHint;
61            if (hint == SvgRenderingHint.Clipping)
62            {
63                return;
64            }
65            if (element.ParentNode is SvgClipPathElement)
66            {
67                return;
68            }
69
70            SvgTextElement textElement = element as SvgTextElement;
71            if (textElement == null)
72            {
73                return;
74            }
75
76            string sVisibility = textElement.GetPropertyValue("visibility");
77            string sDisplay    = textElement.GetPropertyValue("display");
78            if (String.Equals(sVisibility, "hidden") || String.Equals(sDisplay, "none"))
79            {
80                return;
81            }
82
83            Clip(_graphics);
84
85            PointF ctp = new PointF(0, 0); // current text position
86           
87            ctp = GetCurrentTextPosition(textElement, ctp);
88            string sBaselineShift = textElement.GetPropertyValue("baseline-shift").Trim();
89            double shiftBy = 0;
90
91            if (sBaselineShift.Length > 0)
92            {
93                float textFontSize = GetComputedFontSize(textElement);
94                if (sBaselineShift.EndsWith("%"))
95                {
96                    shiftBy = SvgNumber.ParseNumber(sBaselineShift.Substring(0,
97                        sBaselineShift.Length - 1)) / 100 * textFontSize;
98                }
99                else if (sBaselineShift == "sub")
100                {
101                    shiftBy = -0.6F * textFontSize;
102                }
103                else if (sBaselineShift == "super")
104                {
105                    shiftBy = 0.6F * textFontSize;
106                }
107                else if (sBaselineShift == "baseline")
108                {
109                    shiftBy = 0;
110                }
111                else
112                {
113                    shiftBy = SvgNumber.ParseNumber(sBaselineShift);
114                }
115            }
116
117            XmlNodeType nodeType = XmlNodeType.None;
118            foreach (XmlNode child in element.ChildNodes)
119            {
120                nodeType = child.NodeType;
121                if (nodeType == XmlNodeType.Text)
122                {
123                    ctp.Y -= (float)shiftBy;
124                    AddGraphicsPath(textElement, ref ctp, GetText(textElement, child));
125                    ctp.Y += (float)shiftBy;
126                }
127                else if (nodeType == XmlNodeType.Element)
128                {
129                    string nodeName = child.Name;
130                    if (String.Equals(nodeName, "tref"))
131                    {
132                        AddTRefElementPath((SvgTRefElement)child, ref ctp);
133                    }
134                    else if (String.Equals(nodeName, "tspan"))
135                    {
136                        AddTSpanElementPath((SvgTSpanElement)child, ref ctp);
137                    }
138                }
139            }
140
141            PaintMarkers(renderer, textElement, _graphics);
142
143            _graphics = null;
144        }
145
146        #endregion
147
148        #region Private Methods
149
150        private Brush GetBrush(GraphicsPath gp)
151        {
152            GdiSvgPaint paint = new GdiSvgPaint(element as SvgStyleableElement, "fill");
153            return paint.GetBrush(gp);
154        }
155
156        private Pen GetPen(GraphicsPath gp)
157        {
158            GdiSvgPaint paint = new GdiSvgPaint(element as SvgStyleableElement, "stroke");
159            return paint.GetPen(gp);
160        }
161
162        #region Private Text Methods
163
164        private string TrimText(SvgTextContentElement element, string val)
165        {
166            Regex tabNewline = new Regex(@"[\n\f\t]");
167            if (element.XmlSpace != "preserve")
168                val = val.Replace("\n", String.Empty);
169            val = tabNewline.Replace(val, " ");
170
171            if (element.XmlSpace == "preserve")
172                return val;
173            else
174                return val.Trim();
175        }
176
177        private string GetText(SvgTextContentElement element, XmlNode child)
178        {
179            return TrimText(element, child.Value);
180        }
181
182        private void AddGraphicsPath(SvgTextContentElement element, ref PointF ctp, string text)
183        {
184            if (text.Length == 0)
185                return;
186
187            float emSize      = GetComputedFontSize(element);
188            FontFamily family = GetGDIFontFamily(element, emSize);
189            int style         = GetGDIFontStyle(element);
190            StringFormat sf   = GetGDIStringFormat(element);
191
192            GraphicsPath textGeometry = new GraphicsPath();
193
194            float xCorrection = 0;
195            if (sf.Alignment == StringAlignment.Near)
196                xCorrection = emSize * 1 / 6;
197            else if (sf.Alignment == StringAlignment.Far)
198                xCorrection = -emSize * 1 / 6;
199
200            float yCorrection = (float)(family.GetCellAscent(FontStyle.Regular)) / (float)(family.GetEmHeight(FontStyle.Regular)) * emSize;
201
202            // TODO: font property
203            PointF p = new PointF(ctp.X - xCorrection, ctp.Y - yCorrection);
204
205            textGeometry.AddString(text, family, style, emSize, p, sf);
206            if (!textGeometry.GetBounds().IsEmpty)
207            {
208                float bboxWidth = textGeometry.GetBounds().Width;
209                if (sf.Alignment == StringAlignment.Center)
210                    bboxWidth /= 2;
211                else if (sf.Alignment == StringAlignment.Far)
212                    bboxWidth = 0;
213
214                ctp.X += bboxWidth + emSize / 4;
215            }
216
217            GdiSvgPaint fillPaint = new GdiSvgPaint(element, "fill");
218            Brush brush = fillPaint.GetBrush(textGeometry);
219
220            GdiSvgPaint strokePaint = new GdiSvgPaint(element, "stroke");
221            Pen pen = strokePaint.GetPen(textGeometry);
222
223            if (brush != null)
224            {
225                if (brush is PathGradientBrush)
226                {
227                    GdiGradientFill gps = fillPaint.PaintFill as GdiGradientFill;
228
229                    _graphics.SetClip(gps.GetRadialGradientRegion(textGeometry.GetBounds()), CombineMode.Exclude);
230
231                    SolidBrush tempBrush = new SolidBrush(((PathGradientBrush)brush).InterpolationColors.Colors[0]);
232                    _graphics.FillPath(this, tempBrush, textGeometry);
233                    tempBrush.Dispose();
234                    _graphics.ResetClip();
235                }
236
237                _graphics.FillPath(this, brush, textGeometry);
238                brush.Dispose();
239            }
240
241            if (pen != null)
242            {
243                if (pen.Brush is PathGradientBrush)
244                {
245                    GdiGradientFill gps = strokePaint.PaintFill as GdiGradientFill;
246                    GdiGraphicsContainer container = _graphics.BeginContainer();
247
248                    _graphics.SetClip(gps.GetRadialGradientRegion(textGeometry.GetBounds()), CombineMode.Exclude);
249
250                    SolidBrush tempBrush = new SolidBrush(((PathGradientBrush)pen.Brush).InterpolationColors.Colors[0]);
251                    Pen tempPen = new Pen(tempBrush, pen.Width);
252                    _graphics.DrawPath(this, tempPen, textGeometry);
253                    tempPen.Dispose();
254                    tempBrush.Dispose();
255
256                    _graphics.EndContainer(container);
257                }
258
259                _graphics.DrawPath(this, pen, textGeometry);
260                pen.Dispose();
261            }
262
263            textGeometry.Dispose();
264        }
265
266        public string GetTRefText(SvgTRefElement element)
267        {
268            XmlElement refElement = element.ReferencedElement;
269            if (refElement != null)
270            {
271                return TrimText(element, refElement.InnerText);
272            }
273            else
274            {
275                return String.Empty;
276            }
277        }
278
279        private void AddTRefElementPath(SvgTRefElement element, ref PointF ctp)
280        {
281            ctp = GetCurrentTextPosition(element, ctp);
282
283            this.AddGraphicsPath(element, ref ctp, GetTRefText(element));
284        }
285
286        private void AddTSpanElementPath(SvgTSpanElement element, ref PointF ctp)
287        {
288            ctp = GetCurrentTextPosition(element, ctp);
289            string sBaselineShift = element.GetPropertyValue("baseline-shift").Trim();
290            double shiftBy = 0;
291
292            if (sBaselineShift.Length > 0)
293            {
294                SvgTextElement textElement = (SvgTextElement)element.SelectSingleNode("ancestor::svg:text",
295                    element.OwnerDocument.NamespaceManager);
296
297                float textFontSize = GetComputedFontSize(textElement);
298                if (sBaselineShift.EndsWith("%"))
299                {
300                    shiftBy = SvgNumber.ParseNumber(sBaselineShift.Substring(0,
301                        sBaselineShift.Length - 1)) / 100 * textFontSize;
302                }
303                else if (sBaselineShift == "sub")
304                {
305                    shiftBy = -0.6F * textFontSize;
306                }
307                else if (sBaselineShift == "super")
308                {
309                    shiftBy = 0.6F * textFontSize;
310                }
311                else if (sBaselineShift == "baseline")
312                {
313                    shiftBy = 0;
314                }
315                else
316                {
317                    shiftBy = SvgNumber.ParseNumber(sBaselineShift);
318                }
319            }
320
321            foreach (XmlNode child in element.ChildNodes)
322            {
323                if (child.NodeType == XmlNodeType.Text)
324                {
325                    ctp.Y -= (float)shiftBy;
326                    AddGraphicsPath(element, ref ctp, GetText(element, child));
327                    ctp.Y += (float)shiftBy;
328                }
329            }
330        }
331
332        private PointF GetCurrentTextPosition(SvgTextPositioningElement posElement, PointF p)
333        {
334            if (posElement.X.AnimVal.NumberOfItems > 0)
335            {
336                p.X = (float)posElement.X.AnimVal.GetItem(0).Value;
337            }
338            if (posElement.Y.AnimVal.NumberOfItems > 0)
339            {
340                p.Y = (float)posElement.Y.AnimVal.GetItem(0).Value;
341            }
342            if (posElement.Dx.AnimVal.NumberOfItems > 0)
343            {
344                p.X += (float)posElement.Dx.AnimVal.GetItem(0).Value;
345            }
346            if (posElement.Dy.AnimVal.NumberOfItems > 0)
347            {
348                p.Y += (float)posElement.Dy.AnimVal.GetItem(0).Value;
349            }
350            return p;
351        }
352
353        private int GetGDIFontStyle(SvgTextContentElement element)
354        {
355            int style = (int)FontStyle.Regular;
356            string fontWeight = element.GetPropertyValue("font-weight");
357            if (fontWeight == "bold" || fontWeight == "bolder" || fontWeight == "600" || fontWeight == "700" || fontWeight == "800" || fontWeight == "900")
358            {
359                style = style | (int)FontStyle.Bold;
360            }
361
362            if (element.GetPropertyValue("font-style") == "italic")
363            {
364                style = style | (int)FontStyle.Italic;
365            }
366
367            string textDeco = element.GetPropertyValue("text-decoration");
368            if (textDeco == "line-through")
369            {
370                style = style | (int)FontStyle.Strikeout;
371            }
372            else if (textDeco == "underline")
373            {
374                style = style | (int)FontStyle.Underline;
375            }
376            return style;
377        }
378
379        private FontFamily GetGDIFontFamily(SvgTextContentElement element, float fontSize)
380        {
381            string fontFamily  = element.GetPropertyValue("font-family");
382            string[] fontNames = fontNames = fontFamily.Split(new char[1] { ',' });
383
384            FontFamily family;
385
386            foreach (string fn in fontNames)
387            {
388                try
389                {
390                    string fontName = fn.Trim(new char[] { ' ', '\'', '"' });
391
392                    if (fontName == "serif")
393                        family = FontFamily.GenericSerif;
394                    else if (fontName == "sans-serif")
395                        family = FontFamily.GenericSansSerif;
396                    else if (fontName == "monospace")
397                        family = FontFamily.GenericMonospace;
398                    else
399                        family = new FontFamily(fontName);    // Font(,fontSize).FontFamily; 
400
401                    return family;
402                }
403                catch
404                {
405                }
406            }
407
408            // no known font-family was found => default to arial
409            return new FontFamily("Arial");
410        }
411
412        private StringFormat GetGDIStringFormat(SvgTextContentElement element)
413        {
414            StringFormat sf = new StringFormat();
415
416            bool doAlign = true;
417            if (element is SvgTSpanElement || element is SvgTRefElement)
418            {
419                SvgTextPositioningElement posElement = (SvgTextPositioningElement)element;
420                if (posElement.X.AnimVal.NumberOfItems == 0) doAlign = false;
421            }
422
423            if (doAlign)
424            {
425                string anchor = element.GetPropertyValue("text-anchor");
426                if (anchor == "middle")
427                    sf.Alignment = StringAlignment.Center;
428                if (anchor == "end")
429                    sf.Alignment = StringAlignment.Far;
430            }
431
432            string dir = element.GetPropertyValue("direction");
433            if (dir == "rtl")
434            {
435                if (sf.Alignment == StringAlignment.Far)
436                    sf.Alignment = StringAlignment.Near;
437                else if (sf.Alignment == StringAlignment.Near)
438                    sf.Alignment = StringAlignment.Far;
439                sf.FormatFlags = StringFormatFlags.DirectionRightToLeft;
440            }
441
442            dir = element.GetPropertyValue("writing-mode");
443            if (dir == "tb")
444            {
445                sf.FormatFlags = sf.FormatFlags | StringFormatFlags.DirectionVertical;
446            }
447
448            sf.FormatFlags = sf.FormatFlags | StringFormatFlags.MeasureTrailingSpaces;
449
450            return sf;
451        }
452
453        private float GetComputedFontSize(SvgTextContentElement element)
454        {
455            string str = element.GetPropertyValue("font-size");
456            float fontSize = 12;
457            if (str.EndsWith("%"))
458            {
459                // percentage of inherited value
460            }
461            else if (new Regex(@"^\d").IsMatch(str))
462            {
463                // svg length
464                fontSize = (float)new SvgLength(element, "font-size",
465                    SvgLengthDirection.Viewport, str, "10px").Value;
466            }
467            else if (str == "larger")
468            {
469            }
470            else if (str == "smaller")
471            {
472
473            }
474            else
475            {
476                // check for absolute value
477            }
478
479            return fontSize;
480        }
481
482        #endregion
483
484        #endregion
485    }
486}
Note: See TracBrowser for help on using the repository browser.