public void TestFuncAttr()
    {
        XmlElement elm = getElm();

        elm.SetAttribute("kalle", "", "roffe");
        CssCollectedStyleDeclaration csd = new CssCollectedStyleDeclaration(elm);

        csd.CollectProperty("foo", 1, CssValue.GetCssValue("attr(kalle)", false), CssStyleSheetType.Author, "");

        CssPrimitiveValue cssPrimValue = csd.GetPropertyCssValue("foo") as CssPrimitiveValue;

        Assert.IsNotNull(cssPrimValue);
        Assert.AreEqual("roffe", cssPrimValue.GetStringValue());
    }
        protected void SetClip(GdiGraphics graphics)
        {
            if (_svgElement == null)
            {
                return;
            }

            SvgRenderingHint hint = _svgElement.RenderingHint;

            // todo: should we correct the clipping to adjust to the off-one-pixel drawing?
            graphics.TranslateClip(1, 1);

            #region Clip with clip
            // see http://www.w3.org/TR/SVG/masking.html#OverflowAndClipProperties
            if (_svgElement is ISvgSvgElement || _svgElement is ISvgMarkerElement ||
                _svgElement is ISvgSymbolElement || _svgElement is ISvgPatternElement)
            {
                // check overflow property
                CssValue overflow = _svgElement.GetComputedCssValue("overflow", string.Empty) as CssValue;
                // TODO: clip can have "rect(10 10 auto 10)"
                CssPrimitiveValue clip = _svgElement.GetComputedCssValue("clip", string.Empty) as CssPrimitiveValue;

                string sOverflow = null;

                if (overflow != null || overflow.CssText == "")
                {
                    sOverflow = overflow.CssText;
                }
                else
                {
                    if (this is ISvgSvgElement)
                    {
                        sOverflow = "hidden";
                    }
                }

                if (sOverflow != null)
                {
                    // "If the 'overflow' property has a value other than hidden or scroll, the property has no effect (i.e., a clipping rectangle is not created)."
                    if (sOverflow == "hidden" || sOverflow == "scroll")
                    {
                        RectangleF clipRect = RectangleF.Empty;
                        if (clip != null && clip.PrimitiveType == CssPrimitiveType.Rect)
                        {
                            if (_svgElement is ISvgSvgElement)
                            {
                                ISvgSvgElement svgElement = (ISvgSvgElement)_svgElement;
                                SvgRect        viewPort   = svgElement.Viewport as SvgRect;
                                clipRect = GdiConverter.ToRectangle(viewPort);
                                ICssRect clipShape = (CssRect)clip.GetRectValue();
                                if (clipShape.Top.PrimitiveType != CssPrimitiveType.Ident)
                                {
                                    clipRect.Y += (float)clipShape.Top.GetFloatValue(CssPrimitiveType.Number);
                                }
                                if (clipShape.Left.PrimitiveType != CssPrimitiveType.Ident)
                                {
                                    clipRect.X += (float)clipShape.Left.GetFloatValue(CssPrimitiveType.Number);
                                }
                                if (clipShape.Right.PrimitiveType != CssPrimitiveType.Ident)
                                {
                                    clipRect.Width = (clipRect.Right - clipRect.X) - (float)clipShape.Right.GetFloatValue(CssPrimitiveType.Number);
                                }
                                if (clipShape.Bottom.PrimitiveType != CssPrimitiveType.Ident)
                                {
                                    clipRect.Height = (clipRect.Bottom - clipRect.Y) - (float)clipShape.Bottom.GetFloatValue(CssPrimitiveType.Number);
                                }
                            }
                        }
                        else if (clip == null || (clip.PrimitiveType == CssPrimitiveType.Ident && clip.GetStringValue() == "auto"))
                        {
                            if (_svgElement is ISvgSvgElement)
                            {
                                ISvgSvgElement svgElement = (ISvgSvgElement)_svgElement;
                                SvgRect        viewPort   = svgElement.Viewport as SvgRect;
                                clipRect = GdiConverter.ToRectangle(viewPort);
                            }
                            else if (_svgElement is ISvgMarkerElement || _svgElement is ISvgSymbolElement ||
                                     _svgElement is ISvgPatternElement)
                            {
                                // TODO: what to do here?
                            }
                        }
                        if (clipRect != RectangleF.Empty)
                        {
                            graphics.SetClip(clipRect);
                        }
                    }
                }
            }
            #endregion

            #region Clip with clip-path

            // see: http://www.w3.org/TR/SVG/masking.html#EstablishingANewClippingPath

            if (hint == SvgRenderingHint.Shape || hint == SvgRenderingHint.Text ||
                hint == SvgRenderingHint.Clipping || hint == SvgRenderingHint.Masking ||
                hint == SvgRenderingHint.Containment || hint == SvgRenderingHint.Image)
            {
                CssPrimitiveValue clipPath = _svgElement.GetComputedCssValue("clip-path", string.Empty) as CssPrimitiveValue;

                if (clipPath != null && clipPath.PrimitiveType == CssPrimitiveType.Uri)
                {
                    string absoluteUri = _svgElement.ResolveUri(clipPath.GetStringValue());

                    SvgClipPathElement eClipPath = _svgElement.OwnerDocument.GetNodeByUri(absoluteUri) as SvgClipPathElement;

                    if (eClipPath != null)
                    {
                        GraphicsPath gpClip = CreateClippingRegion(graphics, eClipPath);

                        RectangleF clipBounds = gpClip != null?gpClip.GetBounds() : RectangleF.Empty;

                        if (clipBounds.Width.Equals(0) || clipBounds.Height.Equals(0))
                        {
                            return;
                        }

                        SvgUnitType pathUnits = (SvgUnitType)eClipPath.ClipPathUnits.AnimVal;

                        if (pathUnits == SvgUnitType.ObjectBoundingBox)
                        {
                            SvgTransformableElement transElement = _svgElement as SvgTransformableElement;

                            if (transElement != null)
                            {
                                ISvgRect bbox = transElement.GetBBox();

                                // scale clipping path
                                Matrix matrix = new Matrix();
                                matrix.Scale((float)bbox.Width, (float)bbox.Height);
                                gpClip.Transform(matrix);
                                graphics.SetClip(gpClip);

                                // offset clip
                                graphics.TranslateClip((float)bbox.X, (float)bbox.Y);
                            }
                            else
                            {
                                throw new NotImplementedException("clip-path with SvgUnitType.ObjectBoundingBox "
                                                                  + "not supported for this type of element: " + _svgElement.GetType());
                            }
                        }
                        else
                        {
                            graphics.SetClip(gpClip);
                        }

                        gpClip.Dispose();
                        gpClip = null;
                    }
                }
            }
            #endregion
        }
        protected void SetMask(WpfDrawingContext context)
        {
            _maskUnits        = SvgUnitType.UserSpaceOnUse;
            _maskContentUnits = SvgUnitType.UserSpaceOnUse;

            CssPrimitiveValue maskPath = _svgElement.GetComputedCssValue("mask", string.Empty) as CssPrimitiveValue;

            SvgMaskElement maskElement = null;

            if (maskPath != null && maskPath.PrimitiveType == CssPrimitiveType.Uri)
            {
                string absoluteUri = _svgElement.ResolveUri(maskPath.GetStringValue());

                maskElement = _svgElement.OwnerDocument.GetNodeByUri(absoluteUri) as SvgMaskElement;
            }
            else if (string.Equals(_svgElement.ParentNode.LocalName, "use"))
            {
                var parentElement = _svgElement.ParentNode as SvgElement;

                maskPath = parentElement.GetComputedCssValue("mask", string.Empty) as CssPrimitiveValue;

                if (maskPath != null && maskPath.PrimitiveType == CssPrimitiveType.Uri)
                {
                    string absoluteUri = _svgElement.ResolveUri(maskPath.GetStringValue());

                    maskElement = _svgElement.OwnerDocument.GetNodeByUri(absoluteUri) as SvgMaskElement;
                }
            }

            if (maskElement != null)
            {
                WpfDrawingRenderer renderer = new WpfDrawingRenderer();
                renderer.Window = _svgElement.OwnerDocument.Window as SvgWindow;

                WpfDrawingSettings settings = context.Settings.Clone();
                settings.TextAsGeometry = true;
                WpfDrawingContext maskContext = new WpfDrawingContext(true, settings);

                //maskContext.Initialize(null, context.FontFamilyVisitor, null);
                maskContext.Initialize(context.LinkVisitor, context.FontFamilyVisitor, context.ImageVisitor);

                renderer.RenderMask(maskElement, maskContext);
                DrawingGroup maskDrawing = renderer.Drawing;

                Rect bounds = new Rect(0, 0, 1, 1);
                //Rect destRect = GetMaskDestRect(maskElement, bounds);

                //destRect = bounds;

                //DrawingImage drawImage = new DrawingImage(image);

                //DrawingVisual drawingVisual = new DrawingVisual();
                //DrawingContext drawingContext = drawingVisual.RenderOpen();
                //drawingContext.DrawDrawing(image);
                //drawingContext.Close();

                //RenderTargetBitmap drawImage = new RenderTargetBitmap((int)200,
                //    (int)200, 96, 96, PixelFormats.Pbgra32);
                //drawImage.Render(drawingVisual);

                //ImageBrush imageBrush = new ImageBrush(drawImage);
                //imageBrush.Viewbox = image.Bounds;
                //imageBrush.Viewport = image.Bounds;
                //imageBrush.ViewboxUnits = BrushMappingMode.Absolute;
                //imageBrush.ViewportUnits = BrushMappingMode.Absolute;
                //imageBrush.TileMode = TileMode.None;
                //imageBrush.Stretch = Stretch.None;

                //this.Masking = imageBrush;

                DrawingBrush maskBrush = new DrawingBrush(maskDrawing);
                //tb.Viewbox = new Rect(0, 0, destRect.Width, destRect.Height);
                //tb.Viewport = new Rect(0, 0, destRect.Width, destRect.Height);
                maskBrush.Viewbox       = maskDrawing.Bounds;
                maskBrush.Viewport      = maskDrawing.Bounds;
                maskBrush.ViewboxUnits  = BrushMappingMode.Absolute;
                maskBrush.ViewportUnits = BrushMappingMode.Absolute;
                maskBrush.TileMode      = TileMode.None;
                maskBrush.Stretch       = Stretch.Uniform;

                ////maskBrush.AlignmentX = AlignmentX.Center;
                ////maskBrush.AlignmentY = AlignmentY.Center;

                this.Masking = maskBrush;

                _maskUnits        = (SvgUnitType)maskElement.MaskUnits.AnimVal;
                _maskContentUnits = (SvgUnitType)maskElement.MaskContentUnits.AnimVal;
            }
        }
        protected void SetClip(WpfDrawingContext context)
        {
            _clipPathUnits = SvgUnitType.UserSpaceOnUse;

            if (_svgElement == null)
            {
                return;
            }

            #region Clip with clip

            // see http://www.w3.org/TR/SVG/masking.html#OverflowAndClipProperties
            if (_svgElement is ISvgSvgElement || _svgElement is ISvgMarkerElement ||
                _svgElement is ISvgSymbolElement || _svgElement is ISvgPatternElement)
            {
                // check overflow property
                CssValue overflow = _svgElement.GetComputedCssValue("overflow", string.Empty) as CssValue;
                // TODO: clip can have "rect(10 10 auto 10)"
                CssPrimitiveValue clip = _svgElement.GetComputedCssValue("clip", string.Empty) as CssPrimitiveValue;

                string sOverflow = null;

                if (overflow != null && !string.IsNullOrWhiteSpace(overflow.CssText))
                {
                    sOverflow = overflow.CssText;
                }
                else
                {
                    if (this is ISvgSvgElement)
                    {
                        sOverflow = "hidden";
                    }
                }

                if (sOverflow != null)
                {
                    // "If the 'overflow' property has a value other than hidden or scroll,
                    // the property has no effect (i.e., a clipping rectangle is not created)."
                    if (sOverflow == "hidden" || sOverflow == "scroll")
                    {
                        Rect clipRect = Rect.Empty;
                        if (clip != null && clip.PrimitiveType == CssPrimitiveType.Rect)
                        {
                            if (_svgElement is ISvgSvgElement)
                            {
                                ISvgSvgElement svgElement = (ISvgSvgElement)_svgElement;
                                SvgRect        viewPort   = svgElement.Viewport as SvgRect;
                                clipRect = WpfConvert.ToRect(viewPort);
                                ICssRect clipShape = (CssRect)clip.GetRectValue();
                                if (clipShape.Top.PrimitiveType != CssPrimitiveType.Ident)
                                {
                                    clipRect.Y += clipShape.Top.GetFloatValue(CssPrimitiveType.Number);
                                }
                                if (clipShape.Left.PrimitiveType != CssPrimitiveType.Ident)
                                {
                                    clipRect.X += clipShape.Left.GetFloatValue(CssPrimitiveType.Number);
                                }
                                if (clipShape.Right.PrimitiveType != CssPrimitiveType.Ident)
                                {
                                    clipRect.Width = (clipRect.Right - clipRect.X) - clipShape.Right.GetFloatValue(CssPrimitiveType.Number);
                                }
                                if (clipShape.Bottom.PrimitiveType != CssPrimitiveType.Ident)
                                {
                                    clipRect.Height = (clipRect.Bottom - clipRect.Y) - clipShape.Bottom.GetFloatValue(CssPrimitiveType.Number);
                                }
                            }
                        }
                        else if (clip == null || (clip.PrimitiveType == CssPrimitiveType.Ident && clip.GetStringValue() == "auto"))
                        {
                            if (_svgElement is ISvgSvgElement)
                            {
                                ISvgSvgElement svgElement = (ISvgSvgElement)_svgElement;
                                SvgRect        viewPort   = svgElement.Viewport as SvgRect;
                                clipRect = WpfConvert.ToRect(viewPort);
                            }
                            else if (_svgElement is ISvgMarkerElement || _svgElement is ISvgSymbolElement ||
                                     _svgElement is ISvgPatternElement)
                            {
                                // TODO: what to do here?
                            }
                        }
                        if (clipRect != Rect.Empty)
                        {
                            _clipGeometry = new RectangleGeometry(clipRect);
                            //gr.SetClip(clipRect);
                        }
                    }
                }
            }
            #endregion

            #region Clip with clip-path

            SvgRenderingHint hint = _svgElement.RenderingHint;

            if (hint == SvgRenderingHint.Image)
            {
            }

            // see: http://www.w3.org/TR/SVG/masking.html#EstablishingANewClippingPath

            if (hint == SvgRenderingHint.Shape || hint == SvgRenderingHint.Text ||
                hint == SvgRenderingHint.Clipping || hint == SvgRenderingHint.Masking ||
                hint == SvgRenderingHint.Containment || hint == SvgRenderingHint.Image)
            {
                CssPrimitiveValue clipPath = _svgElement.GetComputedCssValue("clip-path", string.Empty) as CssPrimitiveValue;

                if (clipPath != null && clipPath.PrimitiveType == CssPrimitiveType.Uri)
                {
                    string absoluteUri = _svgElement.ResolveUri(clipPath.GetStringValue());

                    SvgClipPathElement eClipPath = _svgElement.OwnerDocument.GetNodeByUri(absoluteUri) as SvgClipPathElement;

                    if (eClipPath != null)
                    {
                        GeometryCollection geomColl = CreateClippingRegion(eClipPath, context);
                        if (geomColl == null || geomColl.Count == 0)
                        {
                            return;
                        }
                        Geometry gpClip    = geomColl[0];
                        int      geomCount = geomColl.Count;
                        if (geomCount > 1)
                        {
                            //GeometryGroup clipGroup = new GeometryGroup();
                            //clipGroup.Children.Add(gpClip);
                            for (int k = 1; k < geomCount; k++)
                            {
                                gpClip = Geometry.Combine(gpClip, geomColl[k],
                                                          GeometryCombineMode.Union, null);
                                //clipGroup.Children.Add(geomColl[k]);
                            }

                            //clipGroup.Children.Reverse();

                            //gpClip = clipGroup;
                        }

                        if (gpClip == null || gpClip.IsEmpty())
                        {
                            return;
                        }

                        _clipPathUnits = (SvgUnitType)eClipPath.ClipPathUnits.AnimVal;

                        //if (_clipPathUnits == SvgUnitType.ObjectBoundingBox)
                        //{
                        //    SvgTransformableElement transElement = _svgElement as SvgTransformableElement;

                        //    if (transElement != null)
                        //    {
                        //        ISvgRect bbox = transElement.GetBBox();

                        //        // scale clipping path
                        //        gpClip.Transform = new ScaleTransform(bbox.Width, bbox.Height);
                        //        //gr.SetClip(gpClip);

                        //        // offset clip
                        //        //TODO--PAUL gr.TranslateClip((float)bbox.X, (float)bbox.Y);

                        //        _clipGeometry = gpClip;
                        //    }
                        //    else
                        //    {
                        //        throw new NotImplementedException("clip-path with SvgUnitType.ObjectBoundingBox "
                        //          + "not supported for this type of element: " + _svgElement.GetType());
                        //    }
                        //}
                        //else
                        {
                            //gr.SetClip(gpClip);

                            _clipGeometry = gpClip;
                        }
                    }
                }
            }

            #endregion
        }