Esempio n. 1
0
        private Tuple <string, ICssValue> ParseValue(string name, string value, string priority, bool presentation)
        {
            var important = priority == "important";

            if (!presentation)
            {
                name = name.ToLower();
            }

            ICssValue parsedValue = null;

            switch (name)
            {
            case "fill":
            case "stroke":
                parsedValue = new SvgPaint(value);
                break;

            case "stroke-width":
                parsedValue = SvgLength.Parse(value, presentation);
                break;

            case "stop-color":
                parsedValue = new SvgColor(value);
                break;

            case "fill-opacity":
            case "stroke-opacity":
            case "stop-opacity":
            case "opacity":
                parsedValue = SvgNumber.Parse(value, 0.0F, 1.0F);
                break;

            case "clip-path":
                parsedValue = new SvgIri(value);
                break;

            case "fill-rule":
            case "clip-rule":
                parsedValue = new SvgFillRule(presentation ? value : value.ToLower());
                break;
            }

            if (!this._cache.ContainsKey(name))
            {
                var result = Tuple.Create(value, parsedValue);
                this._cache.Add(name, result);
                return(result);
            }
            else if (important)
            {
                var result = Tuple.Create(value, parsedValue);
                this._cache[name] = result;
                return(result);
            }

            return(null);
        }
Esempio n. 2
0
        /// <summary>
        /// Common code for rendering a marker once the orientation angle has been calculated
        /// </summary>
        /// <param name="fAngle"></param>
        /// <param name="pRenderer"></param>
        /// <param name="pOwner"></param>
        /// <param name="pMarkerPoint"></param>
        private void RenderPart2(float fAngle, ISvgRenderer pRenderer, SvgVisualElement pOwner, PointF pMarkerPoint)
        {
            using (var pRenderPen = CreatePen(pOwner, pRenderer))
            {
                using (var markerPath = GetClone(pOwner))
                {
                    using (var transMatrix = new Matrix())
                    {
                        transMatrix.Translate(pMarkerPoint.X, pMarkerPoint.Y);
                        if (Orient.IsAuto)
                        {
                            transMatrix.Rotate(fAngle);
                        }
                        else
                        {
                            transMatrix.Rotate(Orient.Angle);
                        }
                        switch (MarkerUnits)
                        {
                        case SvgMarkerUnits.strokeWidth:
                            transMatrix.Translate(AdjustForViewBoxWidth(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this) *
                                                                        pOwner.StrokeWidth.ToDeviceValue(pRenderer, UnitRenderingType.Other, this)),
                                                  AdjustForViewBoxHeight(-RefY.ToDeviceValue(pRenderer, UnitRenderingType.Vertical, this) *
                                                                         pOwner.StrokeWidth.ToDeviceValue(pRenderer, UnitRenderingType.Other, this)));
                            break;

                        case SvgMarkerUnits.userSpaceOnUse:
                            transMatrix.Translate(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this),
                                                  -RefY.ToDeviceValue(pRenderer, UnitRenderingType.Vertical, this));
                            break;
                        }
                        markerPath.Transform(transMatrix);
                        if (pRenderPen != null)
                        {
                            pRenderer.DrawPath(pRenderPen, markerPath);
                        }

                        SvgPaintServer pFill     = this.Children.First().Fill;
                        SvgFillRule    pFillRule = FillRule;                                                            // TODO: What do we use the fill rule for?
                        float          fOpacity  = FillOpacity;

                        if (pFill != null)
                        {
                            using (var pBrush = pFill.GetBrush(this, pRenderer, fOpacity))
                            {
                                pRenderer.FillPath(pBrush, markerPath);
                            }
                        }
                    }
                }
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Common code for rendering a marker once the orientation angle has been calculated
        /// </summary>
        /// <param name="fAngle"></param>
        /// <param name="pRenderer"></param>
        /// <param name="pOwner"></param>
        /// <param name="pMarkerPoint"></param>
        private void RenderPart2(float fAngle, SvgRenderer pRenderer, SvgPath pOwner, PointF pMarkerPoint)
        {
            Pen pRenderPen = CreatePen(pOwner);

            GraphicsPath markerPath = GetClone(pOwner);

            Matrix transMatrix = new Matrix();

            transMatrix.Translate(pMarkerPoint.X, pMarkerPoint.Y);
            if (Orient.IsAuto)
            {
                transMatrix.Rotate(fAngle);
            }
            else
            {
                transMatrix.Rotate(Orient.Angle);
            }
            switch (MarkerUnits)
            {
            case SvgMarkerUnits.strokeWidth:
                transMatrix.Translate(AdjustForViewBoxWidth(-RefX * pOwner.StrokeWidth), AdjustForViewBoxHeight(-RefY * pOwner.StrokeWidth));
                break;

            case SvgMarkerUnits.userSpaceOnUse:
                transMatrix.Translate(-RefX, -RefY);
                break;
            }
            markerPath.Transform(transMatrix);
            pRenderer.DrawPath(pRenderPen, markerPath);

            SvgPaintServer pFill     = Fill;
            SvgFillRule    pFillRule = FillRule;                                                        // TODO: What do we use the fill rule for?
            float          fOpacity  = FillOpacity;

            if (pFill != null)
            {
                Brush pBrush = pFill.GetBrush(this, fOpacity);
                pRenderer.FillPath(pBrush, markerPath);
                pBrush.Dispose();
            }
            pRenderPen.Dispose();
            markerPath.Dispose();
            transMatrix.Dispose();
        }
