/// <summary> /// AfterRender - Dispose of Graphics object created for rendering. /// </summary> private void OnAfterRender() { if (_ownsGraphics) { if (_graphics != null) { if (_hitTestHelper != null) { if (_hitTestHelper != _graphics.HitTestHelper) { _hitTestHelper.Dispose(); _hitTestHelper = _graphics.HitTestHelper; } } _graphics.HitTestHelper = GdiHitTestHelper.NoHit; // Prevent disposal actual height test _graphics.Dispose(); _graphics = null; } } if (_hitTestHelper == null) { _hitTestHelper = GdiHitTestHelper.NoHit; } }
/// <summary> /// BeforeRender - Make sure we have a Graphics object to render to. /// If we don't have one, then create one to match the SvgWindow's /// physical dimensions. /// </summary> private void RendererBeforeRender() { // Testing for null here allows "advanced" developers to create their own Graphics object for rendering if (_graphics == null) { // Get the current SVGWindow's width and height int innerWidth = (int)_svgWindow.InnerWidth; int innerHeight = (int)_svgWindow.InnerHeight; // Make sure we have an actual area to render to if (innerWidth > 0 && innerHeight > 0) { // See if we already have a rasterImage that matches the current SVGWindow dimensions if (_rasterImage == null || _rasterImage.Width != innerWidth || _rasterImage.Height != innerHeight) { // Nope, so create one if (_rasterImage != null) { _rasterImage.Dispose(); _rasterImage = null; } _rasterImage = new Bitmap(innerWidth, innerHeight); } // Make a GraphicsWrapper object from the rasterImage and clear it to the background color // _graphics = GdiGraphicsWrapper.FromImage(_rasterImage, _isStatic); _graphics = GdiGraphicsImpl.FromImage(_rasterImage, _isStatic); _graphics.Clear(_backColor); _hitTestHelper = _graphics.HitTestHelper; } } }
public GdiGraphicsRenderer(GdiGraphics graphics, SvgWindow svgWindow) : this(graphics) { _svgWindow = svgWindow; if (_svgWindow != null) { _svgWindow.Renderer = this; } }
protected void FitToViewbox(GdiGraphics graphics, RectangleF elmRect) { ISvgFitToViewBox fitToVBElm = _svgElement as ISvgFitToViewBox; if (fitToVBElm != null) { SvgPreserveAspectRatio spar = (SvgPreserveAspectRatio)fitToVBElm.PreserveAspectRatio.AnimVal; double[] translateAndScale = spar.FitToViewBox((SvgRect)fitToVBElm.ViewBox.AnimVal, new SvgRect(elmRect.X, elmRect.Y, elmRect.Width, elmRect.Height)); graphics.TranslateTransform((float)translateAndScale[0], (float)translateAndScale[1]); graphics.ScaleTransform((float)translateAndScale[2], (float)translateAndScale[3]); } }
protected void SetTransform(GdiGraphics gr) { if (_svgElement is ISvgTransformable) { if (_transformMatrix == null) { ISvgTransformable transElm = (ISvgTransformable)_svgElement; SvgTransformList svgTList = (SvgTransformList)transElm.Transform.AnimVal; SvgMatrix svgMatrix = ((SvgTransformList)transElm.Transform.AnimVal).TotalMatrix; _transformMatrix = new Matrix((float)svgMatrix.A, (float)svgMatrix.B, (float)svgMatrix.C, (float)svgMatrix.D, (float)svgMatrix.E, (float)svgMatrix.F); } gr.Transform = _transformMatrix; } }
private SvgWindow GetSvgWindow(GdiGraphics graphics) { SvgImageElement iElm = this.Element as SvgImageElement; SvgWindow wnd = iElm.SvgWindow; if (_embeddedRenderer == null) { _embeddedRenderer = new GdiGraphicsRenderer(graphics, wnd); } else { wnd.Renderer = _embeddedRenderer; _embeddedRenderer.Window = wnd; } return(wnd); }
protected static void PaintMarkers(GdiGraphicsRenderer renderer, SvgStyleableElement styleElm, GdiGraphics gr) { // OPTIMIZE if (styleElm is ISharpMarkerHost) { string markerStartUrl = ExtractMarkerUrl(styleElm.GetPropertyValue("marker-start", "marker")); string markerMiddleUrl = ExtractMarkerUrl(styleElm.GetPropertyValue("marker-mid", "marker")); string markerEndUrl = ExtractMarkerUrl(styleElm.GetPropertyValue("marker-end", "marker")); if (markerStartUrl.Length > 0) { GdiMarkerRendering grNode = CreateByUri(styleElm.OwnerDocument, styleElm.BaseURI, markerStartUrl) as GdiMarkerRendering; if (grNode != null) { grNode.PaintMarker(renderer, gr, SvgMarkerPosition.Start, styleElm); } } if (markerMiddleUrl.Length > 0) { // TODO markerMiddleUrl != markerStartUrl GdiMarkerRendering grNode = CreateByUri(styleElm.OwnerDocument, styleElm.BaseURI, markerMiddleUrl) as GdiMarkerRendering; if (grNode != null) { grNode.PaintMarker(renderer, gr, SvgMarkerPosition.Mid, styleElm); } } if (markerEndUrl.Length > 0) { // TODO: markerEndUrl != markerMiddleUrl GdiMarkerRendering grNode = CreateByUri(styleElm.OwnerDocument, styleElm.BaseURI, markerEndUrl) as GdiMarkerRendering; if (grNode != null) { grNode.PaintMarker(renderer, gr, SvgMarkerPosition.End, styleElm); } } } }
private void Dispose(bool disposing) { if (_hitTestHelper != null) { _hitTestHelper.Dispose(); } if (_disposeRaster && _rasterImage != null) { _rasterImage.Dispose(); } if (_graphics != null) { _graphics.Dispose(); } _graphics = null; _rasterImage = null; _hitTestHelper = null; }
public void ClearAll() { if (_graphics != null) { _graphics.Dispose(); _graphics = null; } if (_rasterImage != null) { _rasterImage.Dispose(); _rasterImage = null; } if (_hitTestHelper != null) { _hitTestHelper.Dispose(); _hitTestHelper = null; } _hitTestHelper = GdiHitTestHelper.NoHit; }
protected void SetQuality(GdiGraphics gr) { Graphics graphics = gr.Graphics; string colorRendering = _svgElement.GetComputedStringValue("color-rendering", string.Empty); switch (colorRendering) { case "optimizeSpeed": graphics.CompositingQuality = CompositingQuality.HighSpeed; break; case "optimizeQuality": graphics.CompositingQuality = CompositingQuality.HighQuality; break; default: // "auto" // todo: could use AssumeLinear for slightly better graphics.CompositingQuality = CompositingQuality.Default; break; } if (_svgElement is SvgTextContentElement) { // Unfortunately the text rendering hints are not applied because the // text path is recorded and painted to the Graphics object as a path // not as text. string textRendering = _svgElement.GetComputedStringValue("text-rendering", string.Empty); switch (textRendering) { case "optimizeSpeed": graphics.SmoothingMode = SmoothingMode.HighSpeed; graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel; break; case "optimizeLegibility": graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; break; case "geometricPrecision": graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; break; default: // "auto" graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault; break; } } else { string shapeRendering = _svgElement.GetComputedStringValue("shape-rendering", string.Empty); switch (shapeRendering) { case "optimizeSpeed": graphics.SmoothingMode = SmoothingMode.HighSpeed; break; case "crispEdges": graphics.SmoothingMode = SmoothingMode.None; break; case "geometricPrecision": graphics.SmoothingMode = SmoothingMode.HighQuality; break; default: // "auto" graphics.SmoothingMode = SmoothingMode.AntiAlias; break; } } }
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 static void PaintMarkers(GdiGraphicsRenderer renderer, SvgStyleableElement styleElm, GdiGraphics gr) { // OPTIMIZE if (styleElm is ISharpMarkerHost) { string markerStartUrl = ExtractMarkerUrl(styleElm.GetPropertyValue("marker-start", "marker")); string markerMiddleUrl = ExtractMarkerUrl(styleElm.GetPropertyValue("marker-mid", "marker")); string markerEndUrl = ExtractMarkerUrl(styleElm.GetPropertyValue("marker-end", "marker")); string markerAll = ExtractMarkerUrl(styleElm.GetPropertyValue("marker", "marker")); // The SVG specification defines three properties to reference markers: marker-start, // marker -mid, marker-end. It also provides a shorthand property, marker. Using the marker // property from a style sheet is equivalent to using all three (start, mid, end). // However, shorthand properties cannot be used as presentation attributes. if (!string.IsNullOrWhiteSpace(markerAll) && !IsPresentationMarker(styleElm)) { if (string.IsNullOrWhiteSpace(markerStartUrl)) { markerStartUrl = markerAll; } if (string.IsNullOrWhiteSpace(markerMiddleUrl)) { markerMiddleUrl = markerAll; } if (string.IsNullOrWhiteSpace(markerEndUrl)) { markerEndUrl = markerAll; } } if (markerStartUrl.Length > 0) { GdiMarkerRendering grNode = CreateByUri(styleElm.OwnerDocument, styleElm.BaseURI, markerStartUrl) as GdiMarkerRendering; if (grNode != null) { grNode.PaintMarker(renderer, gr, SvgMarkerPosition.Start, styleElm); } } if (markerMiddleUrl.Length > 0) { // TODO markerMiddleUrl != markerStartUrl GdiMarkerRendering grNode = CreateByUri(styleElm.OwnerDocument, styleElm.BaseURI, markerMiddleUrl) as GdiMarkerRendering; if (grNode != null) { grNode.PaintMarker(renderer, gr, SvgMarkerPosition.Mid, styleElm); } } if (markerEndUrl.Length > 0) { // TODO: markerEndUrl != markerMiddleUrl GdiMarkerRendering grNode = CreateByUri(styleElm.OwnerDocument, styleElm.BaseURI, markerEndUrl) as GdiMarkerRendering; if (grNode != null) { grNode.PaintMarker(renderer, gr, SvgMarkerPosition.End, styleElm); } } } }
public void PaintMarker(GdiGraphicsRenderer renderer, GdiGraphics gr, SvgMarkerPosition markerPos, SvgStyleableElement refElement) { ISharpMarkerHost markerHostElm = (ISharpMarkerHost)refElement; SvgMarkerElement markerElm = (SvgMarkerElement)_svgElement; SvgPointF[] vertexPositions = markerHostElm.MarkerPositions; if (vertexPositions == null) { return; } var comparer = StringComparison.OrdinalIgnoreCase; bool mayHaveCurves = markerHostElm.MayHaveCurves; int start; int len; // Choose which part of the position array to use switch (markerPos) { case SvgMarkerPosition.Start: start = 0; len = 1; break; case SvgMarkerPosition.Mid: start = 1; len = vertexPositions.Length - 2; break; default: // == MarkerPosition.End start = vertexPositions.Length - 1; len = 1; break; } int end = start + len; for (int i = start; i < end; i++) { SvgPointF point = vertexPositions[i]; GdiGraphicsContainer gc = gr.BeginContainer(); gr.TranslateTransform(point.X, point.Y); if (markerElm.OrientType.AnimVal.Equals((ushort)SvgMarkerOrient.Angle)) { double scaleValue = markerElm.OrientAngle.AnimVal.Value; if (!scaleValue.Equals(0)) { gr.RotateTransform((float)scaleValue); } } else { double angle; switch (markerPos) { case SvgMarkerPosition.Start: angle = markerHostElm.GetStartAngle(i); //angle = markerHostElm.GetStartAngle(i + 1); if (vertexPositions.Length >= 2) { SvgPointF pMarkerPoint1 = vertexPositions[start]; SvgPointF pMarkerPoint2 = vertexPositions[end]; float xDiff = pMarkerPoint2.X - pMarkerPoint1.X; float yDiff = pMarkerPoint2.Y - pMarkerPoint1.Y; double angleMarker = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI); if (!angleMarker.Equals(angle)) { angle = angleMarker; } } break; case SvgMarkerPosition.Mid: //angle = (markerHostElm.GetEndAngle(i) + markerHostElm.GetStartAngle(i + 1)) / 2; angle = SvgNumber.CalcAngleBisection(markerHostElm.GetEndAngle(i), markerHostElm.GetStartAngle(i + 1)); break; default: angle = markerHostElm.GetEndAngle(i - 1); //double angle2 = markerHostElm.GetEndAngle(i); if (vertexPositions.Length >= 2) { SvgPointF pMarkerPoint1 = vertexPositions[start - 1]; SvgPointF pMarkerPoint2 = vertexPositions[start]; float xDiff = pMarkerPoint2.X - pMarkerPoint1.X; float yDiff = pMarkerPoint2.Y - pMarkerPoint1.Y; double angleMarker = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI); if (!angleMarker.Equals(angle)) { angle = angleMarker; } } //if (mayHaveCurves) //{ // angle = this.GetAngleAt(start - 1, angle, markerPos, markerHostElm); //} break; } gr.RotateTransform((float)angle); } // 'viewBox' and 'preserveAspectRatio' attributes // viewBox -> viewport(0, 0, markerWidth, markerHeight) var spar = (SvgPreserveAspectRatio)markerElm.PreserveAspectRatio.AnimVal; double[] translateAndScale = spar.FitToViewBox((SvgRect)markerElm.ViewBox.AnimVal, new SvgRect(0, 0, markerElm.MarkerWidth.AnimVal.Value, markerElm.MarkerHeight.AnimVal.Value)); //// Warning at this time, refX and refY are relative to the painted element's coordinate system. //// We need to move the reference point to the marker's coordinate system //float refX = (float)markerElm.RefX.AnimVal.Value; //float refY = (float)markerElm.RefY.AnimVal.Value; ////if (!(refX.Equals(0) && refY.Equals(0))) ////{ //// var points = new PointF[] { new PointF(refX, refY) }; //// gr.Transform.TransformPoints(points); //// refX = points[0].X; //// refY = points[0].Y; //// gr.TranslateTransform(-refX, -refY); ////} //if (markerElm.MarkerUnits.AnimVal.Equals((ushort)SvgMarkerUnit.StrokeWidth)) //{ // SvgLength strokeWidthLength = new SvgLength(refElement, // "stroke-width", SvgLengthSource.Css, SvgLengthDirection.Viewport, "1"); // float strokeWidth = (float)strokeWidthLength.Value; // gr.ScaleTransform(strokeWidth, strokeWidth); //} //gr.TranslateTransform(-(float)(markerElm.RefX.AnimVal.Value * translateAndScale[2]), // -(float)(markerElm.RefY.AnimVal.Value * translateAndScale[3])); //gr.ScaleTransform((float)translateAndScale[2], (float)translateAndScale[3]); // compute an additional transform for 'strokeWidth' coordinate system ISvgAnimatedEnumeration markerUnits = markerElm.MarkerUnits; if (markerUnits.AnimVal.Equals((ushort)SvgMarkerUnit.StrokeWidth)) { SvgLength strokeWidthLength = new SvgLength(refElement, "stroke-width", SvgLengthSource.Css, SvgLengthDirection.Viewport, SvgConstants.ValOne); double strokeWidth = strokeWidthLength.Value; if (!strokeWidth.Equals(1)) { gr.ScaleTransform((float)strokeWidth, (float)strokeWidth); } } gr.TranslateTransform(-(float)(markerElm.RefX.AnimVal.Value * translateAndScale[2]), -(float)(markerElm.RefY.AnimVal.Value * translateAndScale[3])); if (!(translateAndScale[2].Equals(1) && translateAndScale[3].Equals(1))) { gr.ScaleTransform((float)translateAndScale[2], (float)translateAndScale[3]); } // gr.TranslateTransform(point.X, point.Y); RectangleF rectClip = RectangleF.Empty; if (markerUnits.AnimVal.Equals((ushort)SvgMarkerUnit.StrokeWidth)) { string overflowAttr = markerElm.GetAttribute("overflow"); if (string.IsNullOrWhiteSpace(overflowAttr) || overflowAttr.Equals("scroll", comparer) || overflowAttr.Equals(CssConstants.ValHidden, comparer)) { var markerClip = RectangleF.Empty; SvgRect clipRect = (SvgRect)markerElm.ViewBox.AnimVal; if (clipRect != null && !clipRect.IsEmpty) { rectClip = new RectangleF((float)clipRect.X, (float)clipRect.Y, (float)clipRect.Width, (float)clipRect.Height); } else if (markerElm.IsSizeDefined) { rectClip = new RectangleF(0, 0, (float)markerElm.MarkerWidth.AnimVal.Value, (float)markerElm.MarkerHeight.AnimVal.Value); } } } if (rectClip.IsEmpty) { SetClip(gr); } else { gr.SetClip(rectClip); } renderer.RenderChildren(markerElm); gr.EndContainer(gc); } }
public override void Render(GdiGraphicsRenderer renderer) { _graphics = renderer.GdiGraphics; SvgRenderingHint hint = _svgElement.RenderingHint; if (hint == SvgRenderingHint.Clipping) { return; } if (_svgElement.ParentNode is SvgClipPathElement) { return; } SvgTextElement textElement = _svgElement as SvgTextElement; if (textElement == null) { return; } string sVisibility = textElement.GetPropertyValue("visibility"); string sDisplay = textElement.GetPropertyValue("display"); if (string.Equals(sVisibility, "hidden") || string.Equals(sDisplay, "none")) { return; } Clip(_graphics); PointF ctp = new PointF(0, 0); // current text position ctp = GetCurrentTextPosition(textElement, ctp); string sBaselineShift = textElement.GetPropertyValue("baseline-shift").Trim(); double shiftBy = 0; if (sBaselineShift.Length > 0) { float textFontSize = GetComputedFontSize(textElement); if (sBaselineShift.EndsWith("%", StringComparison.OrdinalIgnoreCase)) { shiftBy = SvgNumber.ParseNumber(sBaselineShift.Substring(0, sBaselineShift.Length - 1)) / 100 * textFontSize; } else if (sBaselineShift == "sub") { shiftBy = -0.6F * textFontSize; } else if (sBaselineShift == "super") { shiftBy = 0.6F * textFontSize; } else if (sBaselineShift == "baseline") { shiftBy = 0; } else { shiftBy = SvgNumber.ParseNumber(sBaselineShift); } } XmlNodeType nodeType = XmlNodeType.None; foreach (XmlNode child in _svgElement.ChildNodes) { SvgStyleableElement stylable = child as SvgStyleableElement; if (stylable != null) { sVisibility = stylable.GetPropertyValue("visibility"); sDisplay = stylable.GetPropertyValue("display"); if (string.Equals(sVisibility, "hidden") || string.Equals(sDisplay, "none")) { continue; } } nodeType = child.NodeType; if (nodeType == XmlNodeType.Text) { ctp.Y -= (float)shiftBy; AddGraphicsPath(textElement, ref ctp, GetText(textElement, child)); ctp.Y += (float)shiftBy; } else if (nodeType == XmlNodeType.Element) { string nodeName = child.Name; if (string.Equals(nodeName, "tref")) { AddTRefElementPath((SvgTRefElement)child, ref ctp); } else if (string.Equals(nodeName, "tspan")) { AddTSpanElementPath((SvgTSpanElement)child, ref ctp); } } } PaintMarkers(renderer, textElement, _graphics); _graphics = null; }
public GdiGraphicsRenderer(GdiGraphics graphics) : this(true, false) { _graphics = graphics; _ownsGraphics = (graphics == null); }
private GraphicsPath CreateClippingRegion(GdiGraphics graphics, SvgClipPathElement clipPath) { GraphicsPath path = new GraphicsPath(); foreach (XmlNode node in clipPath.ChildNodes) { if (node.NodeType != XmlNodeType.Element) { continue; } // Handle a case where the clip element has "use" element as a child... if (string.Equals(node.LocalName, "use")) { SvgUseElement useElement = (SvgUseElement)node; XmlElement refEl = useElement.ReferencedElement; if (refEl != null) { XmlElement refElParent = (XmlElement)refEl.ParentNode; useElement.OwnerDocument.Static = true; useElement.CopyToReferencedElement(refEl); refElParent.RemoveChild(refEl); useElement.AppendChild(refEl); foreach (XmlNode useChild in useElement.ChildNodes) { if (useChild.NodeType != XmlNodeType.Element) { continue; } SvgStyleableElement element = useChild as SvgStyleableElement; if (element != null && element.RenderingHint == SvgRenderingHint.Shape) { GraphicsPath childPath = CreatePath(element); if (childPath != null) { string clipRule = element.GetPropertyValue("clip-rule"); path.FillMode = (clipRule == "evenodd") ? FillMode.Alternate : FillMode.Winding; path.AddPath(childPath, true); } } } useElement.RemoveChild(refEl); useElement.RestoreReferencedElement(refEl); refElParent.AppendChild(refEl); useElement.OwnerDocument.Static = false; } } else { SvgStyleableElement element = node as SvgStyleableElement; if (element != null) { if (element.RenderingHint == SvgRenderingHint.Shape) { GraphicsPath childPath = CreatePath(element); if (childPath != null) { string clipRule = element.GetPropertyValue("clip-rule"); path.FillMode = (clipRule == "evenodd") ? FillMode.Alternate : FillMode.Winding; path.AddPath(childPath, true); } } else if (element.RenderingHint == SvgRenderingHint.Text) { GdiTextRendering textRendering = new GdiTextRendering(element); textRendering.TextMode = GdiTextMode.Outlining; GdiGraphicsRenderer renderer = new GdiGraphicsRenderer(graphics); textRendering.BeforeRender(renderer); textRendering.Render(renderer); textRendering.AfterRender(renderer); GraphicsPath childPath = textRendering.Path; if (childPath != null) { string clipRule = element.GetPropertyValue("clip-rule"); path.FillMode = (clipRule == "evenodd") ? FillMode.Alternate : FillMode.Winding; path.AddPath(childPath, true); } } } } } return(path); }
public override void Render(GdiGraphicsRenderer renderer) { _graphics = renderer.GdiGraphics; //SvgRenderingHint hint = _svgElement.RenderingHint; //if (hint == SvgRenderingHint.Clipping) //{ // return; //} //if (_svgElement.ParentNode is SvgClipPathElement) //{ // return; //} SvgTextBaseElement textElement = _svgElement as SvgTextBaseElement; if (textElement == null) { return; } string sVisibility = textElement.GetPropertyValue("visibility"); string sDisplay = textElement.GetPropertyValue("display"); if (string.Equals(sVisibility, "hidden") || string.Equals(sDisplay, "none")) { return; } if (_textMode != GdiTextMode.Outlining) { SetClip(_graphics); } PointF ctp = new PointF(0, 0); // current text position ctp = GetCurrentTextPosition(textElement, ctp); string sBaselineShift = textElement.GetPropertyValue("baseline-shift").Trim(); double shiftBy = 0; if (sBaselineShift.Length > 0) { float textFontSize = GetComputedFontSize(textElement); if (sBaselineShift.EndsWith("%", StringComparison.OrdinalIgnoreCase)) { shiftBy = SvgNumber.ParseNumber(sBaselineShift.Substring(0, sBaselineShift.Length - 1)) / 100 * textFontSize; } else if (sBaselineShift == "sub") { shiftBy = -0.6F * textFontSize; } else if (sBaselineShift == "super") { shiftBy = 0.6F * textFontSize; } else if (sBaselineShift == "baseline") { shiftBy = 0; } else { shiftBy = SvgNumber.ParseNumber(sBaselineShift); } } // For for fonts loading in the background... var svgDoc = _svgElement.OwnerDocument; if (svgDoc.IsFontsLoaded == false) { //TODO: Use of SpinUntil is known to CPU heavy, but will work for now... SpinWait.SpinUntil(() => svgDoc.IsFontsLoaded == true); } XmlNodeType nodeType = XmlNodeType.None; foreach (XmlNode child in _svgElement.ChildNodes) { SvgStyleableElement stylable = child as SvgStyleableElement; if (stylable != null) { sVisibility = stylable.GetPropertyValue("visibility"); sDisplay = stylable.GetPropertyValue("display"); if (string.Equals(sVisibility, "hidden") || string.Equals(sDisplay, "none")) { continue; } } nodeType = child.NodeType; if (nodeType == XmlNodeType.Text) { ctp.Y -= (float)shiftBy; AddGraphicsPath(textElement, ref ctp, GetText(textElement, child)); ctp.Y += (float)shiftBy; } else if (nodeType == XmlNodeType.Element) { string nodeName = child.Name; if (string.Equals(nodeName, "tref")) { AddTRefElementPath((SvgTRefElement)child, ref ctp); } else if (string.Equals(nodeName, "tspan")) { AddTSpanElementPath((SvgTSpanElement)child, ref ctp); } } } PaintMarkers(renderer, textElement, _graphics); _graphics = null; }
public void PaintMarker(GdiGraphicsRenderer renderer, GdiGraphics gr, SvgMarkerPosition markerPos, SvgStyleableElement refElement) { ISharpMarkerHost markerHostElm = (ISharpMarkerHost)refElement; SvgMarkerElement markerElm = (SvgMarkerElement)_svgElement; SvgPointF[] vertexPositions = markerHostElm.MarkerPositions; int start; int len; // Choose which part of the position array to use switch (markerPos) { case SvgMarkerPosition.Start: start = 0; len = 1; break; case SvgMarkerPosition.Mid: start = 1; len = vertexPositions.Length - 2; break; default: // == MarkerPosition.End start = vertexPositions.Length - 1; len = 1; break; } for (int i = start; i < start + len; i++) { SvgPointF point = vertexPositions[i]; GdiGraphicsContainer gc = gr.BeginContainer(); gr.TranslateTransform(point.X, point.Y); if (markerElm.OrientType.AnimVal.Equals((ushort)SvgMarkerOrient.Angle)) { gr.RotateTransform((float)markerElm.OrientAngle.AnimVal.Value); } else { double angle; switch (markerPos) { case SvgMarkerPosition.Start: angle = markerHostElm.GetStartAngle(i + 1); break; case SvgMarkerPosition.Mid: //angle = (markerHostElm.GetEndAngle(i) + markerHostElm.GetStartAngle(i + 1)) / 2; angle = SvgNumber.CalcAngleBisection(markerHostElm.GetEndAngle(i), markerHostElm.GetStartAngle(i + 1)); break; default: angle = markerHostElm.GetEndAngle(i); break; } gr.RotateTransform((float)angle); } if (markerElm.MarkerUnits.AnimVal.Equals((ushort)SvgMarkerUnit.StrokeWidth)) { SvgLength strokeWidthLength = new SvgLength(refElement, "stroke-width", SvgLengthSource.Css, SvgLengthDirection.Viewport, "1"); float strokeWidth = (float)strokeWidthLength.Value; gr.ScaleTransform(strokeWidth, strokeWidth); } SvgPreserveAspectRatio spar = (SvgPreserveAspectRatio)markerElm.PreserveAspectRatio.AnimVal; double[] translateAndScale = spar.FitToViewBox((SvgRect)markerElm.ViewBox.AnimVal, new SvgRect(0, 0, markerElm.MarkerWidth.AnimVal.Value, markerElm.MarkerHeight.AnimVal.Value)); gr.TranslateTransform(-(float)(markerElm.RefX.AnimVal.Value * translateAndScale[2]), -(float)(markerElm.RefY.AnimVal.Value * translateAndScale[3])); gr.ScaleTransform((float)translateAndScale[2], (float)translateAndScale[3]); Clip(gr); renderer.RenderChildren(markerElm); gr.EndContainer(gc); } }