diff --git a/Output/SharpVectors.Converters.Wpf.dll b/Output/SharpVectors.Converters.Wpf.dll index 9a2cb404d..5b7c007f7 100644 Binary files a/Output/SharpVectors.Converters.Wpf.dll and b/Output/SharpVectors.Converters.Wpf.dll differ diff --git a/Output/SharpVectors.Core.dll b/Output/SharpVectors.Core.dll index 8d86cc415..7c9ea3dcc 100644 Binary files a/Output/SharpVectors.Core.dll and b/Output/SharpVectors.Core.dll differ diff --git a/Output/SharpVectors.Css.dll b/Output/SharpVectors.Css.dll index 7bc440a49..69a1d6471 100644 Binary files a/Output/SharpVectors.Css.dll and b/Output/SharpVectors.Css.dll differ diff --git a/Output/SharpVectors.Dom.dll b/Output/SharpVectors.Dom.dll index 20e962e24..2a3855b26 100644 Binary files a/Output/SharpVectors.Dom.dll and b/Output/SharpVectors.Dom.dll differ diff --git a/Output/SharpVectors.Model.dll b/Output/SharpVectors.Model.dll index ec1e87960..1d32dfeea 100644 Binary files a/Output/SharpVectors.Model.dll and b/Output/SharpVectors.Model.dll differ diff --git a/Output/SharpVectors.Rendering.Gdi.dll b/Output/SharpVectors.Rendering.Gdi.dll index 6d21fa771..925fe6bc0 100644 Binary files a/Output/SharpVectors.Rendering.Gdi.dll and b/Output/SharpVectors.Rendering.Gdi.dll differ diff --git a/Output/SharpVectors.Rendering.Wpf.dll b/Output/SharpVectors.Rendering.Wpf.dll index bfa08b916..796491a4d 100644 Binary files a/Output/SharpVectors.Rendering.Wpf.dll and b/Output/SharpVectors.Rendering.Wpf.dll differ diff --git a/Output/SharpVectors.Runtime.Wpf.dll b/Output/SharpVectors.Runtime.Wpf.dll index 39bb972d3..b79e11fcc 100644 Binary files a/Output/SharpVectors.Runtime.Wpf.dll and b/Output/SharpVectors.Runtime.Wpf.dll differ diff --git a/Samples/WpfSvgTestBox/DebugPage.xaml b/Samples/WpfSvgTestBox/DebugPage.xaml index e80d9de1a..f55a5b267 100644 --- a/Samples/WpfSvgTestBox/DebugPage.xaml +++ b/Samples/WpfSvgTestBox/DebugPage.xaml @@ -3,12 +3,17 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit" xmlns:local="clr-namespace:WpfSvgTestBox" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" Title="DebugPage"> - + + + diff --git a/Samples/WpfSvgTestBox/DebugPage.xaml.cs b/Samples/WpfSvgTestBox/DebugPage.xaml.cs index f2a5499c4..ae88dc90f 100644 --- a/Samples/WpfSvgTestBox/DebugPage.xaml.cs +++ b/Samples/WpfSvgTestBox/DebugPage.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Windows.Controls; @@ -7,28 +8,77 @@ namespace WpfSvgTestBox /// /// Interaction logic for DebugPage.xaml /// - public partial class DebugPage : Page + public partial class DebugPage : Page, ITraceTextSink { + private delegate void AppendTextDelegate(string msg, string style); + + private TraceListener _listener; + public DebugPage() { InitializeComponent(); + + textEditor.IsReadOnly = true; + + Trace.UseGlobalLock = true; + + _listener = new TraceTextSource(this); + Trace.Listeners.Add(_listener); } public void Startup() { - if (traceDocument != null) + if (_listener == null) { - traceDocument.Startup(); + _listener = new TraceTextSource(this); + Trace.Listeners.Add(_listener); } + + Trace.WriteLine("Startup"); } public void Shutdown() { - if (traceDocument != null) + Trace.WriteLine("Shutdown"); + if (_listener != null) { - traceDocument.Shutdown(); + Trace.Listeners.Remove(_listener); + _listener.Dispose(); + _listener = null; } } + public void Event(string msg, TraceEventType eventType) + { + Append(msg, eventType.ToString()); + } + + public void Fail(string msg) + { + Append(msg, "Fail"); + } + + private void Append(string msg, string style) + { + if (Dispatcher.CheckAccess()) + { + if (!this.IsLoaded) + { + return; + } + if (string.IsNullOrWhiteSpace(style)) + { + textEditor.AppendText(msg + Environment.NewLine); + } + else + { + textEditor.AppendText(style + ": " + msg + Environment.NewLine); + } + } + else + { + Dispatcher.Invoke(new AppendTextDelegate(Append), msg, style); + } + } } } diff --git a/Samples/WpfTestThreadSafety/App.config b/Samples/WpfTestThreadSafety/App.config new file mode 100644 index 000000000..88fa4027b --- /dev/null +++ b/Samples/WpfTestThreadSafety/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Samples/WpfTestThreadSafety/App.ico b/Samples/WpfTestThreadSafety/App.ico new file mode 100644 index 000000000..bf398870c Binary files /dev/null and b/Samples/WpfTestThreadSafety/App.ico differ diff --git a/Samples/WpfTestThreadSafety/App.xaml b/Samples/WpfTestThreadSafety/App.xaml new file mode 100644 index 000000000..5bbf37dba --- /dev/null +++ b/Samples/WpfTestThreadSafety/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/Samples/WpfTestThreadSafety/App.xaml.cs b/Samples/WpfTestThreadSafety/App.xaml.cs new file mode 100644 index 000000000..f66a2fe7b --- /dev/null +++ b/Samples/WpfTestThreadSafety/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace WpfTestThreadSafety +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/Samples/WpfTestThreadSafety/MainWindow.xaml b/Samples/WpfTestThreadSafety/MainWindow.xaml new file mode 100644 index 000000000..b0c5bdd7d --- /dev/null +++ b/Samples/WpfTestThreadSafety/MainWindow.xaml @@ -0,0 +1,66 @@ + + + + + + + + + Verbose + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/WpfTestThreadSafety/MainWindow.xaml.cs b/Samples/WpfTestThreadSafety/MainWindow.xaml.cs new file mode 100644 index 000000000..bb27386fa --- /dev/null +++ b/Samples/WpfTestThreadSafety/MainWindow.xaml.cs @@ -0,0 +1,346 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Collections.Concurrent; +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using System.Runtime.InteropServices; + +using System.Windows; +using System.Windows.Media; + +using SharpVectors.Converters; +using SharpVectors.Renderers.Wpf; + +namespace WpfTestThreadSafety +{ + public sealed class ImageData + { + private string _fileName; + private Drawing _drawing; + + public ImageData() + { + } + + public ImageData(Drawing drawing, string fileName) + { + _drawing = drawing; + _fileName = fileName; + } + + public string Name + { + get { + return _fileName; + } + } + + public ImageSource Image + { + get { + return new DrawingImage(_drawing); + } + } + } + + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + private delegate void AppendImageDelegate(Drawing drawing, string fileName); + private delegate void AppendTextDelegate(string msg, string style); + + private const string W3CDirPrefix = "Svg"; + private const string LocalDirBase = @"..\..\..\W3cSvgTestSuites\"; + + [DllImport("Shlwapi.dll", EntryPoint = "PathIsDirectoryEmpty")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool IsDirectoryEmpty([MarshalAs(UnmanagedType.LPStr)]string directory); + + private const int NumberOfImages = 300; + private const int NumberOfColumns = 100; + private const int NumberOfConsumers = 8; + + private bool _isVerbose; + private int _columnCount; + private int _imageCount; + + private ObservableCollection _imageList; + + public MainWindow() + { + InitializeComponent(); + + _imageList = new ObservableCollection(); + this.DataContext = this; + } + + public ObservableCollection ImageList + { + get { + return _imageList; + } + } + + private void OnWindowLoaded(object sender, RoutedEventArgs e) + { + this.SetValidSvgDir(); + + } + + private void OnWindowClosed(object sender, EventArgs e) + { + + } + + private void OnWindowClosing(object sender, System.ComponentModel.CancelEventArgs e) + { + + } + + private void SetValidSvgDir() + { + string svgDir; + if (GetValidSvgTestsDir(out svgDir, 1, 1)) + { + txtSvgSource.Text = svgDir; + return; + } + if (GetValidSvgTestsDir(out svgDir, 1, 2)) + { + txtSvgSource.Text = svgDir; + return; + } + if (GetValidSvgTestsDir(out svgDir, 1, 0)) // this has fewer that 300 images + { + txtSvgSource.Text = svgDir; + return; + } + } + + private void UpdateDrawing(string svgFilePath) + { + var wpfSettings = new WpfDrawingSettings(); + wpfSettings.CultureInfo = wpfSettings.NeutralCultureInfo; + using (var textReader = new StreamReader(svgFilePath)) + { + using (var fileReader = new FileSvgReader(wpfSettings)) + { + _imageCount++; + try + { + if (_isVerbose) + { + this.AppendLine("Start Converting: " + svgFilePath); + } + else + { + _columnCount++; + AppendText("*"); + if (_columnCount >= NumberOfColumns) + { + _columnCount = 0; + if (_imageCount < NumberOfImages) + { + AppendLine(""); + } + } + } + + fileReader.SaveXaml = false; + fileReader.SaveZaml = false; + var drawing = fileReader.Read(textReader); + drawing.Freeze(); + + AppendImage(drawing, Path.GetFileNameWithoutExtension(svgFilePath)); + + if (_isVerbose) + { + this.AppendLine("Completed Converting: " + svgFilePath); + } + } + catch (Exception ex) + { + if (_isVerbose) + { + AppendClear(); + } + this.AppendLine("File: " + svgFilePath); + AppendError(ex.ToString()); + } + } + } + } + + public void AppendError(string msg) + { + AppendLine(msg, "Error"); + } + + public void AppendClear() + { + AppendLine(string.Empty, "Clear"); + } + + private void AppendImage(Drawing drawing, string fileName) + { + if (Dispatcher.CheckAccess()) + { + _imageList.Add(new ImageData(drawing, fileName)); + } + else + { + Dispatcher.Invoke(new AppendImageDelegate(AppendImage), drawing, fileName); + } + } + + private void AppendText(string msg, string style = "") + { + if (Dispatcher.CheckAccess()) + { + txtDebug.AppendText(msg); + } + else + { + Dispatcher.Invoke(new AppendTextDelegate(AppendText), msg, string.Empty); + } + } + + private void AppendLine(string msg, string style = null) + { + if (Dispatcher.CheckAccess()) + { + if (string.IsNullOrWhiteSpace(style)) + { + txtDebug.AppendText(msg + Environment.NewLine); + } + else + { + if (style.Equals("Clear", StringComparison.OrdinalIgnoreCase)) + { + txtDebug.Clear(); + return; + } + else + { + txtDebug.AppendText(style + ": " + msg + Environment.NewLine); + } + } + + txtDebug.CaretIndex = txtDebug.Text.Length; + txtDebug.ScrollToEnd(); + } + else + { + Dispatcher.Invoke(new AppendTextDelegate(AppendLine), msg, style); + } + } + + private static bool GetValidSvgTestsDir(out string svgDir, int majorVersion, int minorVersion) + { + svgDir = ""; + + string versionSuffix = string.Format("{0}{1}", majorVersion, minorVersion); + var suiteDirName = W3CDirPrefix + versionSuffix; + var localSuitePath = Path.GetFullPath(Path.Combine(LocalDirBase, suiteDirName)); + if (Directory.Exists(localSuitePath) == false) + { + return false; + } + if (IsTestSuiteAvailable(localSuitePath)) + { + svgDir = Path.Combine(localSuitePath, "svg"); + return true; + } + return false; + } + + private static bool IsTestSuiteAvailable(string testPath) + { + if (string.IsNullOrWhiteSpace(testPath) || Directory.Exists(testPath) == false) + { + return false; + } + string svgDir = Path.Combine(testPath, "svg"); + if (!Directory.Exists(svgDir) || IsDirectoryEmpty(svgDir) == true) + { + return false; + } + string pngDir = Path.Combine(testPath, "png"); + if (!Directory.Exists(pngDir) || IsDirectoryEmpty(pngDir) == true) + { + return false; + } + + return true; + } + + private async void OnStartClick(object sender, RoutedEventArgs e) + { + string svgPath = txtSvgSource.Text; + if (string.IsNullOrWhiteSpace(svgPath) || Directory.Exists(svgPath) == false) + { + return; + } + + txtDebug.Clear(); + _imageList.Clear(); + + _columnCount = 0; + _imageCount = 0; + _isVerbose = (chkVerbose.IsChecked != null && chkVerbose.IsChecked.Value); + + btnStart.IsEnabled = false; + chkVerbose.IsEnabled = false; + + var queue = new ConcurrentQueue(); + + int imageCount = 0; + foreach (var svgFilePath in Directory.EnumerateFiles(svgPath, "*.svg")) + { + // Eliminate any compressed file, not supported in this test... + if (svgFilePath.EndsWith(".svgz", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + + queue.Enqueue(svgFilePath); + + imageCount++; + if (imageCount >= NumberOfImages) + { + break; + } + } + + AppendLine("Starting Tests ****"); + if (_isVerbose) + { + AppendLine(""); + } + + var allTasks = new List(); + + for (int i = 0; i < NumberOfConsumers; ++i) + { + allTasks.Add(Task.Run(() => + { + while (queue.TryDequeue(out string imageData)) + { + UpdateDrawing(imageData); + } + })); + } + + await Task.WhenAll(allTasks); + + AppendLine(""); + AppendLine("**** Completed Tests"); + + btnStart.IsEnabled = true; + chkVerbose.IsEnabled = true; + } + } +} diff --git a/Samples/WpfTestThreadSafety/Properties/AssemblyInfo.cs b/Samples/WpfTestThreadSafety/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..777c56402 --- /dev/null +++ b/Samples/WpfTestThreadSafety/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// 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("WpfTestThreadSafety")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("WpfTestThreadSafety")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2019")] +[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)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// 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")] diff --git a/Samples/WpfTestThreadSafety/Properties/Resources.Designer.cs b/Samples/WpfTestThreadSafety/Properties/Resources.Designer.cs new file mode 100644 index 000000000..cacdf9897 --- /dev/null +++ b/Samples/WpfTestThreadSafety/Properties/Resources.Designer.cs @@ -0,0 +1,68 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace WpfTestThreadSafety.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // 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() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("WpfTestThreadSafety.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Samples/WpfTestThreadSafety/Properties/Resources.resx b/Samples/WpfTestThreadSafety/Properties/Resources.resx new file mode 100644 index 000000000..af7dbebba --- /dev/null +++ b/Samples/WpfTestThreadSafety/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Samples/WpfTestThreadSafety/Properties/Settings.Designer.cs b/Samples/WpfTestThreadSafety/Properties/Settings.Designer.cs new file mode 100644 index 000000000..6d0f8adad --- /dev/null +++ b/Samples/WpfTestThreadSafety/Properties/Settings.Designer.cs @@ -0,0 +1,29 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace WpfTestThreadSafety.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get { + return defaultInstance; + } + } + } +} diff --git a/Samples/WpfTestThreadSafety/Properties/Settings.settings b/Samples/WpfTestThreadSafety/Properties/Settings.settings new file mode 100644 index 000000000..033d7a5e9 --- /dev/null +++ b/Samples/WpfTestThreadSafety/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Samples/WpfTestThreadSafety/WpfTestThreadSafety.csproj b/Samples/WpfTestThreadSafety/WpfTestThreadSafety.csproj new file mode 100644 index 000000000..7a549b09e --- /dev/null +++ b/Samples/WpfTestThreadSafety/WpfTestThreadSafety.csproj @@ -0,0 +1,134 @@ + + + + + Debug + AnyCPU + {19ED33D1-7D07-43ED-878A-16630CD4035D} + WinExe + WpfTestThreadSafety + WpfTestThreadSafety + v4.5.2 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + App.ico + + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + {e8056611-e49c-4bc3-a682-a629d5cec11c} + SharpVectors.Converters.Wpf + + + {d6bb65fc-240e-4241-b2ed-a7fb3f13e978} + SharpVectors.Core + + + {351b0a6e-2f6b-497a-844b-dcb5a502fb0d} + SharpVectors.Css + + + {fe34cbc0-d23c-4a95-ba64-83a031814010} + SharpVectors.Dom + + + {5d336f48-3fb9-4382-b4b9-06974c764007} + SharpVectors.Model + + + {a2576ce0-e492-490f-97e9-c0e7abafaf27} + SharpVectors.Rendering.Wpf + + + {2cd52982-a1c2-4a14-9d69-d64719357216} + SharpVectors.Runtime.Wpf + + + + + + + \ No newline at end of file diff --git a/Samples/WpfW3cSvgTestSuite/OptionSettings.cs b/Samples/WpfW3cSvgTestSuite/OptionSettings.cs index 4590c0326..ee5cfb111 100644 --- a/Samples/WpfW3cSvgTestSuite/OptionSettings.cs +++ b/Samples/WpfW3cSvgTestSuite/OptionSettings.cs @@ -30,6 +30,10 @@ private static extern int SHOpenFolderAndSelectItems(IntPtr pidlFolder, private static extern void SHParseDisplayName([MarshalAs(UnmanagedType.LPWStr)] string name, IntPtr bindingContext, [Out] out IntPtr pidl, uint sfgaoIn, [Out] out uint psfgaoOut); + [DllImport("Shlwapi.dll", EntryPoint = "PathIsDirectoryEmpty")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool IsDirectoryEmpty([MarshalAs(UnmanagedType.LPStr)]string directory); + #endregion #region Public Events @@ -43,10 +47,6 @@ private static extern void SHParseDisplayName([MarshalAs(UnmanagedType.LPWStr)] private const string ParentSymbol = "..\\"; private const string SharpVectors = "SharpVectors"; - [DllImport("Shlwapi.dll", EntryPoint = "PathIsDirectoryEmpty")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool IsDirectoryEmpty([MarshalAs(UnmanagedType.LPStr)]string directory); - private bool _hidePathsRoot; private string _webSuitePath; private string _localSuitePath; diff --git a/Samples/WpfW3cSvgTestSuite/Output/SvgTestResults12.xml b/Samples/WpfW3cSvgTestSuite/Output/SvgTestResults12.xml index 28034cadd..a1adb5a3e 100644 --- a/Samples/WpfW3cSvgTestSuite/Output/SvgTestResults12.xml +++ b/Samples/WpfW3cSvgTestSuite/Output/SvgTestResults12.xml @@ -19,4 +19,23 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SharpVectorsAll.sln b/SharpVectorsAll.sln index 75706db8c..3e73c2ae9 100644 --- a/SharpVectorsAll.sln +++ b/SharpVectorsAll.sln @@ -40,6 +40,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GdiSvgTestBox", "Samples\Gd EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfTestSvgControl", "Samples\WpfTestSvgControl\WpfTestSvgControl.csproj", "{28586359-004C-45B5-823E-38F714784B31}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfTestThreadSafety", "Samples\WpfTestThreadSafety\WpfTestThreadSafety.csproj", "{19ED33D1-7D07-43ED-878A-16630CD4035D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -149,6 +151,12 @@ Global {28586359-004C-45B5-823E-38F714784B31}.Documentation|Any CPU.Build.0 = Debug|Any CPU {28586359-004C-45B5-823E-38F714784B31}.Release|Any CPU.ActiveCfg = Release|Any CPU {28586359-004C-45B5-823E-38F714784B31}.Release|Any CPU.Build.0 = Release|Any CPU + {19ED33D1-7D07-43ED-878A-16630CD4035D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {19ED33D1-7D07-43ED-878A-16630CD4035D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {19ED33D1-7D07-43ED-878A-16630CD4035D}.Documentation|Any CPU.ActiveCfg = Debug|Any CPU + {19ED33D1-7D07-43ED-878A-16630CD4035D}.Documentation|Any CPU.Build.0 = Debug|Any CPU + {19ED33D1-7D07-43ED-878A-16630CD4035D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {19ED33D1-7D07-43ED-878A-16630CD4035D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -163,6 +171,7 @@ Global {406733B7-B9C5-4100-8D10-F3CCE9C58B2C} = {A1967865-8F3B-4976-A7EC-8F91EAE4C964} {5A71211F-9EDA-4C43-8DDC-E3EB54843113} = {A1967865-8F3B-4976-A7EC-8F91EAE4C964} {28586359-004C-45B5-823E-38F714784B31} = {A1967865-8F3B-4976-A7EC-8F91EAE4C964} + {19ED33D1-7D07-43ED-878A-16630CD4035D} = {A1967865-8F3B-4976-A7EC-8F91EAE4C964} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {ECBBFB65-D6D1-4727-BE82-54D52CE8FCF3} diff --git a/Source/SharpVectorConvertersWpf/Shapes/ShapeRenderingVisitor.cs b/Source/SharpVectorConvertersWpf/Shapes/ShapeRenderingVisitor.cs index deea47c0d..2187499e4 100644 --- a/Source/SharpVectorConvertersWpf/Shapes/ShapeRenderingVisitor.cs +++ b/Source/SharpVectorConvertersWpf/Shapes/ShapeRenderingVisitor.cs @@ -335,7 +335,7 @@ public void Visit(ISvgTextElement element) } else if (TryCast.Cast(child, out simpleText)) { - geometry = ConstructTextGeometry(element as SvgTextElement, + geometry = ConstructTextGeometry(element as SvgTextBaseElement, simpleText.InnerText, position, out spanSize); shape = WrapGeometry(geometry, element); shape.IsHitTestVisible = false; diff --git a/Source/SharpVectorCore/SharpVectors.Core.csproj b/Source/SharpVectorCore/SharpVectors.Core.csproj index 185fc497b..028c169cd 100644 --- a/Source/SharpVectorCore/SharpVectors.Core.csproj +++ b/Source/SharpVectorCore/SharpVectors.Core.csproj @@ -111,6 +111,9 @@ + + + @@ -482,15 +485,6 @@ Code - - Code - - - Code - - - Code - Code diff --git a/Source/SharpVectorCore/Svg/ClippingMaskingCompositing/ISharpMarkerHost.cs b/Source/SharpVectorCore/Svg/ClippingMasking/ISharpMarkerHost.cs similarity index 96% rename from Source/SharpVectorCore/Svg/ClippingMaskingCompositing/ISharpMarkerHost.cs rename to Source/SharpVectorCore/Svg/ClippingMasking/ISharpMarkerHost.cs index 33119bb34..ed5b9429e 100644 --- a/Source/SharpVectorCore/Svg/ClippingMaskingCompositing/ISharpMarkerHost.cs +++ b/Source/SharpVectorCore/Svg/ClippingMasking/ISharpMarkerHost.cs @@ -1,64 +1,64 @@ -namespace SharpVectors.Dom.Svg -{ - /// - /// This is an extension to the Svg DOM. It denotes that an element can display markers. - /// - /// - /// - /// A marker is a symbol which is attached to one or more vertices of some Svg elements. In order for - /// a marker to be drawn correctly, its orientation and position needs to be known. - /// See SVG 1.0 Masking - Establishing A New Clipping Path - /// - /// - /// This interface provides the information required to calculate the - /// orientation and position for each marker of an Svg element. - /// - /// - /// To give an Svg element the capability to draw markers, let the Svg element implement this interface. - /// - /// - public interface ISharpMarkerHost - { - /// - /// An array specifying the position of each vertex in the Svg element's shape. - /// - SvgPointF[] MarkerPositions - { - get; - } - - bool IsClosed - { - get; - } - - bool MayHaveCurves - { - get; - } - - ISvgMarker GetMarker(int index); - - /// - /// Get the angle of the path segment entering the specified vertex. - /// - /// - /// Specifies the vertex to which the path segment is entering. - /// - /// - /// The angle of the path segment entering the specified vertex in degrees. - /// - double GetStartAngle(int index); - - /// - /// Get the angle of the path segment leaving the specified vertex in degrees. - /// - /// - /// Specifies the vertex from which the path segment is leaving. - /// - /// - /// The angle of the path segment leaving the specified vertex. - /// - double GetEndAngle(int index); - } -} +namespace SharpVectors.Dom.Svg +{ + /// + /// This is an extension to the Svg DOM. It denotes that an element can display markers. + /// + /// + /// + /// A marker is a symbol which is attached to one or more vertices of some Svg elements. In order for + /// a marker to be drawn correctly, its orientation and position needs to be known. + /// See SVG 1.0 Masking - Establishing A New Clipping Path + /// + /// + /// This interface provides the information required to calculate the + /// orientation and position for each marker of an Svg element. + /// + /// + /// To give an Svg element the capability to draw markers, let the Svg element implement this interface. + /// + /// + public interface ISharpMarkerHost + { + /// + /// An array specifying the position of each vertex in the Svg element's shape. + /// + SvgPointF[] MarkerPositions + { + get; + } + + bool IsClosed + { + get; + } + + bool MayHaveCurves + { + get; + } + + ISvgMarker GetMarker(int index); + + /// + /// Get the angle of the path segment entering the specified vertex. + /// + /// + /// Specifies the vertex to which the path segment is entering. + /// + /// + /// The angle of the path segment entering the specified vertex in degrees. + /// + double GetStartAngle(int index); + + /// + /// Get the angle of the path segment leaving the specified vertex in degrees. + /// + /// + /// Specifies the vertex from which the path segment is leaving. + /// + /// + /// The angle of the path segment leaving the specified vertex. + /// + double GetEndAngle(int index); + } +} diff --git a/Source/SharpVectorCore/Svg/ClippingMaskingCompositing/ISvgClipPathElement.cs b/Source/SharpVectorCore/Svg/ClippingMasking/ISvgClipPathElement.cs similarity index 96% rename from Source/SharpVectorCore/Svg/ClippingMaskingCompositing/ISvgClipPathElement.cs rename to Source/SharpVectorCore/Svg/ClippingMasking/ISvgClipPathElement.cs index 384c24689..a89a5562e 100644 --- a/Source/SharpVectorCore/Svg/ClippingMaskingCompositing/ISvgClipPathElement.cs +++ b/Source/SharpVectorCore/Svg/ClippingMasking/ISvgClipPathElement.cs @@ -1,11 +1,11 @@ -namespace SharpVectors.Dom.Svg -{ - /// - /// Used by SvgClipPathElement. - /// - public interface ISvgClipPathElement : ISvgElement, ISvgTests, ISvgLangSpace, - ISvgExternalResourcesRequired, ISvgStylable, ISvgTransformable - { - ISvgAnimatedEnumeration ClipPathUnits {get;} - } -} +namespace SharpVectors.Dom.Svg +{ + /// + /// Used by SvgClipPathElement. + /// + public interface ISvgClipPathElement : ISvgElement, ISvgTests, ISvgLangSpace, + ISvgExternalResourcesRequired, ISvgStylable, ISvgTransformable + { + ISvgAnimatedEnumeration ClipPathUnits {get;} + } +} diff --git a/Source/SharpVectorCore/Svg/ClippingMaskingCompositing/ISvgMaskElement.cs b/Source/SharpVectorCore/Svg/ClippingMasking/ISvgMaskElement.cs similarity index 96% rename from Source/SharpVectorCore/Svg/ClippingMaskingCompositing/ISvgMaskElement.cs rename to Source/SharpVectorCore/Svg/ClippingMasking/ISvgMaskElement.cs index a18b8e43a..7d82784f6 100644 --- a/Source/SharpVectorCore/Svg/ClippingMaskingCompositing/ISvgMaskElement.cs +++ b/Source/SharpVectorCore/Svg/ClippingMasking/ISvgMaskElement.cs @@ -1,16 +1,16 @@ -namespace SharpVectors.Dom.Svg -{ - /// - /// Used by SvgMaskElement. - /// - public interface ISvgMaskElement : ISvgElement, ISvgTests, ISvgLangSpace, - ISvgExternalResourcesRequired, ISvgStylable - { - ISvgAnimatedEnumeration MaskUnits {get;} - ISvgAnimatedEnumeration MaskContentUnits {get;} - ISvgAnimatedLength X {get;} - ISvgAnimatedLength Y {get;} - ISvgAnimatedLength Width {get;} - ISvgAnimatedLength Height {get;} - } -} +namespace SharpVectors.Dom.Svg +{ + /// + /// Used by SvgMaskElement. + /// + public interface ISvgMaskElement : ISvgElement, ISvgTests, ISvgLangSpace, + ISvgExternalResourcesRequired, ISvgStylable + { + ISvgAnimatedEnumeration MaskUnits {get;} + ISvgAnimatedEnumeration MaskContentUnits {get;} + ISvgAnimatedLength X {get;} + ISvgAnimatedLength Y {get;} + ISvgAnimatedLength Width {get;} + ISvgAnimatedLength Height {get;} + } +} diff --git a/Source/SharpVectorModel/BasicTypes/SvgList.cs b/Source/SharpVectorModel/BasicTypes/SvgList.cs index 82ed3f658..c02f597b7 100644 --- a/Source/SharpVectorModel/BasicTypes/SvgList.cs +++ b/Source/SharpVectorModel/BasicTypes/SvgList.cs @@ -4,7 +4,7 @@ /// Note we're using (as opposed to deriving from) to hide unneeded methods /// Note that a CLR uint is equivalent to an IDL ulong, so uint is used for all index values /// public abstract class SvgList : IEnumerable { #region Private Fields - protected List _items; private static IDictionary> _itemOwnerMap; #endregion + protected List _items; private IDictionary> _itemOwnerMap; #endregion #region Constructor /// /// SvgList constructor /// protected SvgList() { _items = new List(); _itemOwnerMap = new Dictionary>(); } #endregion #region ISvgList Interface /// /// NumberOfItems /// public uint NumberOfItems { get { return (uint) _items.Count; } } diff --git a/Source/SharpVectorModel/ClippingMaskingCompositing/SvgClipPathElement.cs b/Source/SharpVectorModel/ClippingMasking/SvgClipPathElement.cs similarity index 95% rename from Source/SharpVectorModel/ClippingMaskingCompositing/SvgClipPathElement.cs rename to Source/SharpVectorModel/ClippingMasking/SvgClipPathElement.cs index 5cff9be07..d2113f85f 100644 --- a/Source/SharpVectorModel/ClippingMaskingCompositing/SvgClipPathElement.cs +++ b/Source/SharpVectorModel/ClippingMasking/SvgClipPathElement.cs @@ -1,119 +1,119 @@ -using System; - -namespace SharpVectors.Dom.Svg -{ - public sealed class SvgClipPathElement : SvgTransformableElement, ISvgClipPathElement - { - #region Private Fields - - private SvgTests _svgTests; - private ISvgAnimatedEnumeration _clipPathUnits; - private SvgExternalResourcesRequired _externalResourcesRequired; - - #endregion - - #region Constructors and Destructor - - public SvgClipPathElement(string prefix, string localname, string ns, SvgDocument doc) - : base(prefix, localname, ns, doc) - { - _externalResourcesRequired = new SvgExternalResourcesRequired(this); - _svgTests = new SvgTests(this); - } - - #endregion - - #region ISvgElement Members - - /// - /// Gets a value indicating whether this SVG element is renderable. - /// - /// - /// This is if the element is renderable; otherwise, - /// it is . - /// - public override bool IsRenderable - { - get - { - return false; - } - } - - /// - /// Gets a value providing a hint on the rendering defined by this element. - /// - /// - /// An enumeration of the specifying the rendering hint. - /// This will always return - /// - public override SvgRenderingHint RenderingHint - { - get - { - return SvgRenderingHint.Clipping; - } - } - - #endregion - - #region ISvgClipPathElement Members - - public ISvgAnimatedEnumeration ClipPathUnits - { - get - { - if (_clipPathUnits == null) - { - SvgUnitType clipPath = SvgUnitType.UserSpaceOnUse; - if (GetAttribute("clipPathUnits") == "objectBoundingBox") - { - clipPath = SvgUnitType.ObjectBoundingBox; - } - - _clipPathUnits = new SvgAnimatedEnumeration((ushort)clipPath); - } - - return _clipPathUnits; - } - } - - #endregion - - #region ISvgExternalResourcesRequired Members - - public ISvgAnimatedBoolean ExternalResourcesRequired - { - get - { - return _externalResourcesRequired.ExternalResourcesRequired; - } - } - - #endregion - - #region ISvgTests Members - - public ISvgStringList RequiredFeatures - { - get { return _svgTests.RequiredFeatures; } - } - - public ISvgStringList RequiredExtensions - { - get { return _svgTests.RequiredExtensions; } - } - - public ISvgStringList SystemLanguage - { - get { return _svgTests.SystemLanguage; } - } - - public bool HasExtension(string extension) - { - return _svgTests.HasExtension(extension); - } - - #endregion - } -} +using System; + +namespace SharpVectors.Dom.Svg +{ + public sealed class SvgClipPathElement : SvgTransformableElement, ISvgClipPathElement + { + #region Private Fields + + private SvgTests _svgTests; + private ISvgAnimatedEnumeration _clipPathUnits; + private SvgExternalResourcesRequired _externalResourcesRequired; + + #endregion + + #region Constructors and Destructor + + public SvgClipPathElement(string prefix, string localname, string ns, SvgDocument doc) + : base(prefix, localname, ns, doc) + { + _externalResourcesRequired = new SvgExternalResourcesRequired(this); + _svgTests = new SvgTests(this); + } + + #endregion + + #region ISvgElement Members + + /// + /// Gets a value indicating whether this SVG element is renderable. + /// + /// + /// This is if the element is renderable; otherwise, + /// it is . + /// + public override bool IsRenderable + { + get + { + return false; + } + } + + /// + /// Gets a value providing a hint on the rendering defined by this element. + /// + /// + /// An enumeration of the specifying the rendering hint. + /// This will always return + /// + public override SvgRenderingHint RenderingHint + { + get + { + return SvgRenderingHint.Clipping; + } + } + + #endregion + + #region ISvgClipPathElement Members + + public ISvgAnimatedEnumeration ClipPathUnits + { + get + { + if (_clipPathUnits == null) + { + SvgUnitType clipPath = SvgUnitType.UserSpaceOnUse; + if (GetAttribute("clipPathUnits") == "objectBoundingBox") + { + clipPath = SvgUnitType.ObjectBoundingBox; + } + + _clipPathUnits = new SvgAnimatedEnumeration((ushort)clipPath); + } + + return _clipPathUnits; + } + } + + #endregion + + #region ISvgExternalResourcesRequired Members + + public ISvgAnimatedBoolean ExternalResourcesRequired + { + get + { + return _externalResourcesRequired.ExternalResourcesRequired; + } + } + + #endregion + + #region ISvgTests Members + + public ISvgStringList RequiredFeatures + { + get { return _svgTests.RequiredFeatures; } + } + + public ISvgStringList RequiredExtensions + { + get { return _svgTests.RequiredExtensions; } + } + + public ISvgStringList SystemLanguage + { + get { return _svgTests.SystemLanguage; } + } + + public bool HasExtension(string extension) + { + return _svgTests.HasExtension(extension); + } + + #endregion + } +} diff --git a/Source/SharpVectorModel/ClippingMaskingCompositing/SvgMaskElement.cs b/Source/SharpVectorModel/ClippingMasking/SvgMaskElement.cs similarity index 95% rename from Source/SharpVectorModel/ClippingMaskingCompositing/SvgMaskElement.cs rename to Source/SharpVectorModel/ClippingMasking/SvgMaskElement.cs index bbf90d572..3953ca95f 100644 --- a/Source/SharpVectorModel/ClippingMaskingCompositing/SvgMaskElement.cs +++ b/Source/SharpVectorModel/ClippingMasking/SvgMaskElement.cs @@ -1,186 +1,186 @@ -using System; - -namespace SharpVectors.Dom.Svg -{ - public sealed class SvgMaskElement : SvgStyleableElement, ISvgMaskElement - { - #region Private Fields - - private ISvgAnimatedLength _x; - private ISvgAnimatedLength _y; - private ISvgAnimatedLength _width; - private ISvgAnimatedLength _height; - - private ISvgAnimatedEnumeration _maskUnits; - private ISvgAnimatedEnumeration _maskContentUnits; - - private SvgTests _svgTests; - private SvgExternalResourcesRequired _externalResourcesRequired; - - #endregion - - #region Constructors and Destructor - - public SvgMaskElement(string prefix, string localname, string ns, SvgDocument doc) - : base(prefix, localname, ns, doc) - { - _externalResourcesRequired = new SvgExternalResourcesRequired(this); - _svgTests = new SvgTests(this); - } - - #endregion - - #region ISvgElement Members - - /// - /// Gets a value indicating whether this SVG element is renderable. - /// - /// - /// This is if the element is renderable; otherwise, - /// it is . - /// - public override bool IsRenderable - { - get - { - return false; - } - } - - /// - /// Gets a value providing a hint on the rendering defined by this element. - /// - /// - /// An enumeration of the specifying the rendering hint. - /// This will always return - /// - public override SvgRenderingHint RenderingHint - { - get - { - return SvgRenderingHint.Masking; - } - } - - #endregion - - #region ISvgMaskElement Members - - public ISvgAnimatedEnumeration MaskUnits - { - get - { - if (_maskUnits == null) - { - SvgUnitType mask = SvgUnitType.ObjectBoundingBox; - if (GetAttribute("maskUnits") == "userSpaceOnUse") - mask = SvgUnitType.UserSpaceOnUse; - - _maskUnits = new SvgAnimatedEnumeration((ushort)mask); - } - return _maskUnits; - } - } - - public ISvgAnimatedEnumeration MaskContentUnits - { - get - { - if(_maskContentUnits == null) - { - SvgUnitType maskContent = SvgUnitType.UserSpaceOnUse; - if (GetAttribute("maskContentUnits") == "objectBoundingBox") - maskContent = SvgUnitType.ObjectBoundingBox; - _maskContentUnits = new SvgAnimatedEnumeration((ushort)maskContent); - } - return _maskContentUnits; - } - } - - public ISvgAnimatedLength X - { - get - { - if (_x == null) - { - _x = new SvgAnimatedLength(this, "x", SvgLengthDirection.Horizontal, "-10%"); - } - return _x; - } - } - - public ISvgAnimatedLength Y - { - get - { - if(_y == null) - { - _y = new SvgAnimatedLength(this, "y", SvgLengthDirection.Vertical, "-10%"); - } - return _y; - } - } - - public ISvgAnimatedLength Width - { - get - { - if (_width == null) - { - _width = new SvgAnimatedLength(this, "width", SvgLengthDirection.Viewport, "120%"); - } - return _width; - } - } - - public ISvgAnimatedLength Height - { - get - { - if (_height == null) - { - _height = new SvgAnimatedLength(this, "height", SvgLengthDirection.Viewport, "120%"); - } - return _height; - } - } - - #endregion - - #region ISvgExternalResourcesRequired Members - - public ISvgAnimatedBoolean ExternalResourcesRequired - { - get - { - return _externalResourcesRequired.ExternalResourcesRequired; - } - } - - #endregion - - #region ISvgTests Members - - public ISvgStringList RequiredFeatures - { - get { return _svgTests.RequiredFeatures; } - } - - public ISvgStringList RequiredExtensions - { - get { return _svgTests.RequiredExtensions; } - } - - public ISvgStringList SystemLanguage - { - get { return _svgTests.SystemLanguage; } - } - - public bool HasExtension(string extension) - { - return _svgTests.HasExtension(extension); - } - - #endregion - } -} +using System; + +namespace SharpVectors.Dom.Svg +{ + public sealed class SvgMaskElement : SvgStyleableElement, ISvgMaskElement + { + #region Private Fields + + private ISvgAnimatedLength _x; + private ISvgAnimatedLength _y; + private ISvgAnimatedLength _width; + private ISvgAnimatedLength _height; + + private ISvgAnimatedEnumeration _maskUnits; + private ISvgAnimatedEnumeration _maskContentUnits; + + private SvgTests _svgTests; + private SvgExternalResourcesRequired _externalResourcesRequired; + + #endregion + + #region Constructors and Destructor + + public SvgMaskElement(string prefix, string localname, string ns, SvgDocument doc) + : base(prefix, localname, ns, doc) + { + _externalResourcesRequired = new SvgExternalResourcesRequired(this); + _svgTests = new SvgTests(this); + } + + #endregion + + #region ISvgElement Members + + /// + /// Gets a value indicating whether this SVG element is renderable. + /// + /// + /// This is if the element is renderable; otherwise, + /// it is . + /// + public override bool IsRenderable + { + get + { + return false; + } + } + + /// + /// Gets a value providing a hint on the rendering defined by this element. + /// + /// + /// An enumeration of the specifying the rendering hint. + /// This will always return + /// + public override SvgRenderingHint RenderingHint + { + get + { + return SvgRenderingHint.Masking; + } + } + + #endregion + + #region ISvgMaskElement Members + + public ISvgAnimatedEnumeration MaskUnits + { + get + { + if (_maskUnits == null) + { + SvgUnitType mask = SvgUnitType.ObjectBoundingBox; + if (GetAttribute("maskUnits") == "userSpaceOnUse") + mask = SvgUnitType.UserSpaceOnUse; + + _maskUnits = new SvgAnimatedEnumeration((ushort)mask); + } + return _maskUnits; + } + } + + public ISvgAnimatedEnumeration MaskContentUnits + { + get + { + if(_maskContentUnits == null) + { + SvgUnitType maskContent = SvgUnitType.UserSpaceOnUse; + if (GetAttribute("maskContentUnits") == "objectBoundingBox") + maskContent = SvgUnitType.ObjectBoundingBox; + _maskContentUnits = new SvgAnimatedEnumeration((ushort)maskContent); + } + return _maskContentUnits; + } + } + + public ISvgAnimatedLength X + { + get + { + if (_x == null) + { + _x = new SvgAnimatedLength(this, "x", SvgLengthDirection.Horizontal, "-10%"); + } + return _x; + } + } + + public ISvgAnimatedLength Y + { + get + { + if(_y == null) + { + _y = new SvgAnimatedLength(this, "y", SvgLengthDirection.Vertical, "-10%"); + } + return _y; + } + } + + public ISvgAnimatedLength Width + { + get + { + if (_width == null) + { + _width = new SvgAnimatedLength(this, "width", SvgLengthDirection.Viewport, "120%"); + } + return _width; + } + } + + public ISvgAnimatedLength Height + { + get + { + if (_height == null) + { + _height = new SvgAnimatedLength(this, "height", SvgLengthDirection.Viewport, "120%"); + } + return _height; + } + } + + #endregion + + #region ISvgExternalResourcesRequired Members + + public ISvgAnimatedBoolean ExternalResourcesRequired + { + get + { + return _externalResourcesRequired.ExternalResourcesRequired; + } + } + + #endregion + + #region ISvgTests Members + + public ISvgStringList RequiredFeatures + { + get { return _svgTests.RequiredFeatures; } + } + + public ISvgStringList RequiredExtensions + { + get { return _svgTests.RequiredExtensions; } + } + + public ISvgStringList SystemLanguage + { + get { return _svgTests.SystemLanguage; } + } + + public bool HasExtension(string extension) + { + return _svgTests.HasExtension(extension); + } + + #endregion + } +} diff --git a/Source/SharpVectorModel/Diagrams/SvgTextContentElements.cd b/Source/SharpVectorModel/Diagrams/SvgTextContentElements.cd index da0aba960..32ae72e72 100644 --- a/Source/SharpVectorModel/Diagrams/SvgTextContentElements.cd +++ b/Source/SharpVectorModel/Diagrams/SvgTextContentElements.cd @@ -3,8 +3,8 @@ - ACEAAAAFCBAAoCAIACEgQABAQAABAABgAAoARAEFgAQ= - Dom\Svg\Text\SvgTextContentElement.cs + ACEAEIAFCAAAICAAAAUhAABAQAAAAABAAAAARAAEgAQ= + Text\SvgTextContentElement.cs @@ -12,39 +12,47 @@ AAAEAAAAAAAAAAgAAAAAAAAAEAAAAAAAAAAAAAAAYAA= - Dom\Svg\Text\SvgTextPositioningElement.cs + Text\SvgTextPositioningElement.cs - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAA= - Dom\Svg\Text\SvgTextElement.cs + AIAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAABAAAAAA= + Text\SvgTextElement.cs - AAAAAAAAAAAAAAAIAAAAIAAAAAAAAABAABAAAAABAAA= - Dom\Svg\Text\SvgTRefElement.cs + AAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAABAAAAAAAAA= + Text\SvgTRefElement.cs - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= - Dom\Svg\Text\SvgTSpanElement.cs + AIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + Text\SvgTSpanElement.cs + + + + AIAAQAAAAAAAAAAAAAAgAAAAAEAAAABAABAABAAAgAA= + Text\SvgTextPathElement.cs + + + AAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBA= - Dom\Svg\Text\SvgTextContentElement.cs + Text\SvgTextContentElement.cs diff --git a/Source/SharpVectorModel/DocumentStructure/SvgDocument.cs b/Source/SharpVectorModel/DocumentStructure/SvgDocument.cs index 191e4ab5e..4b68a2295 100644 --- a/Source/SharpVectorModel/DocumentStructure/SvgDocument.cs +++ b/Source/SharpVectorModel/DocumentStructure/SvgDocument.cs @@ -387,7 +387,6 @@ public override void Load(string filename) this.Load(zipStream); } } - return; } } @@ -610,10 +609,9 @@ private string OnXmlResolverResolving(string relativeUri) /// private XmlParserContext GetXmlParserContext() { - DynamicXmlNamespaceManager xmlNamespaceManager = new DynamicXmlNamespaceManager(new NameTable()); + var xmlNamespaceManager = new DynamicXmlNamespaceManager(new NameTable()); xmlNamespaceManager.Resolve += OnResolveXmlNamespaceManager; - XmlParserContext xmlParserContext = new XmlParserContext(null, - xmlNamespaceManager, null, XmlSpace.None); + XmlParserContext xmlParserContext = new XmlParserContext(null, xmlNamespaceManager, null, XmlSpace.None); return xmlParserContext; } @@ -628,9 +626,9 @@ private string OnResolveXmlNamespaceManager(string prefix) string uri = null; if (this.ResolveNamespace != null) { - SvgResolveNamespaceEventArgs e = new SvgResolveNamespaceEventArgs(prefix); - ResolveNamespace(this, e); - uri = e.Uri; + var evtArgs = new SvgResolveNamespaceEventArgs(prefix); + ResolveNamespace(this, evtArgs); + uri = evtArgs.Uri; } if (string.IsNullOrWhiteSpace(uri)) { @@ -704,11 +702,8 @@ private XmlReader CreateValidatingXmlReader(string uri, Stream stream) { return XmlReader.Create(stream, xmlReaderSettings, uri); } - else - { - XmlParserContext xmlParserContext = GetXmlParserContext(); - return XmlReader.Create(stream, xmlReaderSettings, xmlParserContext); - } + XmlParserContext xmlParserContext = GetXmlParserContext(); + return XmlReader.Create(stream, xmlReaderSettings, xmlParserContext); } /// @@ -739,68 +734,66 @@ public XmlNode GetNodeByUri(string absoluteUrl) { return GetElementById(absoluteUrl.Substring(1)); } - else - { - Uri docUri = ResolveUri(""); - Uri absoluteUri = new Uri(absoluteUrl); - if (absoluteUri.IsFile) + Uri docUri = ResolveUri(""); + Uri absoluteUri = new Uri(absoluteUrl); + + if (absoluteUri.IsFile) + { + string localFile = absoluteUri.LocalPath; + if (File.Exists(localFile) == false) { - string localFile = absoluteUri.LocalPath; - if (File.Exists(localFile) == false) - { - Trace.TraceError("GetNodeByUri: Locally referenced file not found: " + localFile); - return null; - } - string fileExt = Path.GetExtension(localFile); - if (!string.Equals(fileExt, ".svg", StringComparison.OrdinalIgnoreCase) - && !string.Equals(fileExt, ".svgz", StringComparison.OrdinalIgnoreCase)) - { - Trace.TraceError("GetNodeByUri: Locally referenced file not valid: " + localFile); - return null; - } + Trace.TraceError("GetNodeByUri: Locally referenced file not found: " + localFile); + return null; } - - if (string.Equals(absoluteUri.Scheme, "data", StringComparison.OrdinalIgnoreCase)) + string fileExt = Path.GetExtension(localFile); + if (!string.Equals(fileExt, ".svg", StringComparison.OrdinalIgnoreCase) + && !string.Equals(fileExt, ".svgz", StringComparison.OrdinalIgnoreCase)) { - Trace.TraceError("GetNodeByUri: The Uri Scheme is 'data' is not a valid XmlDode " + absoluteUri); + Trace.TraceError("GetNodeByUri: Locally referenced file not valid: " + localFile); return null; } + } + + if (string.Equals(absoluteUri.Scheme, "data", StringComparison.OrdinalIgnoreCase)) + { + Trace.TraceError("GetNodeByUri: The Uri Scheme is 'data' is not a valid XmlDode " + absoluteUri); + return null; + } - string fragment = absoluteUri.Fragment; + string fragment = absoluteUri.Fragment; - if (fragment.Length == 0) + if (fragment.Length == 0) + { + // no fragment => return entire document + if (docUri != null && string.Equals(docUri.AbsolutePath, + absoluteUri.AbsolutePath, StringComparison.OrdinalIgnoreCase)) { - // no fragment => return entire document - if (docUri != null && docUri.AbsolutePath == absoluteUri.AbsolutePath) - { - return this; - } - - SvgDocument doc = new SvgDocument((SvgWindow)Window); + return this; + } - XmlReaderSettings settings = this.GetXmlReaderSettings(); + SvgDocument doc = new SvgDocument((SvgWindow)Window); - settings.CloseInput = true; + XmlReaderSettings settings = this.GetXmlReaderSettings(); - //PrepareXmlResolver(settings); + settings.CloseInput = true; - using (XmlReader reader = XmlReader.Create( - GetResource(absoluteUri).GetResponseStream(), settings, - absoluteUri.AbsolutePath)) - { - doc.Load(reader); - } + //PrepareXmlResolver(settings); - return doc; - } - else + using (XmlReader reader = XmlReader.Create(GetResource(absoluteUri).GetResponseStream(), + settings, absoluteUri.AbsolutePath)) { - // got a fragment => return XmlElement - string noFragment = absoluteUri.AbsoluteUri.Replace(fragment, ""); - SvgDocument doc = (SvgDocument)GetNodeByUri(new Uri(noFragment)); - return doc.GetElementById(fragment.Substring(1)); + doc.Load(reader); } + + return doc; + } + else + { + // got a fragment => return XmlElement + string noFragment = absoluteUri.AbsoluteUri.Replace(fragment, ""); + SvgDocument doc = (SvgDocument)GetNodeByUri(new Uri(noFragment)); + return doc.GetElementById(fragment.Substring(1)); } } @@ -1150,7 +1143,8 @@ protected virtual IList> GetFontUrls() return fontUrls; } - private static void GetFontUrl(CssStyleSheet cssSheet, IList> fontUrls, IDictionary styledFontIds) + private static void GetFontUrl(CssStyleSheet cssSheet, IList> fontUrls, + IDictionary styledFontIds) { if (cssSheet == null || fontUrls == null) { @@ -1208,7 +1202,7 @@ protected override void OnLoaded() _isFontsLoaded = false; //TODO: Trying a background run... - Task.Factory.StartNew(() => { + var loadTask = Task.Factory.StartNew(() => { SvgWindow ownedWindow = _window.CreateOwnedWindow(); ownedWindow.LoadFonts = false; @@ -1238,7 +1232,7 @@ protected override void OnLoaded() } else { - //TODO + throw new NotSupportedException("Loading fonts from a remote source is not supported."); } } catch (Exception ex) @@ -1250,12 +1244,15 @@ protected override void OnLoaded() _isFontsLoaded = true; }); + + _window.AddTask("SvgDocument", loadTask); } private void LoadLocalFont(string fontPath, SvgWindow ownedWindow, SvgFontFaceElement fontFace) { if (string.IsNullOrWhiteSpace(fontPath) || !File.Exists(fontPath)) { +// Trace.WriteLine("Private font not found: " + fontPath); return; } @@ -1289,6 +1286,12 @@ private void LoadLocalFont(string fontPath, SvgWindow ownedWindow, SvgFontFaceEl else if (string.Equals(fileExt, ".ttf", StringComparison.OrdinalIgnoreCase) || string.Equals(fileExt, ".otf", StringComparison.OrdinalIgnoreCase)) { + Debug.Assert(false, "Testing files with this format"); + } + else if (string.Equals(fileExt, ".woff", StringComparison.OrdinalIgnoreCase) + || string.Equals(fileExt, ".woff2", StringComparison.OrdinalIgnoreCase)) + { + Debug.Assert(false, "Testing files with this format"); } } diff --git a/Source/SharpVectorModel/DocumentStructure/SvgElementFactory.cs b/Source/SharpVectorModel/DocumentStructure/SvgElementFactory.cs index 68653451d..7575f1532 100644 --- a/Source/SharpVectorModel/DocumentStructure/SvgElementFactory.cs +++ b/Source/SharpVectorModel/DocumentStructure/SvgElementFactory.cs @@ -67,6 +67,8 @@ public static XmlElement Create(string prefix, string localName, string ns, SvgD return new SvgSymbolElement(prefix, localName, ns, doc); case "text": return new SvgTextElement(prefix, localName, ns, doc); + case "textArea": + return new SvgTextAreaElement(prefix, localName, ns, doc); case "textPath": return new SvgTextPathElement(prefix, localName, ns, doc); case "title": diff --git a/Source/SharpVectorModel/DocumentStructure/SvgWindow.cs b/Source/SharpVectorModel/DocumentStructure/SvgWindow.cs index cf0304d63..1c71ee73f 100644 --- a/Source/SharpVectorModel/DocumentStructure/SvgWindow.cs +++ b/Source/SharpVectorModel/DocumentStructure/SvgWindow.cs @@ -1,6 +1,8 @@ using System; using System.IO; using System.Xml; +using System.Threading.Tasks; +using System.Collections.Generic; using SharpVectors.Dom.Stylesheets; @@ -10,6 +12,8 @@ public abstract class SvgWindow : ISvgWindow { #region Private fields + protected IDictionary> _mappedTasks; + private bool _loadFonts; private long _innerWidth; @@ -19,12 +23,15 @@ public abstract class SvgWindow : ISvgWindow private ISvgRenderer _renderer; + private object _synchObject; + #endregion #region Contructors and Destructor private SvgWindow() { + _synchObject = new object(); } protected SvgWindow(long innerWidth, long innerHeight, ISvgRenderer renderer) @@ -93,6 +100,60 @@ public SvgDocument CreateEmptySvgDocument() return _document = new SvgDocument(this); } + public void AddTask(string tasksName, Task task) + { + if (string.IsNullOrWhiteSpace(tasksName) || task == null) + { + return; + } + lock (_synchObject) + { + if (_mappedTasks == null) + { + _mappedTasks = new Dictionary>(StringComparer.OrdinalIgnoreCase); + } + if (_mappedTasks.ContainsKey(tasksName)) + { + var namedTasks = _mappedTasks[tasksName]; + if (namedTasks == null) + { + namedTasks = new List(); + } + namedTasks.Add(task); + } + else + { + var namedTasks = new List(); + namedTasks.Add(task); + + _mappedTasks.Add(tasksName, namedTasks); + } + } + } + + public void AwaitTasks(string tasksName) + { + lock (_synchObject) + { + if (string.IsNullOrWhiteSpace(tasksName) || _mappedTasks == null || _mappedTasks.Count == 0) + { + return; + } + if (_mappedTasks.ContainsKey(tasksName)) + { + var namedTasks = _mappedTasks[tasksName]; + if (namedTasks == null || namedTasks.Count == 0) + { + return; + } + + Task.WaitAll(namedTasks.ToArray()); + + _mappedTasks.Remove(tasksName); + } + } + } + #endregion #region ISvgWindow Members diff --git a/Source/SharpVectorModel/SharpVectors.Model.csproj b/Source/SharpVectorModel/SharpVectors.Model.csproj index a874747ea..2b7c023cc 100644 --- a/Source/SharpVectorModel/SharpVectors.Model.csproj +++ b/Source/SharpVectorModel/SharpVectors.Model.csproj @@ -123,6 +123,8 @@ + + @@ -240,12 +242,6 @@ Code - - Code - - - Code - Code @@ -447,10 +443,12 @@ + Code - + + Code diff --git a/Source/SharpVectorModel/Text/SvgAltGlyphElement.cs b/Source/SharpVectorModel/Text/SvgAltGlyphElement.cs index 7247306c8..fddf565a7 100644 --- a/Source/SharpVectorModel/Text/SvgAltGlyphElement.cs +++ b/Source/SharpVectorModel/Text/SvgAltGlyphElement.cs @@ -1,8 +1,5 @@ using System; using System.Xml; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace SharpVectors.Dom.Svg { diff --git a/Source/SharpVectorModel/Text/SvgFontFaceFormatElement.cs b/Source/SharpVectorModel/Text/SvgFontFaceFormatElement.cs index cbb9e4056..8c7a49b7e 100644 --- a/Source/SharpVectorModel/Text/SvgFontFaceFormatElement.cs +++ b/Source/SharpVectorModel/Text/SvgFontFaceFormatElement.cs @@ -1,4 +1,6 @@ -namespace SharpVectors.Dom.Svg +using System; + +namespace SharpVectors.Dom.Svg { /// /// The SvgFontFaceFormatElement interface corresponds to the 'font-face-format' element. diff --git a/Source/SharpVectorModel/Text/SvgFontFaceNameElement.cs b/Source/SharpVectorModel/Text/SvgFontFaceNameElement.cs index 06dc5dfca..88d6f8510 100644 --- a/Source/SharpVectorModel/Text/SvgFontFaceNameElement.cs +++ b/Source/SharpVectorModel/Text/SvgFontFaceNameElement.cs @@ -1,4 +1,6 @@ -namespace SharpVectors.Dom.Svg +using System; + +namespace SharpVectors.Dom.Svg { /// /// The SvgFontFaceNameElement interface corresponds to the 'font-face-name' element. diff --git a/Source/SharpVectorModel/Text/SvgFontFaceUriElement.cs b/Source/SharpVectorModel/Text/SvgFontFaceUriElement.cs index 69d78b993..074ec06bb 100644 --- a/Source/SharpVectorModel/Text/SvgFontFaceUriElement.cs +++ b/Source/SharpVectorModel/Text/SvgFontFaceUriElement.cs @@ -1,4 +1,6 @@ -namespace SharpVectors.Dom.Svg +using System; + +namespace SharpVectors.Dom.Svg { /// /// The SvgFontFaceUriElement interface corresponds to the 'font-face-uri' element. diff --git a/Source/SharpVectorModel/Text/SvgGlyphRefElement.cs b/Source/SharpVectorModel/Text/SvgGlyphRefElement.cs index cbab01c3a..83ff98fee 100644 --- a/Source/SharpVectorModel/Text/SvgGlyphRefElement.cs +++ b/Source/SharpVectorModel/Text/SvgGlyphRefElement.cs @@ -1,4 +1,5 @@ -using System.Xml; +using System; +using System.Xml; namespace SharpVectors.Dom.Svg { diff --git a/Source/SharpVectorModel/Text/SvgHKernElement.cs b/Source/SharpVectorModel/Text/SvgHKernElement.cs index 261fc6710..2ad255d8e 100644 --- a/Source/SharpVectorModel/Text/SvgHKernElement.cs +++ b/Source/SharpVectorModel/Text/SvgHKernElement.cs @@ -1,4 +1,6 @@ -namespace SharpVectors.Dom.Svg +using System; + +namespace SharpVectors.Dom.Svg { /// /// The SvgHKernElement interface corresponds to the 'hkern' element. diff --git a/Source/SharpVectorModel/Text/SvgKernElement.cs b/Source/SharpVectorModel/Text/SvgKernElement.cs index 0eca6e8a1..e4d28922f 100644 --- a/Source/SharpVectorModel/Text/SvgKernElement.cs +++ b/Source/SharpVectorModel/Text/SvgKernElement.cs @@ -1,7 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace SharpVectors.Dom.Svg { diff --git a/Source/SharpVectorModel/Text/SvgMissingGlyphElement.cs b/Source/SharpVectorModel/Text/SvgMissingGlyphElement.cs index d455982e1..4b005ed9f 100644 --- a/Source/SharpVectorModel/Text/SvgMissingGlyphElement.cs +++ b/Source/SharpVectorModel/Text/SvgMissingGlyphElement.cs @@ -1,4 +1,6 @@ -namespace SharpVectors.Dom.Svg +using System; + +namespace SharpVectors.Dom.Svg { /// /// The SvgMissingGlyphElement interface corresponds to the 'missing-glyph' element. diff --git a/Source/SharpVectorModel/Text/SvgTextAreaElement.cs b/Source/SharpVectorModel/Text/SvgTextAreaElement.cs new file mode 100644 index 000000000..95328d539 --- /dev/null +++ b/Source/SharpVectorModel/Text/SvgTextAreaElement.cs @@ -0,0 +1,15 @@ +using System; + +namespace SharpVectors.Dom.Svg +{ + /// + /// Summary description for SvgTextAreaElement. + /// + public sealed class SvgTextAreaElement : SvgTextBaseElement, ISvgTextElement + { + public SvgTextAreaElement(string prefix, string localname, string ns, SvgDocument doc) + : base(prefix, localname, ns, doc) + { + } + } +} diff --git a/Source/SharpVectorModel/Text/SvgTextBaseElement.cs b/Source/SharpVectorModel/Text/SvgTextBaseElement.cs new file mode 100644 index 000000000..4f1996cb4 --- /dev/null +++ b/Source/SharpVectorModel/Text/SvgTextBaseElement.cs @@ -0,0 +1,38 @@ +using System; + +namespace SharpVectors.Dom.Svg +{ + /// + /// Summary description for SvgTextElement. + /// + public abstract class SvgTextBaseElement : SvgTextPositioningElement, ISvgTextElement + { + protected SvgTextBaseElement(string prefix, string localname, string ns, SvgDocument doc) + : base(prefix, localname, ns, doc) + { + } + + public override ISvgAnimatedLength LetterSpacing + { + get { + return new SvgAnimatedLength(this, "letter-spacing", SvgLengthDirection.Horizontal, "0"); + } + } + + public override ISvgAnimatedLength TextLength + { + get { + return new SvgAnimatedLength(this, "textLength", SvgLengthDirection.Horizontal, "0"); + } + } + + #region Implementation of IElementVisitorTarget + + public void Accept(IElementVisitor visitor) + { + visitor.Visit(this); + } + + #endregion + } +} diff --git a/Source/SharpVectorModel/Text/SvgTextContentElement.cs b/Source/SharpVectorModel/Text/SvgTextContentElement.cs index 830c22dbd..01dbda846 100644 --- a/Source/SharpVectorModel/Text/SvgTextContentElement.cs +++ b/Source/SharpVectorModel/Text/SvgTextContentElement.cs @@ -102,13 +102,13 @@ public virtual ISvgAnimatedEnumeration LengthAdjust get { throw new NotImplementedException(); } } - protected SvgTextElement OwnerTextElement + protected SvgTextBaseElement OwnerTextElement { get { XmlNode node = this; while (node != null) { - SvgTextElement text = node as SvgTextElement; + SvgTextBaseElement text = node as SvgTextBaseElement; if (text != null) { return text; diff --git a/Source/SharpVectorModel/Text/SvgTextElement.cs b/Source/SharpVectorModel/Text/SvgTextElement.cs index fbdd35599..b08b70638 100644 --- a/Source/SharpVectorModel/Text/SvgTextElement.cs +++ b/Source/SharpVectorModel/Text/SvgTextElement.cs @@ -5,35 +5,11 @@ namespace SharpVectors.Dom.Svg /// /// Summary description for SvgTextElement. /// - public sealed class SvgTextElement : SvgTextPositioningElement, ISvgTextElement + public sealed class SvgTextElement : SvgTextBaseElement, ISvgTextElement { public SvgTextElement(string prefix, string localname, string ns, SvgDocument doc) : base(prefix, localname, ns, doc) { } - - - public override ISvgAnimatedLength LetterSpacing - { - get { - return new SvgAnimatedLength(this, "letter-spacing", SvgLengthDirection.Horizontal, "0"); - } - } - - public override ISvgAnimatedLength TextLength - { - get { - return new SvgAnimatedLength(this, "textLength", SvgLengthDirection.Horizontal, "0"); - } - } - - #region Implementation of IElementVisitorTarget - - public void Accept(IElementVisitor visitor) - { - visitor.Visit(this); - } - - #endregion } } diff --git a/Source/SharpVectorModel/Text/SvgVKernElement.cs b/Source/SharpVectorModel/Text/SvgVKernElement.cs index c177758f8..09a631de3 100644 --- a/Source/SharpVectorModel/Text/SvgVKernElement.cs +++ b/Source/SharpVectorModel/Text/SvgVKernElement.cs @@ -1,4 +1,6 @@ -namespace SharpVectors.Dom.Svg +using System; + +namespace SharpVectors.Dom.Svg { /// /// The SvgVKernElement interface corresponds to the 'vkern' element. diff --git a/Source/SharpVectorRenderingGdi/Gdi/GdiTextRendering.cs b/Source/SharpVectorRenderingGdi/Gdi/GdiTextRendering.cs index fe59f2792..a371a4746 100644 --- a/Source/SharpVectorRenderingGdi/Gdi/GdiTextRendering.cs +++ b/Source/SharpVectorRenderingGdi/Gdi/GdiTextRendering.cs @@ -118,7 +118,7 @@ public override void Render(GdiGraphicsRenderer renderer) // return; //} - SvgTextElement textElement = _svgElement as SvgTextElement; + SvgTextBaseElement textElement = _svgElement as SvgTextBaseElement; if (textElement == null) { return; @@ -373,7 +373,7 @@ private void AddTSpanElementPath(SvgTSpanElement element, ref PointF ctp) if (sBaselineShift.Length > 0) { - SvgTextElement textElement = (SvgTextElement)element.SelectSingleNode("ancestor::svg:text", + SvgTextBaseElement textElement = (SvgTextBaseElement)element.SelectSingleNode("ancestor::svg:text", element.OwnerDocument.NamespaceManager); float textFontSize = GetComputedFontSize(textElement); diff --git a/Source/SharpVectorRenderingWpf/Texts/WpfHorzTextRenderer.cs b/Source/SharpVectorRenderingWpf/Texts/WpfHorzTextRenderer.cs index ddbe9164c..ae385dfe2 100644 --- a/Source/SharpVectorRenderingWpf/Texts/WpfHorzTextRenderer.cs +++ b/Source/SharpVectorRenderingWpf/Texts/WpfHorzTextRenderer.cs @@ -17,7 +17,7 @@ public sealed class WpfHorzTextRenderer : WpfTextRenderer #region Constructors and Destructor - public WpfHorzTextRenderer(SvgTextElement textElement, WpfTextRendering textRendering) + public WpfHorzTextRenderer(SvgTextBaseElement textElement, WpfTextRendering textRendering) : base(textElement, textRendering) { } @@ -371,7 +371,7 @@ public override void RenderTextRun(SvgTextContentElement element, ref Point ctp, TextDecorationCollection textDecors = GetTextDecoration(element); if (textDecors == null) { - SvgTextElement textElement = element.ParentNode as SvgTextElement; + SvgTextBaseElement textElement = element.ParentNode as SvgTextBaseElement; if (textElement != null) { @@ -911,7 +911,7 @@ private void RenderTextRun(WpfTextTuple textInfo, ref Point ctp, TextDecorationCollection textDecors = GetTextDecoration(element); if (textDecors == null) { - SvgTextElement textElement = element.ParentNode as SvgTextElement; + SvgTextBaseElement textElement = element.ParentNode as SvgTextBaseElement; if (textElement != null) { diff --git a/Source/SharpVectorRenderingWpf/Texts/WpfPathTextBuilder.cs b/Source/SharpVectorRenderingWpf/Texts/WpfPathTextBuilder.cs index 497cd5aab..200daaae5 100644 --- a/Source/SharpVectorRenderingWpf/Texts/WpfPathTextBuilder.cs +++ b/Source/SharpVectorRenderingWpf/Texts/WpfPathTextBuilder.cs @@ -24,7 +24,7 @@ public sealed class WpfPathTextBuilder private IList _pathChars; - private SvgTextElement _textElement; + private SvgTextBaseElement _textElement; private SvgTextPathElement _textPathElement; private IList _pathTextRuns; @@ -33,7 +33,7 @@ public sealed class WpfPathTextBuilder #region Constructors and Destructor - public WpfPathTextBuilder(SvgTextElement textElement) + public WpfPathTextBuilder(SvgTextBaseElement textElement) { _textElement = textElement; _pathChars = new List(); diff --git a/Source/SharpVectorRenderingWpf/Texts/WpfPathTextRenderer.cs b/Source/SharpVectorRenderingWpf/Texts/WpfPathTextRenderer.cs index c2db5517e..c530f2de5 100644 --- a/Source/SharpVectorRenderingWpf/Texts/WpfPathTextRenderer.cs +++ b/Source/SharpVectorRenderingWpf/Texts/WpfPathTextRenderer.cs @@ -17,7 +17,7 @@ public sealed class WpfPathTextRenderer : WpfTextRenderer #region Constructors and Destructor - public WpfPathTextRenderer(SvgTextElement textElement, WpfTextRendering textRendering) + public WpfPathTextRenderer(SvgTextBaseElement textElement, WpfTextRendering textRendering) : base(textElement, textRendering) { } @@ -194,7 +194,7 @@ private void RenderTSpanPath(SvgTSpanElement element, WpfPathTextBuilder pathBui if (sBaselineShift.Length > 0) { - SvgTextElement textElement = (SvgTextElement)element.SelectSingleNode("ancestor::svg:text", + SvgTextBaseElement textElement = (SvgTextBaseElement)element.SelectSingleNode("ancestor::svg:text", element.OwnerDocument.NamespaceManager); double textFontSize = GetComputedFontSize(textElement); diff --git a/Source/SharpVectorRenderingWpf/Texts/WpfPathTextRun.cs b/Source/SharpVectorRenderingWpf/Texts/WpfPathTextRun.cs index 1222ccf3a..9bf5ac5eb 100644 --- a/Source/SharpVectorRenderingWpf/Texts/WpfPathTextRun.cs +++ b/Source/SharpVectorRenderingWpf/Texts/WpfPathTextRun.cs @@ -105,7 +105,7 @@ public void Initialize(string text, Brush brush, Pen pen) } } - public void SetPosition(Point pos, SvgTextPathElement pathElement, SvgTextElement textElement) + public void SetPosition(Point pos, SvgTextPathElement pathElement, SvgTextBaseElement textElement) { _contentPos = pos; _startOffset = this.GetStartOffset(pathElement, textElement); @@ -148,7 +148,7 @@ public void UnInitialize() #region Private Methods - private ISvgAnimatedLength GetStartOffset(SvgTextPathElement pathElement, SvgTextElement textElement) + private ISvgAnimatedLength GetStartOffset(SvgTextPathElement pathElement, SvgTextBaseElement textElement) { ISvgAnimatedLength pathOffset = pathElement.StartOffset; if (pathOffset != null && pathOffset.AnimVal != null) @@ -170,7 +170,7 @@ private ISvgAnimatedLength GetStartOffset(SvgTextPathElement pathElement, SvgTex return this.GetStartOffset(textElement); } - private ISvgAnimatedLength GetStartOffset(SvgTextElement textElement) + private ISvgAnimatedLength GetStartOffset(SvgTextBaseElement textElement) { ISvgAnimatedLengthList pathOffsets = null; SvgTextPositioningElement posElement = _contentElement as SvgTextPositioningElement; diff --git a/Source/SharpVectorRenderingWpf/Texts/WpfTextContext.cs b/Source/SharpVectorRenderingWpf/Texts/WpfTextContext.cs index b5b15ff4e..54233da92 100644 --- a/Source/SharpVectorRenderingWpf/Texts/WpfTextContext.cs +++ b/Source/SharpVectorRenderingWpf/Texts/WpfTextContext.cs @@ -28,7 +28,7 @@ public sealed class WpfTextContext private Point _positioningEnd; private SvgTextContentElement _positioningElement; - private SvgTextElement _textElement; + private SvgTextBaseElement _textElement; private WpfTextRendering _textRendering; private CultureInfo _culture; @@ -39,7 +39,7 @@ public sealed class WpfTextContext #region Constructors and Destructor - public WpfTextContext(SvgTextElement textElement, WpfTextRendering textRendering) + public WpfTextContext(SvgTextBaseElement textElement, WpfTextRendering textRendering) { if (textRendering == null) { @@ -55,7 +55,7 @@ public WpfTextContext(SvgTextElement textElement, WpfTextRendering textRendering #region Public Properties - public SvgTextElement TextElement + public SvgTextBaseElement TextElement { get { return _textElement; @@ -134,7 +134,7 @@ public CultureInfo Culture #region Public Methods - public void SetElement(SvgTextElement textElement) + public void SetElement(SvgTextBaseElement textElement) { if (textElement == null) { diff --git a/Source/SharpVectorRenderingWpf/Texts/WpfTextRenderer.cs b/Source/SharpVectorRenderingWpf/Texts/WpfTextRenderer.cs index f5dc61469..1dd32a270 100644 --- a/Source/SharpVectorRenderingWpf/Texts/WpfTextRenderer.cs +++ b/Source/SharpVectorRenderingWpf/Texts/WpfTextRenderer.cs @@ -32,7 +32,7 @@ public abstract class WpfTextRenderer : WpfRendererObject protected string _actualFontName; protected DrawingContext _drawContext; - protected SvgTextElement _textElement; + protected SvgTextBaseElement _textElement; protected WpfTextRendering _textRendering; @@ -40,7 +40,7 @@ public abstract class WpfTextRenderer : WpfRendererObject #region Constructors and Destructor - protected WpfTextRenderer(SvgTextElement textElement, WpfTextRendering textRendering) + protected WpfTextRenderer(SvgTextBaseElement textElement, WpfTextRendering textRendering) { if (textElement == null) { @@ -75,7 +75,7 @@ public DrawingContext DrawContext } } - public SvgTextElement TextElement + public SvgTextBaseElement TextElement { get { return _textElement; @@ -158,7 +158,7 @@ protected WpfTextContext TextContext #region Public Methods - public virtual void SetElement(SvgTextElement textElement) + public virtual void SetElement(SvgTextBaseElement textElement) { _drawContext = null; _context = null; @@ -202,6 +202,28 @@ public static string TrimText(SvgTextContentElement element, string val) val = val.Replace("\n", string.Empty); val = _tabNewline.Replace(val, " "); + var textTransform = element.GetPropertyValue("text-transform"); + if (!string.IsNullOrWhiteSpace(textTransform)) + { + switch (textTransform) + { + case "capitalize": + val = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(val); + break; + case "uppercase": + val = val.ToUpper(CultureInfo.CurrentCulture); + break; + case "lowercase": + val = val.ToLower(CultureInfo.CurrentCulture); + break; + case "full-width": + case "full-size-kana": + case "none": + default: + break; + } + } + //if (element.XmlSpace == "preserve" || element.XmlSpace == "default") if (element.XmlSpace == "preserve") { @@ -1071,7 +1093,7 @@ protected WpfTextStringFormat GetTextStringFormat(SvgTextContentElement element) } else { - SvgTextElement textElement = element.ParentNode as SvgTextElement; + SvgTextBaseElement textElement = element.ParentNode as SvgTextBaseElement; if (textElement != null) { string anchor = textElement.GetPropertyValue("text-anchor"); diff --git a/Source/SharpVectorRenderingWpf/Texts/WpfVertTextRenderer.cs b/Source/SharpVectorRenderingWpf/Texts/WpfVertTextRenderer.cs index 4ea80d9a1..6f59d5209 100644 --- a/Source/SharpVectorRenderingWpf/Texts/WpfVertTextRenderer.cs +++ b/Source/SharpVectorRenderingWpf/Texts/WpfVertTextRenderer.cs @@ -18,7 +18,7 @@ public sealed class WpfVertTextRenderer : WpfTextRenderer #region Constructors and Destructor - public WpfVertTextRenderer(SvgTextElement textElement, WpfTextRendering textRendering) + public WpfVertTextRenderer(SvgTextBaseElement textElement, WpfTextRendering textRendering) : base(textElement, textRendering) { } diff --git a/Source/SharpVectorRenderingWpf/Wpf/WpfSvgRendering.cs b/Source/SharpVectorRenderingWpf/Wpf/WpfSvgRendering.cs index 4ee853d12..2f90d0406 100644 --- a/Source/SharpVectorRenderingWpf/Wpf/WpfSvgRendering.cs +++ b/Source/SharpVectorRenderingWpf/Wpf/WpfSvgRendering.cs @@ -224,8 +224,37 @@ public override void Render(WpfDrawingRenderer renderer) public override void AfterRender(WpfDrawingRenderer renderer) { + this.OnAfterRender(renderer); + base.AfterRender(renderer); + } + + #endregion + + #region Protected Methods + + protected override void Initialize(SvgElement element) + { + base.Initialize(element); + + _isRoot = false; + _isRecursive = false; + + var svgRootElm = element as SvgSvgElement; + if (svgRootElm != null) + { + _isRoot = svgRootElm.IsOuterMost; + } + + _drawGroup = null; + } + + #endregion + + #region Private Methods + private void OnAfterRender(WpfDrawingRenderer renderer) + { Debug.Assert(_drawGroup != null); WpfDrawingContext context = renderer.Context; @@ -339,25 +368,5 @@ private DrawingGroup CreateOuterGroup() } #endregion - - #region Protected Methods - - protected override void Initialize(SvgElement element) - { - base.Initialize(element); - - _isRoot = false; - _isRecursive = false; - - var svgRootElm = element as SvgSvgElement; - if (svgRootElm != null) - { - _isRoot = svgRootElm.IsOuterMost; - } - - _drawGroup = null; - } - - #endregion } } diff --git a/Source/SharpVectorRenderingWpf/Wpf/WpfTextRendering.cs b/Source/SharpVectorRenderingWpf/Wpf/WpfTextRendering.cs index 7cc115ee8..d3544a263 100644 --- a/Source/SharpVectorRenderingWpf/Wpf/WpfTextRendering.cs +++ b/Source/SharpVectorRenderingWpf/Wpf/WpfTextRendering.cs @@ -30,7 +30,7 @@ public sealed class WpfTextRendering : WpfRendering private double _textWidth; - private SvgTextElement _textElement; + private SvgTextBaseElement _textElement; private DrawingGroup _drawGroup; private DrawingContext _drawContext; @@ -48,7 +48,7 @@ public sealed class WpfTextRendering : WpfRendering public WpfTextRendering(SvgElement element) : base(element) { - _textElement = element as SvgTextElement; + _textElement = element as SvgTextBaseElement; if (_textElement == null) { throw new InvalidOperationException(); @@ -275,7 +275,13 @@ public override void Render(WpfDrawingRenderer renderer) if (svgDoc.IsFontsLoaded == false) { //TODO: Use of SpinUntil is known to CPU heavy, but will work for now... - SpinWait.SpinUntil(() => svgDoc.IsFontsLoaded == true); + //SpinWait.SpinUntil(() => svgDoc.IsFontsLoaded == true); + + var svgWnd = svgDoc.Window as SvgWindow; + if (svgWnd != null) + { + svgWnd.AwaitTasks("SvgDocument"); + } } XmlNodeType nodeType = XmlNodeType.None; @@ -742,7 +748,7 @@ protected override void Initialize(SvgElement element) _textWidth = 0; _drawGroup = null; - _textElement = element as SvgTextElement; + _textElement = element as SvgTextBaseElement; if (_textElement == null) { throw new InvalidOperationException();