Exemplo n.º 1
0
        /// <summary>
        /// Converts the given object to the type of this converter, using the specified context and culture information.
        /// </summary>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
        /// <param name="culture">The <see cref="T:System.Globalization.CultureInfo"/> to use as the current culture.</param>
        /// <param name="value">The <see cref="T:System.Object"/> to convert.</param>
        /// <returns>
        /// An <see cref="T:System.Object"/> that represents the converted value.
        /// </returns>
        /// <exception cref="T:System.NotSupportedException">The conversion cannot be performed. </exception>
        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value is string)
            {
                if (string.Compare(((string)value).Trim(), "none", StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    return(null);
                }
                string[]          points = ((string)value).Trim().Split(new char[] { ',', ' ', '\r', '\n', '\t' }, StringSplitOptions.RemoveEmptyEntries);
                SvgUnitCollection units  = new SvgUnitCollection();

                foreach (string point in points)
                {
                    SvgUnit newUnit = (SvgUnit)_unitConverter.ConvertFrom(point.Trim());
                    if (!newUnit.IsNone)
                    {
                        units.Add(newUnit);
                    }
                }

                return(units);
            }

            return(base.ConvertFrom(context, culture, value));
        }
Exemplo n.º 2
0
        /// <summary>
        /// Converts the given object to the type of this converter, using the specified context and culture information.
        /// </summary>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
        /// <param name="culture">The <see cref="T:System.Globalization.CultureInfo"/> to use as the current culture.</param>
        /// <param name="value">The <see cref="T:System.Object"/> to convert.</param>
        /// <returns>
        /// An <see cref="T:System.Object"/> that represents the converted value.
        /// </returns>
        /// <exception cref="T:System.NotSupportedException">The conversion cannot be performed. </exception>
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value is string)
            {
                var s = ((string)value).Trim();

                if (s.Equals("inherit", StringComparison.OrdinalIgnoreCase))
                {
                    return(null);
                }

                var units = new SvgUnitCollection();
                if (!s.Equals("none", StringComparison.OrdinalIgnoreCase))
                {
                    foreach (var point in s.Split(new char[] { ',', ' ', '\r', '\n', '\t' }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        var newUnit = (SvgUnit)_unitConverter.ConvertFrom(point.Trim());
                        if (!newUnit.IsNone)
                        {
                            units.Add(newUnit);
                        }
                    }
                }

                return(units);
            }

            return(base.ConvertFrom(context, culture, value));
        }
Exemplo n.º 3
0
        public object Clone()
        {
            var units = new SvgUnitCollection
            {
                StringForEmptyValue = StringForEmptyValue
            };

            units.AddRange(this);
            return(units);
        }
Exemplo n.º 4
0
        public static SvgUnitCollection Parse(ReadOnlySpan <char> points)
        {
            var units      = new SvgUnitCollection();
            var splitChars = SplitChars.AsSpan();
            var parts      = new StringSplitEnumerator(points, splitChars);

            foreach (var part in parts)
            {
                var newUnit = SvgUnitConverter.Parse(part.Value);
                if (!newUnit.IsNone)
                {
                    units.Add(newUnit);
                }
            }

            return(units);
        }
        /// <summary>
        /// Converts the given object to the type of this converter, using the specified context and culture information.
        /// </summary>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
        /// <param name="culture">The <see cref="T:System.Globalization.CultureInfo"/> to use as the current culture.</param>
        /// <param name="value">The <see cref="T:System.Object"/> to convert.</param>
        /// <returns>
        /// An <see cref="T:System.Object"/> that represents the converted value.
        /// </returns>
        /// <exception cref="T:System.NotSupportedException">The conversion cannot be performed. </exception>
        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            if (value is string)
            {
                string[]          points = ((string)value).Trim().Split(new char[] { ',', ' ', '\r', '\n', '\t' }, StringSplitOptions.RemoveEmptyEntries);
                SvgUnitCollection units  = new SvgUnitCollection();

                foreach (string point in points)
                {
                    units.Add((SvgUnit)_unitConverter.ConvertFrom(point.Trim()));
                }

                return(units);
            }

            return(base.ConvertFrom(context, culture, value));
        }