Esempio n. 4
0
        /// <summary>
        /// Determine the filled simple segments of a path, splitting lines and curves appropriately.
        /// </summary>
        /// <param name="path">The path that is supposed to be compiled.</param>
        /// <param name="fillRule">The fill rule used to determine the filled components</param>
        /// <returns>The set of simple path components.</returns>
        public static CompiledDrawing CompileFill(SvgPathSegmentList path, SvgFillRule fillRule = SvgFillRule.EvenOdd)
        {
            var curveData = path.SplitCurves();
            var curves    = new List <Curve>();

            foreach (var data in curveData)
            {
                // Add all open curves
                curves.AddRange(data.Curves);

                // Force close the open curves
                var p0 = data.Curves[0].At(0);
                var p1 = data.Curves[data.Curves.Length - 1].At(1);
                if (!DoubleUtils.RoughlyEquals(p0, p1))
                {
                    curves.Add(Curve.Line(p1, p0));
                }
            }

            return(CompileCurves(curves, fillRule));
        }
Esempio n. 5
0
        internal static CompiledDrawing CompileCurves(List <Curve> curves, SvgFillRule fillRule)
        {
            // Reunite all intersections to subdivide the curves
            var curveRootSets = new SortedDictionary <double, Double2> [curves.Count];

            for (int i = 0; i < curveRootSets.Length; i++)
            {
                curveRootSets[i] = new SortedDictionary <double, Double2>()
                {
                    [0] = curves[i].At(0), [1] = curves[i].At(1)
                }
            }
            ;

            // Get all intersections
            for (int i = 0; i < curves.Count; i++)
            {
                for (int j = i + 1; j < curves.Count; j++)
                {
                    foreach (var pair in Curve.Intersections(curves[i], curves[j]))
                    {
                        if (!GeometricUtils.Inside01(pair.A) || !GeometricUtils.Inside01(pair.B))
                        {
                            continue;
                        }

                        curveRootSets[i][pair.A] = curves[i].At(pair.A);
                        curveRootSets[j][pair.B] = curves[j].At(pair.B);
                    }
                }
            }

            // Cluster the intersections
            var curveRootClusters = DerivePointClustersFromRootSets(curveRootSets);

            // Finally, we can start building the DCEL
            var dcel = new DCEL.DCEL();

            for (int i = 0; i < curves.Count; i++)
            {
                var prevPair = new KeyValuePair <double, int>(double.NaN, 0);
                foreach (var curPair in curveRootClusters[i])
                {
                    if (!double.IsNaN(prevPair.Key))
                    {
                        Curve curve;
                        if (prevPair.Key == 0 && curPair.Key == 1)
                        {
                            curve = curves[i];
                        }
                        else
                        {
                            curve = curves[i].Subcurve(prevPair.Key, curPair.Key);
                        }

                        foreach (var c in curve.Simplify())
                        {
                            // Skip degenerate curves
                            if (c.IsDegenerate)
                            {
                                continue;
                            }
                            dcel.AddCurve(c, prevPair.Value, curPair.Value);
                            //Console.WriteLine(dcel);
                            //Console.ReadLine();
                        }
                    }

                    prevPair = curPair;
                }
            }

            //Console.WriteLine(dcel);
            //Console.ReadLine();

            // Now, we remove wedges and assign the fill numbers

            dcel.RemoveWedges();
            //Console.WriteLine(dcel);
            //Console.ReadLine();
            dcel.AssignFillNumbers();
            //Console.WriteLine(dcel);
            //Console.ReadLine();

            // Pick the appropriate predicate for the fill rule
            Func <DCEL.Face, bool> facePredicate;

            if (fillRule == SvgFillRule.EvenOdd)
            {
                facePredicate = f => f.FillNumber % 2 != 0;
            }
            else
            {
                facePredicate = f => f.FillNumber != 0;
            }

            // Simplify the faces
            dcel.SimplifyFaces(facePredicate);
            //Console.WriteLine(dcel);
            //Console.ReadLine();

            // Generate the filled faces
            var fills = dcel.Faces.Where(facePredicate).Select(face =>
                                                               new FillFace(face.Contours.Select(contour =>
                                                                                                 contour.CyclicalSequence.Select(e => e.Curve).ToArray()).ToArray()));

            // Generace the filled faces
            return(CompiledDrawing.ConcatMany(fills.Select(CompiledDrawing.FromFace)));
        }
