示例#1
0
        public static SKPath?GetClipPathClipPath(SvgClipPath svgClipPath, SKRect skBounds, HashSet <Uri> uris, CompositeDisposable disposable)
        {
            var svgClipPathRef = svgClipPath.GetUriElementReference <SvgClipPath>("clip-path", uris);

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

            var clipPath = GetClipPath(svgClipPathRef, skBounds, uris, disposable);

            if (clipPath != null)
            {
                var skMatrix = SKMatrix.MakeIdentity();

                if (svgClipPathRef.ClipPathUnits == SvgCoordinateUnits.ObjectBoundingBox)
                {
                    var skScaleMatrix = SKMatrix.MakeScale(skBounds.Width, skBounds.Height);
                    skMatrix = skMatrix.PostConcat(skScaleMatrix);

                    var skTranslateMatrix = SKMatrix.MakeTranslation(skBounds.Left, skBounds.Top);
                    skMatrix = skMatrix.PostConcat(skTranslateMatrix);
                }

                var skTransformsMatrix = SvgTransformsExtensions.ToSKMatrix(svgClipPathRef.Transforms);
                skMatrix = skMatrix.PostConcat(skTransformsMatrix);

                clipPath.Transform(skMatrix);
            }

            return(clipPath);
        }
示例#2
0
        public SwitchDrawable(SvgSwitch svgSwitch, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgSwitch, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = CanDraw(svgSwitch, IgnoreAttributes) && HasFeatures(svgSwitch, IgnoreAttributes);

            if (!IsDrawable)
            {
                return;
            }

            foreach (var child in svgSwitch.Children)
            {
                if (!IsKnownElement(child))
                {
                    continue;
                }

                bool hasRequiredFeatures   = HasRequiredFeatures(child);
                bool hasRequiredExtensions = HasRequiredExtensions(child);
                bool hasSystemLanguage     = HasSystemLanguage(child);

                if (hasRequiredFeatures && hasRequiredExtensions && hasSystemLanguage)
                {
                    //var ignoreAttributesSwitch = ignoreAttributes
                    //    | Attributes.Visibility
                    //    | Attributes.Display
                    //    | Attributes.RequiredFeatures
                    //    | Attributes.RequiredExtensions
                    //    | Attributes.SystemLanguage;

                    var drawable = DrawableFactory.Create(child, skOwnerBounds, root, parent, ignoreAttributes);
                    if (drawable != null)
                    {
                        FirstChild = drawable;
                        _disposable.Add(FirstChild);
                    }
                    break;
                }
            }

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

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgSwitch);

            TransformedBounds = FirstChild.TransformedBounds;

            Transform = SvgTransformsExtensions.ToSKMatrix(svgSwitch.Transforms);

            Fill   = null;
            Stroke = null;

            // TODO: Transform _skBounds using _skMatrix.
            TransformedBounds = Transform.MapRect(TransformedBounds);
        }
示例#3
0
        public PolylineDrawable(SvgPolyline svgPolyline, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgPolyline, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = CanDraw(svgPolyline, IgnoreAttributes) && HasFeatures(svgPolyline, IgnoreAttributes);

            if (!IsDrawable)
            {
                return;
            }

            Path = svgPolyline.Points?.ToSKPath(svgPolyline.FillRule, false, skOwnerBounds, _disposable);
            if (Path == null || Path.IsEmpty)
            {
                IsDrawable = false;
                return;
            }

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgPolyline);

            TransformedBounds = Path.Bounds;

            Transform = SvgTransformsExtensions.ToSKMatrix(svgPolyline.Transforms);

            bool canDrawFill   = true;
            bool canDrawStroke = true;

            if (SvgPaintingExtensions.IsValidFill(svgPolyline))
            {
                Fill = SvgPaintingExtensions.GetFillSKPaint(svgPolyline, TransformedBounds, ignoreAttributes, _disposable);
                if (Fill == null)
                {
                    canDrawFill = false;
                }
            }

            if (SvgPaintingExtensions.IsValidStroke(svgPolyline, TransformedBounds))
            {
                Stroke = SvgPaintingExtensions.GetStrokeSKPaint(svgPolyline, TransformedBounds, ignoreAttributes, _disposable);
                if (Stroke == null)
                {
                    canDrawStroke = false;
                }
            }

            if (canDrawFill && !canDrawStroke)
            {
                IsDrawable = false;
                return;
            }

            SvgMarkerExtensions.CreateMarkers(svgPolyline, Path, skOwnerBounds, ref MarkerDrawables, _disposable);

            // TODO: Transform _skBounds using _skMatrix.
            TransformedBounds = Transform.MapRect(TransformedBounds);
        }
