Commit 06d69e68 authored by Tebjan Halm's avatar Tebjan Halm
Browse files

Merge pull request #128 from JoshMcCullough/master

Working on making this export valid SVG documents.
parents ed525d27 e0568e61
...@@ -50,6 +50,7 @@ namespace Svg ...@@ -50,6 +50,7 @@ namespace Svg
} }
[TypeConverter(typeof(SvgPreserveAspectRatioConverter))]
public enum SvgPreserveAspectRatio public enum SvgPreserveAspectRatio
{ {
xMidYMid, //default xMidYMid, //default
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
namespace Svg.DataTypes namespace Svg.DataTypes
{ {
/// <summary>Specifies the color space for gradient interpolations, color animations and alpha compositing.</summary>
/// <remarks>When a child element is blended into a background, the value of the ‘color-interpolation’ property on the child determines the type of blending, not the value of the ‘color-interpolation’ on the parent. For gradients which make use of the ‘xlink:href’ attribute to reference another gradient, the gradient uses the ‘color-interpolation’ property value from the gradient element which is directly referenced by the ‘fill’ or ‘stroke’ property. When animating colors, color interpolation is performed according to the value of the ‘color-interpolation’ property on the element being animated.</remarks>
[TypeConverter(typeof(SvgColourInterpolationConverter))]
public enum SvgColourInterpolation public enum SvgColourInterpolation
{ {
auto, /// <summary>Indicates that the user agent can choose either the sRGB or linearRGB spaces for color interpolation. This option indicates that the author doesn't require that color interpolation occur in a particular color space.</summary>
sRGB, Auto,
linearRGB,
inherit /// <summary>Indicates that color interpolation should occur in the sRGB color space.</summary>
SRGB,
/// <summary>Indicates that color interpolation should occur in the linearized RGB color space as described above.</summary>
LinearRGB,
/// <summary>The value is inherited from the parent element.</summary>
Inherit
} }
} }
...@@ -6,17 +6,21 @@ using System.ComponentModel; ...@@ -6,17 +6,21 @@ using System.ComponentModel;
namespace Svg namespace Svg
{ {
//TODO Need to split this enum into separate inherited enums for GradientCoordinateUnits, ClipPathCoordinateUnits, etc. as each should have its own converter since they have different defaults.
/// <summary> /// <summary>
/// Defines the various coordinate units certain SVG elements may use. /// Defines the various coordinate units certain SVG elements may use.
/// </summary> /// </summary>
[TypeConverter(typeof(SvgCoordinateUnitsConverter))] [TypeConverter(typeof(SvgCoordinateUnitsConverter))]
public enum SvgCoordinateUnits public enum SvgCoordinateUnits
{ {
//TODO Inherit is not actually valid
Inherit, Inherit,
/// <summary> /// <summary>
/// Indicates that the coordinate system of the owner element is to be used. /// Indicates that the coordinate system of the owner element is to be used.
/// </summary> /// </summary>
ObjectBoundingBox, ObjectBoundingBox,
/// <summary> /// <summary>
/// Indicates that the coordinate system of the entire document is to be used. /// Indicates that the coordinate system of the entire document is to be used.
/// </summary> /// </summary>
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
namespace Svg namespace Svg
{ {
/// <summary>This is the descriptor for the style of a font and takes the same values as the 'font-style' property, except that a comma-separated list is permitted.</summary>
[TypeConverter(typeof(SvgFontStyleConverter))]
[Flags]
public enum SvgFontStyle public enum SvgFontStyle
{ {
normal, /// <summary>Indicates that the font-face supplies all styles (normal, oblique and italic).</summary>
italic, All = (Normal | Oblique | Italic),
oblique,
inherit /// <summary>Specifies a font that is classified as 'normal' in the UA's font database.</summary>
Normal = 1,
/// <summary>Specifies a font that is classified as 'oblique' in the UA's font database. Fonts with Oblique, Slanted, or Incline in their names will typically be labeled 'oblique' in the font database. A font that is labeled 'oblique' in the UA's font database may actually have been generated by electronically slanting a normal font.</summary>
Oblique = 2,
/// <summary>Specifies a font that is classified as 'italic' in the UA's font database, or, if that is not available, one labeled 'oblique'. Fonts with Italic, Cursive, or Kursiv in their names will typically be labeled 'italic'</summary>
Italic = 4
} }
} }
...@@ -9,8 +9,8 @@ namespace Svg ...@@ -9,8 +9,8 @@ namespace Svg
[TypeConverter(typeof(SvgFontVariantConverter))] [TypeConverter(typeof(SvgFontVariantConverter))]
public enum SvgFontVariant public enum SvgFontVariant
{ {
normal, Normal,
smallcaps, Smallcaps,
inherit Inherit
} }
} }
...@@ -6,22 +6,57 @@ using System.ComponentModel; ...@@ -6,22 +6,57 @@ using System.ComponentModel;
namespace Svg namespace Svg
{ {
//TODO This should be split out to define an enum for the font face element and text element.
/// <summary>The weight of a face relative to others in the same font family.</summary>
[TypeConverter(typeof(SvgFontWeightConverter))] [TypeConverter(typeof(SvgFontWeightConverter))]
[Flags]
public enum SvgFontWeight public enum SvgFontWeight
{ {
inherit, //TODO All Is not valid for text elements, but is is for font face elements.
normal, /// <summary>All font weights.</summary>
bold, All = (W100 | W200 | W300 | W400 | W500 | W600 | W700 | W800 | W900),
bolder,
lighter, //TODO Inherit Is not valid for font face elements, but is is for text elements.
w100, /// <summary>The value is inherited from the parent element.</summary>
w200, Inherit = 0,
w300,
w400, // same as normal /// <summary>Same as <see cref="W400"/>.</summary>
w500, Normal = W400,
w600,
w700, // same as bold /// <summary>Same as <see cref="W700"/>.</summary>
w800, Bold = W700,
w900
/// <summary>One font weight darker than the parent element.</summary>
Bolder = 512,
/// <summary>One font weight lighter than the parent element.</summary>
Lighter = 1024,
/// <summary></summary>
W100 = 1,
/// <summary></summary>
W200 = 2,
/// <summary></summary>
W300 = 4,
/// <summary>Same as <see cref="Normal"/>.</summary>
W400 = 8,
/// <summary></summary>
W500 = 16,
/// <summary></summary>
W600 = 32,
/// <summary>Same as <see cref="Bold"/>.</summary>
W700 = 64,
/// <summary></summary>
W800 = 128,
/// <summary></summary>
W900 = 256
} }
} }
...@@ -2,10 +2,14 @@ ...@@ -2,10 +2,14 @@
namespace Svg.DataTypes namespace Svg.DataTypes
{ {
/// <summary>Defines the coordinate system for attributes ‘markerWidth’, ‘markerHeight’ and the contents of the ‘marker’.</summary>
[TypeConverter(typeof(SvgMarkerUnitsConverter))] [TypeConverter(typeof(SvgMarkerUnitsConverter))]
public enum SvgMarkerUnits public enum SvgMarkerUnits
{ {
strokeWidth, /// <summary>If markerUnits="strokeWidth", ‘markerWidth’, ‘markerHeight’ and the contents of the ‘marker’ represent values in a coordinate system which has a single unit equal the size in user units of the current stroke width (see the ‘stroke-width’ property) in place for the graphic object referencing the marker.</summary>
userSpaceOnUse StrokeWidth,
/// <summary>If markerUnits="userSpaceOnUse", ‘markerWidth’, ‘markerHeight’ and the contents of the ‘marker’ represent values in the current user coordinate system in place for the graphic object referencing the marker (i.e., the user coordinate system for the element referencing the ‘marker’ element via a ‘marker’, ‘marker-start’, ‘marker-mid’ or ‘marker-end’ property).</summary>
UserSpaceOnUse
} }
} }
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
namespace Svg namespace Svg
{ {
/// <summary>The ‘overflow’ property applies to elements that establish new viewports (e.g., ‘svg’ elements), ‘pattern’ elements and ‘marker’ elements. For all other elements, the property has no effect (i.e., a clipping rectangle is not created).</summary>
/// <remarks>
/// <para>The ‘overflow’ property has the same parameter values and has the same meaning as defined in CSS2 ([CSS2], section 11.1.1); however, the following additional points apply:</para>
/// <para>The ‘overflow’ property applies to elements that establish new viewports (e.g., ‘svg’ elements), ‘pattern’ elements and ‘marker’ elements. For all other elements, the property has no effect (i.e., a clipping rectangle is not created).</para>
/// <para>For those elements to which the ‘overflow’ property can apply, if the ‘overflow’ property has the value hidden or scroll, the effect is that a new clipping path in the shape of a rectangle is created. The result is equivalent to defining a ‘clipPath’ element whose content is a ‘rect’ element which defines the equivalent rectangle, and then specifying the <uri> of this ‘clipPath’ element on the ‘clip-path’ property for the given element.</para>
/// <para>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).</para>
/// <para>Within SVG content, the value auto is equivalent to the value visible.</para>
/// <para>When an outermost svg element is embedded inline within a parent XML grammar which uses CSS layout ([CSS2], chapter 9) or XSL formatting [XSL], if the ‘overflow’ property has the value hidden or scroll, then the user agent will establish an initial clipping path equal to the bounds of the initial viewport; otherwise, the initial clipping path is set according to the clipping rules as defined in CSS2 ([CSS2], section 11.1.1).</para>
/// <para>When an outermost svg element is stand-alone or embedded inline within a parent XML grammar which does not use CSS layout or XSL formatting, the ‘overflow’ property on the outermost svg element is ignored for the purposes of visual rendering and the initial clipping path is set to the bounds of the initial viewport.</para>
/// <para>The initial value for ‘overflow’ as defined in [CSS2-overflow] is 'visible', and this applies also to the root ‘svg’ element; however, for child elements of an SVG document, SVG's user agent style sheet overrides this initial value and sets the ‘overflow’ property on elements that establish new viewports (e.g., ‘svg’ elements), ‘pattern’ elements and ‘marker’ elements to the value 'hidden'.</para>
/// <para>As a result of the above, the default behavior of SVG user agents is to establish a clipping path to the bounds of the initial viewport and to establish a new clipping path for each element which establishes a new viewport and each ‘pattern’ and ‘marker’ element.</para>
/// </remarks>
[TypeConverter(typeof(SvgOverflowConverter))]
public enum SvgOverflow public enum SvgOverflow
{ {
inherit, /// <summary>The value is inherited from the parent element.</summary>
auto, Inherit,
visible,
hidden, /// <summary>The overflow is rendered - same as "visible".</summary>
scroll Auto,
/// <summary>Overflow is rendered.</summary>
Visible,
/// <summary>Overflow is not rendered.</summary>
Hidden,
/// <summary>Overflow causes a scrollbar to appear (horizontal, vertical or both).</summary>
Scroll
} }
} }
...@@ -6,14 +6,27 @@ using System.ComponentModel; ...@@ -6,14 +6,27 @@ using System.ComponentModel;
namespace Svg namespace Svg
{ {
/// <summary>This property describes decorations that are added to the text of an element. Conforming SVG Viewers are not required to support the blink value.</summary>
[TypeConverter(typeof(SvgTextDecorationConverter))] [TypeConverter(typeof(SvgTextDecorationConverter))]
[Flags]
public enum SvgTextDecoration public enum SvgTextDecoration
{ {
inherit, /// <summary>The value is inherited from the parent element.</summary>
none, Inherit = 0,
underline,
overline, /// <summary>The text is not decorated</summary>
lineThrough, None = 1,
blink
/// <summary>The text is underlined.</summary>
Underline = 2,
/// <summary>The text is overlined.</summary>
Overline = 4,
/// <summary>The text is struck through.</summary>
LineThrough = 8,
/// <summary>The text will blink.</summary>
Blink = 16
} }
} }
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
namespace Svg namespace Svg
{ {
/// <summary>Indicates the type of adjustments which the user agent shall make to make the rendered length of the text match the value specified on the ‘textLength’ attribute.</summary>
/// <remarks>
/// <para>The user agent is required to achieve correct start and end positions for the text strings, but the locations of intermediate glyphs are not predictable because user agents might employ advanced algorithms to stretch or compress text strings in order to balance correct start and end positioning with optimal typography.</para>
/// <para>Note that, for a text string that contains n characters, the adjustments to the advance values often occur only for n−1 characters (see description of attribute ‘textLength’), whereas stretching or compressing of the glyphs will be applied to all n characters.</para>
/// </remarks>
[TypeConverter(typeof(SvgTextLengthAdjustConverter))]
public enum SvgTextLengthAdjust public enum SvgTextLengthAdjust
{ {
spacing, /// <summary>Indicates that only the advance values are adjusted. The glyphs themselves are not stretched or compressed.</summary>
spacingAndGlyphs Spacing,
/// <summary>Indicates that the advance values are adjusted and the glyphs themselves stretched or compressed in one axis (i.e., a direction parallel to the inline-progression-direction).</summary>
SpacingAndGlyphs
} }
} }
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
namespace Svg namespace Svg
{ {
/// <summary>Indicates the method by which text should be rendered along the path.</summary>
[TypeConverter(typeof(SvgTextPathMethodConverter))]
public enum SvgTextPathMethod public enum SvgTextPathMethod
{ {
align, /// <summary>Indicates that the glyphs should be rendered using simple 2x3 transformations such that there is no stretching/warping of the glyphs. Typically, supplemental rotation, scaling and translation transformations are done for each glyph to be rendered. As a result, with align, fonts where the glyphs are designed to be connected (e.g., cursive fonts), the connections may not align properly when text is rendered along a path.</summary>
stretch Align,
/// <summary>Indicates that the glyph outlines will be converted into paths, and then all end points and control points will be adjusted to be along the perpendicular vectors from the path, thereby stretching and possibly warping the glyphs. With this approach, connected glyphs, such as in cursive scripts, will maintain their connections.</summary>
Stretch
} }
} }
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
namespace Svg namespace Svg
{ {
/// <summary>Indicates how the user agent should determine the spacing between glyphs that are to be rendered along a path.</summary>
[TypeConverter(typeof(SvgTextPathSpacingConverter))]
public enum SvgTextPathSpacing public enum SvgTextPathSpacing
{ {
exact, /// <summary>Indicates that the glyphs should be rendered exactly according to the spacing rules as specified in Text on a path layout rules.</summary>
auto Exact,
/// <summary>Indicates that the user agent should use text-on-a-path layout algorithms to adjust the spacing between glyphs in order to achieve visually appealing results.</summary>
Auto
} }
} }
using System; using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Xml;
namespace Svg namespace Svg
{ {
...@@ -41,7 +42,7 @@ namespace Svg ...@@ -41,7 +42,7 @@ namespace Svg
private SvgUnit _x; private SvgUnit _x;
private SvgUnit _y; private SvgUnit _y;
/// <summary> /// <summary>
/// Gets or sets the position where the left point of the svg should start. /// Gets or sets the position where the left point of the svg should start.
/// </summary> /// </summary>
...@@ -51,10 +52,10 @@ namespace Svg ...@@ -51,10 +52,10 @@ namespace Svg
get { return _x; } get { return _x; }
set set
{ {
if(_x != value) if (_x != value)
{ {
_x = value; _x = value;
OnAttributeChanged(new AttributeEventArgs{ Attribute = "x", Value = value }); OnAttributeChanged(new AttributeEventArgs { Attribute = "x", Value = value });
} }
} }
} }
...@@ -68,10 +69,10 @@ namespace Svg ...@@ -68,10 +69,10 @@ namespace Svg
get { return _y; } get { return _y; }
set set
{ {
if(_y != value) if (_y != value)
{ {
_y = value; _y = value;
OnAttributeChanged(new AttributeEventArgs{ Attribute = "y", Value = value }); OnAttributeChanged(new AttributeEventArgs { Attribute = "y", Value = value });
} }
} }
} }
...@@ -115,7 +116,7 @@ namespace Svg ...@@ -115,7 +116,7 @@ namespace Svg
get { return this.Attributes.GetAttribute<SvgViewBox>("viewBox"); } get { return this.Attributes.GetAttribute<SvgViewBox>("viewBox"); }
set { this.Attributes["viewBox"] = value; } set { this.Attributes["viewBox"] = value; }
} }
/// <summary> /// <summary>
/// Gets or sets the aspect of the viewport. /// Gets or sets the aspect of the viewport.
/// </summary> /// </summary>
...@@ -162,9 +163,9 @@ namespace Svg ...@@ -162,9 +163,9 @@ namespace Svg
{ {
switch (this.Overflow) switch (this.Overflow)
{ {
case SvgOverflow.auto: case SvgOverflow.Auto:
case SvgOverflow.visible: case SvgOverflow.Visible:
case SvgOverflow.scroll: case SvgOverflow.Scroll:
base.Render(renderer); base.Render(renderer);
break; break;
default: default:
...@@ -185,29 +186,29 @@ namespace Svg ...@@ -185,29 +186,29 @@ namespace Svg
break; break;
} }
} }
/// <summary> /// <summary>
/// Gets the <see cref="GraphicsPath"/> for this element. /// Gets the <see cref="GraphicsPath"/> for this element.
/// </summary> /// </summary>
/// <value></value> /// <value></value>
public GraphicsPath Path public GraphicsPath Path
{ {
get get
{ {
var path = new GraphicsPath(); var path = new GraphicsPath();
AddPaths(this, path); AddPaths(this, path);
return path; return path;
} }
} }
/// <summary> /// <summary>
/// Gets the bounds of the svg element. /// Gets the bounds of the svg element.
/// </summary> /// </summary>
/// <value>The bounds.</value> /// <value>The bounds.</value>
public RectangleF Bounds public RectangleF Bounds
{ {
get get
{ {
return this.Path.GetBounds(); return this.Path.GetBounds();
...@@ -246,7 +247,7 @@ namespace Svg ...@@ -246,7 +247,7 @@ namespace Svg
} }
} }
if (isWidthperc) if (isWidthperc)
{ {
w = (bounds.Width + bounds.X) * (Width.Value * 0.01f); w = (bounds.Width + bounds.X) * (Width.Value * 0.01f);
} }
...@@ -254,11 +255,11 @@ namespace Svg ...@@ -254,11 +255,11 @@ namespace Svg
{ {
w = Width.ToDeviceValue(null, UnitRenderingType.Horizontal, this); w = Width.ToDeviceValue(null, UnitRenderingType.Horizontal, this);
} }
if (isHeightperc) if (isHeightperc)
{ {
h = (bounds.Height + bounds.Y) * (Height.Value * 0.01f); h = (bounds.Height + bounds.Y) * (Height.Value * 0.01f);
} }
else else
{ {
h = Height.ToDeviceValue(null, UnitRenderingType.Vertical, this); h = Height.ToDeviceValue(null, UnitRenderingType.Vertical, this);
} }
...@@ -282,6 +283,20 @@ namespace Svg ...@@ -282,6 +283,20 @@ namespace Svg
return newObj; return newObj;
} }
//Override the default behavior, writing out the namespaces.
protected override void WriteStartElement(XmlTextWriter writer)
{
base.WriteStartElement(writer);
foreach (var ns in SvgAttributeAttribute.Namespaces)
{
if (string.IsNullOrEmpty(ns.Key))
writer.WriteAttributeString("xmlns", ns.Value);
else
writer.WriteAttributeString("xmlns:" + ns.Key, ns.Value);
}
writer.WriteAttributeString("version", "1.1");
}
} }
} }
\ No newline at end of file
...@@ -42,7 +42,7 @@ namespace Svg.FilterEffects ...@@ -42,7 +42,7 @@ namespace Svg.FilterEffects
float value; float value;
switch (this.Type) switch (this.Type)
{ {
case SvgColourMatrixType.hueRotate: case SvgColourMatrixType.HueRotate:
value = (string.IsNullOrEmpty(this.Values) ? 0 : float.Parse(this.Values)); value = (string.IsNullOrEmpty(this.Values) ? 0 : float.Parse(this.Values));
colorMatrixElements = new float[][] { colorMatrixElements = new float[][] {
new float[] {(float)(0.213 + Math.Cos(value) * +0.787 + Math.Sin(value) * -0.213), new float[] {(float)(0.213 + Math.Cos(value) * +0.787 + Math.Sin(value) * -0.213),
...@@ -58,7 +58,7 @@ namespace Svg.FilterEffects ...@@ -58,7 +58,7 @@ namespace Svg.FilterEffects
new float[] {0, 0, 0, 0, 1} new float[] {0, 0, 0, 0, 1}
}; };
break; break;
case SvgColourMatrixType.luminanceToAlpha: case SvgColourMatrixType.LuminanceToAlpha:
colorMatrixElements = new float[][] { colorMatrixElements = new float[][] {
new float[] {0, 0, 0, 0, 0}, new float[] {0, 0, 0, 0, 0},
new float[] {0, 0, 0, 0, 0}, new float[] {0, 0, 0, 0, 0},
...@@ -67,7 +67,7 @@ namespace Svg.FilterEffects ...@@ -67,7 +67,7 @@ namespace Svg.FilterEffects
new float[] {0, 0, 0, 0, 1} new float[] {0, 0, 0, 0, 1}
}; };
break; break;
case SvgColourMatrixType.saturate: case SvgColourMatrixType.Saturate:
value = (string.IsNullOrEmpty(this.Values) ? 1 : float.Parse(this.Values)); value = (string.IsNullOrEmpty(this.Values) ? 1 : float.Parse(this.Values));
colorMatrixElements = new float[][] { colorMatrixElements = new float[][] {
new float[] {(float)(0.213+0.787*value), (float)(0.715-0.715*value), (float)(0.072-0.072*value), 0, 0}, new float[] {(float)(0.213+0.787*value), (float)(0.715-0.715*value), (float)(0.072-0.072*value), 0, 0},
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
namespace Svg.FilterEffects namespace Svg.FilterEffects
{ {
[TypeConverter(typeof(EnumBaseConverter<SvgColourMatrixType>))]
public enum SvgColourMatrixType public enum SvgColourMatrixType
{ {
matrix, Matrix,
saturate, Saturate,
hueRotate, HueRotate,
luminanceToAlpha LuminanceToAlpha
} }
} }
...@@ -66,11 +66,29 @@ namespace Svg ...@@ -66,11 +66,29 @@ namespace Svg
//converts enums to lower case strings //converts enums to lower case strings
public class EnumBaseConverter<T> : BaseConverter public class EnumBaseConverter<T> : BaseConverter
where T : struct
{ {
/// <summary>If specified, upon conversion, the default value will result in 'null'.</summary>
public T? DefaultValue { get; protected set;}
/// <summary>Creates a new instance.</summary>
public EnumBaseConverter() { }
/// <summary>Creates a new instance.</summary>
/// <param name="defaultValue">Specified the default value of the enum.</param>
public EnumBaseConverter(T defaultValue)
{
this.DefaultValue = defaultValue;
}
/// <summary>Attempts to convert the provided value to <typeparamref name="T"/>.</summary>
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{ {
if (value == null) if (value == null)
{ {
if (this.DefaultValue.HasValue)
return this.DefaultValue.Value;
return Activator.CreateInstance(typeof(T)); return Activator.CreateInstance(typeof(T));
} }
...@@ -82,112 +100,166 @@ namespace Svg ...@@ -82,112 +100,166 @@ namespace Svg
return (T)Enum.Parse(typeof(T), (string)value, true); return (T)Enum.Parse(typeof(T), (string)value, true);
} }
/// <summary>Attempts to convert the value to the destination type.</summary>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{ {
if (destinationType == typeof(string)) if (destinationType == typeof(string) && value is T)
{ {
return ((T)value).ToString().ToLower(); //If the value id the default value, no need to write the attribute.
if (this.DefaultValue.HasValue && Enum.Equals(value, this.DefaultValue.Value))
return null;
else
{
//SVG attributes should be camelCase.
string stringValue = ((T)value).ToString();
stringValue = string.Format("{0}{1}", stringValue[0].ToString().ToLower(), stringValue.Substring(1));
return stringValue;
}
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }
} }
//implementation for fill-rule
public sealed class SvgFillRuleConverter : EnumBaseConverter<SvgFillRule> public sealed class SvgFillRuleConverter : EnumBaseConverter<SvgFillRule>
{ {
public SvgFillRuleConverter() : base(SvgFillRule.NonZero) { }
}
public sealed class SvgColourInterpolationConverter : EnumBaseConverter<SvgColourInterpolation>
{
public SvgColourInterpolationConverter() : base(SvgColourInterpolation.SRGB) { }
} }
//implementaton for clip rule
public sealed class SvgClipRuleConverter : EnumBaseConverter<SvgClipRule> public sealed class SvgClipRuleConverter : EnumBaseConverter<SvgClipRule>
{ {
public SvgClipRuleConverter() : base(SvgClipRule.NonZero) { }
} }
//implementaton for clip rule
public sealed class SvgTextAnchorConverter : EnumBaseConverter<SvgTextAnchor> public sealed class SvgTextAnchorConverter : EnumBaseConverter<SvgTextAnchor>
{ {
public SvgTextAnchorConverter() : base(SvgTextAnchor.Start) { }
} }
public sealed class SvgStrokeLineCapConverter : EnumBaseConverter<SvgStrokeLineCap> public sealed class SvgStrokeLineCapConverter : EnumBaseConverter<SvgStrokeLineCap>
{ {
public SvgStrokeLineCapConverter() : base(SvgStrokeLineCap.Butt) { }
} }
public sealed class SvgStrokeLineJoinConverter : EnumBaseConverter<SvgStrokeLineJoin> public sealed class SvgStrokeLineJoinConverter : EnumBaseConverter<SvgStrokeLineJoin>
{ {
public SvgStrokeLineJoinConverter() : base(SvgStrokeLineJoin.Miter) { }
} }
public sealed class SvgMarkerUnitsConverter : EnumBaseConverter<SvgMarkerUnits> public sealed class SvgMarkerUnitsConverter : EnumBaseConverter<SvgMarkerUnits>
{ {
public SvgMarkerUnitsConverter() : base(SvgMarkerUnits.StrokeWidth) { }
}
public sealed class SvgFontStyleConverter : EnumBaseConverter<SvgFontStyle>
{
public SvgFontStyleConverter() : base(SvgFontStyle.All) { }
}
public sealed class SvgOverflowConverter : EnumBaseConverter<SvgOverflow>
{
public SvgOverflowConverter() : base(SvgOverflow.Auto) { }
}
public sealed class SvgTextLengthAdjustConverter : EnumBaseConverter<SvgTextLengthAdjust>
{
public SvgTextLengthAdjustConverter() : base(SvgTextLengthAdjust.Spacing) { }
}
public sealed class SvgTextPathMethodConverter : EnumBaseConverter<SvgTextPathMethod>
{
public SvgTextPathMethodConverter() : base(SvgTextPathMethod.Align) { }
}
public sealed class SvgTextPathSpacingConverter : EnumBaseConverter<SvgTextPathSpacing>
{
public SvgTextPathSpacingConverter() : base(SvgTextPathSpacing.Exact) { }
} }
public sealed class SvgFontVariantConverter : EnumBaseConverter<SvgFontVariant> public sealed class SvgFontVariantConverter : EnumBaseConverter<SvgFontVariant>
{ {
public SvgFontVariantConverter() : base(SvgFontVariant.Normal) { }
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value.ToString() == "small-caps") return SvgFontVariant.smallcaps; if (value.ToString() == "small-caps")
return SvgFontVariant.Smallcaps;
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{ {
if (destinationType == typeof(string) && value is SvgFontVariant && (SvgFontVariant)value == SvgFontVariant.smallcaps) if (destinationType == typeof(string) && value is SvgFontVariant && (SvgFontVariant)value == SvgFontVariant.Smallcaps)
{ {
return "small-caps"; return "small-caps";
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }
} }
public sealed class SvgCoordinateUnitsConverter : EnumBaseConverter<SvgCoordinateUnits> public sealed class SvgCoordinateUnitsConverter : EnumBaseConverter<SvgCoordinateUnits>
{ {
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) //TODO Inherit is not actually valid. See TODO on SvgCoordinateUnits enum.
{ public SvgCoordinateUnitsConverter() : base(SvgCoordinateUnits.Inherit) { }
if (value == null || value.ToString() == "") return SvgCoordinateUnits.Inherit; }
return base.ConvertFrom(context, culture, value);
} public sealed class SvgGradientSpreadMethodConverter : EnumBaseConverter<SvgGradientSpreadMethod>
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
{ public SvgGradientSpreadMethodConverter() : base(SvgGradientSpreadMethod.Pad) { }
if (destinationType == typeof(string) && value is SvgCoordinateUnits && (SvgCoordinateUnits)value == SvgCoordinateUnits.Inherit)
{
return null;
}
return base.ConvertTo(context, culture, value, destinationType);
}
} }
public sealed class SvgTextDecorationConverter : EnumBaseConverter<SvgTextDecoration> public sealed class SvgTextDecorationConverter : EnumBaseConverter<SvgTextDecoration>
{ {
public SvgTextDecorationConverter() : base(SvgTextDecoration.None) { }
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value.ToString() == "line-through") return SvgTextDecoration.lineThrough; if (value.ToString() == "line-through")
return SvgTextDecoration.LineThrough;
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
} }
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{ {
if (destinationType == typeof(string) && value is SvgTextDecoration && (SvgTextDecoration)value == SvgTextDecoration.lineThrough) if (destinationType == typeof(string) && value is SvgTextDecoration && (SvgTextDecoration)value == SvgTextDecoration.LineThrough)
{ {
return "line-through"; return "line-through";
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
} }
} }
public sealed class SvgFontWeightConverter : EnumBaseConverter<SvgFontWeight> public sealed class SvgFontWeightConverter : EnumBaseConverter<SvgFontWeight>
{ {
//TODO Defaulting to Normal although it should be All if this is used on a font face.
public SvgFontWeightConverter() : base(SvgFontWeight.Normal) { }
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
if (value is string) if (value is string)
{ {
switch ((string)value) switch ((string)value)
{ {
case "100": return SvgFontWeight.w100; case "100": return SvgFontWeight.W100;
case "200": return SvgFontWeight.w200; case "200": return SvgFontWeight.W200;
case "300": return SvgFontWeight.w300; case "300": return SvgFontWeight.W300;
case "400": return SvgFontWeight.w400; case "400": return SvgFontWeight.W400;
case "500": return SvgFontWeight.w500; case "500": return SvgFontWeight.W500;
case "600": return SvgFontWeight.w600; case "600": return SvgFontWeight.W600;
case "700": return SvgFontWeight.w700; case "700": return SvgFontWeight.W700;
case "800": return SvgFontWeight.w800; case "800": return SvgFontWeight.W800;
case "900": return SvgFontWeight.w900; case "900": return SvgFontWeight.W900;
} }
} }
return base.ConvertFrom(context, culture, value); return base.ConvertFrom(context, culture, value);
...@@ -198,15 +270,15 @@ namespace Svg ...@@ -198,15 +270,15 @@ namespace Svg
{ {
switch ((SvgFontWeight)value) switch ((SvgFontWeight)value)
{ {
case SvgFontWeight.w100: return "100"; case SvgFontWeight.W100: return "100";
case SvgFontWeight.w200: return "200"; case SvgFontWeight.W200: return "200";
case SvgFontWeight.w300: return "300"; case SvgFontWeight.W300: return "300";
case SvgFontWeight.w400: return "400"; case SvgFontWeight.W400: return "400";
case SvgFontWeight.w500: return "500"; case SvgFontWeight.W500: return "500";
case SvgFontWeight.w600: return "600"; case SvgFontWeight.W600: return "600";
case SvgFontWeight.w700: return "700"; case SvgFontWeight.W700: return "700";
case SvgFontWeight.w800: return "800"; case SvgFontWeight.W800: return "800";
case SvgFontWeight.w900: return "900"; case SvgFontWeight.W900: return "900";
} }
} }
return base.ConvertTo(context, culture, value, destinationType); return base.ConvertTo(context, culture, value, destinationType);
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
namespace Svg namespace Svg
{ {
/// <summary>Indicates what happens if the gradient starts or ends inside the bounds of the target rectangle.</summary>
/// <remarks>
/// <para>Possible values are: 'pad', which says to use the terminal colors of the gradient to fill the remainder of the target region, 'reflect', which says to reflect the gradient pattern start-to-end, end-to-start, start-to-end, etc. continuously until the target rectangle is filled, and repeat, which says to repeat the gradient pattern start-to-end, start-to-end, start-to-end, etc. continuously until the target region is filled.</para>
/// <para>If the attribute is not specified, the effect is as if a value of 'pad' were specified.</para>
/// </remarks>
[TypeConverter(typeof(SvgGradientSpreadMethodConverter))]
public enum SvgGradientSpreadMethod public enum SvgGradientSpreadMethod
{ {
/// <summary>Use the terminal colors of the gradient to fill the remainder of the target region.</summary>
Pad, Pad,
/// <summary>Reflect the gradient pattern start-to-end, end-to-start, start-to-end, etc. continuously until the target rectangle is filled.</summary>
Reflect, Reflect,
/// <summary>Repeat the gradient pattern start-to-end, start-to-end, start-to-end, etc. continuously until the target region is filled.</summary>
Repeat Repeat
} }
} }
\ No newline at end of file
...@@ -81,10 +81,10 @@ namespace Svg ...@@ -81,10 +81,10 @@ namespace Svg
public SvgMarker() public SvgMarker()
{ {
MarkerUnits = SvgMarkerUnits.strokeWidth; MarkerUnits = SvgMarkerUnits.StrokeWidth;
MarkerHeight = 3; MarkerHeight = 3;
MarkerWidth = 3; MarkerWidth = 3;
Overflow = SvgOverflow.hidden; Overflow = SvgOverflow.Hidden;
} }
public override System.Drawing.Drawing2D.GraphicsPath Path(ISvgRenderer renderer) public override System.Drawing.Drawing2D.GraphicsPath Path(ISvgRenderer renderer)
...@@ -183,13 +183,13 @@ namespace Svg ...@@ -183,13 +183,13 @@ namespace Svg
transMatrix.Rotate(Orient.Angle); transMatrix.Rotate(Orient.Angle);
switch (MarkerUnits) switch (MarkerUnits)
{ {
case SvgMarkerUnits.strokeWidth: case SvgMarkerUnits.StrokeWidth:
transMatrix.Translate(AdjustForViewBoxWidth(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this) * transMatrix.Translate(AdjustForViewBoxWidth(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this) *
pOwner.StrokeWidth.ToDeviceValue(pRenderer, UnitRenderingType.Other, this)), pOwner.StrokeWidth.ToDeviceValue(pRenderer, UnitRenderingType.Other, this)),
AdjustForViewBoxHeight(-RefY.ToDeviceValue(pRenderer, UnitRenderingType.Vertical, this) * AdjustForViewBoxHeight(-RefY.ToDeviceValue(pRenderer, UnitRenderingType.Vertical, this) *
pOwner.StrokeWidth.ToDeviceValue(pRenderer, UnitRenderingType.Other, this))); pOwner.StrokeWidth.ToDeviceValue(pRenderer, UnitRenderingType.Other, this)));
break; break;
case SvgMarkerUnits.userSpaceOnUse: case SvgMarkerUnits.UserSpaceOnUse:
transMatrix.Translate(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this), transMatrix.Translate(-RefX.ToDeviceValue(pRenderer, UnitRenderingType.Horizontal, this),
-RefY.ToDeviceValue(pRenderer, UnitRenderingType.Vertical, this)); -RefY.ToDeviceValue(pRenderer, UnitRenderingType.Vertical, this));
break; break;
...@@ -224,10 +224,10 @@ namespace Svg ...@@ -224,10 +224,10 @@ namespace Svg
Brush pBrush = pPath.Stroke.GetBrush(this, renderer, Opacity); Brush pBrush = pPath.Stroke.GetBrush(this, renderer, Opacity);
switch (MarkerUnits) switch (MarkerUnits)
{ {
case SvgMarkerUnits.strokeWidth: case SvgMarkerUnits.StrokeWidth:
return (new Pen(pBrush, StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this) * return (new Pen(pBrush, StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this) *
pPath.StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this))); pPath.StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this)));
case SvgMarkerUnits.userSpaceOnUse: case SvgMarkerUnits.UserSpaceOnUse:
return (new Pen(pBrush, StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this))); return (new Pen(pBrush, StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this)));
} }
return (new Pen(pBrush, StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this))); return (new Pen(pBrush, StrokeWidth.ToDeviceValue(renderer, UnitRenderingType.Other, this)));
...@@ -242,14 +242,14 @@ namespace Svg ...@@ -242,14 +242,14 @@ namespace Svg
GraphicsPath pRet = Path(null).Clone() as GraphicsPath; GraphicsPath pRet = Path(null).Clone() as GraphicsPath;
switch (MarkerUnits) switch (MarkerUnits)
{ {
case SvgMarkerUnits.strokeWidth: case SvgMarkerUnits.StrokeWidth:
using (var transMatrix = new Matrix()) using (var transMatrix = new Matrix())
{ {
transMatrix.Scale(AdjustForViewBoxWidth(pPath.StrokeWidth), AdjustForViewBoxHeight(pPath.StrokeWidth)); transMatrix.Scale(AdjustForViewBoxWidth(pPath.StrokeWidth), AdjustForViewBoxHeight(pPath.StrokeWidth));
pRet.Transform(transMatrix); pRet.Transform(transMatrix);
} }
break; break;
case SvgMarkerUnits.userSpaceOnUse: case SvgMarkerUnits.UserSpaceOnUse:
break; break;
} }
return (pRet); return (pRet);
......
...@@ -5,12 +5,20 @@ using System.ComponentModel; ...@@ -5,12 +5,20 @@ using System.ComponentModel;
namespace Svg namespace Svg
{ {
/// <summary>Specifies the shape to be used at the end of open subpaths when they are stroked.</summary>
[TypeConverter(typeof(SvgStrokeLineCapConverter))] [TypeConverter(typeof(SvgStrokeLineCapConverter))]
public enum SvgStrokeLineCap public enum SvgStrokeLineCap
{ {
/// <summary>The value is inherited from the parent element.</summary>
Inherit,
/// <summary>The ends of the subpaths are square but do not extend past the end of the subpath.</summary>
Butt, Butt,
/// <summary>The ends of the subpaths are rounded.</summary>
Round, Round,
Square,
Inherit /// <summary>The ends of the subpaths are square.</summary>
Square
} }
} }
...@@ -5,11 +5,20 @@ using System.ComponentModel; ...@@ -5,11 +5,20 @@ using System.ComponentModel;
namespace Svg namespace Svg
{ {
/// <summary>Specifies the shape to be used at the corners of paths or basic shapes when they are stroked.</summary>
[TypeConverter(typeof(SvgStrokeLineJoinConverter))] [TypeConverter(typeof(SvgStrokeLineJoinConverter))]
public enum SvgStrokeLineJoin public enum SvgStrokeLineJoin
{ {
/// <summary>The value is inherited from the parent element.</summary>
Inherit,
/// <summary>The corners of the paths are joined sharply.</summary>
Miter, Miter,
/// <summary>The corners of the paths are rounded off.</summary>
Round, Round,
/// <summary>The corners of the paths are "flattened".</summary>
Bevel Bevel
} }
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment