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;
}
}
}