示例#4
0
        public static SKPath?GetClipPath(SvgClipPath svgClipPath, SKRect skBounds, HashSet <Uri> uris, CompositeDisposable disposable)
        {
            var skPathClip = default(SKPath);

            var clipPathClipPath = GetClipPathClipPath(svgClipPath, skBounds, uris, disposable);

            if (clipPathClipPath != null && !clipPathClipPath.IsEmpty)
            {
                skPathClip = clipPathClipPath;
            }

            var clipPath = GetClipPath(svgClipPath.Children, skBounds, uris, disposable);

            if (clipPath != null)
            {
                var skMatrix = SKMatrix.MakeIdentity();

                if (svgClipPath.ClipPathUnits == SvgCoordinateUnits.ObjectBoundingBox)
                {
                    var skScaleMatrix = SKMatrix.MakeScale(skBounds.Width, skBounds.Height);
                    SKMatrix.PostConcat(ref skMatrix, ref skScaleMatrix);

                    var skTranslateMatrix = SKMatrix.MakeTranslation(skBounds.Left, skBounds.Top);
                    SKMatrix.PostConcat(ref skMatrix, ref skTranslateMatrix);
                }

                var skTransformsMatrix = SvgTransformsExtensions.ToSKMatrix(svgClipPath.Transforms);
                SKMatrix.PostConcat(ref skMatrix, ref skTransformsMatrix);

                clipPath.Transform(skMatrix);

                if (skPathClip == null)
                {
                    skPathClip = clipPath;
                }
                else
                {
                    var result = skPathClip.Op(clipPath, SKPathOp.Intersect);
                    disposable.Add(result);
                    skPathClip = result;
                }
            }

            if (skPathClip == null)
            {
                skPathClip = new SKPath();
                disposable.Add(skPathClip);
            }

            return(skPathClip);
        }
示例#5
0
        public GroupDrawable(SvgGroup svgGroup, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgGroup, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = CanDraw(svgGroup, IgnoreAttributes) && HasFeatures(svgGroup, IgnoreAttributes);

            // NOTE: Call AddMarkers only once.
            SvgMarkerExtensions.AddMarkers(svgGroup);

            CreateChildren(svgGroup, skOwnerBounds, root, this, ignoreAttributes);

            // TODO: Check if children are explicitly set to be visible.
            //foreach (var child in ChildrenDrawables)
            //{
            //    if (child.IsDrawable)
            //    {
            //        IsDrawable = true;
            //        break;
            //    }
            //}

            if (!IsDrawable)
            {
                return;
            }

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgGroup);

            TransformedBounds = SKRect.Empty;

            CreateTransformedBounds();

            Transform = SvgTransformsExtensions.ToSKMatrix(svgGroup.Transforms);

            Fill   = null;
            Stroke = null;

            // TODO: Transform _skBounds using _skMatrix.
            TransformedBounds = Transform.MapRect(TransformedBounds);
        }
示例#6
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);
        }
