Example #1
0
        public static SKPath?GetSvgVisualElementClipPath(SvgVisualElement svgVisualElement, SKRect skBounds, HashSet <Uri> uris, CompositeDisposable disposable)
        {
            if (svgVisualElement == null || svgVisualElement.ClipPath == null)
            {
                return(null);
            }

            if (SvgExtensions.HasRecursiveReference(svgVisualElement, (e) => e.ClipPath, uris))
            {
                return(null);
            }

            var svgClipPath = SvgExtensions.GetReference <SvgClipPath>(svgVisualElement, svgVisualElement.ClipPath);

            if (svgClipPath == null || svgClipPath.Children == null)
            {
                return(null);
            }

            return(GetClipPath(svgClipPath, skBounds, uris, disposable));
        }
Example #2
0
        public static void CreateMarkers(this SvgMarkerElement svgMarkerElement, SKPath skPath, SKRect skOwnerBounds, ref List <Drawable>?markerDrawables, CompositeDisposable disposable)
        {
            var pathTypes  = skPath.GetPathTypes();
            var pathLength = pathTypes.Count;

            var markerStart = svgMarkerElement.MarkerStart;

            if (markerStart != null && pathLength > 0 && !SvgExtensions.HasRecursiveReference(svgMarkerElement, (e) => e.MarkerStart, new HashSet <Uri>()))
            {
                var marker = SvgExtensions.GetReference <SvgMarker>(svgMarkerElement, markerStart);
                if (marker != null)
                {
                    var refPoint1 = pathTypes[0].Point;
                    var index     = 1;
                    while (index < pathLength && pathTypes[index].Point == refPoint1)
                    {
                        ++index;
                    }
                    var refPoint2 = pathLength == 1 ? refPoint1 : pathTypes[index].Point;
                    CreateMarker(marker, svgMarkerElement, refPoint1, refPoint1, refPoint2, true, skOwnerBounds, ref markerDrawables, disposable);
                }
            }

            var markerMid = svgMarkerElement.MarkerMid;

            if (markerMid != null && pathLength > 0 && !SvgExtensions.HasRecursiveReference(svgMarkerElement, (e) => e.MarkerMid, new HashSet <Uri>()))
            {
                var marker = SvgExtensions.GetReference <SvgMarker>(svgMarkerElement, markerMid);
                if (marker != null)
                {
                    int bezierIndex = -1;
                    for (int i = 1; i <= pathLength - 2; i++)
                    {
                        // for Bezier curves, the marker shall only been shown at the last point
                        if ((pathTypes[i].Type & (byte)PathPointType.PathTypeMask) == (byte)PathPointType.Bezier)
                        {
                            bezierIndex = (bezierIndex + 1) % 3;
                        }
                        else
                        {
                            bezierIndex = -1;
                        }

                        if (bezierIndex == -1 || bezierIndex == 2)
                        {
                            CreateMarker(marker, svgMarkerElement, pathTypes[i].Point, pathTypes[i - 1].Point, pathTypes[i].Point, pathTypes[i + 1].Point, skOwnerBounds, ref markerDrawables, disposable);
                        }
                    }
                }
            }

            var markerEnd = svgMarkerElement.MarkerEnd;

            if (markerEnd != null && pathLength > 0 && !SvgExtensions.HasRecursiveReference(svgMarkerElement, (e) => e.MarkerEnd, new HashSet <Uri>()))
            {
                var marker = SvgExtensions.GetReference <SvgMarker>(svgMarkerElement, markerEnd);
                if (marker != null)
                {
                    var index     = pathLength - 1;
                    var refPoint1 = pathTypes[index].Point;
                    if (pathLength > 1)
                    {
                        --index;
                        while (index > 0 && pathTypes[index].Point == refPoint1)
                        {
                            --index;
                        }
                    }
                    var refPoint2 = pathLength == 1 ? refPoint1 : pathTypes[index].Point;
                    CreateMarker(marker, svgMarkerElement, refPoint1, refPoint2, pathTypes[pathLength - 1].Point, false, skOwnerBounds, ref markerDrawables, disposable);
                }
            }
        }
Example #3
0
        public static SKPath?GetClipPath(SvgVisualElement svgVisualElement, SKRect skBounds, HashSet <Uri> uris, CompositeDisposable disposable)
        {
            if (!CanDraw(svgVisualElement, Attributes.None))
            {
                return(null);
            }
            switch (svgVisualElement)
            {
            case SvgPath svgPath:
            {
                var fillRule = (svgPath.ClipRule == SvgClipRule.EvenOdd) ? SvgFillRule.EvenOdd : SvgFillRule.NonZero;
                var skPath   = svgPath.PathData?.ToSKPath(fillRule, disposable);
                if (skPath != null)
                {
                    var skMatrix = SvgTransformsExtensions.ToSKMatrix(svgPath.Transforms);
                    skPath.Transform(skMatrix);

                    var skPathClip = GetSvgVisualElementClipPath(svgPath, skPath.Bounds, uris, disposable);
                    if (skPathClip != null)
                    {
                        var result = skPath.Op(skPathClip, SKPathOp.Intersect);
                        disposable.Add(result);
                        return(result);
                    }

                    return(skPath);
                }
            }
            break;

            case SvgRectangle svgRectangle:
            {
                var fillRule = (svgRectangle.ClipRule == SvgClipRule.EvenOdd) ? SvgFillRule.EvenOdd : SvgFillRule.NonZero;
                var skPath   = svgRectangle.ToSKPath(fillRule, skBounds, disposable);
                if (skPath != null)
                {
                    var skMatrix = SvgTransformsExtensions.ToSKMatrix(svgRectangle.Transforms);
                    skPath.Transform(skMatrix);

                    var skPathClip = GetSvgVisualElementClipPath(svgRectangle, skPath.Bounds, uris, disposable);
                    if (skPathClip != null)
                    {
                        var result = skPath.Op(skPathClip, SKPathOp.Intersect);
                        disposable.Add(result);
                        return(result);
                    }

                    return(skPath);
                }
            }
            break;

            case SvgCircle svgCircle:
            {
                var fillRule = (svgCircle.ClipRule == SvgClipRule.EvenOdd) ? SvgFillRule.EvenOdd : SvgFillRule.NonZero;
                var skPath   = svgCircle.ToSKPath(fillRule, skBounds, disposable);
                if (skPath != null)
                {
                    var skMatrix = SvgTransformsExtensions.ToSKMatrix(svgCircle.Transforms);
                    skPath.Transform(skMatrix);

                    var skPathClip = GetSvgVisualElementClipPath(svgCircle, skPath.Bounds, uris, disposable);
                    if (skPathClip != null)
                    {
                        var result = skPath.Op(skPathClip, SKPathOp.Intersect);
                        disposable.Add(result);
                        return(result);
                    }

                    return(skPath);
                }
            }
            break;

            case SvgEllipse svgEllipse:
            {
                var fillRule = (svgEllipse.ClipRule == SvgClipRule.EvenOdd) ? SvgFillRule.EvenOdd : SvgFillRule.NonZero;
                var skPath   = svgEllipse.ToSKPath(fillRule, skBounds, disposable);
                if (skPath != null)
                {
                    var skMatrix = SvgTransformsExtensions.ToSKMatrix(svgEllipse.Transforms);
                    skPath.Transform(skMatrix);

                    var skPathClip = GetSvgVisualElementClipPath(svgEllipse, skPath.Bounds, uris, disposable);
                    if (skPathClip != null)
                    {
                        var result = skPath.Op(skPathClip, SKPathOp.Intersect);
                        disposable.Add(result);
                        return(result);
                    }

                    return(skPath);
                }
            }
            break;

            case SvgLine svgLine:
            {
                var fillRule = (svgLine.ClipRule == SvgClipRule.EvenOdd) ? SvgFillRule.EvenOdd : SvgFillRule.NonZero;
                var skPath   = svgLine.ToSKPath(fillRule, skBounds, disposable);
                if (skPath != null)
                {
                    var skMatrix = SvgTransformsExtensions.ToSKMatrix(svgLine.Transforms);
                    skPath.Transform(skMatrix);

                    var skPathClip = GetSvgVisualElementClipPath(svgLine, skPath.Bounds, uris, disposable);
                    if (skPathClip != null)
                    {
                        var result = skPath.Op(skPathClip, SKPathOp.Intersect);
                        disposable.Add(result);
                        return(result);
                    }

                    return(skPath);
                }
            }
            break;

            case SvgPolyline svgPolyline:
            {
                var fillRule = (svgPolyline.ClipRule == SvgClipRule.EvenOdd) ? SvgFillRule.EvenOdd : SvgFillRule.NonZero;
                var skPath   = svgPolyline.Points?.ToSKPath(fillRule, false, skBounds, disposable);
                if (skPath != null)
                {
                    var skMatrix = SvgTransformsExtensions.ToSKMatrix(svgPolyline.Transforms);
                    skPath.Transform(skMatrix);

                    var skPathClip = GetSvgVisualElementClipPath(svgPolyline, skPath.Bounds, uris, disposable);
                    if (skPathClip != null)
                    {
                        var result = skPath.Op(skPathClip, SKPathOp.Intersect);
                        disposable.Add(result);
                        return(result);
                    }

                    return(skPath);
                }
            }
            break;

            case SvgPolygon svgPolygon:
            {
                var fillRule = (svgPolygon.ClipRule == SvgClipRule.EvenOdd) ? SvgFillRule.EvenOdd : SvgFillRule.NonZero;
                var skPath   = svgPolygon.Points?.ToSKPath(fillRule, true, skBounds, disposable);
                if (skPath != null)
                {
                    var skMatrix = SvgTransformsExtensions.ToSKMatrix(svgPolygon.Transforms);
                    skPath.Transform(skMatrix);

                    var skPathClip = GetSvgVisualElementClipPath(svgPolygon, skPath.Bounds, uris, disposable);
                    if (skPathClip != null)
                    {
                        var result = skPath.Op(skPathClip, SKPathOp.Intersect);
                        disposable.Add(result);
                        return(result);
                    }

                    return(skPath);
                }
            }
            break;

            case SvgUse svgUse:
            {
                if (SvgExtensions.HasRecursiveReference(svgUse, (e) => e.ReferencedElement, new HashSet <Uri>()))
                {
                    break;
                }

                var svgReferencedVisualElement = SvgExtensions.GetReference <SvgVisualElement>(svgUse, svgUse.ReferencedElement);
                if (svgReferencedVisualElement == null || svgReferencedVisualElement is SvgSymbol)
                {
                    break;
                }

                if (!CanDraw(svgReferencedVisualElement, Attributes.None))
                {
                    break;
                }

                var skPath = GetClipPath(svgReferencedVisualElement, skBounds, uris, disposable);
                if (skPath != null)
                {
                    var skMatrix = SvgTransformsExtensions.ToSKMatrix(svgUse.Transforms);
                    skPath.Transform(skMatrix);

                    var skPathClip = GetSvgVisualElementClipPath(svgUse, skPath.Bounds, uris, disposable);
                    if (skPathClip != null)
                    {
                        var result = skPath.Op(skPathClip, SKPathOp.Intersect);
                        disposable.Add(result);
                        return(result);
                    }

                    return(skPath);
                }
            }
            break;

            case SvgText svgText:
            {
                // TODO: Get path from SvgText.
            }
            break;

            default:
                break;
            }
            return(null);
        }
