Commit d5c659a5 authored by Eric Domke's avatar Eric Domke
Browse files

Refactoring while working through W3C tests

- Adding W3C test cases and a test fixture
- Fixed support for CSS stylesheets (particularly when class names are
referenced)
- Refactoring unit calculations so that percentages and fractions
calculate more accurately
- SvgImage:
- Support PreserveAspectRatio attribute
- Support for referencing svg images
- Refactored text rendering to use the AttributeCollection inheritance
scheme
- Initial attempt at 'ex' unit support
- Added support for system color names
- Changed parsing of entities to support XML entities
- Supporting loading of a svg document directly from a XmlDocument with
requiring serializing the document as a string first.
- ...
parent 3aedd8e8
......@@ -82,6 +82,7 @@
<AssemblyOriginatorKeyFile>svgkey.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
......@@ -99,6 +100,9 @@
<Compile Include="Clipping and Masking\SvgClipRule.cs" />
<Compile Include="Clipping and Masking\SvgClipPath.cs" />
<Compile Include="Clipping and Masking\SvgMask.cs" />
<Compile Include="DataTypes\ISvgSupportsCoordinateUnits.cs" />
<Compile Include="Painting\GenericBoundable.cs" />
<Compile Include="SvgNodeReader.cs" />
<Compile Include="Css\CssQuery.cs" />
<Compile Include="Css\SvgElementOps.cs" />
<Compile Include="DataTypes\SvgAspectRatioConverter.cs" />
......@@ -227,6 +231,7 @@
<Compile Include="SvgContentNode.cs" />
<Compile Include="SvgDefinitionDefaults.cs" />
<Compile Include="NonSvgElement.cs" />
<Compile Include="SvgReader.cs" />
<Compile Include="SvgUnknownElement.cs" />
<Compile Include="SvgElementAttribute.cs" />
<Compile Include="SvgExtentions.cs" />
......

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
# SharpDevelop 4.4
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Svg", "Svg.csproj", "{886A98C5-37C0-4E8B-885E-30C1D2F98B47}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SVGViewer", "..\Samples\SVGViewer\SVGViewer.csproj", "{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Svg.UnitTests", "..\Tests\Svg.UnitTests\Svg.UnitTests.csproj", "{E702EB7D-D01D-438A-BADD-E72D4E49109F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A417AF1E-BEDB-4715-B4FD-D795579217F9}"
ProjectSection(SolutionItems) = preProject
Local.testsettings = Local.testsettings
Svg.vsmdi = Svg.vsmdi
TraceAndTestImpact.testsettings = TraceAndTestImpact.testsettings
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SvgW3CTestRunner", "..\Tests\SvgW3CTestRunner\SvgW3CTestRunner.csproj", "{8ED74C39-6CFF-421E-952A-30F9E6957108}"
EndProject
Global
GlobalSection(TestCaseManagementSettings) = postSolution
CategoryFile = Svg.vsmdi
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|Mixed Platforms = Debug|Mixed Platforms
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|Mixed Platforms = Release|Mixed Platforms
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{886A98C5-37C0-4E8B-885E-30C1D2F98B47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{886A98C5-37C0-4E8B-885E-30C1D2F98B47}.Debug|Any CPU.Build.0 = Debug|Any CPU
{886A98C5-37C0-4E8B-885E-30C1D2F98B47}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{886A98C5-37C0-4E8B-885E-30C1D2F98B47}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{886A98C5-37C0-4E8B-885E-30C1D2F98B47}.Debug|x86.ActiveCfg = Debug|Any CPU
{886A98C5-37C0-4E8B-885E-30C1D2F98B47}.Release|Any CPU.ActiveCfg = Release|Any CPU
{886A98C5-37C0-4E8B-885E-30C1D2F98B47}.Release|Any CPU.Build.0 = Release|Any CPU
{886A98C5-37C0-4E8B-885E-30C1D2F98B47}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{886A98C5-37C0-4E8B-885E-30C1D2F98B47}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{886A98C5-37C0-4E8B-885E-30C1D2F98B47}.Release|x86.ActiveCfg = Release|Any CPU
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Debug|x86.Build.0 = Debug|Any CPU
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Debug|Mixed Platforms.Build.0 = Debug|x86
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Debug|x86.ActiveCfg = Debug|x86
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Release|Any CPU.Build.0 = Release|Any CPU
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Debug|x86.Build.0 = Debug|Any CPU
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Release|x86.Build.0 = Release|Any CPU
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Release|Any CPU.Build.0 = Release|Any CPU
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Release|Mixed Platforms.ActiveCfg = Release|x86
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Release|Mixed Platforms.Build.0 = Release|x86
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Release|x86.ActiveCfg = Release|Any CPU
{1B8F3C8A-CCAC-474E-B09D-522FBA93DCFD}.Release|x86.Build.0 = Release|Any CPU
{E702EB7D-D01D-438A-BADD-E72D4E49109F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E702EB7D-D01D-438A-BADD-E72D4E49109F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E702EB7D-D01D-438A-BADD-E72D4E49109F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{E702EB7D-D01D-438A-BADD-E72D4E49109F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{E702EB7D-D01D-438A-BADD-E72D4E49109F}.Debug|x86.ActiveCfg = Debug|Any CPU
{E702EB7D-D01D-438A-BADD-E72D4E49109F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E702EB7D-D01D-438A-BADD-E72D4E49109F}.Release|Any CPU.Build.0 = Release|Any CPU
{E702EB7D-D01D-438A-BADD-E72D4E49109F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{E702EB7D-D01D-438A-BADD-E72D4E49109F}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{E702EB7D-D01D-438A-BADD-E72D4E49109F}.Release|x86.ActiveCfg = Release|Any CPU
{8ED74C39-6CFF-421E-952A-30F9E6957108}.Debug|Any CPU.ActiveCfg = Debug|x86
{8ED74C39-6CFF-421E-952A-30F9E6957108}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
{8ED74C39-6CFF-421E-952A-30F9E6957108}.Debug|Mixed Platforms.Build.0 = Debug|x86
{8ED74C39-6CFF-421E-952A-30F9E6957108}.Debug|x86.ActiveCfg = Debug|x86
{8ED74C39-6CFF-421E-952A-30F9E6957108}.Debug|x86.Build.0 = Debug|x86
{8ED74C39-6CFF-421E-952A-30F9E6957108}.Release|Any CPU.ActiveCfg = Release|x86
{8ED74C39-6CFF-421E-952A-30F9E6957108}.Release|Mixed Platforms.ActiveCfg = Release|x86
{8ED74C39-6CFF-421E-952A-30F9E6957108}.Release|Mixed Platforms.Build.0 = Release|x86
{8ED74C39-6CFF-421E-952A-30F9E6957108}.Release|x86.ActiveCfg = Release|x86
{8ED74C39-6CFF-421E-952A-30F9E6957108}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
......
<?xml version="1.0" encoding="UTF-8"?>
<TestLists xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<TestList name="Lists of Tests" id="8c43106b-9dc1-4907-a29f-aa66a61bf5b6">
<RunConfiguration id="616d39c5-86e4-40f8-97e9-b8a423ce7322" name="Local" storage="local.testsettings" type="Microsoft.VisualStudio.TestTools.Common.TestRunConfiguration, Microsoft.VisualStudio.QualityTools.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</TestList>
</TestLists>
\ No newline at end of file
......@@ -63,9 +63,12 @@ namespace Svg
/// <returns>The attribute value if available; otherwise the ancestors value for the same attribute; otherwise the default value of <typeparamref name="TAttributeType"/>.</returns>
public TAttributeType GetInheritedAttribute<TAttributeType>(string attributeName)
{
if (this.ContainsKey(attributeName) /*&& base[attributeName] != null*/)
if (this.ContainsKey(attributeName) && !IsInheritValue(base[attributeName]))
{
return (TAttributeType)base[attributeName];
var result = (TAttributeType)base[attributeName];
var deferred = result as SvgDeferredPaintServer;
if (deferred != null) deferred.EnsureServer(_owner);
return result;
}
if (this._owner.Parent != null)
......@@ -79,6 +82,16 @@ namespace Svg
return default(TAttributeType);
}
private bool IsInheritValue(object value)
{
return (value == null ||
(value is SvgFontStyle && (SvgFontStyle)value == SvgFontStyle.inherit) ||
(value is SvgFontWeight && (SvgFontWeight)value == SvgFontWeight.inherit) ||
(value is SvgTextAnchor && (SvgTextAnchor)value == SvgTextAnchor.inherit) ||
(value == "inherit")
);
}
/// <summary>
/// Gets the attribute with the specified name.
/// </summary>
......
......@@ -30,6 +30,8 @@ namespace Svg
Ppi = PointsPerInch;
}
public Uri BaseUri { get; set; }
/// <summary>
/// Gets an <see cref="SvgElementIdManager"/> for this document.
/// </summary>
......@@ -157,7 +159,9 @@ namespace Svg
throw new FileNotFoundException("The specified document cannot be found.", path);
}
return Open<T>(File.OpenRead(path), entities);
var doc = Open<T>(File.OpenRead(path), entities);
doc.BaseUri = new Uri(System.IO.Path.GetFullPath(path));
return doc;
}
/// <summary>
......@@ -305,9 +309,23 @@ namespace Svg
var cssTotal = styles.Select((s) => s.Content).Aggregate((p, c) => p + Environment.NewLine + c);
var cssParser = new Parser();
var sheet = cssParser.Parse(cssTotal);
AggregateSelectorList aggList;
IEnumerable<BaseSelector> selectors;
IEnumerable<SvgElement> elemsToStyle;
foreach (var rule in sheet.StyleRules)
{
aggList = rule.Selector as AggregateSelectorList;
if (aggList != null && aggList.Delimiter == ",")
{
selectors = aggList;
}
else
{
selectors = Enumerable.Repeat(rule.Selector, 1);
}
foreach (var selector in selectors)
{
elemsToStyle = svgDocument.QuerySelectorAll(rule.Selector.ToString());
foreach (var elem in elemsToStyle)
......@@ -319,8 +337,9 @@ namespace Svg
}
}
}
}
FlushStyles(svgDocument);
if (svgDocument != null) FlushStyles(svgDocument);
return svgDocument;
}
......@@ -345,10 +364,8 @@ namespace Svg
throw new ArgumentNullException("document");
}
using (var stream = new MemoryStream(UTF8Encoding.Default.GetBytes(document.InnerXml)))
{
return Open<SvgDocument>(stream, null);
}
var reader = new SvgNodeReader(document.DocumentElement, null);
return Open<SvgDocument>(reader);
}
public static Bitmap OpenAsBitmap(string path)
......@@ -373,6 +390,7 @@ namespace Svg
throw new ArgumentNullException("renderer");
}
renderer.Boundable(this);
this.Render(renderer);
}
......@@ -388,7 +406,9 @@ namespace Svg
throw new ArgumentNullException("graphics");
}
this.Render(SvgRenderer.FromGraphics(graphics));
var renderer = SvgRenderer.FromGraphics(graphics);
renderer.Boundable(this);
this.Render(renderer);
}
/// <summary>
......@@ -427,6 +447,7 @@ namespace Svg
{
using (var renderer = SvgRenderer.FromImage(bitmap))
{
renderer.Boundable(this);
renderer.TextRenderingHint = TextRenderingHint.AntiAlias;
renderer.TextContrast = 1;
renderer.PixelOffsetMode = PixelOffsetMode.Half;
......
......@@ -40,6 +40,7 @@ namespace Svg
private EventHandlerList _eventHandlers;
private SvgElementCollection _children;
private static readonly object _loadEventKey = new object();
private Region _graphicsClip;
private Matrix _graphicsMatrix;
private SvgCustomAttributeCollection _customAttributes;
private List<ISvgNode> _nodes = new List<ISvgNode>();
......@@ -89,6 +90,16 @@ namespace Svg
internal set { this._elementName = value; }
}
/// <summary>
/// Gets or sets the color <see cref="SvgPaintServer"/> of this element which drives the currentColor property.
/// </summary>
[SvgAttribute("color")]
public virtual SvgPaintServer Color
{
get { return (this.Attributes["color"] == null) ? SvgColourServer.NotSet : (SvgPaintServer)this.Attributes["color"]; }
set { this.Attributes["color"] = value; }
}
/// <summary>
/// Gets or sets the content of the element.
/// </summary>
......@@ -247,15 +258,17 @@ namespace Svg
/// Applies the required transforms to <see cref="SvgRenderer"/>.
/// </summary>
/// <param name="renderer">The <see cref="SvgRenderer"/> to be transformed.</param>
protected internal virtual void PushTransforms(SvgRenderer renderer)
protected internal virtual bool PushTransforms(SvgRenderer renderer)
{
_graphicsMatrix = renderer.Transform;
_graphicsClip = renderer.Clip;
// Return if there are no transforms
if (this.Transforms == null || this.Transforms.Count == 0)
{
return;
return true;
}
if (this.Transforms.Count == 1 && this.Transforms[0].Matrix.Equals(new Matrix(0, 0, 0, 0, 0, 0))) return false;
Matrix transformMatrix = renderer.Transform;
......@@ -265,6 +278,8 @@ namespace Svg
}
renderer.Transform = transformMatrix;
return true;
}
/// <summary>
......@@ -275,6 +290,8 @@ namespace Svg
{
renderer.Transform = _graphicsMatrix;
_graphicsMatrix = null;
renderer.SetClip(_graphicsClip);
_graphicsClip = null;
}
/// <summary>
......@@ -659,7 +676,7 @@ namespace Svg
{
if(!(child is SvgGroup))
{
var childPath = ((SvgVisualElement)child).Path;
var childPath = ((SvgVisualElement)child).Path(null);
if (childPath != null)
{
......@@ -672,7 +689,7 @@ namespace Svg
}
}
AddPaths(child, path);
if (!(child is SvgPaintServer)) AddPaths(child, path);
}
}
......@@ -681,7 +698,7 @@ namespace Svg
/// </summary>
/// <param name="elem"></param>
/// <param name="path"></param>
protected GraphicsPath GetPaths(SvgElement elem)
protected GraphicsPath GetPaths(SvgElement elem, SvgRenderer renderer)
{
var ret = new GraphicsPath();
......@@ -691,7 +708,7 @@ namespace Svg
{
if(!(child is SvgGroup))
{
var childPath = ((SvgVisualElement)child).Path;
var childPath = ((SvgVisualElement)child).Path(renderer);
if (childPath != null)
{
......@@ -704,7 +721,7 @@ namespace Svg
}
else
{
var childPath = GetPaths(child);
var childPath = GetPaths(child, renderer);
if(child.Transforms != null)
childPath.Transform(child.Transforms.GetMatrix());
}
......
......@@ -130,40 +130,6 @@ namespace Svg
while (reader.MoveToNextAttribute())
{
//// Special treatment for "style"
//if (reader.LocalName.Equals("style") && !(element is NonSvgElement))
//{
// styles = reader.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
// for (i = 0; i < styles.Length; i++)
// {
// if (!styles[i].Contains(":"))
// {
// continue;
// }
// style = styles[i].Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
// SetPropertyValue(element, style[0].Trim(), style[1].Trim(), document);
// }
// //defaults for text can come from the document
// if (element.ElementName == "text")
// {
// if (!styles.Contains("font-size") && document.CustomAttributes.ContainsKey("font-size") && document.CustomAttributes["font-size"] != null)
// {
// SetPropertyValue(element, "font-size", document.CustomAttributes["font-size"], document);
// }
// if (!styles.Contains("font-family") && document.CustomAttributes.ContainsKey("font-family") && document.CustomAttributes["font-family"] != null)
// {
// SetPropertyValue(element, "font-family", document.CustomAttributes["font-family"], document);
// }
// }
// continue;
//}
//SetPropertyValue(element, reader.LocalName, reader.Value, document);
if (reader.LocalName.Equals("style") && !(element is NonSvgElement))
{
var inlineSheet = cssParser.Parse("#a{" + reader.Value + "}");
......@@ -175,15 +141,89 @@ namespace Svg
}
}
}
else
else if (IsStyleAttribute(reader.LocalName))
{
element.AddStyle(reader.LocalName, reader.Value, 2 << 16);
}
else
{
SetPropertyValue(element, reader.LocalName, reader.Value, document);
}
}
//Trace.TraceInformation("End SetAttributes");
}
private static bool IsStyleAttribute(string name)
{
switch (name)
{
case "alignment-baseline":
case "baseline-shift":
case "clip":
case "clip-path":
case "clip-rule":
case "color":
case "color-interpolation":
case "color-interpolation-filters":
case "color-profile":
case "color-rendering":
case "cursor":
case "direction":
case "display":
case "dominant-baseline":
case "enable-background":
case "fill":
case "fill-opacity":
case "fill-rule":
case "filter":
case "flood-color":
case "flood-opacity":
case "font":
case "font-family":
case "font-size":
case "font-size-adjust":
case "font-stretch":
case "font-style":
case "font-variant":
case "font-weight":
case "glyph-orientation-horizontal":
case "glyph-orientation-vertical":
case "image-rendering":
case "kerning":
case "letter-spacing":
case "lighting-color":
case "marker":
case "marker-end":
case "marker-mid":
case "marker-start":
case "mask":
case "opacity":
case "overflow":
case "pointer-events":
case "shape-rendering":
case "stop-color":
case "stop-opacity":
case "stroke":
case "stroke-dasharray":
case "stroke-dashoffset":
case "stroke-linecap":
case "stroke-linejoin":
case "stroke-miterlimit":
case "stroke-opacity":
case "stroke-width":
case "text-anchor":
case "text-decoration":
case "text-rendering":
case "unicode-bidi":
case "visibility":
case "word-spacing":
case "writing-mode":
return true;
}
return false;
}
private static Dictionary<Type, Dictionary<string, PropertyDescriptorCollection>> _propertyDescriptors = new Dictionary<Type, Dictionary<string, PropertyDescriptorCollection>>();
private static object syncLock = new object();
......
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Collections.Specialized;
namespace Svg
{
internal sealed class SvgNodeReader : XmlNodeReader
{
private Dictionary<string, string> _entities;
private string _value;
private bool _customValue = false;
private string _localName;
public SvgNodeReader(XmlNode node, Dictionary<string, string> entities)
: base(node)
{
this._entities = entities;
}
/// <summary>
/// Gets the text value of the current node.
/// </summary>
/// <value></value>
/// <returns>The value returned depends on the <see cref="P:System.Xml.XmlTextReader.NodeType"/> of the node. The following table lists node types that have a value to return. All other node types return String.Empty.Node Type Value AttributeThe value of the attribute. CDATAThe content of the CDATA section. CommentThe content of the comment. DocumentTypeThe internal subset. ProcessingInstructionThe entire content, excluding the target. SignificantWhitespaceThe white space within an xml:space= 'preserve' scope. TextThe content of the text node. WhitespaceThe white space between markup. XmlDeclarationThe content of the declaration. </returns>
public override string Value
{
get
{
return (this._customValue) ? this._value : base.Value;
}
}
/// <summary>
/// Gets the local name of the current node.
/// </summary>
/// <value></value>
/// <returns>The name of the current node with the prefix removed. For example, LocalName is book for the element &lt;bk:book&gt;.For node types that do not have a name (like Text, Comment, and so on), this property returns String.Empty.</returns>
public override string LocalName
{
get
{
return (this._customValue) ? this._localName : base.LocalName;
}
}
private IDictionary<string, string> Entities
{
get
{
if (this._entities == null)
{
this._entities = new Dictionary<string, string>();
}
return this._entities;
}
}
/// <summary>
/// Moves to the next attribute.
/// </summary>
/// <returns>
/// true if there is a next attribute; false if there are no more attributes.
/// </returns>
public override bool MoveToNextAttribute()
{
bool moved = base.MoveToNextAttribute();
if (moved)
{
this._localName = base.LocalName;
if (this.ReadAttributeValue())
{
if (this.NodeType == XmlNodeType.EntityReference)
{
this.ResolveEntity();
}
else
{
this._value = base.Value;
}
}
this._customValue = true;
}
return moved;
}
/// <summary>
/// Reads the next node from the stream.
/// </summary>
/// <returns>
/// true if the next node was read successfully; false if there are no more nodes to read.
/// </returns>
/// <exception cref="T:System.Xml.XmlException">An error occurred while parsing the XML. </exception>
public override bool Read()
{
this._customValue = false;
bool read = base.Read();
if (this.NodeType == XmlNodeType.DocumentType)
{
this.ParseEntities();
}
return read;
}
private void ParseEntities()
{
const string entityText = "<!ENTITY";
string[] entities = this.Value.Split(new string[]{entityText}, StringSplitOptions.None);
string[] parts = null;
string name = null;
string value = null;
foreach (string entity in entities)
{
if (string.IsNullOrEmpty(entity.Trim()))
{
continue;
}
parts = entity.Trim().Split(new char[]{' ', '\t'}, StringSplitOptions.RemoveEmptyEntries);
name = parts[0];
value = parts[1].Split(new char[] { this.QuoteChar }, StringSplitOptions.RemoveEmptyEntries)[0];
this.Entities.Add(name, value);
}
}
/// <summary>
/// Resolves the entity reference for EntityReference nodes.
/// </summary>
public override void ResolveEntity()
{
if (this.NodeType == XmlNodeType.EntityReference)
{
if (this._entities.ContainsKey(this.Name))
{
this._value = this._entities[this.Name];
}
else
{
this._value = string.Empty;
}
this._customValue = true;
}
}
}
}
\ No newline at end of file
......@@ -8,9 +8,26 @@ using System.Drawing.Text;
namespace Svg
{
/// <summary>
/// Convenience wrapper around a graphics object
/// </summary>
public sealed class SvgRenderer : IDisposable
{
private Graphics _innerGraphics;
private Stack<ISvgBoundable> _boundables = new Stack<ISvgBoundable>();
public void Boundable(ISvgBoundable boundable)
{
_boundables.Push(boundable);
}
public ISvgBoundable Boundable()
{
return _boundables.Peek();
}
public ISvgBoundable PopBoundable()
{
return _boundables.Pop();
}
/// <summary>
/// Initializes a new instance of the <see cref="SvgRenderer"/> class.
......@@ -47,6 +64,14 @@ namespace Svg
return renderer;
}
public static SvgRenderer FromNull()
{
SvgRenderer renderer = new SvgRenderer();
var img = new Bitmap(1, 1);
renderer._innerGraphics = Graphics.FromImage(img);
return renderer;
}
public void DrawImageUnscaled(Image image, Point location)
{
this._innerGraphics.DrawImageUnscaled(image, location);
......@@ -57,9 +82,13 @@ namespace Svg
_innerGraphics.DrawImage(image, destRect, srcRect, graphicsUnit);
}
public void AddClip(Region region)
{
this._innerGraphics.SetClip(region, CombineMode.Intersect);
}
public void SetClip(Region region)
{
this._innerGraphics.SetClip(region, CombineMode.Complement);
this._innerGraphics.SetClip(region, CombineMode.Replace);
}
public void FillPath(Brush brush, GraphicsPath path)
......@@ -151,9 +180,10 @@ namespace Svg
public SizeF MeasureString(string text, Font font)
{
var ff = font.FontFamily;
float lineSpace = ff.GetLineSpacing(font.Style);
//Baseline calculation to match http://bobpowell.net/formattingtext.aspx
float ascent = ff.GetCellAscent(font.Style);
float baseline = font.GetHeight(this._innerGraphics) * ascent / lineSpace;
float baselineOffset = font.SizeInPoints / ff.GetEmHeight(font.Style) * ascent;
float baselineOffsetPixels = this._innerGraphics.DpiY / 72f * baselineOffset;
StringFormat format = StringFormat.GenericTypographic;
format.SetMeasurableCharacterRanges(new CharacterRange[]{new CharacterRange(0, text.Length)});
......@@ -161,7 +191,7 @@ namespace Svg
Region[] r = this._innerGraphics.MeasureCharacterRanges(text, font, new Rectangle(0, 0, 1000, 1000), format);
RectangleF rect = r[0].GetBounds(this._innerGraphics);
return new SizeF(rect.Width, baseline);
return new SizeF(rect.Width, baselineOffsetPixels);
}
}
}
\ No newline at end of file
......@@ -18,14 +18,14 @@ namespace Svg
public SvgTextReader(Stream stream, Dictionary<string, string> entities)
: base(stream)
{
this.EntityHandling = EntityHandling.ExpandCharEntities;
this.EntityHandling = EntityHandling.ExpandEntities;
this._entities = entities;
}
public SvgTextReader(TextReader reader, Dictionary<string, string> entities)
: base(reader)
{
this.EntityHandling = EntityHandling.ExpandCharEntities;
this.EntityHandling = EntityHandling.ExpandEntities;
this._entities = entities;
}
......@@ -126,6 +126,7 @@ namespace Svg
string[] parts = null;
string name = null;
string value = null;
int quoteIndex;
foreach (string entity in entities)
{
......@@ -134,13 +135,16 @@ namespace Svg
continue;
}
parts = entity.Trim().Split(new char[]{' ', '\t'}, StringSplitOptions.RemoveEmptyEntries);
name = parts[0];
value = parts[1].Split(new char[] { this.QuoteChar }, StringSplitOptions.RemoveEmptyEntries)[0];
name = entity.Trim();
quoteIndex = name.IndexOf(this.QuoteChar);
if (quoteIndex > 0)
{
value = name.Substring(quoteIndex + 1, name.LastIndexOf(this.QuoteChar) - quoteIndex - 1);
name = name.Substring(0, quoteIndex).Trim();
this.Entities.Add(name, value);
}
}
}
/// <summary>
/// Resolves the entity reference for EntityReference nodes.
......
......@@ -25,9 +25,7 @@ namespace Svg
private SvgUnitCollection _dx = new SvgUnitCollection();
private SvgUnit _letterSpacing;
private SvgUnit _wordSpacing;
private SvgTextAnchor _textAnchor = SvgTextAnchor.inherit;
private static readonly SvgRenderer _stringMeasure;
private const string DefaultFontFamily = "Times New Roman";
private XmlSpaceHandling _space = XmlSpaceHandling.@default;
......@@ -57,8 +55,15 @@ namespace Svg
[SvgAttribute("text-anchor")]
public virtual SvgTextAnchor TextAnchor
{
get { return this._textAnchor; }
set { this._textAnchor = value; this.IsPathDirty = true; }
get { return (this.Attributes["text-anchor"] == null) ? SvgTextAnchor.inherit : (SvgTextAnchor)this.Attributes["text-anchor"]; }
set { this.Attributes["text-anchor"] = value; this.IsPathDirty = true; }
}
[SvgAttribute("baseline-shift")]
public virtual string BaselineShift
{
get { return this.Attributes["baseline-shift"] as string; }
set { this.Attributes["baseline-shift"] = value; this.IsPathDirty = true; }
}
/// <summary>
......@@ -166,7 +171,7 @@ namespace Svg
/// <value>The fill.</value>
public override SvgPaintServer Fill
{
get { return (this.Attributes["fill"] == null) ? new SvgColourServer(Color.Black) : (SvgPaintServer)this.Attributes["fill"]; }
get { return (this.Attributes["fill"] == null) ? new SvgColourServer(System.Drawing.Color.Black) : (SvgPaintServer)this.Attributes["fill"]; }
set { this.Attributes["fill"] = value; }
}
......@@ -198,33 +203,15 @@ namespace Svg
{
get
{
var path = this.Path;
var path = this.Path(null);
foreach (var elem in this.Children.OfType<SvgVisualElement>())
{
path.AddPath(elem.Path, false);
path.AddPath(elem.Path(null), false);
}
return path.GetBounds();
}
}
private static string ValidateFontFamily(string fontFamilyList)
{
// Split font family list on "," and then trim start and end spaces and quotes.
var fontParts = fontFamilyList.Split(new[] { ',' }).Select(fontName => fontName.Trim(new[] { '"', ' ', '\'' }));
var families = System.Drawing.FontFamily.Families;
// Find a the first font that exists in the list of installed font families.
//styles from IE get sent through as lowercase.
foreach (var f in fontParts.Where(f => families.Any(family => family.Name.ToLower() == f.ToLower())))
{
return f;
}
// No valid font family found from the list requested.
return null;
}
/// <summary>
/// Renders the <see cref="SvgElement"/> and contents to the specified <see cref="Graphics"/> object.
/// </summary>
......@@ -232,7 +219,7 @@ namespace Svg
/// <remarks>Necessary to make sure that any internal tspan elements get rendered as well</remarks>
protected override void Render(SvgRenderer renderer)
{
if ((this.Path != null) && this.Visible && this.Displayable)
if ((this.Path(renderer) != null) && this.Visible && this.Displayable)
{
this.PushTransforms(renderer);
this.SetClip(renderer);
......@@ -275,9 +262,9 @@ namespace Svg
}
public SizeF Bounds { get; set; }
}
protected BoundsData GetTextBounds()
protected BoundsData GetTextBounds(SvgRenderer renderer)
{
var font = GetFont();
var font = GetFont(renderer);
SvgTextBase innerText;
SizeF stringBounds;
float totalHeight = 0;
......@@ -305,7 +292,8 @@ namespace Svg
{
Bounds = stringBounds,
Node = new SvgContentNode() { Content = ch },
xOffset = (i == 0 ? 0 : _x[i].ToDeviceValue(this) - _x[0].ToDeviceValue(this))
xOffset = (i == 0 ? 0 : _x[i].ToDeviceValue(renderer, UnitRenderingType.Horizontal, this) -
_x[0].ToDeviceValue(renderer, UnitRenderingType.Horizontal, this))
});
}
}
......@@ -326,9 +314,9 @@ namespace Svg
}
else
{
stringBounds = innerText.GetTextBounds().Bounds;
stringBounds = innerText.GetTextBounds(renderer).Bounds;
result.Nodes.Add(new NodeBounds() { Bounds = stringBounds, Node = node, xOffset = totalWidth });
if (innerText.Dx.Count == 1) totalWidth += innerText.Dx[0].ToDeviceValue(this);
if (innerText.Dx.Count == 1) totalWidth += innerText.Dx[0].ToDeviceValue(renderer, UnitRenderingType.Horizontal, this);
}
totalHeight = Math.Max(totalHeight, stringBounds.Height);
totalWidth += stringBounds.Width;
......@@ -345,9 +333,7 @@ namespace Svg
/// Gets the <see cref="GraphicsPath"/> for this element.
/// </summary>
/// <value></value>
public override System.Drawing.Drawing2D.GraphicsPath Path
{
get
public override System.Drawing.Drawing2D.GraphicsPath Path(SvgRenderer renderer)
{
// Make sure the path is always null if there is no text
//if there is a TSpan inside of this text element then path should not be null (even if this text is empty!)
......@@ -358,21 +344,22 @@ namespace Svg
if (_path == null || this.IsPathDirty)
{
renderer = (renderer ?? SvgRenderer.FromNull());
// Measure the overall bounds of all the text
var boundsData = GetTextBounds();
var boundsData = GetTextBounds(renderer);
var font = GetFont();
var font = GetFont(renderer);
SvgTextBase innerText;
float x = (_x.Count < 1 ? _calcX : _x[0].ToDeviceValue(this)) + (_dx.Count < 1 ? 0 : _dx[0].ToDeviceValue(this));
float y = (_y.Count < 1 ? _calcY : _y[0].ToDeviceValue(this, true)) + (_dy.Count < 1 ? 0 : _dy[0].ToDeviceValue(this, true));
float x = (_x.Count < 1 ? _calcX : _x[0].ToDeviceValue(renderer, UnitRenderingType.HorizontalOffset, this)) +
(_dx.Count < 1 ? 0 : _dx[0].ToDeviceValue(renderer, UnitRenderingType.Horizontal, this));
float y = (_y.Count < 1 ? _calcY : _y[0].ToDeviceValue(renderer, UnitRenderingType.VerticalOffset, this)) +
(_dy.Count < 1 ? 0 : _dy[0].ToDeviceValue(renderer, UnitRenderingType.Vertical, this));
_path = new GraphicsPath();
_path.StartFigure();
var anchorElem = (from e in this.ParentsAndSelf.OfType<SvgTextBase>() where e.TextAnchor != SvgTextAnchor.inherit select e).FirstOrDefault();
// Determine the location of the start point
switch (anchorElem == null ? this.TextAnchor : anchorElem.TextAnchor)
switch (this.TextAnchor)
{
case SvgTextAnchor.Middle:
x -= (boundsData.Bounds.Width / 2);
......@@ -382,6 +369,35 @@ namespace Svg
break;
}
try
{
renderer.Boundable(new FontBoundable(font));
switch (this.BaselineShift)
{
case null:
case "":
case "baseline":
case "inherit":
// do nothing
break;
case "sub":
y += new SvgUnit(SvgUnitType.Ex, 1).ToDeviceValue(renderer, UnitRenderingType.Vertical, this);
break;
case "super":
y -= new SvgUnit(SvgUnitType.Ex, 1).ToDeviceValue(renderer, UnitRenderingType.Vertical, this);
break;
default:
var convert = new SvgUnitConverter();
var shift = (SvgUnit)convert.ConvertFromInvariantString(this.BaselineShift);
y -= shift.ToDeviceValue(renderer, UnitRenderingType.Vertical, this);
break;
}
}
finally
{
renderer.PopBoundable();
}
NodeBounds data;
var yCummOffset = 0.0f;
for (var i = 0; i < boundsData.Nodes.Count; i++)
......@@ -391,7 +407,7 @@ namespace Svg
if (innerText == null)
{
// Minus FontSize because the x/y coords mark the bottom left, not bottom top.
DrawString(_path, x + data.xOffset, y - boundsData.Bounds.Height, font,
DrawString(renderer, _path, x + data.xOffset, y - boundsData.Bounds.Height, font,
PrepareText(data.Node.Content, i > 0 && boundsData.Nodes[i - 1].Node is SvgTextBase,
i < boundsData.Nodes.Count - 1 && boundsData.Nodes[i + 1].Node is SvgTextBase));
}
......@@ -399,7 +415,7 @@ namespace Svg
{
innerText._calcX = x + data.xOffset;
innerText._calcY = y + yCummOffset;
if (innerText.Dy.Count == 1) yCummOffset += innerText.Dy[0].ToDeviceValue(this);
if (innerText.Dy.Count == 1) yCummOffset += innerText.Dy[0].ToDeviceValue(renderer, UnitRenderingType.Vertical, this);
}
}
......@@ -408,11 +424,8 @@ namespace Svg
}
return _path;
}
protected set
{
_path = value;
}
}
private static readonly Regex MultipleSpaces = new Regex(@" {2,}", RegexOptions.Compiled);
/// <summary>
/// Prepare the text according to the whitespace handling rules. <see href="http://www.w3.org/TR/SVG/text.html">SVG Spec</see>.
......@@ -423,82 +436,21 @@ namespace Svg
{
if (_space == XmlSpaceHandling.preserve)
{
return (leadingSpace ? " " : "") + value.Replace('\t', ' ').Replace("\r\n", " ").Replace('\r', ' ').Replace('\n', ' ') + (trailingSpace ? " " : "");
return value.Replace('\t', ' ').Replace("\r\n", " ").Replace('\r', ' ').Replace('\n', ' ');
}
else
{
return (leadingSpace ? " " : "") + value.Replace("\r", "").Replace("\n", "").Replace('\t', ' ').Trim().Replace(" ", " ") + (trailingSpace ? " " : "");
var convValue = MultipleSpaces.Replace(value.Replace("\r", "").Replace("\n", "").Replace('\t', ' '), " ");
if (!leadingSpace) convValue = convValue.TrimStart();
if (!trailingSpace) convValue = convValue.TrimEnd();
return convValue;
}
}
/// <summary>
/// Get the font information based on data stored with the text object or inherited from the parent.
/// </summary>
/// <returns></returns>
internal Font GetFont()
{
var parentList = this.ParentsAndSelf.OfType<SvgVisualElement>().ToList();
// Get the font-size
float fontSize;
var fontSizeUnit = GetInheritedFontSize();
if (fontSizeUnit == SvgUnit.None)
{
fontSize = 1.0f;
}
else
{
fontSize = fontSizeUnit.ToDeviceValue(this);
}
var fontStyle = System.Drawing.FontStyle.Regular;
// Get the font-weight
var weightElement = (from e in parentList where e.FontWeight != SvgFontWeight.inherit select e).FirstOrDefault();
if (weightElement != null)
{
switch (weightElement.FontWeight)
{
case SvgFontWeight.bold:
case SvgFontWeight.bolder:
case SvgFontWeight.w700:
case SvgFontWeight.w800:
case SvgFontWeight.w900:
fontStyle |= System.Drawing.FontStyle.Bold;
break;
}
}
// Get the font-style
var styleElement = (from e in parentList where e.FontStyle != SvgFontStyle.inherit select e).FirstOrDefault();
if (styleElement != null)
{
switch (styleElement.FontStyle)
{
case SvgFontStyle.italic:
case SvgFontStyle.oblique:
fontStyle |= System.Drawing.FontStyle.Italic;
break;
}
}
// Get the font-family
var fontFamilyElement = (from e in parentList where e.FontFamily != null && e.FontFamily != "inherit" select e).FirstOrDefault();
string family;
if (fontFamilyElement == null)
{
family = DefaultFontFamily;
}
else
{
family = ValidateFontFamily(fontFamilyElement.FontFamily) ?? DefaultFontFamily;
}
return new Font(family, fontSize, fontStyle, GraphicsUnit.Pixel);
}
/// <summary>
/// Draws a string on a path at a specified location and with a specified font.
/// </summary>
internal void DrawString(GraphicsPath path, float x, float y, Font font, string text)
internal void DrawString(SvgRenderer renderer, GraphicsPath path, float x, float y, Font font, string text)
{
PointF location = new PointF(x, y);
......@@ -507,8 +459,8 @@ namespace Svg
{
// Cut up into words, or just leave as required
string[] words = (this.WordSpacing.Value > 0.0f) ? text.Split(' ') : new string[] { text };
float wordSpacing = this.WordSpacing.ToDeviceValue(this);
float letterSpacing = this.LetterSpacing.ToDeviceValue(this);
float wordSpacing = this.WordSpacing.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this);
float letterSpacing = this.LetterSpacing.ToDeviceValue(renderer, UnitRenderingType.Horizontal, this);
float start = x;
foreach (string word in words)
......@@ -579,5 +531,30 @@ namespace Svg
}
#endif
private class FontBoundable : ISvgBoundable
{
private Font _font;
public FontBoundable(Font font)
{
_font = font;
}
public PointF Location
{
get { return PointF.Empty; }
}
public SizeF Size
{
get { return new SizeF(1, _font.Size); }
}
public RectangleF Bounds
{
get { return new RectangleF(this.Location, this.Size); }
}
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<TestSettings name="Trace and Test Impact" id="23149ffc-ac6c-4c10-b846-c450c14dcd05" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Description>These are test settings for Trace and Test Impact.</Description>
<Execution>
<TestTypeSpecific />
<AgentRule name="Execution Agents">
</AgentRule>
</Execution>
</TestSettings>
\ No newline at end of file
......@@ -21,7 +21,8 @@ namespace Svg.Transforms
if (transforms[i] == ')')
{
yield return transforms.Substring(transformEnd, i - transformEnd + 1).Trim();
transformEnd = i + 1;
while (i < transforms.Length && !char.IsLetter(transforms[i])) i++;
transformEnd = i;
}
}
}
......
using Svg.Css;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using ExCSS;
namespace Svg.UnitTests
{
/// <summary>
///This is a test class for CssQueryTest and is intended
///to contain all CssQueryTest Unit Tests
///</summary>
[TestClass()]
public class CssQueryTest
{
private TestContext testContextInstance;
/// <summary>
///Gets or sets the test context which provides
///information about and functionality for the current test run.
///</summary>
public TestContext TestContext
{
get
{
return testContextInstance;
}
set
{
testContextInstance = value;
}
}
#region Additional test attributes
//
//You can use the following additional attributes as you write your tests:
//
//Use ClassInitialize to run code before running the first test in the class
//[ClassInitialize()]
//public static void MyClassInitialize(TestContext testContext)
//{
//}
//
//Use ClassCleanup to run code after all tests in a class have run
//[ClassCleanup()]
//public static void MyClassCleanup()
//{
//}
//
//Use TestInitialize to run code before running each test
//[TestInitialize()]
//public void MyTestInitialize()
//{
//}
//
//Use TestCleanup to run code after each test has run
//[TestCleanup()]
//public void MyTestCleanup()
//{
//}
//
#endregion
private void TestSelectorSpecificity(string selector, int specificity)
{
var parser = new ExCSS.Parser();
var sheet = parser.Parse(selector + " {color:black}");
Assert.AreEqual(specificity, CssQuery.GetSpecificity(sheet.StyleRules[0].Selector));
}
/// <summary>
///A test for GetSpecificity
///</summary>
///<remarks>Lifted from http://www.smashingmagazine.com/2007/07/27/css-specificity-things-you-should-know/, and http://css-tricks.com/specifics-on-css-specificity/ </remarks>
[TestMethod()]
public void RunSpecificityTests()
{
TestSelectorSpecificity("*", 0x0);
TestSelectorSpecificity("li", 0x10);
TestSelectorSpecificity("li:first-line", 0x20);
TestSelectorSpecificity("ul li", 0x20);
TestSelectorSpecificity("ul ol+li", 0x30);
TestSelectorSpecificity("h1 + *[rel=up]", 0x110);
TestSelectorSpecificity("ul ol li.red", 0x130);
TestSelectorSpecificity("li.red.level", 0x210);
TestSelectorSpecificity("p", 0x010);
TestSelectorSpecificity("div p", 0x020);
TestSelectorSpecificity(".sith", 0x100);
TestSelectorSpecificity("div p.sith", 0x120);
TestSelectorSpecificity("#sith", 0x1000);
TestSelectorSpecificity("body #darkside .sith p", 0x1120);
TestSelectorSpecificity("body #content .data img:hover", 0x1220);
TestSelectorSpecificity("a#a-02", 0x1010);
TestSelectorSpecificity("a[id=\"a-02\"]", 0x0110);
TestSelectorSpecificity("ul#nav li.active a", 0x1130);
TestSelectorSpecificity("body.ie7 .col_3 h2 ~ h2", 0x0230);
TestSelectorSpecificity("#footer *:not(nav) li", 0x1020);
TestSelectorSpecificity("ul > li ul li ol li:first-letter", 0x0070);
}
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Svg.UnitTests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Svg.UnitTests")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("6ab1d266-f201-46c0-9d14-523768eb18db")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>
</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{E702EB7D-D01D-438A-BADD-E72D4E49109F}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Svg.UnitTests</RootNamespace>
<AssemblyName>Svg.UnitTests</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Web" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
<Visible>False</Visible>
</CodeAnalysisDependentAssemblyPaths>
</ItemGroup>
<ItemGroup>
<Compile Include="CssQueryTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Source\Svg.csproj">
<Project>{886A98C5-37C0-4E8B-885E-30C1D2F98B47}</Project>
<Name>Svg</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
namespace SvgW3CTestRunner
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new View());
}
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("SvgW3CTestRunner")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SvgW3CTestRunner")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("bf75ea0d-e099-432c-bad5-7fd6cf53d5ee")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.18444
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace SvgW3CTestRunner.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SvgW3CTestRunner.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
\ No newline at end of file
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