示例#7
0
        public MarkerDrawable(SvgMarker svgMarker, SvgVisualElement pOwner, SKPoint pMarkerPoint, float fAngle, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgMarker, root, parent)
        {
            IgnoreAttributes = Attributes.Display | ignoreAttributes;
            IsDrawable       = true;

            if (!IsDrawable)
            {
                return;
            }

            var markerElement = GetMarkerElement(svgMarker);

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

            var skMarkerMatrix = SKMatrix.MakeIdentity();

            var skMatrixMarkerPoint = SKMatrix.MakeTranslation(pMarkerPoint.X, pMarkerPoint.Y);

            skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixMarkerPoint);

            var skMatrixAngle = SKMatrix.MakeRotationDegrees(svgMarker.Orient.IsAuto ? fAngle : svgMarker.Orient.Angle);

            skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixAngle);

            var strokeWidth = pOwner.StrokeWidth.ToDeviceValue(UnitRenderingType.Other, svgMarker, skOwnerBounds);

            var   refX         = svgMarker.RefX.ToDeviceValue(UnitRenderingType.Horizontal, svgMarker, skOwnerBounds);
            var   refY         = svgMarker.RefY.ToDeviceValue(UnitRenderingType.Vertical, svgMarker, skOwnerBounds);
            float markerWidth  = svgMarker.MarkerWidth.ToDeviceValue(UnitRenderingType.Other, svgMarker, skOwnerBounds);
            float markerHeight = svgMarker.MarkerHeight.ToDeviceValue(UnitRenderingType.Other, svgMarker, skOwnerBounds);
            float viewBoxToMarkerUnitsScaleX = 1f;
            float viewBoxToMarkerUnitsScaleY = 1f;

            switch (svgMarker.MarkerUnits)
            {
            case SvgMarkerUnits.StrokeWidth:
            {
                var skMatrixStrokeWidth = SKMatrix.MakeScale(strokeWidth, strokeWidth);
                skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixStrokeWidth);

                var viewBoxWidth  = svgMarker.ViewBox.Width;
                var viewBoxHeight = svgMarker.ViewBox.Height;

                var scaleFactorWidth  = (viewBoxWidth <= 0) ? 1 : (markerWidth / viewBoxWidth);
                var scaleFactorHeight = (viewBoxHeight <= 0) ? 1 : (markerHeight / viewBoxHeight);

                viewBoxToMarkerUnitsScaleX = Math.Min(scaleFactorWidth, scaleFactorHeight);
                viewBoxToMarkerUnitsScaleY = Math.Min(scaleFactorWidth, scaleFactorHeight);

                var skMatrixTranslateRefXY = SKMatrix.MakeTranslation(-refX * viewBoxToMarkerUnitsScaleX, -refY * viewBoxToMarkerUnitsScaleY);
                skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixTranslateRefXY);

                var skMatrixScaleXY = SKMatrix.MakeScale(viewBoxToMarkerUnitsScaleX, viewBoxToMarkerUnitsScaleY);
                skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixScaleXY);
            }
            break;

            case SvgMarkerUnits.UserSpaceOnUse:
            {
                var skMatrixTranslateRefXY = SKMatrix.MakeTranslation(-refX, -refY);
                skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixTranslateRefXY);
            }
            break;
            }

            switch (svgMarker.Overflow)
            {
            case SvgOverflow.Auto:
            case SvgOverflow.Visible:
            case SvgOverflow.Inherit:
                break;

            default:
                MarkerClipRect = SKRect.Create(
                    svgMarker.ViewBox.MinX,
                    svgMarker.ViewBox.MinY,
                    markerWidth / viewBoxToMarkerUnitsScaleX,
                    markerHeight / viewBoxToMarkerUnitsScaleY);
                break;
            }

            var drawable = DrawableFactory.Create(markerElement, skOwnerBounds, root, this, Attributes.Display);

            if (drawable != null)
            {
                MarkerElementDrawable = drawable;
                _disposable.Add(MarkerElementDrawable);
            }
            else
            {
                IsDrawable = false;
                return;
            }

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgMarker);

            TransformedBounds = MarkerElementDrawable.TransformedBounds;

            Transform = SvgTransformsExtensions.ToSKMatrix(svgMarker.Transforms);
            Transform = Transform.PreConcat(skMarkerMatrix);

            Fill   = null;
            Stroke = null;

            // TODO: Transform _skBounds using _skMatrix.
            TransformedBounds = Transform.MapRect(TransformedBounds);
        }