Example #4
0
        public UseDrawable(SvgUse svgUse, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgUse, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = CanDraw(svgUse, IgnoreAttributes) && HasFeatures(svgUse, IgnoreAttributes);

            if (!IsDrawable)
            {
                return;
            }

            if (SvgExtensions.HasRecursiveReference(svgUse, (e) => e.ReferencedElement, new HashSet <Uri>()))
            {
                IsDrawable = false;
                return;
            }

            var svgReferencedElement = SvgExtensions.GetReference <SvgElement>(svgUse, svgUse.ReferencedElement);

            if (svgReferencedElement == null)
            {
                IsDrawable = false;
                return;
            }

            float x      = svgUse.X.ToDeviceValue(UnitRenderingType.Horizontal, svgUse, skOwnerBounds);
            float y      = svgUse.Y.ToDeviceValue(UnitRenderingType.Vertical, svgUse, skOwnerBounds);
            float width  = svgUse.Width.ToDeviceValue(UnitRenderingType.Horizontal, svgUse, skOwnerBounds);
            float height = svgUse.Height.ToDeviceValue(UnitRenderingType.Vertical, svgUse, skOwnerBounds);

            if (width <= 0f)
            {
                width = new SvgUnit(SvgUnitType.Percentage, 100f).ToDeviceValue(UnitRenderingType.Horizontal, svgUse, skOwnerBounds);
            }

            if (height <= 0f)
            {
                height = new SvgUnit(SvgUnitType.Percentage, 100f).ToDeviceValue(UnitRenderingType.Vertical, svgUse, skOwnerBounds);
            }

            var originalReferencedElementParent = svgReferencedElement.Parent;
            var referencedElementParent         = default(FieldInfo);

            try
            {
                referencedElementParent = svgReferencedElement.GetType().GetField("_parent", BindingFlags.NonPublic | BindingFlags.Instance);
                if (referencedElementParent != null)
                {
                    referencedElementParent.SetValue(svgReferencedElement, svgUse);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                Debug.WriteLine(ex.StackTrace);
            }

            svgReferencedElement.InvalidateChildPaths();

            if (svgReferencedElement is SvgSymbol svgSymbol)
            {
                ReferencedDrawable = new SymbolDrawable(svgSymbol, x, y, width, height, skOwnerBounds, root, this, ignoreAttributes);
                _disposable.Add(ReferencedDrawable);
            }
            else
            {
                var drawable = DrawableFactory.Create(svgReferencedElement, skOwnerBounds, root, this, ignoreAttributes);
                if (drawable != null)
                {
                    ReferencedDrawable = drawable;
                    _disposable.Add(ReferencedDrawable);
                }
                else
                {
                    IsDrawable = false;
                    return;
                }
            }

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgUse);

            TransformedBounds = ReferencedDrawable.TransformedBounds;

            Transform = SvgTransformsExtensions.ToSKMatrix(svgUse.Transforms);
            if (!(svgReferencedElement is SvgSymbol))
            {
                var skMatrixTranslateXY = SKMatrix.MakeTranslation(x, y);
                Transform = Transform.PreConcat(skMatrixTranslateXY);
            }

            Fill   = null;
            Stroke = null;

            // TODO: Transform _skBounds using _skMatrix.
            TransformedBounds = Transform.MapRect(TransformedBounds);

            try
            {
                if (referencedElementParent != null)
                {
                    referencedElementParent.SetValue(svgReferencedElement, originalReferencedElementParent);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                Debug.WriteLine(ex.StackTrace);
            }
        }