Exemplo n.º 6
0
        /// <summary>
        /// Converts the given object to the type of this converter, using the specified context and culture information.
        /// </summary>
        /// <param name="context">An <see cref="T:System.ComponentModel.ITypeDescriptorContext"/> that provides a format context.</param>
        /// <param name="culture">The <see cref="T:System.Globalization.CultureInfo"/> to use as the current culture.</param>
        /// <param name="value">The <see cref="T:System.Object"/> to convert.</param>
        /// <returns>
        /// An <see cref="T:System.Object"/> that represents the converted value.
        /// </returns>
        /// <exception cref="T:System.NotSupportedException">The conversion cannot be performed. </exception>
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value is string)
            {
                var points = ((string)value).Trim().Split(new char[] { ',', ' ', '\r', '\n', '\t' }, StringSplitOptions.RemoveEmptyEntries);
                var units  = new SvgUnitCollection();

                foreach (var point in points)
                {
                    var newUnit = (SvgUnit)_unitConverter.ConvertFrom(point.Trim());
                    if (!newUnit.IsNone)
                    {
                        units.Add(newUnit);
                    }
                }

                return(units);
            }

            return(base.ConvertFrom(context, culture, value));
        }
Exemplo n.º 7
0
        public void AddRange(IEnumerable <SvgUnit> collection)
        {
            if (collection == null)
            {
                throw new ArgumentNullException(nameof(collection));
            }

            if (collection == this)
            {
                // handle special case where the collection is duplicated
                // we need to clone it to avoid an exception during enumeration
                var clonedCollection = new SvgUnitCollection();
                foreach (var unit in collection)
                {
                    clonedCollection.Add(unit);
                }
                collection = clonedCollection;
            }

            foreach (var unit in collection)
            {
                Add(unit);
            }
        }
Exemplo n.º 8
0
 public static bool IsNullOrEmpty(SvgUnitCollection collection)
 {
     return(collection == null || collection.Count < 1 ||
            (collection.Count == 1 && (collection[0] == SvgUnit.Empty || collection[0] == SvgUnit.None)));
 }
