public WpfTextStringFormat(FlowDirection direction, TextTrimming trimming,
     WpfTextAnchor anchor)
 {
     this.Direction = direction;
     this.Trimming = trimming;
     this.Anchor = anchor;
 }
 public WpfTextStringFormat(FlowDirection direction, TextTrimming trimming,
                            WpfTextAnchor anchor)
 {
     this.Direction = direction;
     this.Trimming  = trimming;
     this.Anchor    = anchor;
 }
        public override void Render(WpfDrawingRenderer renderer)
        {
            if (_drawGroup == null || _drawContext == null)
            {
                return;
            }

            Point ctp = new Point(0, 0); // current text position

            WpfTextPlacement placement = WpfTextRenderer.GetCurrentTextPosition(_textElement, ctp);

            ctp = placement.Location;
            double rotate = placement.Rotation;

            if (!placement.HasPositions)
            {
                placement = null; // render it useless
            }
            string sBaselineShift = _textElement.GetPropertyValue("baseline-shift").Trim();
            double shiftBy        = 0;

            if (sBaselineShift.Length > 0)
            {
                double textFontSize = WpfTextRenderer.GetComputedFontSize(_textElement);
                if (sBaselineShift.EndsWith("%", StringComparison.OrdinalIgnoreCase))
                {
                    shiftBy = SvgNumber.ParseNumber(sBaselineShift.Substring(0,
                                                                             sBaselineShift.Length - 1)) / 100 * textFontSize;
                }
                else if (sBaselineShift == "sub")
                {
                    shiftBy = -0.6F * textFontSize;
                }
                else if (sBaselineShift == "super")
                {
                    shiftBy = 0.6F * textFontSize;
                }
                else if (sBaselineShift == "baseline")
                {
                    shiftBy = 0;
                }
                else
                {
                    shiftBy = SvgNumber.ParseNumber(sBaselineShift);
                }
            }

            XmlNodeType nodeType = XmlNodeType.None;

            bool   isVertical  = false;
            string writingMode = _textElement.GetPropertyValue("writing-mode");

            if (!string.IsNullOrWhiteSpace(writingMode) &&
                string.Equals(writingMode, "tb", StringComparison.OrdinalIgnoreCase))
            {
                isVertical = true;
            }

            if (_svgElement.ChildNodes.Count == 1)
            {
                XmlNode child = _svgElement.ChildNodes[0];
                nodeType = child.NodeType;
                if (nodeType == XmlNodeType.Text || nodeType == XmlNodeType.CDATA)
                {
                    if (isVertical)
                    {
                        ctp.X -= shiftBy;
                        RenderSingleLineTextV(_textElement, ref ctp,
                                              WpfTextRenderer.GetText(_textElement, child), rotate, placement);
                        ctp.X += shiftBy;
                    }
                    else
                    {
                        ctp.Y -= shiftBy;
                        RenderSingleLineTextH(_textElement, ref ctp,
                                              WpfTextRenderer.GetText(_textElement, child), rotate, placement);
                        ctp.Y += shiftBy;
                    }
                }
                else if (nodeType == XmlNodeType.Element)
                {
                    string nodeName = child.Name;
                    if (string.Equals(nodeName, "tref"))
                    {
                        AddTRefElementRun((SvgTRefElement)child, ref ctp, isVertical, true);
                    }
                    else if (string.Equals(nodeName, "tspan"))
                    {
                        AddTSpanElementRun((SvgTSpanElement)child, ref ctp, isVertical, true);
                    }
                    else if (string.Equals(nodeName, "textPath"))
                    {
                        RenderTextPath((SvgTextPathElement)child, ref ctp, rotate, placement);
                    }
                }
                else if (nodeType == XmlNodeType.Whitespace)
                {
                    if (isVertical)
                    {
                        ctp.X -= shiftBy;
                        RenderSingleLineTextV(_textElement, ref ctp,
                                              WpfTextRenderer.GetText(_textElement, child), rotate, placement);
                        ctp.X += shiftBy;
                    }
                    else
                    {
                        ctp.Y -= shiftBy;
                        RenderSingleLineTextH(_textElement, ref ctp,
                                              WpfTextRenderer.GetText(_textElement, child), rotate, placement);
                        ctp.Y += shiftBy;
                    }
                }
            }
            else
            {
                string textAnchor = _textElement.GetPropertyValue("text-anchor");

                WpfTextAnchor anchor = WpfTextAnchor.None;

                if (textAnchor == "middle")
                {
                    anchor = WpfTextAnchor.Middle;
                }
                else if (textAnchor == "end")
                {
                    anchor = WpfTextAnchor.End;
                }

                XmlNodeList nodeList = _svgElement.ChildNodes;
                // This is a very simply hack to change centered text to left align, since for
                // text containing spans, different font weights may be applied to the spans...
                if (anchor == WpfTextAnchor.Middle)
                {
                    // Suspend the rendering...
                    _isMeasuring = true;

                    foreach (XmlNode child in nodeList)
                    {
                        nodeType = child.NodeType;
                        if (nodeType == XmlNodeType.Text)
                        {
                            if (isVertical)
                            {
                                ctp.X -= shiftBy;
                                RenderTextRunV(_textElement, ref ctp,
                                               WpfTextRenderer.GetText(_textElement, child), rotate, placement);
                                ctp.X += shiftBy;
                            }
                            else
                            {
                                ctp.Y -= shiftBy;
                                RenderTextRunH(_textElement, ref ctp,
                                               WpfTextRenderer.GetText(_textElement, child), rotate, placement);
                                ctp.Y += shiftBy;
                            }
                        }
                        else if (nodeType == XmlNodeType.Element)
                        {
                            string nodeName = child.Name;
                            if (string.Equals(nodeName, "tref"))
                            {
                                AddTRefElementRun((SvgTRefElement)child, ref ctp, isVertical, false);
                            }
                            else if (string.Equals(nodeName, "tspan"))
                            {
                                AddTSpanElementRun((SvgTSpanElement)child, ref ctp, isVertical, false);
                            }
                            else if (string.Equals(nodeName, "textPath"))
                            {
                                RenderTextPath((SvgTextPathElement)child, ref ctp, rotate, placement);
                            }
                        }
                        else if (nodeType == XmlNodeType.Whitespace)
                        {
                            if (isVertical)
                            {
                                ctp.X -= shiftBy;
                                //RenderTextRunV(_textElement, ref ctp, GetText(_textElement, child));
                                RenderTextRunV(_textElement, ref ctp, Whitespace, rotate, placement);
                                ctp.X += shiftBy;
                            }
                            else
                            {
                                ctp.Y -= shiftBy;
                                //RenderTextRunH(_textElement, ref ctp, GetText(_textElement, child));
                                RenderTextRunH(_textElement, ref ctp, Whitespace, rotate, placement);
                                ctp.Y += shiftBy;
                            }
                        }
                    }

                    ctp.X -= (_textWidth / 2d);

                    // Resume the rendering...
                    _isMeasuring = false;
                }

                bool textRendered = false;

                for (int i = 0; i < nodeList.Count; i++)
                {
                    XmlNode child = nodeList[i];
                    nodeType = child.NodeType;
                    if (nodeType == XmlNodeType.Text)
                    {
                        if (isVertical)
                        {
                            ctp.X -= shiftBy;
                            RenderTextRunV(_textElement, ref ctp,
                                           WpfTextRenderer.GetText(_textElement, child), rotate, placement);
                            ctp.X += shiftBy;
                        }
                        else
                        {
                            ctp.Y -= shiftBy;
                            RenderTextRunH(_textElement, ref ctp,
                                           WpfTextRenderer.GetText(_textElement, child), rotate, placement);
                            ctp.Y += shiftBy;
                        }

                        textRendered = true;
                    }
                    else if (nodeType == XmlNodeType.Element)
                    {
                        string nodeName = child.Name;
                        if (string.Equals(nodeName, "tref"))
                        {
                            AddTRefElementRun((SvgTRefElement)child, ref ctp, isVertical, false);

                            textRendered = true;
                        }
                        else if (string.Equals(nodeName, "tspan"))
                        {
                            AddTSpanElementRun((SvgTSpanElement)child, ref ctp, isVertical, false);

                            textRendered = true;
                        }
                        else if (string.Equals(nodeName, "textPath"))
                        {
                            RenderTextPath((SvgTextPathElement)child, ref ctp, rotate, placement);

                            textRendered = false;
                        }
                    }
                    else if (nodeType == XmlNodeType.Whitespace)
                    {
                        if (textRendered)
                        {
                            if (isVertical)
                            {
                                ctp.X -= shiftBy;
                                //RenderTextRunV(_textElement, ref ctp, GetText(_textElement, child));
                                RenderTextRunV(_textElement, ref ctp, Whitespace, rotate, placement);
                                ctp.X += shiftBy;
                            }
                            else
                            {
                                ctp.Y -= shiftBy;
                                //RenderTextRunH(_textElement, ref ctp, GetText(_textElement, child));
                                RenderTextRunH(_textElement, ref ctp, Whitespace, rotate, placement);
                                ctp.Y += shiftBy;
                            }

                            textRendered = false;
                        }
                    }
                }
            }
        }
        public override void Render(WpfDrawingRenderer renderer)
        {
            if (_drawGroup == null || _drawContext == null)
            {
                return;
            }

            var comparer = StringComparison.OrdinalIgnoreCase;

            Point ctp = new Point(0, 0); // current text position

            WpfTextPlacement placement = WpfTextPlacement.Create(_textElement, ctp, _textContext.IsTextPath);

            ctp = placement.Location;
            double rotate = placement.Rotation;

            if (!placement.HasPositions)
            {
                placement = null; // render it useless
            }
            string sBaselineShift = _textElement.GetPropertyValue("baseline-shift").Trim();
            double shiftBy        = 0;

            if (sBaselineShift.Length > 0)
            {
                double textFontSize = WpfTextRenderer.GetComputedFontSize(_textElement);
                if (sBaselineShift.EndsWith("%", comparer))
                {
                    shiftBy = SvgNumber.ParseNumber(sBaselineShift.Substring(0,
                                                                             sBaselineShift.Length - 1)) / 100 * textFontSize;
                }
                else if (string.Equals(sBaselineShift, "sub", comparer))
                {
                    shiftBy = -0.6F * textFontSize;
                }
                else if (string.Equals(sBaselineShift, "super", comparer))
                {
                    shiftBy = 0.6F * textFontSize;
                }
                else if (string.Equals(sBaselineShift, "baseline", comparer))
                {
                    shiftBy = 0;
                }
                else
                {
                    shiftBy = SvgNumber.ParseNumber(sBaselineShift);
                }
            }

            // For for fonts loading in the background...
            var svgDoc = _svgElement.OwnerDocument;

            if (svgDoc.IsFontsLoaded == false)
            {
                //TODO: Use of SpinUntil is known to CPU heavy, but will work for now...
                //SpinWait.SpinUntil(() => svgDoc.IsFontsLoaded == true);

                var svgWnd = svgDoc.Window as SvgWindow;
                if (svgWnd != null)
                {
                    svgWnd.AwaitTasks("SvgDocument");
                }
            }

            XmlNodeType nodeType = XmlNodeType.None;

            bool   isVertical  = false;
            string writingMode = _textElement.GetPropertyValue("writing-mode");

            if (!string.IsNullOrWhiteSpace(writingMode) && string.Equals(writingMode, "tb", comparer))
            {
                isVertical = true;
            }

            if (_svgElement.ChildNodes.Count == 1)
            {
                XmlNode child = _svgElement.ChildNodes[0];
                nodeType = child.NodeType;
                if (nodeType == XmlNodeType.Text || nodeType == XmlNodeType.CDATA)
                {
                    if (isVertical)
                    {
                        ctp.X -= shiftBy;
                        RenderVertText(_textElement, ref ctp,
                                       WpfTextRenderer.GetText(_textElement, child), rotate, placement);
                        ctp.X += shiftBy;
                    }
                    else
                    {
                        ctp.Y -= shiftBy;
                        RenderHorzText(_textElement, ref ctp,
                                       WpfTextRenderer.GetText(_textElement, child), rotate, placement);
                        ctp.Y += shiftBy;
                    }
                }
                else if (nodeType == XmlNodeType.Element)
                {
                    string nodeName = child.Name;
                    if (string.Equals(nodeName, "tref", comparer))
                    {
                        AddTRefElementRun((SvgTRefElement)child, ref ctp, isVertical, true);
                    }
                    else if (string.Equals(nodeName, "tspan", comparer))
                    {
                        AddTSpanElementRun((SvgTSpanElement)child, ref ctp, isVertical, true);
                    }
                    else if (string.Equals(nodeName, "textPath", comparer))
                    {
                        RenderTextPath((SvgTextPathElement)child, ref ctp, rotate, placement);
                    }
                    else if (string.Equals(nodeName, "altGlyph", comparer))
                    {
                        AddAltGlyphElementRun((SvgAltGlyphElement)child, ref ctp, isVertical, true);
                    }
                }
                else if (nodeType == XmlNodeType.Whitespace)
                {
                    if (isVertical)
                    {
                        ctp.X -= shiftBy;
                        RenderVertText(_textElement, ref ctp,
                                       WpfTextRenderer.GetText(_textElement, child), rotate, placement);
                        ctp.X += shiftBy;
                    }
                    else
                    {
                        ctp.Y -= shiftBy;
                        RenderHorzText(_textElement, ref ctp,
                                       WpfTextRenderer.GetText(_textElement, child), rotate, placement);
                        ctp.Y += shiftBy;
                    }
                }
            }
            else
            {
                string textAnchor = _textElement.GetPropertyValue("text-anchor");

                WpfTextAnchor anchor = WpfTextAnchor.None;

                if (string.Equals(textAnchor, "middle", comparer))
                {
                    anchor = WpfTextAnchor.Middle;
                }
                else if (string.Equals(textAnchor, "end", comparer))
                {
                    anchor = WpfTextAnchor.End;
                }

                XmlNodeList nodeList  = _svgElement.ChildNodes;
                int         nodeCount = nodeList.Count;
                // This is a very simply hack to change centered text to left align, since for
                // text containing spans, different font weights may be applied to the spans...
                if (anchor == WpfTextAnchor.Middle)
                {
                    // Suspend the rendering...
                    _isMeasuring = true;
                    Point savedPt = new Point(ctp.X, ctp.Y);

                    _textContext.BeginMeasure(nodeCount);

                    for (int i = 0; i < nodeCount; i++)
                    {
                        XmlNode child = nodeList[i];
                        nodeType = child.NodeType;
                        //if (i == 0 && nodeType == XmlNodeType.Whitespace)
                        //{
                        //    continue;
                        //}
                        if (nodeType == XmlNodeType.Text)
                        {
                            var nodeText = WpfTextRenderer.GetText(_textElement, child);
                            if (i == (nodeCount - 1))
                            {
                                // No need to render the last white space...
                                nodeText = nodeText.TrimEnd();
                            }
                            else if (i == 0)
                            {
                                nodeText = nodeText.Trim();
                            }

                            if (isVertical)
                            {
                                ctp.X -= shiftBy;
                                RenderVertTextRun(_textElement, ref ctp, nodeText, rotate, placement);
                                ctp.X += shiftBy;
                            }
                            else
                            {
                                ctp.Y -= shiftBy;
                                RenderHorzTextRun(_textElement, ref ctp, nodeText, rotate, placement);
                                ctp.Y += shiftBy;
                            }
                        }
                        else if (nodeType == XmlNodeType.Element)
                        {
                            string nodeName = child.Name;
                            if (string.Equals(nodeName, "tref", comparer))
                            {
                                AddTRefElementRun((SvgTRefElement)child, ref ctp, isVertical, false);
                            }
                            else if (string.Equals(nodeName, "tspan", comparer))
                            {
                                bool isAdded = false;
                                if ((i + 1) < nodeCount - 1)
                                {
                                    XmlNode nextChild = nodeList[i + 1];
                                    if (nextChild.NodeType == XmlNodeType.Whitespace)
                                    {
                                        isAdded = true;
                                        AddTSpanElementRun((SvgTSpanElement)child, ref ctp, isVertical, false, nextChild);
                                        i++;
                                    }
                                }
                                if (!isAdded)
                                {
                                    AddTSpanElementRun((SvgTSpanElement)child, ref ctp, isVertical, false);
                                }
                            }
                            else if (string.Equals(nodeName, "textPath", comparer))
                            {
                                RenderTextPath((SvgTextPathElement)child, ref ctp, rotate, placement);
                            }
                            else if (string.Equals(nodeName, "altGlyph", comparer))
                            {
                                AddAltGlyphElementRun((SvgAltGlyphElement)child, ref ctp, isVertical, false);
                            }
                        }
                        else if (nodeType == XmlNodeType.Whitespace)
                        {
                            if (isVertical)
                            {
                                ctp.X -= shiftBy;
                                RenderVertTextRun(_textElement, ref ctp, Whitespace, rotate, placement, true);
                                ctp.X += shiftBy;
                            }
                            else
                            {
                                ctp.Y -= shiftBy;
                                RenderHorzTextRun(_textElement, ref ctp, Whitespace, rotate, placement, true);
                                ctp.Y += shiftBy;
                            }
                        }
                    }

                    _textContext.EndMeasure();

                    ctp = savedPt;

                    ctp.X -= (_textWidth / 2d);

                    // Resume the rendering...
                    _isMeasuring = false;
                }

                bool textRendered = false;

                for (int i = 0; i < nodeCount; i++)
                {
                    XmlNode child = nodeList[i];
                    nodeType = child.NodeType;
                    //if (i == 0 && nodeType == XmlNodeType.Whitespace)
                    //{
                    //    continue;
                    //}

                    if (nodeType == XmlNodeType.Text)
                    {
                        var nodeText = WpfTextRenderer.GetText(_textElement, child);
                        if (i == (nodeCount - 1))
                        {
                            // No need to render the last white space...
                            nodeText = nodeText.TrimEnd();
                        }
                        else if (i == 0)
                        {
                            nodeText = nodeText.Trim();
                        }

                        if (isVertical)
                        {
                            ctp.X -= shiftBy;
                            RenderVertTextRun(_textElement, ref ctp, nodeText, rotate, placement);
                            ctp.X += shiftBy;
                        }
                        else
                        {
                            ctp.Y -= shiftBy;
                            RenderHorzTextRun(_textElement, ref ctp, nodeText, rotate, placement);
                            ctp.Y += shiftBy;
                        }

                        textRendered = true;
                    }
                    else if (nodeType == XmlNodeType.Element)
                    {
                        string nodeName = child.Name;
                        if (string.Equals(nodeName, "tref", comparer))
                        {
                            AddTRefElementRun((SvgTRefElement)child, ref ctp, isVertical, false);

                            textRendered = true;
                        }
                        else if (string.Equals(nodeName, "tspan", comparer))
                        {
                            bool isAdded = false;
                            if ((i + 1) < nodeCount - 1)
                            {
                                XmlNode nextChild = nodeList[i + 1];
                                if (nextChild.NodeType == XmlNodeType.Whitespace)
                                {
                                    isAdded = true;
                                    AddTSpanElementRun((SvgTSpanElement)child, ref ctp, isVertical, false, nextChild);
                                    i++;
                                }
                            }
                            if (!isAdded)
                            {
                                AddTSpanElementRun((SvgTSpanElement)child, ref ctp, isVertical, false);
                            }

                            textRendered = true;
                        }
                        else if (string.Equals(nodeName, "textPath", comparer))
                        {
                            RenderTextPath((SvgTextPathElement)child, ref ctp, rotate, placement);

                            textRendered = false;
                        }
                        else if (string.Equals(nodeName, "altGlyph", comparer))
                        {
                            AddAltGlyphElementRun((SvgAltGlyphElement)child, ref ctp, isVertical, false);
                        }
                    }
                    else if (nodeType == XmlNodeType.Whitespace)
                    {
                        if (textRendered)
                        {
                            if (isVertical)
                            {
                                ctp.X -= shiftBy;
                                RenderVertTextRun(_textElement, ref ctp, Whitespace, rotate, placement, true);
                                ctp.X += shiftBy;
                            }
                            else
                            {
                                ctp.Y -= shiftBy;
                                RenderHorzTextRun(_textElement, ref ctp, Whitespace, rotate, placement, true);
                                ctp.Y += shiftBy;
                            }

                            textRendered = false;
                        }
                    }
                }
            }

            // Register this drawing with the Drawing-Document...
            if (_drawGroup != null)
            {
                this.Rendered(_drawGroup);
            }
        }