Esempio n. 6
0
        //==========================================================================
        public SvgDrawableBaseElement(SvgDocument document, SvgBaseElement parent, XElement drawableBaseElement)
            : base(document, parent, drawableBaseElement)
        {
            XAttribute opacity_attribute = drawableBaseElement.Attribute("opacity");

            if (opacity_attribute != null)
            {
                Opacity = SvgLength.Parse(opacity_attribute.Value);
            }

            XAttribute fill_opacity_attribute = drawableBaseElement.Attribute("fill-opacity");

            if (fill_opacity_attribute != null)
            {
                FillOpacity = SvgLength.Parse(fill_opacity_attribute.Value);
            }

            XAttribute stroke_opacity_attribute = drawableBaseElement.Attribute("stroke-opacity");

            if (stroke_opacity_attribute != null)
            {
                StrokeOpacity = SvgLength.Parse(stroke_opacity_attribute.Value);
            }

            XAttribute transform_attribute = drawableBaseElement.Attribute("transform");

            if (transform_attribute != null)
            {
                Transform = SvgTransform.Parse(transform_attribute.Value);
            }

            XAttribute fill_attribute = drawableBaseElement.Attribute("fill");

            if (fill_attribute != null)
            {
                Fill = SvgPaint.Parse(fill_attribute.Value);
            }

            XAttribute stroke_attribute = drawableBaseElement.Attribute("stroke");

            if (stroke_attribute != null)
            {
                Stroke = SvgPaint.Parse(stroke_attribute.Value);
            }

            XAttribute stroke_width_attribute = drawableBaseElement.Attribute("stroke-width");

            if (stroke_width_attribute != null)
            {
                StrokeWidth = SvgLength.Parse(stroke_width_attribute.Value);
            }

            XAttribute stroke_linecap_attribute = drawableBaseElement.Attribute("stroke-linecap");

            if (stroke_linecap_attribute != null)
            {
                switch (stroke_linecap_attribute.Value)
                {
                case "butt":
                    StrokeLinecap = SvgStrokeLinecap.Butt;
                    break;

                case "round":
                    StrokeLinecap = SvgStrokeLinecap.Round;
                    break;

                case "square":
                    StrokeLinecap = SvgStrokeLinecap.Square;
                    break;

                case "inherit":
                    StrokeLinecap = SvgStrokeLinecap.Inherit;
                    break;

                default:
                    throw new NotImplementedException();
                }
            }

            XAttribute stroke_linejoin_attribute = drawableBaseElement.Attribute("stroke-linejoin");

            if (stroke_linejoin_attribute != null)
            {
                switch (stroke_linejoin_attribute.Value)
                {
                case "miter":
                    StrokeLinejoin = SvgStrokeLinejoin.Miter;
                    break;

                case "round":
                    StrokeLinejoin = SvgStrokeLinejoin.Round;
                    break;

                case "bevel":
                    StrokeLinejoin = SvgStrokeLinejoin.Bevel;
                    break;

                case "inherit":
                    StrokeLinejoin = SvgStrokeLinejoin.Inherit;
                    break;

                default:
                    throw new NotSupportedException();
                }
            }

            XAttribute stroke_miterlimit_attribute = drawableBaseElement.Attribute("stroke-miterlimit");

            if (stroke_miterlimit_attribute != null)
            {
                if (stroke_miterlimit_attribute.Value == "inherit")
                {
                    StrokeMiterlimit = Double.NaN;
                }
                else
                {
                    double miterlimit = Double.Parse(stroke_miterlimit_attribute.Value, CultureInfo.InvariantCulture.NumberFormat);
                    //if(miterlimit < 1)
                    //throw new NotSupportedException("A miterlimit less than 1 is not supported.");
                    StrokeMiterlimit = miterlimit;
                }
            }

            XAttribute stroke_dasharray_attribute = drawableBaseElement.Attribute("stroke-dasharray");

            if (stroke_dasharray_attribute != null)
            {
                if (stroke_dasharray_attribute.Value == "none")
                {
                    StrokeDasharray = null;
                }
                else if (stroke_dasharray_attribute.Value == "inherit")
                {
                    StrokeDasharray = new SvgLength[0];
                }
                else
                {
                    List <SvgLength> lengths = new List <SvgLength>();
                    foreach (string length in stroke_dasharray_attribute.Value.Split(','))
                    {
                        lengths.Add(SvgLength.Parse(length));
                    }

                    if (lengths.Count % 2 == 1)
                    {
                        StrokeDasharray = new SvgLength[lengths.Count * 2];
                        for (int i = 0; i < lengths.Count - 1; ++i)
                        {
                            StrokeDasharray[i] = lengths[i];
                            StrokeDasharray[i + lengths.Count] = lengths[i];
                        }
                    }
                    else
                    {
                        StrokeDasharray = lengths.ToArray();
                    }
                }
            }

            XAttribute stroke_dashoffset_attribute = drawableBaseElement.Attribute("stroke-dashoffset");

            if (stroke_dashoffset_attribute != null)
            {
                StrokeDashoffset = SvgLength.Parse(stroke_dashoffset_attribute.Value);
            }

            XAttribute clip_attribute = drawableBaseElement.Attribute("clip-path");

            if (clip_attribute != null)
            {
                string clip_path = clip_attribute.Value.Trim();
                if (clip_path.StartsWith("url"))
                {
                    clip_path = clip_path.Substring(3).Trim();
                    if (clip_path.StartsWith("(") && clip_path.EndsWith(")"))
                    {
                        clip_path = clip_path.Substring(1, clip_path.Length - 2).Trim();
                        if (clip_path.StartsWith("#"))
                        {
                            ClipPath = clip_path.Substring(1);
                        }
                    }
                }
            }

            XAttribute filter_attribute = drawableBaseElement.Attribute("filter");

            if (filter_attribute != null)
            {
                string filter = filter_attribute.Value.Trim();
                if (filter.StartsWith("url"))
                {
                    filter = filter.Substring(3).Trim();
                    if (filter.StartsWith("(") && filter.EndsWith(")"))
                    {
                        filter = filter.Substring(1, filter.Length - 2).Trim();
                        if (filter.StartsWith("#"))
                        {
                            Filter = filter.Substring(1);
                        }
                    }
                }
            }

            XAttribute mask_attribute = drawableBaseElement.Attribute("mask");

            if (mask_attribute != null)
            {
                string mask = mask_attribute.Value.Trim();
                if (mask.StartsWith("url"))
                {
                    mask = mask.Substring(3).Trim();
                    if (mask.StartsWith("(") && mask.EndsWith(")"))
                    {
                        mask = mask.Substring(1, mask.Length - 2).Trim();
                        if (mask.StartsWith("#"))
                        {
                            Mask = mask.Substring(1);
                        }
                    }
                }
            }

            XAttribute display_attribute = drawableBaseElement.Attribute("display");

            if (display_attribute != null)
            {
                switch (display_attribute.Value)
                {
                case "inline":
                    Display = SvgDisplay.Inline;
                    break;

                case "block":
                    Display = SvgDisplay.Block;
                    break;

                case "list-item":
                    Display = SvgDisplay.ListItem;
                    break;

                case "run-in":
                    Display = SvgDisplay.RunIn;
                    break;

                case "compact":
                    Display = SvgDisplay.Compact;
                    break;

                case "marker":
                    Display = SvgDisplay.Marker;
                    break;

                case "table":
                    Display = SvgDisplay.Table;
                    break;

                case "inline-table":
                    Display = SvgDisplay.InlineTable;
                    break;

                case "table-row-group":
                    Display = SvgDisplay.TableRowGroup;
                    break;

                case "table-header-group":
                    Display = SvgDisplay.TableHeaderGroup;
                    break;

                case "table-footer-group":
                    Display = SvgDisplay.TableFooterGroup;
                    break;

                case "table-row":
                    Display = SvgDisplay.TableRow;
                    break;

                case "table-column-group":
                    Display = SvgDisplay.TableColumnGroup;
                    break;

                case "table-column":
                    Display = SvgDisplay.TableColumn;
                    break;

                case "table-cell":
                    Display = SvgDisplay.TableCell;
                    break;

                case "table-caption":
                    Display = SvgDisplay.TableCaption;
                    break;

                case "none":
                    Display = SvgDisplay.None;
                    break;

                default:
                    throw new NotImplementedException();
                }
            }

            XAttribute fill_rule_attribute = drawableBaseElement.Attribute("fill-rule");

            if (fill_rule_attribute != null)
            {
                switch (fill_rule_attribute.Value)
                {
                case "nonzero":
                    FillRule = SvgFillRule.Nonzero;
                    break;

                case "evenodd":
                    FillRule = SvgFillRule.Evenodd;
                    break;

                case "inherit":
                    FillRule = SvgFillRule.Inherit;
                    break;

                default:
                    throw new NotImplementedException();
                }
            }

            // color, color-interpolation, color-rendering

            // viewBox attribute
            // preserveAspectRatio attribute

            // overflow


            foreach (XElement element in from element in drawableBaseElement.Elements()
                     where element.Name.NamespaceName == "http://www.w3.org/2000/svg"
                     select element)
            {
                switch (element.Name.LocalName)
                {
                default:
                    throw new NotImplementedException(String.Format("Unhandled element: {0}", element));
                }
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Common code for rendering a marker once the orientation angle has been calculated
        /// </summary>
        /// <param name="fAngle"></param>
        /// <param name="pRenderer"></param>
        /// <param name="pOwner"></param>
        /// <param name="pMarkerPoint"></param>
        private void RenderPart2(float fAngle, ISvgRenderer pRenderer, SvgVisualElement pOwner, PointF pMarkerPoint)
        {
            using (var pRenderPen = CreatePen(pOwner, pRenderer))
            {
                using (var markerPath = GetClone(pOwner, pRenderer))
                {
                    using (var transMatrix = new Matrix())
                    {
                        transMatrix.Translate(pMarkerPoint.X, pMarkerPoint.Y);
                        if (Orient.IsAuto)
                        {
                            transMatrix.Rotate(fAngle);
                        }
                        else
                        {
                            transMatrix.Rotate(Orient.Angle);
                        }
                        switch (MarkerUnits)
                        {
                        case SvgMarkerUnits.StrokeWidth:
                            if (ViewBox.Width > 0 && ViewBox.Height > 0)
                            {
                                transMatrix.Scale(MarkerWidth, MarkerHeight);
                                var strokeWidth = pOwner.StrokeWidth.ToDeviceValue(pRenderer, UnitRenderingType.Other, this);
                                transMatrix.Translate(AdjustForViewBoxWidth(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this) *
                                                                            strokeWidth),
                                                      AdjustForViewBoxHeight(-RefY.ToDeviceValue(pRenderer, UnitRenderingType.Vertical, this) *
                                                                             strokeWidth));
                            }
                            else
                            {
                                // SvgMarkerUnits.UserSpaceOnUse
                                // TODO: We know this isn't correct.
                                //        But use this until the TODOs from AdjustForViewBoxWidth and AdjustForViewBoxHeight are done.
                                //  MORE see Unit Test "MakerEndTest.TestArrowCodeCreation()"
                                transMatrix.Translate(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this),
                                                      -RefY.ToDeviceValue(pRenderer, UnitRenderingType.Vertical, this));
                            }
                            break;

                        case SvgMarkerUnits.UserSpaceOnUse:
                            transMatrix.Translate(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this),
                                                  -RefY.ToDeviceValue(pRenderer, UnitRenderingType.Vertical, this));
                            break;
                        }

                        if (MarkerElement != null && MarkerElement.Transforms != null)
                        {
                            using (var matrix = MarkerElement.Transforms.GetMatrix())
                                transMatrix.Multiply(matrix);
                        }
                        markerPath.Transform(transMatrix);
                        if (pRenderPen != null)
                        {
                            pRenderer.DrawPath(pRenderPen, markerPath);
                        }

                        SvgPaintServer pFill     = this.Children.First().Fill;
                        SvgFillRule    pFillRule = FillRule; // TODO: What do we use the fill rule for?

                        if (pFill != null)
                        {
                            using (var pBrush = pFill.GetBrush(this, pRenderer, FixOpacityValue(FillOpacity)))
                            {
                                pRenderer.FillPath(pBrush, markerPath);
                            }
                        }
                    }
                }
            }
        }
        //==========================================================================
        public SvgDrawableContainerBaseElement(SvgDocument document, SvgBaseElement parent, XElement drawableContainerElement)
            : base(document, parent, drawableContainerElement)
        {
            XAttribute viewBox_attribute = drawableContainerElement.Attribute("viewBox");

            if (viewBox_attribute != null)
            {
                this.ViewBox = SvgViewbox.Parse(viewBox_attribute.Value);
            }

            XAttribute opacity_attribute = drawableContainerElement.Attribute("opacity");

            SvgLength.TryUpdate(ref Opacity, opacity_attribute?.Value);

            XAttribute transform_attribute = drawableContainerElement.Attribute("transform");

            if (transform_attribute != null)
            {
                Transform = SvgTransform.Parse(transform_attribute.Value);
            }

            XAttribute clip_attribute = drawableContainerElement.Attribute("clip-path");

            if (clip_attribute != null)
            {
                ClipPath = SvgURL.Parse(clip_attribute.Value);
            }

            XAttribute filter_attribute = drawableContainerElement.Attribute("filter");

            if (filter_attribute != null)
            {
                Filter = SvgURL.Parse(filter_attribute.Value);
            }

            XAttribute mask_attribute = drawableContainerElement.Attribute("mask");

            if (mask_attribute != null)
            {
                Mask = SvgURL.Parse(mask_attribute.Value);
            }

            XAttribute display_attribute = drawableContainerElement.Attribute("display");

            if (display_attribute != null)
            {
                switch (display_attribute.Value)
                {
                case "inline":
                    Display = SvgDisplay.Inline;
                    break;

                case "block":
                    Display = SvgDisplay.Block;
                    break;

                case "list-item":
                    Display = SvgDisplay.ListItem;
                    break;

                case "run-in":
                    Display = SvgDisplay.RunIn;
                    break;

                case "compact":
                    Display = SvgDisplay.Compact;
                    break;

                case "marker":
                    Display = SvgDisplay.Marker;
                    break;

                case "table":
                    Display = SvgDisplay.Table;
                    break;

                case "inline-table":
                    Display = SvgDisplay.InlineTable;
                    break;

                case "table-row-group":
                    Display = SvgDisplay.TableRowGroup;
                    break;

                case "table-header-group":
                    Display = SvgDisplay.TableHeaderGroup;
                    break;

                case "table-footer-group":
                    Display = SvgDisplay.TableFooterGroup;
                    break;

                case "table-row":
                    Display = SvgDisplay.TableRow;
                    break;

                case "table-column-group":
                    Display = SvgDisplay.TableColumnGroup;
                    break;

                case "table-column":
                    Display = SvgDisplay.TableColumn;
                    break;

                case "table-cell":
                    Display = SvgDisplay.TableCell;
                    break;

                case "table-caption":
                    Display = SvgDisplay.TableCaption;
                    break;

                case "none":
                    Display = SvgDisplay.None;
                    break;

                default:
                    throw new NotImplementedException();
                }
            }

            XAttribute fill_opacity_attribute = drawableContainerElement.Attribute("fill-opacity");

            SvgLength.TryUpdate(ref FillOpacity, fill_opacity_attribute?.Value);

            XAttribute stroke_opacity_attribute = drawableContainerElement.Attribute("stroke-opacity");

            SvgLength.TryUpdate(ref StrokeOpacity, stroke_opacity_attribute?.Value);

            XAttribute fill_attribute = drawableContainerElement.Attribute("fill");

            if (fill_attribute != null)
            {
                Fill = SvgPaint.Parse(fill_attribute.Value);
            }

            XAttribute stroke_attribute = drawableContainerElement.Attribute("stroke");

            if (stroke_attribute != null)
            {
                Stroke = SvgPaint.Parse(stroke_attribute.Value);
            }

            XAttribute stroke_width_attribute = drawableContainerElement.Attribute("stroke-width");

            SvgLength.TryUpdate(ref StrokeWidth, stroke_width_attribute?.Value);

            XAttribute stroke_linecap_attribute = drawableContainerElement.Attribute("stroke-linecap");

            if (stroke_linecap_attribute != null)
            {
                switch (stroke_linecap_attribute.Value)
                {
                case "butt":
                    StrokeLinecap = SvgStrokeLinecap.Butt;
                    break;

                case "round":
                    StrokeLinecap = SvgStrokeLinecap.Round;
                    break;

                case "square":
                    StrokeLinecap = SvgStrokeLinecap.Square;
                    break;

                case "inherit":
                    StrokeLinecap = SvgStrokeLinecap.Inherit;
                    break;

                default:
                    throw new NotImplementedException();
                }
            }

            XAttribute stroke_linejoin_attribute = drawableContainerElement.Attribute("stroke-linejoin");

            if (stroke_linejoin_attribute != null)
            {
                switch (stroke_linejoin_attribute.Value)
                {
                case "miter":
                    StrokeLinejoin = SvgStrokeLinejoin.Miter;
                    break;

                case "round":
                    StrokeLinejoin = SvgStrokeLinejoin.Round;
                    break;

                case "bevel":
                    StrokeLinejoin = SvgStrokeLinejoin.Bevel;
                    break;

                case "inherit":
                    StrokeLinejoin = SvgStrokeLinejoin.Inherit;
                    break;

                default:
                    throw new NotSupportedException();
                }
            }

            XAttribute stroke_miterlimit_attribute = drawableContainerElement.Attribute("stroke-miterlimit");

            if (stroke_miterlimit_attribute != null)
            {
                if (stroke_miterlimit_attribute.Value == "inherit")
                {
                    StrokeMiterlimit = Double.NaN;
                }
                else
                {
                    double miterlimit = Double.Parse(stroke_miterlimit_attribute.Value, CultureInfo.InvariantCulture.NumberFormat);
                    //if(miterlimit < 1)
                    //throw new NotSupportedException("A miterlimit less than 1 is not supported.");
                    StrokeMiterlimit = miterlimit;
                }
            }

            XAttribute stroke_dasharray_attribute = drawableContainerElement.Attribute("stroke-dasharray");

            if (stroke_dasharray_attribute != null)
            {
                if (stroke_dasharray_attribute.Value == "none")
                {
                    StrokeDasharray = null;
                }
                else if (stroke_dasharray_attribute.Value == "inherit")
                {
                    StrokeDasharray = new SvgLength[0];
                }
                else
                {
                    List <SvgLength> lengths = new List <SvgLength>();
                    var lengthTokens         = stroke_dasharray_attribute.Value.Replace(";", "")
                                               .Trim()
                                               .Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (string length in lengthTokens)
                    {
                        lengths.Add(SvgLength.Parse(length));
                    }

                    if (lengths.Count % 2 == 1)
                    {
                        StrokeDasharray = new SvgLength[lengths.Count * 2];
                        for (int i = 0; i < lengths.Count - 1; ++i)
                        {
                            StrokeDasharray[i] = lengths[i];
                            StrokeDasharray[i + lengths.Count] = lengths[i];
                        }
                    }
                    else
                    {
                        StrokeDasharray = lengths.ToArray();
                    }
                }
            }

            XAttribute stroke_dashoffset_attribute = drawableContainerElement.Attribute("stroke-dashoffset");

            SvgLength.TryUpdate(ref StrokeDashoffset, stroke_dashoffset_attribute?.Value);

            XAttribute fill_rule_attribute = drawableContainerElement.Attribute("fill-rule");

            if (fill_rule_attribute != null)
            {
                switch (fill_rule_attribute.Value)
                {
                case "nonzero":
                    FillRule = SvgFillRule.Nonzero;
                    break;

                case "evenodd":
                    FillRule = SvgFillRule.Evenodd;
                    break;

                case "inherit":
                    FillRule = SvgFillRule.Inherit;
                    break;

                default:
                    throw new NotImplementedException();
                }
            }

            // color, color-interpolation, color-rendering

            XAttribute width_attribute = drawableContainerElement.Attribute("width");

            SvgLength.TryUpdate(ref Width, width_attribute?.Value);
            XAttribute height_attribute = drawableContainerElement.Attribute("height");

            SvgLength.TryUpdate(ref Height, height_attribute?.Value);

            XAttribute preserveAspectRatio_attribute = drawableContainerElement.Attribute("preserveAspectRatio");

            if (preserveAspectRatio_attribute != null)
            {
                switch (preserveAspectRatio_attribute.Value)
                {
                case "none":
                    if (Width != null && Height != null)
                    {
                        var scaleTransform = new SvgScaleTransform(
                            Width.ToDouble() / ViewBox.Value.Width,
                            Height.ToDouble() / ViewBox.Value.Height);
                        Width.ToDouble();
                        if (Transform == null)
                        {
                            Transform = scaleTransform;
                        }
                        else
                        {
                            Transform = new SvgTransformGroup(new[] { Transform, scaleTransform });
                        }
                    }
                    break;
                }
            }
            // overflow
        }
        //==========================================================================
        public SvgDrawableBaseElement(SvgDocument document, SvgBaseElement parent, XElement drawableBaseElement)
            : base(document, parent, drawableBaseElement)
        {
            XAttribute opacity_attribute = drawableBaseElement.Attribute("opacity");
              if(opacity_attribute != null)
            Opacity = SvgLength.Parse(opacity_attribute.Value);

              XAttribute fill_opacity_attribute = drawableBaseElement.Attribute("fill-opacity");
              if(fill_opacity_attribute != null)
            FillOpacity = SvgLength.Parse(fill_opacity_attribute.Value);

              XAttribute stroke_opacity_attribute = drawableBaseElement.Attribute("stroke-opacity");
              if(stroke_opacity_attribute != null)
            StrokeOpacity = SvgLength.Parse(stroke_opacity_attribute.Value);

              XAttribute transform_attribute = drawableBaseElement.Attribute("transform");
              if(transform_attribute != null)
            Transform = SvgTransform.Parse(transform_attribute.Value);

              XAttribute fill_attribute = drawableBaseElement.Attribute("fill");
              if(fill_attribute != null)
            Fill = SvgPaint.Parse(fill_attribute.Value);

              XAttribute stroke_attribute = drawableBaseElement.Attribute("stroke");
              if(stroke_attribute != null)
            Stroke = SvgPaint.Parse(stroke_attribute.Value);

              XAttribute stroke_width_attribute = drawableBaseElement.Attribute("stroke-width");
              if(stroke_width_attribute != null)
            StrokeWidth = SvgLength.Parse(stroke_width_attribute.Value);

              XAttribute stroke_linecap_attribute = drawableBaseElement.Attribute("stroke-linecap");
              if(stroke_linecap_attribute != null)
            switch(stroke_linecap_attribute.Value)
            {
              case "butt":
            StrokeLinecap = SvgStrokeLinecap.Butt;
            break;

              case "round":
            StrokeLinecap = SvgStrokeLinecap.Round;
            break;

              case "square":
            StrokeLinecap = SvgStrokeLinecap.Square;
            break;

              case "inherit":
            StrokeLinecap = SvgStrokeLinecap.Inherit;
            break;

              default:
            throw new NotImplementedException();
            }

              XAttribute stroke_linejoin_attribute = drawableBaseElement.Attribute("stroke-linejoin");
              if(stroke_linejoin_attribute != null)
            switch(stroke_linejoin_attribute.Value)
            {
              case "miter":
            StrokeLinejoin = SvgStrokeLinejoin.Miter;
            break;

              case "round":
            StrokeLinejoin = SvgStrokeLinejoin.Round;
            break;

              case "bevel":
            StrokeLinejoin = SvgStrokeLinejoin.Bevel;
            break;

              case "inherit":
            StrokeLinejoin = SvgStrokeLinejoin.Inherit;
            break;

              default:
            throw new NotSupportedException();
            }

              XAttribute stroke_miterlimit_attribute = drawableBaseElement.Attribute("stroke-miterlimit");
              if(stroke_miterlimit_attribute != null)
              {
            if(stroke_miterlimit_attribute.Value == "inherit")
              StrokeMiterlimit = Double.NaN;
            else
            {
              double miterlimit = Double.Parse(stroke_miterlimit_attribute.Value, CultureInfo.InvariantCulture.NumberFormat);
              //if(miterlimit < 1)
            //throw new NotSupportedException("A miterlimit less than 1 is not supported.");
              StrokeMiterlimit = miterlimit;
            }
              }

              XAttribute stroke_dasharray_attribute = drawableBaseElement.Attribute("stroke-dasharray");
              if(stroke_dasharray_attribute != null)
              {
            if(stroke_dasharray_attribute.Value == "none")
              StrokeDasharray = null;
            else if(stroke_dasharray_attribute.Value == "inherit")
              StrokeDasharray = new SvgLength[0];
            else
            {
              List<SvgLength> lengths = new List<SvgLength>();
              foreach(string length in stroke_dasharray_attribute.Value.Split(','))
            lengths.Add(SvgLength.Parse(length));

              if(lengths.Count % 2 == 1)
              {
            StrokeDasharray = new SvgLength[lengths.Count * 2];
            for(int i = 0; i < lengths.Count - 1; ++i)
            {
              StrokeDasharray[i] = lengths[i];
              StrokeDasharray[i + lengths.Count] = lengths[i];
            }
              }
              else
            StrokeDasharray = lengths.ToArray();

            }
              }

              XAttribute stroke_dashoffset_attribute = drawableBaseElement.Attribute("stroke-dashoffset");
              if(stroke_dashoffset_attribute != null)
            StrokeDashoffset = SvgLength.Parse(stroke_dashoffset_attribute.Value);

              XAttribute clip_attribute = drawableBaseElement.Attribute("clip-path");
              if(clip_attribute != null)
              {
            string clip_path = clip_attribute.Value.Trim();
            if(clip_path.StartsWith("url"))
            {
              clip_path = clip_path.Substring(3).Trim();
              if(clip_path.StartsWith("(") && clip_path.EndsWith(")"))
              {
            clip_path = clip_path.Substring(1, clip_path.Length - 2).Trim();
            if(clip_path.StartsWith("#"))
              ClipPath = clip_path.Substring(1);
              }
            }
              }

              XAttribute filter_attribute = drawableBaseElement.Attribute("filter");
              if(filter_attribute != null)
              {
            string filter = filter_attribute.Value.Trim();
            if(filter.StartsWith("url"))
            {
              filter = filter.Substring(3).Trim();
              if(filter.StartsWith("(") && filter.EndsWith(")"))
              {
            filter = filter.Substring(1, filter.Length - 2).Trim();
            if(filter.StartsWith("#"))
              Filter = filter.Substring(1);
              }
            }
              }

              XAttribute mask_attribute = drawableBaseElement.Attribute("mask");
              if(mask_attribute != null)
              {
            string mask = mask_attribute.Value.Trim();
            if(mask.StartsWith("url"))
            {
              mask = mask.Substring(3).Trim();
              if(mask.StartsWith("(") && mask.EndsWith(")"))
              {
            mask = mask.Substring(1, mask.Length - 2).Trim();
            if(mask.StartsWith("#"))
              Mask = mask.Substring(1);
              }
            }
              }

              XAttribute display_attribute = drawableBaseElement.Attribute("display");
              if(display_attribute != null)
            switch(display_attribute.Value)
            {
              case "inline":
            Display = SvgDisplay.Inline;
            break;

              case "block":
            Display = SvgDisplay.Block;
            break;

              case "list-item":
            Display = SvgDisplay.ListItem;
            break;

              case "run-in":
            Display = SvgDisplay.RunIn;
            break;

              case "compact":
            Display = SvgDisplay.Compact;
            break;

              case "marker":
            Display = SvgDisplay.Marker;
            break;

              case "table":
            Display = SvgDisplay.Table;
            break;

              case "inline-table":
            Display = SvgDisplay.InlineTable;
            break;

              case "table-row-group":
            Display = SvgDisplay.TableRowGroup;
            break;

              case "table-header-group":
            Display = SvgDisplay.TableHeaderGroup;
            break;

              case "table-footer-group":
            Display = SvgDisplay.TableFooterGroup;
            break;

              case "table-row":
            Display = SvgDisplay.TableRow;
            break;

              case "table-column-group":
            Display = SvgDisplay.TableColumnGroup;
            break;

              case "table-column":
            Display = SvgDisplay.TableColumn;
            break;

              case "table-cell":
            Display = SvgDisplay.TableCell;
            break;

              case "table-caption":
            Display = SvgDisplay.TableCaption;
            break;

              case "none":
            Display = SvgDisplay.None;
            break;

              default:
            throw new NotImplementedException();
            }

              XAttribute fill_rule_attribute = drawableBaseElement.Attribute("fill-rule");
              if(fill_rule_attribute != null)
            switch(fill_rule_attribute.Value)
            {
              case "nonzero":
            FillRule = SvgFillRule.Nonzero;
            break;

              case "evenodd":
            FillRule = SvgFillRule.Evenodd;
            break;

              case "inherit":
            FillRule = SvgFillRule.Inherit;
            break;

              default:
            throw new NotImplementedException();
            }

              // color, color-interpolation, color-rendering

              // viewBox attribute
              // preserveAspectRatio attribute

              // overflow

              foreach(XElement element in from element in drawableBaseElement.Elements()
                                  where element.Name.NamespaceName == "http://www.w3.org/2000/svg"
                                  select element)
            switch(element.Name.LocalName)
            {
              default:
            throw new NotImplementedException(String.Format("Unhandled element: {0}", element));
            }
        }