public static bool TryGetTransform(ISvgTransformable element, out Transform transform) { transform = null; if (element == null) { return(false); } ISvgTransformList svgTList = element.Transform.AnimVal; ISvgMatrix svgMatrix = ((SvgTransformList)element.Transform.AnimVal).TotalMatrix; ISvgElement nVE = element.NearestViewportElement; if (nVE != null) { SvgTransformableElement par = (element as SvgElement).ParentNode as SvgTransformableElement; while (par != null && par != nVE) { svgTList = par.Transform.AnimVal; svgMatrix = svgTList.Consolidate().Matrix.Multiply(svgMatrix); par = par.ParentNode as SvgTransformableElement; } } if (svgMatrix.IsIdentity) { transform = Transform.Identity; return(false); } transform = new MatrixTransform(ToWpfMatrix(svgMatrix)); return(true); }
public void TestShapeBBox() { SvgTransformableElement elm = Util.GetXmlElement("<rect x='1' y='2' width='3' height='4' />", "", "rect") as SvgTransformableElement; ISvgRect rect = elm.GetBBox(); Assert.AreEqual(1, rect.X); Assert.AreEqual(2, rect.Y); Assert.AreEqual(3, rect.Width); Assert.AreEqual(4, rect.Height); }
public void TestContainerBBoxWithMulipleChilds() { SvgTransformableElement elm = Util.GetXmlElement("<g><rect x='1' y='2' width='3' height='4' /><rect x='10' y='20' width='3' height='4' /></g>", "", "g") as SvgTransformableElement; ISvgRect rect = elm.GetBBox(); Assert.AreEqual(1, rect.X); Assert.AreEqual(2, rect.Y); Assert.AreEqual(12, rect.Width); Assert.AreEqual(22, rect.Height); }
public ISvgRect GetRenderedBounds(ISvgElement element, float margin) { SvgTransformableElement transElement = element as SvgTransformableElement; if (transElement != null) { SvgRectF rect = this.GetElementBounds(transElement, margin); return(new SvgRect(rect.X, rect.Y, rect.Width, rect.Height)); } return(null); }
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 }
private SvgRectF GetElementBounds(SvgTransformableElement element, float margin) { SvgRenderingHint hint = element.RenderingHint; if (hint == SvgRenderingHint.Shape || hint == SvgRenderingHint.Text) { GraphicsPath gp = GdiRendering.CreatePath(element); ISvgMatrix svgMatrix = element.GetScreenCTM(); Matrix matrix = new Matrix((float)svgMatrix.A, (float)svgMatrix.B, (float)svgMatrix.C, (float)svgMatrix.D, (float)svgMatrix.E, (float)svgMatrix.F); SvgRectF bounds = SvgConverter.ToRect(gp.GetBounds(matrix)); bounds = SvgRectF.Inflate(bounds, margin, margin); return(bounds); } SvgUseElement useElement = element as SvgUseElement; if (useElement != null) { SvgTransformableElement refEl = useElement.ReferencedElement as SvgTransformableElement; if (refEl == null) { return(SvgRectF.Empty); } XmlElement refElParent = (XmlElement)refEl.ParentNode; element.OwnerDocument.Static = true; useElement.CopyToReferencedElement(refEl); element.AppendChild(refEl); SvgRectF bbox = this.GetElementBounds(refEl, margin); element.RemoveChild(refEl); useElement.RestoreReferencedElement(refEl); refElParent.AppendChild(refEl); element.OwnerDocument.Static = false; return(bbox); } SvgRectF union = SvgRectF.Empty; SvgTransformableElement transformChild; foreach (XmlNode childNode in element.ChildNodes) { if (childNode is SvgDefsElement) { continue; } if (childNode is ISvgTransformable) { transformChild = (SvgTransformableElement)childNode; SvgRectF bbox = this.GetElementBounds(transformChild, margin); if (bbox != SvgRectF.Empty) { if (union == SvgRectF.Empty) { union = bbox; } else { union = SvgRectF.Union(union, bbox); } } } } return(union); }
protected FontWeight GetTextFontWeight(SvgTextContentElement element) { string fontWeight = element.GetPropertyValue("font-weight"); if (string.IsNullOrWhiteSpace(fontWeight)) { return(FontWeights.Normal); } switch (fontWeight) { case "normal": return(FontWeights.Normal); case "bold": return(FontWeights.Bold); case "100": return(FontWeights.Thin); case "200": return(FontWeights.ExtraLight); case "300": return(FontWeights.Light); case "400": return(FontWeights.Normal); case "500": return(FontWeights.Medium); case "600": return(FontWeights.SemiBold); case "700": return(FontWeights.Bold); case "800": return(FontWeights.ExtraBold); case "900": return(FontWeights.Black); case "950": return(FontWeights.UltraBlack); } if (string.Equals(fontWeight, "bolder", StringComparison.OrdinalIgnoreCase)) { SvgTransformableElement parentElement = element.ParentNode as SvgTransformableElement; if (parentElement != null) { fontWeight = parentElement.GetPropertyValue("font-weight"); if (!string.IsNullOrWhiteSpace(fontWeight)) { return(this.GetBolderFontWeight(fontWeight)); } } return(FontWeights.ExtraBold); } if (string.Equals(fontWeight, "lighter", StringComparison.OrdinalIgnoreCase)) { SvgTransformableElement parentElement = element.ParentNode as SvgTransformableElement; if (parentElement != null) { fontWeight = parentElement.GetPropertyValue("font-weight"); if (!string.IsNullOrWhiteSpace(fontWeight)) { return(this.GetLighterFontWeight(fontWeight)); } } return(FontWeights.Light); } return(FontWeights.Normal); }