Exemplo n.º 9
0
        /// <summary>
        /// Renders the stroke of the <see cref="SvgVisualElement"/> to the specified <see cref="ISvgRenderer"/>
        /// </summary>
        /// <param name="renderer">The <see cref="ISvgRenderer"/> object to render to.</param>
        protected internal virtual bool RenderStroke(ISvgRenderer renderer)
        {
            if (Stroke != null && Stroke != SvgPaintServer.None && StrokeWidth > 0f)
            {
                var strokeWidth = StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this);
                using (var brush = Stroke.GetBrush(this, renderer, FixOpacityValue(StrokeOpacity), true))
                {
                    if (brush != null)
                    {
                        var path   = Path(renderer);
                        var bounds = path.GetBounds();
                        if (path.PointCount < 1)
                        {
                            return(false);
                        }
                        if (bounds.Width <= 0f && bounds.Height <= 0f)
                        {
                            switch (StrokeLineCap)
                            {
                            case SvgStrokeLineCap.Round:
                                using (var capPath = new GraphicsPath())
                                {
                                    capPath.AddEllipse(path.PathPoints[0].X - strokeWidth / 2f, path.PathPoints[0].Y - strokeWidth / 2f, strokeWidth, strokeWidth);
                                    renderer.FillPath(brush, capPath);
                                }
                                break;

                            case SvgStrokeLineCap.Square:
                                using (var capPath = new GraphicsPath())
                                {
                                    capPath.AddRectangle(new RectangleF(path.PathPoints[0].X - strokeWidth / 2f, path.PathPoints[0].Y - strokeWidth / 2f, strokeWidth, strokeWidth));
                                    renderer.FillPath(brush, capPath);
                                }
                                break;
                            }
                        }
                        else
                        {
                            using (var pen = new Pen(brush, strokeWidth))
                            {
                                if (StrokeDashArray != null && StrokeDashArray.Count > 0)
                                {
                                    var strokeDashArray = StrokeDashArray;
                                    if (strokeDashArray.Count % 2 != 0)
                                    {
                                        // handle odd dash arrays by repeating them once
                                        strokeDashArray = new SvgUnitCollection();
                                        strokeDashArray.AddRange(StrokeDashArray);
                                        strokeDashArray.AddRange(StrokeDashArray);
                                    }
                                    var dashOffset = StrokeDashOffset;

                                    strokeWidth = Math.Max(strokeWidth, 1f);

                                    /* divide by stroke width - GDI uses stroke width as unit.*/
                                    var dashPattern = strokeDashArray.Select(u => ((u.ToDeviceValue(renderer, UnitRenderingType.Other, this) <= 0f) ? 1f :
                                                                                   u.ToDeviceValue(renderer, UnitRenderingType.Other, this)) / strokeWidth).ToArray();
                                    var length = dashPattern.Length;

                                    if (StrokeLineCap == SvgStrokeLineCap.Round)
                                    {
                                        // to handle round caps, we have to adapt the dash pattern
                                        // by increasing the dash length by the stroke width - GDI draws the rounded
                                        // edge inside the dash line, SVG draws it outside the line
                                        var pattern = new float[length];
                                        var offset  = 1; // the values are already normalized to dash width
                                        for (var i = 0; i < length; i++)
                                        {
                                            pattern[i] = dashPattern[i] + offset;
                                            if (pattern[i] <= 0f)
                                            {
                                                // overlapping caps - remove the gap for simplicity, see #508
                                                if (i < length - 1)
                                                {
                                                    // add the next dash segment to the current one
                                                    dashPattern[i - 1] += dashPattern[i] + dashPattern[i + 1];
                                                    length             -= 2;
                                                    for (var k = i; k < length; k++)
                                                    {
                                                        dashPattern[k] = dashPattern[k + 2];
                                                    }

                                                    // and handle the combined segment again
                                                    i -= 2;
                                                }
                                                else if (i > 2)
                                                {
                                                    // add the last dash segment to the first one
                                                    // this will change the start point, so adapt the offset
                                                    var dashLength = dashPattern[i - 1] + dashPattern[i];
                                                    pattern[0] += dashLength;
                                                    length     -= 2;
                                                    dashOffset += dashLength * strokeWidth;
                                                }
                                                else
                                                {
                                                    // we have only one dash with the gap too small -
                                                    // do not use dash at all
                                                    length = 0;
                                                    break;
                                                }
                                            }
                                            offset *= -1; // increase dash length, decrease spaces
                                        }
                                        if (length > 0)
                                        {
                                            if (length < dashPattern.Length)
                                            {
                                                Array.Resize(ref pattern, length);
                                            }
                                            dashPattern = pattern;
                                            pen.DashCap = DashCap.Round;
                                        }
                                    }

                                    if (length > 0)
                                    {
                                        pen.DashPattern = dashPattern;

                                        if (dashOffset != 0f)
                                        {
                                            pen.DashOffset = ((dashOffset.ToDeviceValue(renderer, UnitRenderingType.Other, this) <= 0f) ? 1f :
                                                              dashOffset.ToDeviceValue(renderer, UnitRenderingType.Other, this)) / strokeWidth;
                                        }
                                    }
                                }
                                switch (StrokeLineJoin)
                                {
                                case SvgStrokeLineJoin.Bevel:
                                    pen.LineJoin = LineJoin.Bevel;
                                    break;

                                case SvgStrokeLineJoin.Round:
                                    pen.LineJoin = LineJoin.Round;
                                    break;

                                default:
                                    pen.LineJoin = LineJoin.Miter;
                                    break;
                                }
                                pen.MiterLimit = StrokeMiterLimit;
                                switch (StrokeLineCap)
                                {
                                case SvgStrokeLineCap.Round:
                                    pen.StartCap = LineCap.Round;
                                    pen.EndCap   = LineCap.Round;
                                    break;

                                case SvgStrokeLineCap.Square:
                                    pen.StartCap = LineCap.Square;
                                    pen.EndCap   = LineCap.Square;
                                    break;
                                }

                                renderer.DrawPath(pen, path);

                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }