using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; namespace Svg { /// /// Provides the base class for all paint servers that wish to render a gradient. /// public abstract class SvgGradientServer : SvgPaintServer { private SvgCoordinateUnits _gradientUnits; private SvgGradientSpreadMethod _spreadMethod = SvgGradientSpreadMethod.Pad; private SvgGradientServer _inheritGradient; private List _stops; /// /// Initializes a new instance of the class. /// internal SvgGradientServer() { this.GradientUnits = SvgCoordinateUnits.ObjectBoundingBox; this._stops = new List(); } /// /// Called by the underlying when an element has been added to the /// collection. /// /// The that has been added. /// An representing the index where the element was added to the collection. protected override void AddElement(SvgElement child, int index) { if (child is SvgGradientStop) { this.Stops.Add((SvgGradientStop)child); } base.AddElement(child, index); } /// /// Called by the underlying when an element has been removed from the /// collection. /// /// The that has been removed. protected override void RemoveElement(SvgElement child) { if (child is SvgGradientStop) { this.Stops.Remove((SvgGradientStop)child); } base.RemoveElement(child); } /// /// Gets the ramp of colors to use on a gradient. /// public List Stops { get { return this._stops; } } /// /// Specifies what happens if the gradient starts or ends inside the bounds of the target rectangle. /// [SvgAttribute("spreadMethod")] public SvgGradientSpreadMethod SpreadMethod { get { return this._spreadMethod; } set { this._spreadMethod = value; } } /// /// Gets or sets the coordinate system of the gradient. /// [SvgAttribute("gradientUnits")] public SvgCoordinateUnits GradientUnits { get { return this._gradientUnits; } set { this._gradientUnits = value; } } /// /// Gets or sets another gradient fill from which to inherit the stops from. /// [SvgAttribute("href")] public SvgGradientServer InheritGradient { get { return this._inheritGradient; } set { this._inheritGradient = value; this.InheritStops(); } } /// /// Gets a representing the 's gradient stops. /// /// The parent . /// The opacity of the colour blend. protected ColorBlend GetColourBlend(SvgVisualElement owner, float opacity, bool radial) { int colourBlends = this.Stops.Count; bool insertStart = false; bool insertEnd = false; //gradient.Transform = renderingElement.Transforms.Matrix; //stops should be processed in reverse order if it's a radial gradient // May need to increase the number of colour blends because the range *must* be from 0.0 to 1.0. // E.g. 0.5 - 0.8 isn't valid therefore the rest need to be calculated. // If the first stop doesn't start at zero if (this.Stops[0].Offset.Value > 0) { colourBlends++; if (radial) { insertEnd = true; } else { insertStart = true; } } // If the last stop doesn't end at 1 a stop float lastValue = this.Stops[this.Stops.Count - 1].Offset.Value; if (lastValue < 100 || lastValue < 1) { colourBlends++; if (radial) { insertStart = true; } else { insertEnd = true; } } ColorBlend blend = new ColorBlend(colourBlends); // Set positions and colour values int actualStops = 0; float mergedOpacity = 0.0f; float position = 0.0f; Color colour = Color.Black; for (int i = 0; i < colourBlends; i++) { var currentStop = this.Stops[radial ? this.Stops.Count - 1 - actualStops : actualStops]; mergedOpacity = opacity * currentStop.Opacity; position = radial ? 1 - (currentStop.Offset.ToDeviceValue(owner) / owner.Bounds.Width) : (currentStop.Offset.ToDeviceValue(owner) / owner.Bounds.Width); colour = Color.FromArgb((int)(mergedOpacity * 255), currentStop.Colour); actualStops++; // Insert this colour before itself at position 0 if (insertStart && i == 0) { blend.Positions[i] = 0.0f; blend.Colors[i] = colour; i++; } blend.Positions[i] = position; blend.Colors[i] = colour; // Insert this colour after itself at position 0 if (insertEnd && i == colourBlends - 2) { i++; blend.Positions[i] = 1.0f; blend.Colors[i] = colour; } } return blend; } /// // If this gradient contains no stops then it will search any inherited gradients for stops. /// protected virtual void InheritStops() { if (this.Stops.Count == 0 && this.InheritGradient != null) { _stops.AddRange(this.InheritGradient.Stops); } } public override SvgElement DeepCopy() { var newObj = base.DeepCopy() as SvgGradientServer; newObj.SpreadMethod = this.SpreadMethod; newObj.GradientUnits = this.GradientUnits; newObj.InheritGradient = this.InheritGradient; return newObj; } } }