示例#8
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);
            }
        }
示例#9
0
        public ImageDrawable(SvgImage svgImage, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgImage, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = CanDraw(svgImage, IgnoreAttributes) && HasFeatures(svgImage, IgnoreAttributes);

            if (!IsDrawable)
            {
                return;
            }

            float width    = svgImage.Width.ToDeviceValue(UnitRenderingType.Horizontal, svgImage, skOwnerBounds);
            float height   = svgImage.Height.ToDeviceValue(UnitRenderingType.Vertical, svgImage, skOwnerBounds);
            float x        = svgImage.Location.X.ToDeviceValue(UnitRenderingType.Horizontal, svgImage, skOwnerBounds);
            float y        = svgImage.Location.Y.ToDeviceValue(UnitRenderingType.Vertical, svgImage, skOwnerBounds);
            var   location = new SKPoint(x, y);

            if (width <= 0f || height <= 0f || svgImage.Href == null)
            {
                IsDrawable = false;
                return;
            }

            // TODO: Check for image recursive references.
            //if (SkiaUtil.HasRecursiveReference(svgImage, (e) => e.Href))
            //{
            //    _canDraw = false;
            //    return;
            //}

            var image       = SvgImageExtensions.GetImage(svgImage.Href, svgImage.OwnerDocument);
            var skImage     = image as SKImage;
            var svgFragment = image as SvgFragment;

            if (skImage == null && svgFragment == null)
            {
                IsDrawable = false;
                return;
            }

            if (skImage != null)
            {
                _disposable.Add(skImage);
            }

            SrcRect = default;

            if (skImage != null)
            {
                SrcRect = SKRect.Create(0f, 0f, skImage.Width, skImage.Height);
            }

            if (svgFragment != null)
            {
                var skSize = SvgExtensions.GetDimensions(svgFragment);
                SrcRect = SKRect.Create(0f, 0f, skSize.Width, skSize.Height);
            }

            var destClip = SKRect.Create(location.X, location.Y, width, height);

            var aspectRatio = svgImage.AspectRatio;

            if (aspectRatio.Align != SvgPreserveAspectRatio.none)
            {
                var fScaleX = destClip.Width / SrcRect.Width;
                var fScaleY = destClip.Height / SrcRect.Height;
                var xOffset = 0f;
                var yOffset = 0f;

                if (aspectRatio.Slice)
                {
                    fScaleX = Math.Max(fScaleX, fScaleY);
                    fScaleY = Math.Max(fScaleX, fScaleY);
                }
                else
                {
                    fScaleX = Math.Min(fScaleX, fScaleY);
                    fScaleY = Math.Min(fScaleX, fScaleY);
                }

                switch (aspectRatio.Align)
                {
                case SvgPreserveAspectRatio.xMinYMin:
                    break;

                case SvgPreserveAspectRatio.xMidYMin:
                    xOffset = (destClip.Width - SrcRect.Width * fScaleX) / 2;
                    break;

                case SvgPreserveAspectRatio.xMaxYMin:
                    xOffset = (destClip.Width - SrcRect.Width * fScaleX);
                    break;

                case SvgPreserveAspectRatio.xMinYMid:
                    yOffset = (destClip.Height - SrcRect.Height * fScaleY) / 2;
                    break;

                case SvgPreserveAspectRatio.xMidYMid:
                    xOffset = (destClip.Width - SrcRect.Width * fScaleX) / 2;
                    yOffset = (destClip.Height - SrcRect.Height * fScaleY) / 2;
                    break;

                case SvgPreserveAspectRatio.xMaxYMid:
                    xOffset = (destClip.Width - SrcRect.Width * fScaleX);
                    yOffset = (destClip.Height - SrcRect.Height * fScaleY) / 2;
                    break;

                case SvgPreserveAspectRatio.xMinYMax:
                    yOffset = (destClip.Height - SrcRect.Height * fScaleY);
                    break;

                case SvgPreserveAspectRatio.xMidYMax:
                    xOffset = (destClip.Width - SrcRect.Width * fScaleX) / 2;
                    yOffset = (destClip.Height - SrcRect.Height * fScaleY);
                    break;

                case SvgPreserveAspectRatio.xMaxYMax:
                    xOffset = (destClip.Width - SrcRect.Width * fScaleX);
                    yOffset = (destClip.Height - SrcRect.Height * fScaleY);
                    break;
                }

                DestRect = SKRect.Create(
                    destClip.Left + xOffset,
                    destClip.Top + yOffset,
                    SrcRect.Width * fScaleX,
                    SrcRect.Height * fScaleY);
            }
            else
            {
                DestRect = destClip;
            }

            Clip = destClip;

            var skClipRect = SvgClippingExtensions.GetClipRect(svgImage, destClip);

            if (skClipRect != null)
            {
                Clip = skClipRect;
            }

            if (skImage != null)
            {
                Image = skImage;
            }

            if (svgFragment != null)
            {
                FragmentDrawable = new FragmentDrawable(svgFragment, skOwnerBounds, root, this, ignoreAttributes);
                _disposable.Add(FragmentDrawable);
            }

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgImage);

            if (Image != null)
            {
                TransformedBounds = DestRect;
            }

            if (FragmentDrawable != null)
            {
                //_skBounds = _fragmentDrawable._skBounds;
                TransformedBounds = DestRect;
            }

            Transform         = SvgTransformsExtensions.ToSKMatrix(svgImage.Transforms);
            FragmentTransform = SKMatrix.MakeIdentity();
            if (FragmentDrawable != null)
            {
                float dx = DestRect.Left;
                float dy = DestRect.Top;
                float sx = DestRect.Width / SrcRect.Width;
                float sy = DestRect.Height / SrcRect.Height;
                var   skTranslationMatrix = SKMatrix.MakeTranslation(dx, dy);
                var   skScaleMatrix       = SKMatrix.MakeScale(sx, sy);
                FragmentTransform = FragmentTransform.PreConcat(skTranslationMatrix);
                FragmentTransform = FragmentTransform.PreConcat(skScaleMatrix);
            }

            Fill   = null;
            Stroke = null;

            // TODO: Transform _skBounds using _skMatrix.
            TransformedBounds = Transform.MapRect(TransformedBounds);
        }
示例#10
0
        public FragmentDrawable(SvgFragment svgFragment, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None)
            : base(svgFragment, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = HasFeatures(svgFragment, IgnoreAttributes);

            if (!IsDrawable)
            {
                return;
            }

            var svgFragmentParent = svgFragment.Parent;

            float x = svgFragmentParent == null ? 0f : svgFragment.X.ToDeviceValue(UnitRenderingType.Horizontal, svgFragment, skOwnerBounds);
            float y = svgFragmentParent == null ? 0f : svgFragment.Y.ToDeviceValue(UnitRenderingType.Vertical, svgFragment, skOwnerBounds);

            var skSize = SvgExtensions.GetDimensions(svgFragment);

            if (skOwnerBounds.IsEmpty)
            {
                skOwnerBounds = SKRect.Create(x, y, skSize.Width, skSize.Height);
            }

            CreateChildren(svgFragment, skOwnerBounds, this, this, ignoreAttributes);

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgFragment);

            TransformedBounds = skOwnerBounds;

            CreateTransformedBounds();

            Transform = SvgTransformsExtensions.ToSKMatrix(svgFragment.Transforms);
            var skMatrixViewBox = SvgTransformsExtensions.ToSKMatrix(svgFragment.ViewBox, svgFragment.AspectRatio, x, y, skSize.Width, skSize.Height);

            SKMatrix.PreConcat(ref Transform, ref skMatrixViewBox);

            switch (svgFragment.Overflow)
            {
            case SvgOverflow.Auto:
            case SvgOverflow.Visible:
            case SvgOverflow.Inherit:
                break;

            default:
                if (skSize.IsEmpty)
                {
                    Overflow = SKRect.Create(
                        x,
                        y,
                        Math.Abs(TransformedBounds.Left) + TransformedBounds.Width,
                        Math.Abs(TransformedBounds.Top) + TransformedBounds.Height);
                }
                else
                {
                    Overflow = SKRect.Create(x, y, skSize.Width, skSize.Height);
                }
                break;
            }

            var clipPathUris = new HashSet <Uri>();
            var svgClipPath  = svgFragment.GetUriElementReference <SvgClipPath>("clip-path", clipPathUris);

            if (svgClipPath != null && svgClipPath.Children != null)
            {
                ClipPath = IgnoreAttributes.HasFlag(Attributes.ClipPath) ? null : SvgClippingExtensions.GetClipPath(svgClipPath, TransformedBounds, clipPathUris, _disposable);
            }
            else
            {
                ClipPath = null;
            }

            Fill   = null;
            Stroke = null;

            // TODO: Transform _skBounds using _skMatrix.
            SKMatrix.MapRect(ref Transform, out TransformedBounds, ref TransformedBounds);
        }
示例#11
0
        public SymbolDrawable(SvgSymbol svgSymbol, float x, float y, float width, float height, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes)
            : base(svgSymbol, root, parent)
        {
            IgnoreAttributes = ignoreAttributes;
            IsDrawable       = CanDraw(svgSymbol, IgnoreAttributes) && HasFeatures(svgSymbol, IgnoreAttributes);

            if (!IsDrawable)
            {
                return;
            }

            if (svgSymbol.CustomAttributes.TryGetValue("width", out string?_widthString))
            {
                if (new SvgUnitConverter().ConvertFromString(_widthString) is SvgUnit _width)
                {
                    width = _width.ToDeviceValue(UnitRenderingType.Horizontal, svgSymbol, skOwnerBounds);
                }
            }

            if (svgSymbol.CustomAttributes.TryGetValue("height", out string?heightString))
            {
                if (new SvgUnitConverter().ConvertFromString(heightString) is SvgUnit _height)
                {
                    height = _height.ToDeviceValue(UnitRenderingType.Vertical, svgSymbol, skOwnerBounds);
                }
            }

            SvgOverflow svgOverflow = SvgOverflow.Hidden;

            if (svgSymbol.TryGetAttribute("overflow", out string overflowString))
            {
                if (new SvgOverflowConverter().ConvertFromString(overflowString) is SvgOverflow _svgOverflow)
                {
                    svgOverflow = _svgOverflow;
                }
            }

            switch (svgOverflow)
            {
            case SvgOverflow.Auto:
            case SvgOverflow.Visible:
            case SvgOverflow.Inherit:
                break;

            default:
                Overflow = SKRect.Create(x, y, width, height);
                break;
            }

            CreateChildren(svgSymbol, skOwnerBounds, root, this, ignoreAttributes);

            IsAntialias = SvgPaintingExtensions.IsAntialias(svgSymbol);

            TransformedBounds = SKRect.Empty;

            CreateTransformedBounds();

            Transform = SvgTransformsExtensions.ToSKMatrix(svgSymbol.Transforms);
            var skMatrixViewBox = SvgTransformsExtensions.ToSKMatrix(svgSymbol.ViewBox, svgSymbol.AspectRatio, x, y, width, height);

            Transform = Transform.PreConcat(skMatrixViewBox);

            Fill   = null;
            Stroke = null;

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