diff --git a/.github/workflows/build-action.yml b/.github/workflows/build-action.yml new file mode 100644 index 000000000..47d345a3a --- /dev/null +++ b/.github/workflows/build-action.yml @@ -0,0 +1,26 @@ +#Builds on every commit to main. +name: CI Build + +on: + push: + branches: [ features/net60 ] + pull_request: + branches: [ features/net60 ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v2 + with: + dotnet-version: 7.0.x + + - name: Restore dependencies + run: dotnet restore Source/HtmlRenderer.sln + + - name: Debug Build + run: dotnet build Source/HtmlRenderer.sln --no-restore -p:Version=${{ format('0.9.{0}', github.run_number) }} \ No newline at end of file diff --git a/.github/workflows/release-action.yml b/.github/workflows/release-action.yml new file mode 100644 index 000000000..dd99688b0 --- /dev/null +++ b/.github/workflows/release-action.yml @@ -0,0 +1,68 @@ +name: Release + +on: + push: + tags: [ v* ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + #Extract the version from the github tag + - id: version + run: echo "::set-output name=version_str::`echo "${{ github.ref }}" | sed -n 's/.*v\(.*\)/\1/p'`" + + - name: Create release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + body: TODO - Document Changes for Tagged Release + draft: true + prerelease: ${{ contains(steps.version.outputs.version_str, '-') }} + + - name: Setup .NET + uses: actions/setup-dotnet@v2 + with: + dotnet-version: 7.0.x + + - name: Restore dependencies + run: dotnet restore Source/HtmlRenderer.sln + + - name: Release Build + run: dotnet build --no-restore Source/HtmlRenderer.sln -c Release -p:Version=${{ steps.version.outputs.version_str }} + + - name: Pack + run: dotnet pack 'Source/HtmlRenderer.sln' --include-symbols --include-source --no-build -c Release -p:Version=${{ steps.version.outputs.version_str }} -p:SymbolPackageFormat=snupkg -o dist + + - name: Add Nuget Packages as Release Asset + id: upload-release-asset-core + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: dist/ThreeCS.HtmlRenderer.${{ steps.version.outputs.version_str }}.nupkg + asset_name: ThreeCS.HtmlRenderer.${{ steps.version.outputs.version_str }}.nupkg + asset_content_type: application/octet-stream + + - name: Add Skia Nuget Packages as Release Asset + id: upload-release-asset-skia + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: dist/ThreeCS.HtmlRenderer.SkiaSharp.${{ steps.version.outputs.version_str }}.nupkg + asset_name: ThreeCS.HtmlRenderer.SkiaSharp.${{ steps.version.outputs.version_str }}.nupkg + asset_content_type: application/octet-stream + + - name: Push to Nuget + run: dotnet nuget push dist/ThreeCS.HtmlRenderer*.${{ steps.version.outputs.version_str }}.nupkg --api-key ${{ secrets.NUGET_ORG_MSTANCOMBE_KEY }} --source https://api.nuget.org/v3/index.json \ No newline at end of file diff --git a/.gitignore b/.gitignore index ce3a150ad..6251d1d7f 100644 --- a/.gitignore +++ b/.gitignore @@ -107,4 +107,8 @@ _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML -*.DotSettings \ No newline at end of file +*.DotSettings + +Source/.vs/ +/Source/Demos/HtmlRenderer.Demo.Console/Output +dist/ \ No newline at end of file diff --git a/README.md b/README.md index 5a21ca388..14983cc46 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ HTML Renderer [![Build status](https://ci.appveyor.com/api/projects/status/cm8xpf8ebt3hyi3e)](https://ci.appveyor.com/project/ArthurHub/html-renderer) ============= -## Help Wanted +## Help wanted * Looking for a contributor(s) to take this project forward as I'm unable to continue supporting it. * Contribute directly to the repository and update nuget packages. diff --git a/Source/Demo/Common/HtmlRenderer.Demo.Common.csproj b/Source/Demo/Common/HtmlRenderer.Demo.Common.csproj deleted file mode 100644 index 7413cc397..000000000 --- a/Source/Demo/Common/HtmlRenderer.Demo.Common.csproj +++ /dev/null @@ -1,178 +0,0 @@ - - - - - Debug - AnyCPU - {2390B71F-9400-47F4-B23A-7F2649C87D35} - Library - Properties - TheArtOfDev.HtmlRenderer.Demo.Common - HtmlRendererDemoCommon - v2.0 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - Resources.resx - True - True - - - - - - - - - - - - - PublicResXFileCodeGenerator - Resources.Designer.cs - Designer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {FE611685-391F-4E3E-B27E-D3150E51E49B} - HtmlRenderer - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Source/Demo/Common/TestSamples/19.Many images.htm b/Source/Demo/Common/TestSamples/19.Many images.htm deleted file mode 100644 index a7cd2582c..000000000 --- a/Source/Demo/Common/TestSamples/19.Many images.htm +++ /dev/null @@ -1,103 +0,0 @@ - - -

Contains many images that should not load until in scroll view

-

Image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- -

Another image

- - - \ No newline at end of file diff --git a/Source/Demo/WPF/HtmlRenderer.Demo.WPF.csproj b/Source/Demo/WPF/HtmlRenderer.Demo.WPF.csproj deleted file mode 100644 index 8c26cdcc4..000000000 --- a/Source/Demo/WPF/HtmlRenderer.Demo.WPF.csproj +++ /dev/null @@ -1,149 +0,0 @@ - - - - - Debug - AnyCPU - {F02E0216-4AE3-474F-9381-FCB93411CDB0} - WinExe - Properties - TheArtOfDev.HtmlRenderer.Demo.WPF - HtmlRendererWpfDemo - v4.0 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - - ..\..\ - true - - - x86 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - html.ico - - - - - - - - - - - ..\..\packages\Extended.Wpf.Toolkit.2.2.1\lib\net40\Xceed.Wpf.DataGrid.dll - - - ..\..\packages\Extended.Wpf.Toolkit.2.2.1\lib\net40\Xceed.Wpf.Toolkit.dll - - - - - MSBuild:Compile - Designer - - - GenerateImageWindow.xaml - - - SampleWindow.xaml - - - - MSBuild:Compile - Designer - - - App.xaml - Code - - - DemoWindow.xaml - Code - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - - - - MainControl.xaml - - - Code - - - - - - {7e4e8db5-85ad-4388-bdcb-38c6f423b8b0} - HtmlRenderer.WPF - - - {fe611685-391f-4e3e-b27e-d3150e51e49b} - HtmlRenderer - - - {2390B71F-9400-47F4-B23A-7F2649C87D35} - HtmlRenderer.Demo.Common - - - - - - - - - - - - - - - - %(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension) - - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/Source/Demo/WPF/Properties/AssemblyInfo.cs b/Source/Demo/WPF/Properties/AssemblyInfo.cs deleted file mode 100644 index d5c8b4eb2..000000000 --- a/Source/Demo/WPF/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Reflection; -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("HTML Renderer WPF Demo")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("HTML Renderer WPF Demo")] -[assembly: AssemblyCopyright("Copyright © 2013")] -[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")] \ No newline at end of file diff --git a/Source/Demo/WPF/packages.config b/Source/Demo/WPF/packages.config deleted file mode 100644 index d3eaa3c6b..000000000 --- a/Source/Demo/WPF/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Source/Demo/WinForms/HtmlRenderer.Demo.WinForms.csproj b/Source/Demo/WinForms/HtmlRenderer.Demo.WinForms.csproj deleted file mode 100644 index 95dafc2f1..000000000 --- a/Source/Demo/WinForms/HtmlRenderer.Demo.WinForms.csproj +++ /dev/null @@ -1,198 +0,0 @@ - - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {8AD34FE8-8382-4A8A-B3AA-A0392ED42423} - WinExe - Properties - TheArtOfDev.HtmlRenderer.Demo.WinForms - HtmlRendererWinFormsDemo - v2.0 - - - - - 2.0 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - ..\..\ - true - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - x86 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - x86 - false - - - html.ico - - - - ..\..\packages\PDFsharp.1.50.4000-beta3b\lib\net20\PdfSharp.dll - True - - - ..\..\packages\PDFsharp.1.50.4000-beta3b\lib\net20\PdfSharp.Charting.dll - True - - - - - - - - - - Form - - - GenerateImageForm.cs - - - - UserControl - - - MainControl.cs - - - Form - - - PerfForm.cs - - - Form - - - DemoForm.cs - - - - - GenerateImageForm.cs - - - MainControl.cs - - - PerfForm.cs - Designer - - - Designer - DemoForm.cs - - - Form - - - SampleForm.cs - - - - - Designer - SampleForm.cs - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - {ca249f5d-9285-40a6-b217-5889ef79fd7e} - HtmlRenderer.PdfSharp - - - {1b058920-24b4-4140-8ae7-c8c6c38ca52d} - HtmlRenderer.WinForms - - - {fe611685-391f-4e3e-b27e-d3150e51e49b} - HtmlRenderer - - - {2390b71f-9400-47f4-b23a-7f2649c87d35} - HtmlRenderer.Demo.Common - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - %(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension) - - - - - \ No newline at end of file diff --git a/Source/Demo/Common/DemoUtils.cs b/Source/Demos/HtmlRenderer.Demo.Common/DemoUtils.cs similarity index 98% rename from Source/Demo/Common/DemoUtils.cs rename to Source/Demos/HtmlRenderer.Demo.Common/DemoUtils.cs index f695886bc..61aece7b5 100644 --- a/Source/Demo/Common/DemoUtils.cs +++ b/Source/Demos/HtmlRenderer.Demo.Common/DemoUtils.cs @@ -74,8 +74,8 @@ public static string GetStylesheet(string src) a:link { text-decoration: none; } a:hover { text-decoration: underline; } .gray { color:gray; } - .example { background-color:#efefef; corner-radius:5px; padding:0.5em; } - .whitehole { background-color:white; corner-radius:10px; padding:15px; } + .example { background-color:#efefef; border-radius:5px; padding:0.5em; } + .whitehole { background-color:white; border-radius:10px; padding:15px; } .caption { font-size: 1.1em } .comment { color: green; margin-bottom: 5px; margin-left: 3px; } .comment2 { color: green; }"; diff --git a/Source/Demos/HtmlRenderer.Demo.Common/HtmlRenderer.Demo.Common.csproj b/Source/Demos/HtmlRenderer.Demo.Common/HtmlRenderer.Demo.Common.csproj new file mode 100644 index 000000000..12bf0c0e8 --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.Common/HtmlRenderer.Demo.Common.csproj @@ -0,0 +1,300 @@ + + + + net7.0 + enable + disable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + + + + diff --git a/Source/Demo/Common/HtmlSample.cs b/Source/Demos/HtmlRenderer.Demo.Common/HtmlSample.cs similarity index 100% rename from Source/Demo/Common/HtmlSample.cs rename to Source/Demos/HtmlRenderer.Demo.Common/HtmlSample.cs diff --git a/Source/Demo/Common/HtmlSyntaxHighlighter.cs b/Source/Demos/HtmlRenderer.Demo.Common/HtmlSyntaxHighlighter.cs similarity index 100% rename from Source/Demo/Common/HtmlSyntaxHighlighter.cs rename to Source/Demos/HtmlRenderer.Demo.Common/HtmlSyntaxHighlighter.cs diff --git a/Source/Demo/Common/PerfSamples/1.Big table.htm b/Source/Demos/HtmlRenderer.Demo.Common/PerfSamples/1.Big table.htm similarity index 100% rename from Source/Demo/Common/PerfSamples/1.Big table.htm rename to Source/Demos/HtmlRenderer.Demo.Common/PerfSamples/1.Big table.htm diff --git a/Source/Demo/Common/PerfSamples/2.Lots blocks in inline.htm b/Source/Demos/HtmlRenderer.Demo.Common/PerfSamples/2.Lots blocks in inline.htm similarity index 100% rename from Source/Demo/Common/PerfSamples/2.Lots blocks in inline.htm rename to Source/Demos/HtmlRenderer.Demo.Common/PerfSamples/2.Lots blocks in inline.htm diff --git a/Source/Demo/Common/Properties/AssemblyInfo.cs b/Source/Demos/HtmlRenderer.Demo.Common/Properties/AssemblyInfo.cs similarity index 100% rename from Source/Demo/Common/Properties/AssemblyInfo.cs rename to Source/Demos/HtmlRenderer.Demo.Common/Properties/AssemblyInfo.cs diff --git a/Source/Demo/Common/Properties/Resources.Designer.cs b/Source/Demos/HtmlRenderer.Demo.Common/Properties/Resources.Designer.cs similarity index 95% rename from Source/Demo/Common/Properties/Resources.Designer.cs rename to Source/Demos/HtmlRenderer.Demo.Common/Properties/Resources.Designer.cs index 8b1aa6a38..811f5d1c6 100644 --- a/Source/Demo/Common/Properties/Resources.Designer.cs +++ b/Source/Demos/HtmlRenderer.Demo.Common/Properties/Resources.Designer.cs @@ -1,7 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34014 +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -19,7 +19,7 @@ namespace TheArtOfDev.HtmlRenderer.Demo.Common.Properties { // 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.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Resources { @@ -39,7 +39,7 @@ internal Resources() { public static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TheArtOfDev.HtmlRenderer.Demo.Common.Properties.Resources", typeof(Resources).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("HtmlRenderer.Demo.Common.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; diff --git a/Source/Demo/Common/Properties/Resources.resx b/Source/Demos/HtmlRenderer.Demo.Common/Properties/Resources.resx similarity index 99% rename from Source/Demo/Common/Properties/Resources.resx rename to Source/Demos/HtmlRenderer.Demo.Common/Properties/Resources.resx index 081d86fd7..1f6a9275d 100644 --- a/Source/Demo/Common/Properties/Resources.resx +++ b/Source/Demos/HtmlRenderer.Demo.Common/Properties/Resources.resx @@ -137,6 +137,6 @@ ..\Resources\code.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\resources\browser.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\browser.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a \ No newline at end of file diff --git a/Source/Demo/Common/Resources.cs b/Source/Demos/HtmlRenderer.Demo.Common/Resources.cs similarity index 97% rename from Source/Demo/Common/Resources.cs rename to Source/Demos/HtmlRenderer.Demo.Common/Resources.cs index 6370c567c..f4550c0c6 100644 --- a/Source/Demo/Common/Resources.cs +++ b/Source/Demos/HtmlRenderer.Demo.Common/Resources.cs @@ -96,7 +96,7 @@ public static string Tooltip private static Stream GetManifestResourceStream(string name) { - return typeof(Resources).Assembly.GetManifestResourceStream("TheArtOfDev.HtmlRenderer.Demo.Common.Resources." + name); + return typeof(Resources).Assembly.GetManifestResourceStream("HtmlRenderer.Demo.Common.Resources." + name); } } } \ No newline at end of file diff --git a/Source/Demo/Common/Resources/CustomFont.ttf b/Source/Demos/HtmlRenderer.Demo.Common/Resources/CustomFont.ttf similarity index 100% rename from Source/Demo/Common/Resources/CustomFont.ttf rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/CustomFont.ttf diff --git a/Source/Demo/Common/Resources/Event16.png b/Source/Demos/HtmlRenderer.Demo.Common/Resources/Event16.png similarity index 100% rename from Source/Demo/Common/Resources/Event16.png rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/Event16.png diff --git a/Source/Demo/Common/Resources/Tooltip.html b/Source/Demos/HtmlRenderer.Demo.Common/Resources/Tooltip.html similarity index 100% rename from Source/Demo/Common/Resources/Tooltip.html rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/Tooltip.html diff --git a/Source/Demo/Common/Resources/browser.png b/Source/Demos/HtmlRenderer.Demo.Common/Resources/browser.png similarity index 100% rename from Source/Demo/Common/Resources/browser.png rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/browser.png diff --git a/Source/Demo/Common/Resources/chrome.png b/Source/Demos/HtmlRenderer.Demo.Common/Resources/chrome.png similarity index 100% rename from Source/Demo/Common/Resources/chrome.png rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/chrome.png diff --git a/Source/Demo/Common/Resources/code.png b/Source/Demos/HtmlRenderer.Demo.Common/Resources/code.png similarity index 100% rename from Source/Demo/Common/Resources/code.png rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/code.png diff --git a/Source/Demo/Common/Resources/comment16.gif b/Source/Demos/HtmlRenderer.Demo.Common/Resources/comment16.gif similarity index 100% rename from Source/Demo/Common/Resources/comment16.gif rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/comment16.gif diff --git a/Source/Demo/Common/Resources/delete16.gif b/Source/Demos/HtmlRenderer.Demo.Common/Resources/delete16.gif similarity index 100% rename from Source/Demo/Common/Resources/delete16.gif rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/delete16.gif diff --git a/Source/Demo/Common/Resources/delete32.gif b/Source/Demos/HtmlRenderer.Demo.Common/Resources/delete32.gif similarity index 100% rename from Source/Demo/Common/Resources/delete32.gif rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/delete32.gif diff --git a/Source/Demo/Common/Resources/favorites32.png b/Source/Demos/HtmlRenderer.Demo.Common/Resources/favorites32.png similarity index 100% rename from Source/Demo/Common/Resources/favorites32.png rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/favorites32.png diff --git a/Source/Demo/Common/Resources/font32.png b/Source/Demos/HtmlRenderer.Demo.Common/Resources/font32.png similarity index 100% rename from Source/Demo/Common/Resources/font32.png rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/font32.png diff --git a/Source/Demo/Common/Resources/form.png b/Source/Demos/HtmlRenderer.Demo.Common/Resources/form.png similarity index 100% rename from Source/Demo/Common/Resources/form.png rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/form.png diff --git a/Source/Demo/Common/Resources/formula32.png b/Source/Demos/HtmlRenderer.Demo.Common/Resources/formula32.png similarity index 100% rename from Source/Demo/Common/Resources/formula32.png rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/formula32.png diff --git a/Source/Demo/Common/Resources/html32.png b/Source/Demos/HtmlRenderer.Demo.Common/Resources/html32.png similarity index 100% rename from Source/Demo/Common/Resources/html32.png rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/html32.png diff --git a/Source/Demo/Common/Resources/image.png b/Source/Demos/HtmlRenderer.Demo.Common/Resources/image.png similarity index 100% rename from Source/Demo/Common/Resources/image.png rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/image.png diff --git a/Source/Demo/Common/Resources/image32.png b/Source/Demos/HtmlRenderer.Demo.Common/Resources/image32.png similarity index 100% rename from Source/Demo/Common/Resources/image32.png rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/image32.png diff --git a/Source/Demo/Common/Resources/method16.gif b/Source/Demos/HtmlRenderer.Demo.Common/Resources/method16.gif similarity index 100% rename from Source/Demo/Common/Resources/method16.gif rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/method16.gif diff --git a/Source/Demo/Common/Resources/pdf.png b/Source/Demos/HtmlRenderer.Demo.Common/Resources/pdf.png similarity index 100% rename from Source/Demo/Common/Resources/pdf.png rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/pdf.png diff --git a/Source/Demo/Common/Resources/property16.gif b/Source/Demos/HtmlRenderer.Demo.Common/Resources/property16.gif similarity index 100% rename from Source/Demo/Common/Resources/property16.gif rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/property16.gif diff --git a/Source/Demo/Common/Resources/stopwatch.png b/Source/Demos/HtmlRenderer.Demo.Common/Resources/stopwatch.png similarity index 100% rename from Source/Demo/Common/Resources/stopwatch.png rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/stopwatch.png diff --git a/Source/Demo/Common/Resources/web_pallete.gif b/Source/Demos/HtmlRenderer.Demo.Common/Resources/web_pallete.gif similarity index 100% rename from Source/Demo/Common/Resources/web_pallete.gif rename to Source/Demos/HtmlRenderer.Demo.Common/Resources/web_pallete.gif diff --git a/Source/Demo/Common/Samples/00.Intro.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/00.Intro.htm similarity index 100% rename from Source/Demo/Common/Samples/00.Intro.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/00.Intro.htm diff --git a/Source/Demo/Common/Samples/01.History.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/01.History.htm similarity index 100% rename from Source/Demo/Common/Samples/01.History.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/01.History.htm diff --git a/Source/Demo/Common/Samples/02.Text.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/02.Text.htm similarity index 99% rename from Source/Demo/Common/Samples/02.Text.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/02.Text.htm index 727d1fea4..b0ba57426 100644 --- a/Source/Demo/Common/Samples/02.Text.htm +++ b/Source/Demos/HtmlRenderer.Demo.Common/Samples/02.Text.htm @@ -2,11 +2,11 @@ Text - diff --git a/Source/Demo/Common/Samples/03.Tables.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/03.Tables.htm similarity index 100% rename from Source/Demo/Common/Samples/03.Tables.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/03.Tables.htm diff --git a/Source/Demo/Common/Samples/04.Links.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/04.Links.htm similarity index 100% rename from Source/Demo/Common/Samples/04.Links.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/04.Links.htm diff --git a/Source/Demo/Common/Samples/05.Images.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/05.Images.htm similarity index 100% rename from Source/Demo/Common/Samples/05.Images.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/05.Images.htm diff --git a/Source/Demo/Common/Samples/06.Embeded video.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/06.Embeded video.htm similarity index 100% rename from Source/Demo/Common/Samples/06.Embeded video.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/06.Embeded video.htm diff --git a/Source/Demo/Common/Samples/07.Additional features.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/07.Additional features.htm similarity index 84% rename from Source/Demo/Common/Samples/07.Additional features.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/07.Additional features.htm index 764e9511c..bffd85781 100644 --- a/Source/Demo/Common/Samples/07.Additional features.htm +++ b/Source/Demos/HtmlRenderer.Demo.Common/Samples/07.Additional features.htm @@ -27,16 +27,16 @@ vertical-align: middle; } - .c1 { corner-radius: 0px; } + .c1 { border-radius: 0px; } - .c2 { corner-radius: 10px; } + .c2 { border-radius: 10px; } - .c3 { corner-radius: 0px 10px 10px 0px; } + .c3 { border-radius: 0px 10px 10px 0px; } - .c4 { corner-radius: 18px; } + .c4 { border-radius: 18px; } .c5 { - corner-radius: 10px; + border-radius: 10px; border: outset #BBBB00 2px; } @@ -121,15 +121,15 @@

In this renderer, the rounded corners are achieved by adding this CSS properties:

    -
  • corner-ne-radius: (length) Indicates the radius of the north-east corner. +
  • border-top-right-radius: (length) Indicates the radius of the top-right corner. Not ineritted
  • -
  • corner-se-radius: (length) Indicates the radius of the south-east corner. +
  • border-bottom-right-radius: (length) Indicates the radius of the bottom-right corner. Not ineritted
  • -
  • corner-sw-radius: (length) Indicates the radius of the south-west corner. +
  • border-bottom-left-radius: (length) Indicates the radius of the bottom-left corner. Not ineritted
  • -
  • corner-nw-radius: (length) Indicates the radius of the north-west corner. +
  • border-top-left-radius: (length) Indicates the radius of the top-left corner. Not ineritted
  • -
  • corner-radius: (length){1,4} Shorthand for the other corner properties. +
  • border-radius: (length){1,4} Shorthand for the other corner properties. Not ineritted
@@ -160,11 +160,11 @@

.c1, .c2, .c3, .c4, .c5 { background-color:olive; border:0px; color:white; vertical-align:middle; }
-.c1  { corner-radius: 0px }
-.c2  { corner-radius: 10px }
-.c3  { corner-radius: 0px 10px 10px 0px }
-.c4  { corner-radius: 18px }
-.c5  { corner-radius: 10px; border: outset #bb0 2px; }
+.c1 { border-radius: 0px } +.c2 { border-radius: 10px } +.c3 { border-radius: 0px 10px 10px 0px } +.c4 { border-radius: 18px } +.c5 { border-radius: 10px; border: outset #bb0 2px; } \ No newline at end of file diff --git a/Source/Demo/Common/Samples/08.Tooltip.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/08.Tooltip.htm similarity index 100% rename from Source/Demo/Common/Samples/08.Tooltip.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/08.Tooltip.htm diff --git a/Source/Demo/Common/Samples/09.Using the library.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/09.Using the library.htm similarity index 100% rename from Source/Demo/Common/Samples/09.Using the library.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/09.Using the library.htm diff --git a/Source/Demo/Common/Samples/10.HtmlPanel.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/10.HtmlPanel.htm similarity index 100% rename from Source/Demo/Common/Samples/10.HtmlPanel.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/10.HtmlPanel.htm diff --git a/Source/Demo/Common/Samples/11.HtmlLabel.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/11.HtmlLabel.htm similarity index 100% rename from Source/Demo/Common/Samples/11.HtmlLabel.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/11.HtmlLabel.htm diff --git a/Source/Demo/Common/Samples/12.HtmlToolTip.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/12.HtmlToolTip.htm similarity index 100% rename from Source/Demo/Common/Samples/12.HtmlToolTip.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/12.HtmlToolTip.htm diff --git a/Source/Demo/Common/Samples/13.HtmlRender.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/13.HtmlRender.htm similarity index 100% rename from Source/Demo/Common/Samples/13.HtmlRender.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/13.HtmlRender.htm diff --git a/Source/Demo/Common/Samples/14.HtmlContainer.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/14.HtmlContainer.htm similarity index 100% rename from Source/Demo/Common/Samples/14.HtmlContainer.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/14.HtmlContainer.htm diff --git a/Source/Demo/Common/Samples/20.About.htm b/Source/Demos/HtmlRenderer.Demo.Common/Samples/20.About.htm similarity index 100% rename from Source/Demo/Common/Samples/20.About.htm rename to Source/Demos/HtmlRenderer.Demo.Common/Samples/20.About.htm diff --git a/Source/Demo/Common/SamplesLoader.cs b/Source/Demos/HtmlRenderer.Demo.Common/SamplesLoader.cs similarity index 100% rename from Source/Demo/Common/SamplesLoader.cs rename to Source/Demos/HtmlRenderer.Demo.Common/SamplesLoader.cs diff --git a/Source/Demo/Common/TestSamples/01.Header.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/01.Header.htm similarity index 100% rename from Source/Demo/Common/TestSamples/01.Header.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/01.Header.htm diff --git a/Source/Demo/Common/TestSamples/02.Line break.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/02.Line break.htm similarity index 100% rename from Source/Demo/Common/TestSamples/02.Line break.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/02.Line break.htm diff --git a/Source/Demo/Common/TestSamples/03.Paragraphs.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/03.Paragraphs.htm similarity index 100% rename from Source/Demo/Common/TestSamples/03.Paragraphs.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/03.Paragraphs.htm diff --git a/Source/Demo/Common/TestSamples/04.Blockquotes.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/04.Blockquotes.htm similarity index 100% rename from Source/Demo/Common/TestSamples/04.Blockquotes.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/04.Blockquotes.htm diff --git a/Source/Demo/Common/TestSamples/05.Images.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/05.Images.htm similarity index 100% rename from Source/Demo/Common/TestSamples/05.Images.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/05.Images.htm diff --git a/Source/Demo/Common/TestSamples/06.External Image.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/06.External Image.htm similarity index 52% rename from Source/Demo/Common/TestSamples/06.External Image.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/06.External Image.htm index 0492a426c..1b8f97f56 100644 --- a/Source/Demo/Common/TestSamples/06.External Image.htm +++ b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/06.External Image.htm @@ -3,12 +3,17 @@
Local File:
- +
From web:
- + +
+
+ From svg: +
+
GIF: @@ -21,6 +26,6 @@

- + \ No newline at end of file diff --git a/Source/Demo/Common/TestSamples/07.Background Image.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/07.Background Image.htm similarity index 100% rename from Source/Demo/Common/TestSamples/07.Background Image.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/07.Background Image.htm diff --git a/Source/Demo/Common/TestSamples/08.White-space.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/08.White-space.htm similarity index 100% rename from Source/Demo/Common/TestSamples/08.White-space.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/08.White-space.htm diff --git a/Source/Demo/Common/TestSamples/09.Inline.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/09.Inline.htm similarity index 100% rename from Source/Demo/Common/TestSamples/09.Inline.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/09.Inline.htm diff --git a/Source/Demo/Common/TestSamples/10.BlockInInline.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/10.BlockInInline.htm similarity index 100% rename from Source/Demo/Common/TestSamples/10.BlockInInline.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/10.BlockInInline.htm diff --git a/Source/Demo/Common/TestSamples/11.LineHeight.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/11.LineHeight.htm similarity index 100% rename from Source/Demo/Common/TestSamples/11.LineHeight.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/11.LineHeight.htm diff --git a/Source/Demo/Common/TestSamples/12.Text.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/12.Text.htm similarity index 99% rename from Source/Demo/Common/TestSamples/12.Text.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/12.Text.htm index c53a43609..833196bae 100644 --- a/Source/Demo/Common/TestSamples/12.Text.htm +++ b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/12.Text.htm @@ -2,13 +2,13 @@ Text - diff --git a/Source/Demo/Common/TestSamples/13.Tables.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/13.Tables.htm similarity index 100% rename from Source/Demo/Common/TestSamples/13.Tables.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/13.Tables.htm diff --git a/Source/Demo/Common/TestSamples/14.Iframes.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/14.Iframes.htm similarity index 100% rename from Source/Demo/Common/TestSamples/14.Iframes.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/14.Iframes.htm diff --git a/Source/Demo/Common/TestSamples/15.MaxWidth.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/15.MaxWidth.htm similarity index 86% rename from Source/Demo/Common/TestSamples/15.MaxWidth.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/15.MaxWidth.htm index d8b98e9ba..7ead83afe 100644 --- a/Source/Demo/Common/TestSamples/15.MaxWidth.htm +++ b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/15.MaxWidth.htm @@ -26,10 +26,10 @@

metus. Integer leo dolor, tristique a, dignissim ac, iaculis eget, elit. Donec arcu.

The image should also be limited by size because it has: style="width:90%"
- - + +

- +

diff --git a/Source/Demo/Common/TestSamples/16.Borders.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/16.Borders.htm similarity index 83% rename from Source/Demo/Common/TestSamples/16.Borders.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/16.Borders.htm index 6fae0757c..117dfbcae 100644 --- a/Source/Demo/Common/TestSamples/16.Borders.htm +++ b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/16.Borders.htm @@ -12,13 +12,13 @@

-

- border 1px with corner-radius 5px +
+ border 1px with border-radius 5px

-

- border 2px with corner-radius 10px +
+ border 2px with border-radius 10px

@@ -37,8 +37,8 @@

-

- dashed border 2px with corner-radius 10px +
+ dashed border 2px with border-radius 10px

diff --git a/Source/Demo/Common/TestSamples/17.Languages.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/17.Languages.htm similarity index 100% rename from Source/Demo/Common/TestSamples/17.Languages.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/17.Languages.htm diff --git a/Source/Demo/Common/TestSamples/18.Anchors.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/18.Anchors.htm similarity index 100% rename from Source/Demo/Common/TestSamples/18.Anchors.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/18.Anchors.htm diff --git a/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/19.Many images.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/19.Many images.htm new file mode 100644 index 000000000..4c11cb2d4 --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/19.Many images.htm @@ -0,0 +1,103 @@ + + +

Contains many images that should not load until in scroll view

+

Image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ +

Another image

+ + + \ No newline at end of file diff --git a/Source/Demo/Common/TestSamples/20.Fonts decorations.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/20.Fonts decorations.htm similarity index 100% rename from Source/Demo/Common/TestSamples/20.Fonts decorations.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/20.Fonts decorations.htm diff --git a/Source/Demo/Common/TestSamples/21.Bullets.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/21.Bullets.htm similarity index 100% rename from Source/Demo/Common/TestSamples/21.Bullets.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/21.Bullets.htm diff --git a/Source/Demo/Common/TestSamples/22.RTL.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/22.RTL.htm similarity index 97% rename from Source/Demo/Common/TestSamples/22.RTL.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/22.RTL.htm index 35bf9bf6c..a24d4f4e7 100644 --- a/Source/Demo/Common/TestSamples/22.RTL.htm +++ b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/22.RTL.htm @@ -1,18 +1,18 @@ - - -
-
שלום עולם, יש ברבורים בעגם הזה
-
-
שלום עולם, יש ברבורים בעגם הזה
-
שלום עולם, יש ברבורים בעגם הזה
-
-
-
-
שלום עולם,hello world יש ברבורים בעגם הזה
-
-
שלום עולם, יש ברבורים בעגם הזה
-
שלום עולם, יש ברבורים בעגם הזה
-
-
- + + +
+
שלום עולם, יש ברבורים בעגם הזה
+
+
שלום עולם, יש ברבורים בעגם הזה
+
שלום עולם, יש ברבורים בעגם הזה
+
+
+
+
שלום עולם,hello world יש ברבורים בעגם הזה
+
+
שלום עולם, יש ברבורים בעגם הזה
+
שלום עולם, יש ברבורים בעגם הזה
+
+
+ \ No newline at end of file diff --git a/Source/Demo/Common/TestSamples/30.Misc.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/30.Misc.htm similarity index 100% rename from Source/Demo/Common/TestSamples/30.Misc.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/30.Misc.htm diff --git a/Source/Demo/Common/TestSamples/31.ACID 1.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/31.ACID 1.htm similarity index 100% rename from Source/Demo/Common/TestSamples/31.ACID 1.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/31.ACID 1.htm diff --git a/Source/Demo/Common/TestSamples/32.Image in css content.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/32.Image in css content.htm similarity index 100% rename from Source/Demo/Common/TestSamples/32.Image in css content.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/32.Image in css content.htm diff --git a/Source/Demo/Common/TestSamples/33.Fixed position.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/33.Fixed position.htm similarity index 100% rename from Source/Demo/Common/TestSamples/33.Fixed position.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/33.Fixed position.htm diff --git a/Source/Demo/Common/TestSamples/34.Breaking pages 1 - Paragraphs.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/34.Breaking pages 1 - Paragraphs.htm similarity index 100% rename from Source/Demo/Common/TestSamples/34.Breaking pages 1 - Paragraphs.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/34.Breaking pages 1 - Paragraphs.htm diff --git a/Source/Demo/Common/TestSamples/35.Breaking pages 2 - Tables.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/35.Breaking pages 2 - Tables.htm similarity index 100% rename from Source/Demo/Common/TestSamples/35.Breaking pages 2 - Tables.htm rename to Source/Demos/HtmlRenderer.Demo.Common/TestSamples/35.Breaking pages 2 - Tables.htm diff --git a/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/36.Breaking Pages Divs.htm b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/36.Breaking Pages Divs.htm new file mode 100644 index 000000000..55522a541 --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.Common/TestSamples/36.Breaking Pages Divs.htm @@ -0,0 +1,17 @@ + + +
+ This is on page 1. +
+ +
+ This is on page 2. +
+
+ Also on page 2. +
+
+ On page 3, because the previous section pushed it. +
+ + \ No newline at end of file diff --git a/Source/Demos/HtmlRenderer.Demo.Console/HtmlRenderer.Demo.Console.csproj b/Source/Demos/HtmlRenderer.Demo.Console/HtmlRenderer.Demo.Console.csproj new file mode 100644 index 000000000..89139f338 --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.Console/HtmlRenderer.Demo.Console.csproj @@ -0,0 +1,24 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + + + + + + + + + + + diff --git a/Source/Demos/HtmlRenderer.Demo.Console/PdfSharpCoreConverter.cs b/Source/Demos/HtmlRenderer.Demo.Console/PdfSharpCoreConverter.cs new file mode 100644 index 000000000..983c888e8 --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.Console/PdfSharpCoreConverter.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TheArtOfDev.HtmlRenderer.Demo.Common; +using TheArtOfDev.HtmlRenderer.PdfSharp; + +namespace HtmlRenderer.Demo.Console +{ + public class PdfSharpCoreConverter : SampleConverterBase + { + public PdfSharpCoreConverter(string sampleRunIdentifier, string basePath) : base(sampleRunIdentifier, basePath) + { + } + + public async Task GenerateSampleAsync(HtmlSample sample) + { + var config = new PdfGenerateConfig(); + + config.PageSize = PdfSharpCore.PageSize.A4; + config.MarginLeft = 0; + config.MarginRight = 0; + config.MarginTop = 0; + config.MarginBottom = 0; + + var pdf = await PdfGenerator.GeneratePdfAsync(sample.Html, config, imageLoad: OnImageLoaded); + pdf.Save(GetSamplePath(sample)); + } + } +} diff --git a/Source/Demos/HtmlRenderer.Demo.Console/Program.cs b/Source/Demos/HtmlRenderer.Demo.Console/Program.cs new file mode 100644 index 000000000..328899812 --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.Console/Program.cs @@ -0,0 +1,33 @@ +using HtmlRenderer.Demo.Console; +using System.Diagnostics; +using TheArtOfDev.HtmlRenderer.Demo.Common; + +//By default, write to a sub folder 'output' +string basePath= @".\Ouput"; +if (args.Length > 0) +{ + //And if there's an output path given, use that. + basePath = args[0]; +} + +//Probably won't be running a suite of tests more than once a second, so this will do. +string runIdentifier = DateTime.Now.ToString("yyyyMMdd-hhmmss"); + +var skia = new SkiaConverter(runIdentifier, basePath); +var pdfSharp = new PdfSharpCoreConverter(runIdentifier, basePath); + +SamplesLoader.Init("Console", typeof(Program).Assembly.GetName().Version.ToString()); + +var samples = SamplesLoader.TestSamples; + +foreach (var htmlSample in samples) +{ + ////Just doing one test here. Comment this for all of them. + if (!htmlSample.FullName.Contains("02", StringComparison.OrdinalIgnoreCase)) continue; + + await skia.GenerateSampleAsync(htmlSample); + //await pdfSharp.GenerateSampleAsync(htmlSample); +} + + +//At this point.. there should be something!! \ No newline at end of file diff --git a/Source/Demos/HtmlRenderer.Demo.Console/Properties/launchSettings.json b/Source/Demos/HtmlRenderer.Demo.Console/Properties/launchSettings.json new file mode 100644 index 000000000..6deb4f2a6 --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.Console/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "HtmlRenderer.Demo.Console": { + "commandName": "Project", + "commandLineArgs": "..\\..\\..\\Output" + } + } +} \ No newline at end of file diff --git a/Source/Demos/HtmlRenderer.Demo.Console/SampleConverterBase.cs b/Source/Demos/HtmlRenderer.Demo.Console/SampleConverterBase.cs new file mode 100644 index 000000000..8c1e4b2cb --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.Console/SampleConverterBase.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Drawing.Imaging; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; +using TheArtOfDev.HtmlRenderer.Core; +using TheArtOfDev.HtmlRenderer.Core.Entities; +using TheArtOfDev.HtmlRenderer.Demo.Common; + +namespace HtmlRenderer.Demo.Console +{ + public class SampleConverterBase + { + private string _sampleRunIdentifier; + private string _thisTypeName; + private string _basePath; + + public SampleConverterBase(string sampleRunIdentifier, string basePath) + { + _sampleRunIdentifier = sampleRunIdentifier; + _basePath = basePath; + _thisTypeName = this.GetType().Name; + + this.OnImageLoaded += ImageLoad; + this.OnStyleLoaded += StylesheetLoad; + } + + public CssData CssData => null; + + protected string GetSamplePath(HtmlSample sample) + { + var path = Path.Combine(_basePath, _sampleRunIdentifier); + Directory.CreateDirectory(path); + return Path.Combine(path, sample.FullName + _thisTypeName + "_" + ".pdf"); + } + + protected EventHandler OnImageLoaded; + protected EventHandler OnStyleLoaded; + + internal void ImageLoad(object? sender, HtmlImageLoadEventArgs e) + { + //The samples use some well known image resources, so do that here. + var imageStream = DemoUtils.GetImageStream(e.Src); + if (imageStream != null) + { + e.Handled = true; + e.Callback(imageStream); + } + } + + internal void StylesheetLoad(object? sender, HtmlStylesheetLoadEventArgs e) + { + throw new NotImplementedException(); + } + } +} diff --git a/Source/Demos/HtmlRenderer.Demo.Console/SkiaConverter.cs b/Source/Demos/HtmlRenderer.Demo.Console/SkiaConverter.cs new file mode 100644 index 000000000..93a749b38 --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.Console/SkiaConverter.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TheArtOfDev.HtmlRenderer.Demo.Common; +using TheArtOfDev.HtmlRenderer.SkiaSharp; + +namespace HtmlRenderer.Demo.Console +{ + public class SkiaConverter : SampleConverterBase + { + public SkiaConverter(string sampleRunIdentifier, string basePath) : base(sampleRunIdentifier, basePath) + { + } + + public async Task GenerateSampleAsync(HtmlSample sample) + { + var config = new PdfGenerateConfig(); + + config.PageSize = PageSize.A4; + + config.MarginLeft = 0; + config.MarginRight = 0; + config.MarginTop = 0; + config.MarginBottom = 0; + + using (var fileStream = File.Open(GetSamplePath(sample), FileMode.CreateNew)) + { + await PdfGenerator.GeneratePdfAsync(sample.Html, fileStream, config, imageLoad: OnImageLoaded); + fileStream.Flush(); + } + } + } +} diff --git a/Source/Demos/HtmlRenderer.Demo.SkiaSharp/HtmlRenderer.Demo.SkiaSharp.csproj b/Source/Demos/HtmlRenderer.Demo.SkiaSharp/HtmlRenderer.Demo.SkiaSharp.csproj new file mode 100644 index 000000000..d14493737 --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.SkiaSharp/HtmlRenderer.Demo.SkiaSharp.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + diff --git a/Source/Demos/HtmlRenderer.Demo.SkiaSharp/Program.cs b/Source/Demos/HtmlRenderer.Demo.SkiaSharp/Program.cs new file mode 100644 index 000000000..fa147813d --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.SkiaSharp/Program.cs @@ -0,0 +1,59 @@ +// See https://aka.ms/new-console-template for more information + +using SkiaSharp; +using TheArtOfDev.HtmlRenderer.SkiaSharp; +/* +var info = new SKImageInfo(256, 256); +using (var surface = SKSurface.Create(info)) +{ +SKCanvas canvas = surface.Canvas; + +canvas.Clear(SKColors.White); + +// configure our brush +var redBrush = new SKPaint +{ +Color = new SKColor(0xff, 0, 0), +IsStroke = true +}; +var blueBrush = new SKPaint +{ +Color = new SKColor(0, 0, 0xff), +IsStroke = true +}; + +for (int i = 0; i < 64; i += 8) +{ +var rect = new SKRect(i, i, 256 - i - 1, 256 - i - 1); +canvas.DrawRect(rect, (i % 16 == 0) ? redBrush : blueBrush); +} + +using (var image = surface.Snapshot()) +using (var data = image.Encode(SKEncodedImageFormat.Png, 80)) +using (var stream = File.OpenWrite(Path.Combine(@"c:\temp\SkiaSharpTests", "1.png"))) +{ +// save the data to a stream +data.SaveTo(stream); +} + +Console.ReadLine(); +}*/ + +using (var outputFile = new FileStream(@"c:\temp\SkiaSharpTests\test.pdf", FileMode.Create)) +{ + var pdfDocument = PdfGenerator.GeneratePdfAsync(@" + + + w3resource tutorial + +

we are learning html

+

we are learning html at w3resource.com.

+

This section covers the introduction to html

+

Look here to get a list of the topics covered in + w3resource.com

+ + ", outputFile); + + await outputFile.FlushAsync(); +} diff --git a/Source/Demo/WPF/App.xaml b/Source/Demos/HtmlRenderer.Demo.WPF/App.xaml similarity index 98% rename from Source/Demo/WPF/App.xaml rename to Source/Demos/HtmlRenderer.Demo.WPF/App.xaml index 680903bfb..b48841847 100644 --- a/Source/Demo/WPF/App.xaml +++ b/Source/Demos/HtmlRenderer.Demo.WPF/App.xaml @@ -27,4 +27,4 @@ - + \ No newline at end of file diff --git a/Source/Demo/WPF/App.xaml.cs b/Source/Demos/HtmlRenderer.Demo.WPF/App.xaml.cs similarity index 100% rename from Source/Demo/WPF/App.xaml.cs rename to Source/Demos/HtmlRenderer.Demo.WPF/App.xaml.cs diff --git a/Source/Demos/HtmlRenderer.Demo.WPF/AssemblyInfo.cs b/Source/Demos/HtmlRenderer.Demo.WPF/AssemblyInfo.cs new file mode 100644 index 000000000..8b5504ecf --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.WPF/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Windows; + +[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) +)] diff --git a/Source/Demo/WPF/DemoWindow.xaml b/Source/Demos/HtmlRenderer.Demo.WPF/DemoWindow.xaml similarity index 99% rename from Source/Demo/WPF/DemoWindow.xaml rename to Source/Demos/HtmlRenderer.Demo.WPF/DemoWindow.xaml index 538e685e5..80b1ca646 100644 --- a/Source/Demo/WPF/DemoWindow.xaml +++ b/Source/Demos/HtmlRenderer.Demo.WPF/DemoWindow.xaml @@ -59,4 +59,4 @@ - + \ No newline at end of file diff --git a/Source/Demo/WPF/DemoWindow.xaml.cs b/Source/Demos/HtmlRenderer.Demo.WPF/DemoWindow.xaml.cs similarity index 97% rename from Source/Demo/WPF/DemoWindow.xaml.cs rename to Source/Demos/HtmlRenderer.Demo.WPF/DemoWindow.xaml.cs index 474572865..56510b7db 100644 --- a/Source/Demo/WPF/DemoWindow.xaml.cs +++ b/Source/Demos/HtmlRenderer.Demo.WPF/DemoWindow.xaml.cs @@ -1,3 +1,8 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; // "Therefore those skilled at the unorthodox // are infinite as heaven and earth, // inexhaustible as the great rivers. diff --git a/Source/Demo/WPF/GenerateImageWindow.xaml b/Source/Demos/HtmlRenderer.Demo.WPF/GenerateImageWindow.xaml similarity index 98% rename from Source/Demo/WPF/GenerateImageWindow.xaml rename to Source/Demos/HtmlRenderer.Demo.WPF/GenerateImageWindow.xaml index 8d8cb6b94..be06c88b6 100644 --- a/Source/Demo/WPF/GenerateImageWindow.xaml +++ b/Source/Demos/HtmlRenderer.Demo.WPF/GenerateImageWindow.xaml @@ -12,4 +12,4 @@ - + \ No newline at end of file diff --git a/Source/Demo/WPF/GenerateImageWindow.xaml.cs b/Source/Demos/HtmlRenderer.Demo.WPF/GenerateImageWindow.xaml.cs similarity index 100% rename from Source/Demo/WPF/GenerateImageWindow.xaml.cs rename to Source/Demos/HtmlRenderer.Demo.WPF/GenerateImageWindow.xaml.cs diff --git a/Source/Demos/HtmlRenderer.Demo.WPF/HtmlRenderer.Demo.WPF.csproj b/Source/Demos/HtmlRenderer.Demo.WPF/HtmlRenderer.Demo.WPF.csproj new file mode 100644 index 000000000..f6a48b62a --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.WPF/HtmlRenderer.Demo.WPF.csproj @@ -0,0 +1,29 @@ + + + + WinExe + net7.0-windows + enable + true + + + + + + + + + PreserveNewest + + + + + + + + + + + + + diff --git a/Source/Demo/WPF/HtmlRenderingHelper.cs b/Source/Demos/HtmlRenderer.Demo.WPF/HtmlRenderingHelper.cs similarity index 100% rename from Source/Demo/WPF/HtmlRenderingHelper.cs rename to Source/Demos/HtmlRenderer.Demo.WPF/HtmlRenderingHelper.cs diff --git a/Source/Demo/WPF/MainControl.xaml b/Source/Demos/HtmlRenderer.Demo.WPF/MainControl.xaml similarity index 99% rename from Source/Demo/WPF/MainControl.xaml rename to Source/Demos/HtmlRenderer.Demo.WPF/MainControl.xaml index 714c2dbf1..c8156d383 100644 --- a/Source/Demo/WPF/MainControl.xaml +++ b/Source/Demos/HtmlRenderer.Demo.WPF/MainControl.xaml @@ -50,3 +50,4 @@ + diff --git a/Source/Demo/WPF/MainControl.xaml.cs b/Source/Demos/HtmlRenderer.Demo.WPF/MainControl.xaml.cs similarity index 100% rename from Source/Demo/WPF/MainControl.xaml.cs rename to Source/Demos/HtmlRenderer.Demo.WPF/MainControl.xaml.cs diff --git a/Source/Demos/HtmlRenderer.Demo.WPF/MainWindow.xaml b/Source/Demos/HtmlRenderer.Demo.WPF/MainWindow.xaml new file mode 100644 index 000000000..fd573e40d --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.WPF/MainWindow.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/Source/Demos/HtmlRenderer.Demo.WPF/MainWindow.xaml.cs b/Source/Demos/HtmlRenderer.Demo.WPF/MainWindow.xaml.cs new file mode 100644 index 000000000..a3d871eb3 --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.WPF/MainWindow.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace HtmlRenderer.Demo.WPF +{ + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + } +} diff --git a/Source/Demo/WPF/SampleWindow.xaml b/Source/Demos/HtmlRenderer.Demo.WPF/SampleWindow.xaml similarity index 100% rename from Source/Demo/WPF/SampleWindow.xaml rename to Source/Demos/HtmlRenderer.Demo.WPF/SampleWindow.xaml diff --git a/Source/Demo/WPF/SampleWindow.xaml.cs b/Source/Demos/HtmlRenderer.Demo.WPF/SampleWindow.xaml.cs similarity index 96% rename from Source/Demo/WPF/SampleWindow.xaml.cs rename to Source/Demos/HtmlRenderer.Demo.WPF/SampleWindow.xaml.cs index 8b13056de..7be876f63 100644 --- a/Source/Demo/WPF/SampleWindow.xaml.cs +++ b/Source/Demos/HtmlRenderer.Demo.WPF/SampleWindow.xaml.cs @@ -14,6 +14,7 @@ using System.Windows.Input; using TheArtOfDev.HtmlRenderer.Demo.Common; using Xceed.Wpf.Toolkit.PropertyGrid; +//using Xceed.Wpf.Toolkit.PropertyGrid; namespace TheArtOfDev.HtmlRenderer.Demo.WPF { diff --git a/Source/Demo/WPF/ToolStripImageConverter.cs b/Source/Demos/HtmlRenderer.Demo.WPF/ToolStripImageConverter.cs similarity index 90% rename from Source/Demo/WPF/ToolStripImageConverter.cs rename to Source/Demos/HtmlRenderer.Demo.WPF/ToolStripImageConverter.cs index 9e3804993..bf303d177 100644 --- a/Source/Demo/WPF/ToolStripImageConverter.cs +++ b/Source/Demos/HtmlRenderer.Demo.WPF/ToolStripImageConverter.cs @@ -21,7 +21,7 @@ public class ToolStripImageConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - var imageStream = typeof(Resources).Assembly.GetManifestResourceStream("TheArtOfDev.HtmlRenderer.Demo.Common.Resources." + parameter + ".png"); + var imageStream = typeof(Resources).Assembly.GetManifestResourceStream("HtmlRenderer.Demo.Common.Resources." + parameter + ".png"); return HtmlRenderingHelper.ImageFromStream(imageStream); } diff --git a/Source/Demo/WPF/fonts/CustomFont.ttf b/Source/Demos/HtmlRenderer.Demo.WPF/fonts/CustomFont.ttf similarity index 100% rename from Source/Demo/WPF/fonts/CustomFont.ttf rename to Source/Demos/HtmlRenderer.Demo.WPF/fonts/CustomFont.ttf diff --git a/Source/Demo/WPF/html.ico b/Source/Demos/HtmlRenderer.Demo.WPF/html.ico similarity index 100% rename from Source/Demo/WPF/html.ico rename to Source/Demos/HtmlRenderer.Demo.WPF/html.ico diff --git a/Source/Demo/WinForms/DemoForm.Designer.cs b/Source/Demos/HtmlRenderer.Demo.WinForms/DemoForm.Designer.cs similarity index 100% rename from Source/Demo/WinForms/DemoForm.Designer.cs rename to Source/Demos/HtmlRenderer.Demo.WinForms/DemoForm.Designer.cs diff --git a/Source/Demo/WinForms/DemoForm.cs b/Source/Demos/HtmlRenderer.Demo.WinForms/DemoForm.cs similarity index 93% rename from Source/Demo/WinForms/DemoForm.cs rename to Source/Demos/HtmlRenderer.Demo.WinForms/DemoForm.cs index 3e7287b70..948fb340d 100644 --- a/Source/Demo/WinForms/DemoForm.cs +++ b/Source/Demos/HtmlRenderer.Demo.WinForms/DemoForm.cs @@ -19,7 +19,7 @@ using TheArtOfDev.HtmlRenderer.Demo.Common; using TheArtOfDev.HtmlRenderer.PdfSharp; using TheArtOfDev.HtmlRenderer.WinForms; -using PdfSharp; +using PdfSharpCore; namespace TheArtOfDev.HtmlRenderer.Demo.WinForms { @@ -138,17 +138,21 @@ private void OnGenerateImage_Click(object sender, EventArgs e) /// /// Create PDF using PdfSharp project, save to file and open that file. /// - private void OnGeneratePdf_Click(object sender, EventArgs e) + private async void OnGeneratePdf_Click(object sender, EventArgs e) { PdfGenerateConfig config = new PdfGenerateConfig(); config.PageSize = PageSize.A4; config.SetMargins(20); - var doc = PdfGenerator.GeneratePdf(_mainControl.GetHtml(), config, null, DemoUtils.OnStylesheetLoad, HtmlRenderingHelper.OnImageLoadPdfSharp); + var doc = await PdfGenerator.GeneratePdfAsync(_mainControl.GetHtml(), config, null, DemoUtils.OnStylesheetLoad, HtmlRenderingHelper.OnImageLoadPdfSharp); var tmpFile = Path.GetTempFileName(); tmpFile = Path.GetFileNameWithoutExtension(tmpFile) + ".pdf"; doc.Save(tmpFile); - Process.Start(tmpFile); + + ProcessStartInfo psi = new ProcessStartInfo(); + psi.FileName = tmpFile; + psi.UseShellExecute = true; + Process.Start(psi); } /// diff --git a/Source/Demo/WinForms/DemoForm.resx b/Source/Demos/HtmlRenderer.Demo.WinForms/DemoForm.resx similarity index 100% rename from Source/Demo/WinForms/DemoForm.resx rename to Source/Demos/HtmlRenderer.Demo.WinForms/DemoForm.resx diff --git a/Source/Demo/WinForms/GenerateImageForm.Designer.cs b/Source/Demos/HtmlRenderer.Demo.WinForms/GenerateImageForm.Designer.cs similarity index 100% rename from Source/Demo/WinForms/GenerateImageForm.Designer.cs rename to Source/Demos/HtmlRenderer.Demo.WinForms/GenerateImageForm.Designer.cs diff --git a/Source/Demo/WinForms/GenerateImageForm.cs b/Source/Demos/HtmlRenderer.Demo.WinForms/GenerateImageForm.cs similarity index 100% rename from Source/Demo/WinForms/GenerateImageForm.cs rename to Source/Demos/HtmlRenderer.Demo.WinForms/GenerateImageForm.cs diff --git a/Source/Demo/WinForms/GenerateImageForm.resx b/Source/Demos/HtmlRenderer.Demo.WinForms/GenerateImageForm.resx similarity index 100% rename from Source/Demo/WinForms/GenerateImageForm.resx rename to Source/Demos/HtmlRenderer.Demo.WinForms/GenerateImageForm.resx diff --git a/Source/Demos/HtmlRenderer.Demo.WinForms/HtmlRenderer.Demo.WinForms.csproj b/Source/Demos/HtmlRenderer.Demo.WinForms/HtmlRenderer.Demo.WinForms.csproj new file mode 100644 index 000000000..3df2670a5 --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.WinForms/HtmlRenderer.Demo.WinForms.csproj @@ -0,0 +1,25 @@ + + + + WinExe + net7.0-windows + disable + true + enable + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Source/Demo/WinForms/HtmlRenderingHelper.cs b/Source/Demos/HtmlRenderer.Demo.WinForms/HtmlRenderingHelper.cs similarity index 90% rename from Source/Demo/WinForms/HtmlRenderingHelper.cs rename to Source/Demos/HtmlRenderer.Demo.WinForms/HtmlRenderingHelper.cs index 8ca593314..011030906 100644 --- a/Source/Demo/WinForms/HtmlRenderingHelper.cs +++ b/Source/Demos/HtmlRenderer.Demo.WinForms/HtmlRenderingHelper.cs @@ -10,7 +10,7 @@ // - Sun Tsu, // "The Art of War" -using PdfSharp.Drawing; +using PdfSharpCore.Drawing; using System; using System.Collections.Generic; using System.Drawing; @@ -88,7 +88,7 @@ public static XImage TryLoadResourceXImage(string src) using (var ms = new MemoryStream()) { img.Save(ms, img.RawFormat); - xImg = img != null ? XImage.FromStream(ms) : null; + xImg = img != null ? XImage.FromStream(() => ms) : null; } return xImg; @@ -123,7 +123,8 @@ public static void ImageLoad(HtmlImageLoadEventArgs e, bool pdfSharp) using (var ms = new MemoryStream()) { img.Save(ms, img.RawFormat); - xImg = img != null ? XImage.FromStream(ms) : null; + ms.Seek(0, SeekOrigin.Begin); + xImg = img != null ? XImage.FromStream(() => ms) : null; } } @@ -144,13 +145,13 @@ public static void ImageLoad(HtmlImageLoadEventArgs e, bool pdfSharp) ThreadPool.QueueUserWorkItem(state => { Thread.Sleep(delay); - e.Callback("https://fbcdn-sphotos-a-a.akamaihd.net/hphotos-ak-snc7/c0.44.403.403/p403x403/318890_10151195988833836_1081776452_n.jpg"); + //e.Callback("https://fbcdn-sphotos-a-a.akamaihd.net/hphotos-ak-snc7/c0.44.403.403/p403x403/318890_10151195988833836_1081776452_n.jpg"); }); return; } else { - e.Callback("http://sphotos-a.xx.fbcdn.net/hphotos-ash4/c22.0.403.403/p403x403/263440_10152243591765596_773620816_n.jpg"); + //e.Callback("http://sphotos-a.xx.fbcdn.net/hphotos-ash4/c22.0.403.403/p403x403/263440_10152243591765596_773620816_n.jpg"); return; } } diff --git a/Source/Demo/WinForms/MainControl.Designer.cs b/Source/Demos/HtmlRenderer.Demo.WinForms/MainControl.Designer.cs similarity index 100% rename from Source/Demo/WinForms/MainControl.Designer.cs rename to Source/Demos/HtmlRenderer.Demo.WinForms/MainControl.Designer.cs diff --git a/Source/Demo/WinForms/MainControl.cs b/Source/Demos/HtmlRenderer.Demo.WinForms/MainControl.cs similarity index 100% rename from Source/Demo/WinForms/MainControl.cs rename to Source/Demos/HtmlRenderer.Demo.WinForms/MainControl.cs diff --git a/Source/Demo/WinForms/MainControl.resx b/Source/Demos/HtmlRenderer.Demo.WinForms/MainControl.resx similarity index 100% rename from Source/Demo/WinForms/MainControl.resx rename to Source/Demos/HtmlRenderer.Demo.WinForms/MainControl.resx diff --git a/Source/Demo/WinForms/PerfForm.Designer.cs b/Source/Demos/HtmlRenderer.Demo.WinForms/PerfForm.Designer.cs similarity index 100% rename from Source/Demo/WinForms/PerfForm.Designer.cs rename to Source/Demos/HtmlRenderer.Demo.WinForms/PerfForm.Designer.cs diff --git a/Source/Demo/WinForms/PerfForm.cs b/Source/Demos/HtmlRenderer.Demo.WinForms/PerfForm.cs similarity index 100% rename from Source/Demo/WinForms/PerfForm.cs rename to Source/Demos/HtmlRenderer.Demo.WinForms/PerfForm.cs diff --git a/Source/Demo/WinForms/PerfForm.resx b/Source/Demos/HtmlRenderer.Demo.WinForms/PerfForm.resx similarity index 100% rename from Source/Demo/WinForms/PerfForm.resx rename to Source/Demos/HtmlRenderer.Demo.WinForms/PerfForm.resx diff --git a/Source/Demo/WinForms/Program.cs b/Source/Demos/HtmlRenderer.Demo.WinForms/Program.cs similarity index 100% rename from Source/Demo/WinForms/Program.cs rename to Source/Demos/HtmlRenderer.Demo.WinForms/Program.cs diff --git a/Source/Demo/WinForms/Properties/AssemblyInfo.cs b/Source/Demos/HtmlRenderer.Demo.WinForms/Properties/AssemblyInfo.cs similarity index 100% rename from Source/Demo/WinForms/Properties/AssemblyInfo.cs rename to Source/Demos/HtmlRenderer.Demo.WinForms/Properties/AssemblyInfo.cs diff --git a/Source/Demo/WinForms/SampleForm.Designer.cs b/Source/Demos/HtmlRenderer.Demo.WinForms/SampleForm.Designer.cs similarity index 100% rename from Source/Demo/WinForms/SampleForm.Designer.cs rename to Source/Demos/HtmlRenderer.Demo.WinForms/SampleForm.Designer.cs diff --git a/Source/Demo/WinForms/SampleForm.cs b/Source/Demos/HtmlRenderer.Demo.WinForms/SampleForm.cs similarity index 100% rename from Source/Demo/WinForms/SampleForm.cs rename to Source/Demos/HtmlRenderer.Demo.WinForms/SampleForm.cs diff --git a/Source/Demo/WinForms/SampleForm.resx b/Source/Demos/HtmlRenderer.Demo.WinForms/SampleForm.resx similarity index 100% rename from Source/Demo/WinForms/SampleForm.resx rename to Source/Demos/HtmlRenderer.Demo.WinForms/SampleForm.resx diff --git a/Source/Demos/HtmlRenderer.Demo.WinForms/app.config b/Source/Demos/HtmlRenderer.Demo.WinForms/app.config new file mode 100644 index 000000000..3e0e37cfc --- /dev/null +++ b/Source/Demos/HtmlRenderer.Demo.WinForms/app.config @@ -0,0 +1,3 @@ + + + diff --git a/Source/Demo/WinForms/html.ico b/Source/Demos/HtmlRenderer.Demo.WinForms/html.ico similarity index 100% rename from Source/Demo/WinForms/html.ico rename to Source/Demos/HtmlRenderer.Demo.WinForms/html.ico diff --git a/Source/Demo/WinForms/packages.config b/Source/Demos/HtmlRenderer.Demo.WinForms/packages.config similarity index 100% rename from Source/Demo/WinForms/packages.config rename to Source/Demos/HtmlRenderer.Demo.WinForms/packages.config diff --git a/Source/HtmlRenderer.PdfSharp/Adapters/BrushAdapter.cs b/Source/HtmlRenderer.PdfSharp/Adapters/BrushAdapter.cs index a07a5dcaf..4a3bfe242 100644 --- a/Source/HtmlRenderer.PdfSharp/Adapters/BrushAdapter.cs +++ b/Source/HtmlRenderer.PdfSharp/Adapters/BrushAdapter.cs @@ -12,7 +12,7 @@ using System; using TheArtOfDev.HtmlRenderer.Adapters; -using PdfSharp.Drawing; +using PdfSharpCore.Drawing; namespace TheArtOfDev.HtmlRenderer.PdfSharp.Adapters { diff --git a/Source/HtmlRenderer.PdfSharp/Adapters/FontAdapter.cs b/Source/HtmlRenderer.PdfSharp/Adapters/FontAdapter.cs index 07e7c40a9..d606567f5 100644 --- a/Source/HtmlRenderer.PdfSharp/Adapters/FontAdapter.cs +++ b/Source/HtmlRenderer.PdfSharp/Adapters/FontAdapter.cs @@ -11,7 +11,7 @@ // "The Art of War" using TheArtOfDev.HtmlRenderer.Adapters; -using PdfSharp.Drawing; +using PdfSharpCore.Drawing; namespace TheArtOfDev.HtmlRenderer.PdfSharp.Adapters { diff --git a/Source/HtmlRenderer.PdfSharp/Adapters/FontFamilyAdapter.cs b/Source/HtmlRenderer.PdfSharp/Adapters/FontFamilyAdapter.cs index 5bfd46494..fdb5cb94b 100644 --- a/Source/HtmlRenderer.PdfSharp/Adapters/FontFamilyAdapter.cs +++ b/Source/HtmlRenderer.PdfSharp/Adapters/FontFamilyAdapter.cs @@ -11,7 +11,7 @@ // "The Art of War" using TheArtOfDev.HtmlRenderer.Adapters; -using PdfSharp.Drawing; +using PdfSharpCore.Drawing; namespace TheArtOfDev.HtmlRenderer.PdfSharp.Adapters { diff --git a/Source/HtmlRenderer.PdfSharp/Adapters/GraphicsAdapter.cs b/Source/HtmlRenderer.PdfSharp/Adapters/GraphicsAdapter.cs index c6d406c58..f3e7f9d8c 100644 --- a/Source/HtmlRenderer.PdfSharp/Adapters/GraphicsAdapter.cs +++ b/Source/HtmlRenderer.PdfSharp/Adapters/GraphicsAdapter.cs @@ -10,7 +10,7 @@ // - Sun Tsu, // "The Art of War" -using PdfSharp.Drawing; +using PdfSharpCore.Drawing; using System; using TheArtOfDev.HtmlRenderer.Adapters; using TheArtOfDev.HtmlRenderer.Adapters.Entities; diff --git a/Source/HtmlRenderer.PdfSharp/Adapters/GraphicsPathAdapter.cs b/Source/HtmlRenderer.PdfSharp/Adapters/GraphicsPathAdapter.cs index 48290543c..6646987bb 100644 --- a/Source/HtmlRenderer.PdfSharp/Adapters/GraphicsPathAdapter.cs +++ b/Source/HtmlRenderer.PdfSharp/Adapters/GraphicsPathAdapter.cs @@ -13,7 +13,7 @@ using System; using TheArtOfDev.HtmlRenderer.Adapters; using TheArtOfDev.HtmlRenderer.Adapters.Entities; -using PdfSharp.Drawing; +using PdfSharpCore.Drawing; namespace TheArtOfDev.HtmlRenderer.PdfSharp.Adapters { diff --git a/Source/HtmlRenderer.PdfSharp/Adapters/ImageAdapter.cs b/Source/HtmlRenderer.PdfSharp/Adapters/ImageAdapter.cs index 48b911aca..36f809334 100644 --- a/Source/HtmlRenderer.PdfSharp/Adapters/ImageAdapter.cs +++ b/Source/HtmlRenderer.PdfSharp/Adapters/ImageAdapter.cs @@ -11,7 +11,7 @@ // "The Art of War" using TheArtOfDev.HtmlRenderer.Adapters; -using PdfSharp.Drawing; +using PdfSharpCore.Drawing; namespace TheArtOfDev.HtmlRenderer.PdfSharp.Adapters { diff --git a/Source/HtmlRenderer.PdfSharp/Adapters/PdfSharpAdapter.cs b/Source/HtmlRenderer.PdfSharp/Adapters/PdfSharpAdapter.cs index e5fa309c0..e9aa3c341 100644 --- a/Source/HtmlRenderer.PdfSharp/Adapters/PdfSharpAdapter.cs +++ b/Source/HtmlRenderer.PdfSharp/Adapters/PdfSharpAdapter.cs @@ -10,8 +10,8 @@ // - Sun Tsu, // "The Art of War" -using PdfSharp.Drawing; -using PdfSharp.Pdf; +using PdfSharpCore.Drawing; +using PdfSharpCore.Pdf; using System.Drawing; using System.Drawing.Text; using System.IO; @@ -114,7 +114,7 @@ protected override RImage ConvertImageInt(object image) protected override RImage ImageFromStreamInt(Stream memoryStream) { - return new ImageAdapter(XImage.FromStream(memoryStream)); + return new ImageAdapter(XImage.FromStream(() => memoryStream)); } protected override RFont CreateFontInt(string family, double size, RFontStyle style) diff --git a/Source/HtmlRenderer.PdfSharp/Adapters/PenAdapter.cs b/Source/HtmlRenderer.PdfSharp/Adapters/PenAdapter.cs index bc5cb2099..4391b339c 100644 --- a/Source/HtmlRenderer.PdfSharp/Adapters/PenAdapter.cs +++ b/Source/HtmlRenderer.PdfSharp/Adapters/PenAdapter.cs @@ -12,7 +12,7 @@ using TheArtOfDev.HtmlRenderer.Adapters; using TheArtOfDev.HtmlRenderer.Adapters.Entities; -using PdfSharp.Drawing; +using PdfSharpCore.Drawing; namespace TheArtOfDev.HtmlRenderer.PdfSharp.Adapters { diff --git a/Source/HtmlRenderer.PdfSharp/Adapters/XTextureBrush.cs b/Source/HtmlRenderer.PdfSharp/Adapters/XTextureBrush.cs index 39f1fac82..31ffe3e84 100644 --- a/Source/HtmlRenderer.PdfSharp/Adapters/XTextureBrush.cs +++ b/Source/HtmlRenderer.PdfSharp/Adapters/XTextureBrush.cs @@ -10,7 +10,7 @@ // - Sun Tsu, // "The Art of War" -using PdfSharp.Drawing; +using PdfSharpCore.Drawing; namespace TheArtOfDev.HtmlRenderer.PdfSharp.Adapters { diff --git a/Source/HtmlRenderer.PdfSharp/HtmlContainer.cs b/Source/HtmlRenderer.PdfSharp/HtmlContainer.cs index 9339fd562..ddc1a4891 100644 --- a/Source/HtmlRenderer.PdfSharp/HtmlContainer.cs +++ b/Source/HtmlRenderer.PdfSharp/HtmlContainer.cs @@ -10,7 +10,7 @@ // - Sun Tsu, // "The Art of War" -using PdfSharp.Drawing; +using PdfSharpCore.Drawing; using System; using System.Collections.Generic; using TheArtOfDev.HtmlRenderer.Adapters.Entities; @@ -324,13 +324,13 @@ public string GetLinkAt(XPoint location) /// Measures the bounds of box and children, recursively. /// /// Device context to draw - public void PerformLayout(XGraphics g) + public async Task PerformLayoutAsync(XGraphics g) { ArgChecker.AssertArgNotNull(g, "g"); using (var ig = new GraphicsAdapter(g)) { - _htmlContainerInt.PerformLayout(ig); + await _htmlContainerInt.PerformLayout(ig); } } @@ -338,13 +338,13 @@ public void PerformLayout(XGraphics g) /// Render the html using the given device. /// /// the device to use to render - public void PerformPaint(XGraphics g) + public async Task PerformPaintAsync(XGraphics g) { ArgChecker.AssertArgNotNull(g, "g"); using (var ig = new GraphicsAdapter(g)) { - _htmlContainerInt.PerformPaint(ig); + await _htmlContainerInt.PerformPaint(ig); } } diff --git a/Source/HtmlRenderer.PdfSharp/HtmlRenderer.PdfSharp.csproj b/Source/HtmlRenderer.PdfSharp/HtmlRenderer.PdfSharp.csproj index ef0fd7acc..5aa475723 100644 --- a/Source/HtmlRenderer.PdfSharp/HtmlRenderer.PdfSharp.csproj +++ b/Source/HtmlRenderer.PdfSharp/HtmlRenderer.PdfSharp.csproj @@ -1,90 +1,18 @@ - - - + + - Debug - AnyCPU - {CA249F5D-9285-40A6-B217-5889EF79FD7E} - Library - Properties - TheArtOfDev.HtmlRenderer.PdfSharp - HtmlRenderer.PdfSharp - v2.0 - 512 - ..\ - true + net7.0 + enable + disable - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\packages\PDFsharp.1.50.4000-beta3b\lib\net20\PdfSharp.dll - True - - - ..\packages\PDFsharp.1.50.4000-beta3b\lib\net20\PdfSharp.Charting.dll - True - - - - - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - + - - {fe611685-391f-4e3e-b27e-d3150e51e49b} - HtmlRenderer - + + + - + - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file + + diff --git a/Source/HtmlRenderer.PdfSharp/PdfGenerateConfig.cs b/Source/HtmlRenderer.PdfSharp/PdfGenerateConfig.cs index b0aa0d64c..810570743 100644 --- a/Source/HtmlRenderer.PdfSharp/PdfGenerateConfig.cs +++ b/Source/HtmlRenderer.PdfSharp/PdfGenerateConfig.cs @@ -10,8 +10,8 @@ // - Sun Tsu, // "The Art of War" -using PdfSharp; -using PdfSharp.Drawing; +using PdfSharpCore; +using PdfSharpCore.Drawing; namespace TheArtOfDev.HtmlRenderer.PdfSharp { diff --git a/Source/HtmlRenderer.PdfSharp/PdfGenerator.cs b/Source/HtmlRenderer.PdfSharp/PdfGenerator.cs index 365be2d95..c7bda8ce4 100644 --- a/Source/HtmlRenderer.PdfSharp/PdfGenerator.cs +++ b/Source/HtmlRenderer.PdfSharp/PdfGenerator.cs @@ -10,9 +10,9 @@ // - Sun Tsu, // "The Art of War" -using PdfSharp; -using PdfSharp.Drawing; -using PdfSharp.Pdf; +using PdfSharpCore; +using PdfSharpCore.Drawing; +using PdfSharpCore.Pdf; using System; using TheArtOfDev.HtmlRenderer.Core; using TheArtOfDev.HtmlRenderer.Core.Entities; @@ -68,12 +68,12 @@ public static CssData ParseStyleSheet(string stylesheet, bool combineWithDefault /// optional: can be used to overwrite stylesheet resolution logic /// optional: can be used to overwrite image resolution logic /// the generated image of the html - public static PdfDocument GeneratePdf(string html, PageSize pageSize, int margin = 20, CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) + public static async Task GeneratePdfAsync(string html, PageSize pageSize, int margin = 20, CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) { var config = new PdfGenerateConfig(); config.PageSize = pageSize; config.SetMargins(margin); - return GeneratePdf(html, config, cssData, stylesheetLoad, imageLoad); + return await GeneratePdfAsync(html, config, cssData, stylesheetLoad, imageLoad); } /// @@ -85,13 +85,13 @@ public static PdfDocument GeneratePdf(string html, PageSize pageSize, int margin /// optional: can be used to overwrite stylesheet resolution logic /// optional: can be used to overwrite image resolution logic /// the generated image of the html - public static PdfDocument GeneratePdf(string html, PdfGenerateConfig config, CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) + public static async Task GeneratePdfAsync(string html, PdfGenerateConfig config, CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) { // create PDF document to render the HTML into var document = new PdfDocument(); // add rendered PDF pages to document - AddPdfPages(document, html, config, cssData, stylesheetLoad, imageLoad); + await AddPdfPagesAsync(document, html, config, cssData, stylesheetLoad, imageLoad); return document; } @@ -107,12 +107,12 @@ public static PdfDocument GeneratePdf(string html, PdfGenerateConfig config, Css /// optional: can be used to overwrite stylesheet resolution logic /// optional: can be used to overwrite image resolution logic /// the generated image of the html - public static void AddPdfPages(PdfDocument document, string html, PageSize pageSize, int margin = 20, CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) + public static async Task AddPdfPagesAsync(PdfDocument document, string html, PageSize pageSize, int margin = 20, CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) { var config = new PdfGenerateConfig(); config.PageSize = pageSize; config.SetMargins(margin); - AddPdfPages(document, html, config, cssData, stylesheetLoad, imageLoad); + await AddPdfPagesAsync(document, html, config, cssData, stylesheetLoad, imageLoad); } /// @@ -125,7 +125,7 @@ public static void AddPdfPages(PdfDocument document, string html, PageSize pageS /// optional: can be used to overwrite stylesheet resolution logic /// optional: can be used to overwrite image resolution logic /// the generated image of the html - public static void AddPdfPages(PdfDocument document, string html, PdfGenerateConfig config, CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) + public static async Task AddPdfPagesAsync(PdfDocument document, string html, PdfGenerateConfig config, CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) { XSize orgPageSize; // get the size of each page to layout the HTML in @@ -163,7 +163,7 @@ public static void AddPdfPages(PdfDocument document, string html, PdfGenerateCon // layout the HTML with the page width restriction to know how many pages are required using (var measure = XGraphics.CreateMeasureContext(pageSize, XGraphicsUnit.Point, XPageDirection.Downwards)) { - container.PerformLayout(measure); + await container.PerformLayoutAsync(measure); } // while there is un-rendered HTML, create another PDF page and render with proper offset for the next page @@ -180,7 +180,7 @@ public static void AddPdfPages(PdfDocument document, string html, PdfGenerateCon g.IntersectClip(new XRect(0, 0, page.Width, page.Height)); container.ScrollOffset = new XPoint(0, scrollOffset); - container.PerformPaint(g); + await container.PerformPaintAsync(g); } scrollOffset -= pageSize.Height; } diff --git a/Source/HtmlRenderer.PdfSharp/Utilities/Utils.cs b/Source/HtmlRenderer.PdfSharp/Utilities/Utils.cs index 59ac2c4b5..106858645 100644 --- a/Source/HtmlRenderer.PdfSharp/Utilities/Utils.cs +++ b/Source/HtmlRenderer.PdfSharp/Utilities/Utils.cs @@ -10,7 +10,7 @@ // - Sun Tsu, // "The Art of War" -using PdfSharp.Drawing; +using PdfSharpCore.Drawing; using System.Drawing; using TheArtOfDev.HtmlRenderer.Adapters.Entities; diff --git a/Source/HtmlRenderer.PdfSharp/packages.config b/Source/HtmlRenderer.PdfSharp/packages.config deleted file mode 100644 index 2f092fd78..000000000 --- a/Source/HtmlRenderer.PdfSharp/packages.config +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/Source/HtmlRenderer.SkiaSharp/Adapters/BrushAdapter.cs b/Source/HtmlRenderer.SkiaSharp/Adapters/BrushAdapter.cs new file mode 100644 index 000000000..09e727b8d --- /dev/null +++ b/Source/HtmlRenderer.SkiaSharp/Adapters/BrushAdapter.cs @@ -0,0 +1,122 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using SkiaSharp; +using System; +using TheArtOfDev.HtmlRenderer.Adapters; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; +using TheArtOfDev.HtmlRenderer.SkiaSharp.Utilities; + +namespace TheArtOfDev.HtmlRenderer.SkiaSharp.Adapters +{ + + + public class SKBrush + { + public enum Types + { + Solid, + LinearGradient + } + + + public static SKBrush Black = new SKBrush(SKColors.Black); + public static SKBrush White = new SKBrush(SKColors.White); + public static SKBrush Transparent = new SKBrush(SKColors.Transparent); + + public SKPaint GetPaint() + { + if (this.Type == Types.Solid) + { + return new SKPaint + { + Color = Color + }; + } + else + { + //TODO: linear gradient. + return new SKPaint + { + Color = Color + }; + } + } + + public Types Type { get; set; } + + public SKColor Color { get; set; } + + public SKPathEffect PathEffect { get; set; } + + public SKShader Shader { get; set; } + + + public SKBrush(SKColor color = default, Types type = Types.Solid) + { + Type = type; + Color = color; + } + + public SKBrush(SKRect rect, SKColor color1, SKColor color2, float angle = 0, Types type = Types.LinearGradient) + { + Type = type; + + var colors = new SKColor[] { + color1, + color2 + }; + + // Leave it Horizontal for now... + var pointA = new SKPoint(rect.Left, rect.MidY); + var pointB = new SKPoint(rect.Right, rect.MidY); + + Shader = SKShader.CreateLinearGradient( + pointA, pointB, + colors, + null, + SKShaderTileMode.Clamp); + } + } + + + /// + /// Adapter for WinForms brushes objects for core. + /// + internal sealed class BrushAdapter : RBrush + { + /// + /// The actual PdfSharp brush instance.
+ /// Should be but there is some fucking issue inheriting from it =/ + ///
+ private readonly Object _brush; + + /// + /// Init. + /// + public BrushAdapter(Object brush) + { + _brush = brush; + } + + /// + /// The actual WinForms brush instance. + /// + public Object Brush + { + get { return _brush; } + } + + public override void Dispose() + { } + } +} \ No newline at end of file diff --git a/Source/HtmlRenderer.SkiaSharp/Adapters/FontAdapter.cs b/Source/HtmlRenderer.SkiaSharp/Adapters/FontAdapter.cs new file mode 100644 index 000000000..e1028f5b3 --- /dev/null +++ b/Source/HtmlRenderer.SkiaSharp/Adapters/FontAdapter.cs @@ -0,0 +1,106 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using SkiaSharp; +using TheArtOfDev.HtmlRenderer.Adapters; + + +namespace TheArtOfDev.HtmlRenderer.SkiaSharp.Adapters +{ + /// + /// Adapter for WinForms Font object for core. + /// + internal sealed class FontAdapter : RFont + { + #region Fields and Consts + + /// + /// the underline win-forms font. + /// + private readonly SKFont _font; + + /// + /// the vertical offset of the font underline location from the top of the font. + /// + private double _underlineOffset = -1; + + /// + /// Cached font height. + /// + private double _height = -1; + + /// + /// Cached font whitespace width. + /// + private double _whitespaceWidth = -1; + + #endregion + + + /// + /// Init. + /// + public FontAdapter(SKFont font) + { + _font = font; + } + + /// + /// the underline win-forms font. + /// + public SKFont Font + { + get { return _font; } + } + + public override double Size + { + get { return _font.Size; } + } + + public override double UnderlineOffset + { + get { return _underlineOffset; } + } + + public override double Height + { + get { return _height; } + } + + public override double LeftPadding + { + get { return _height / 6f; } + } + + + public override double GetWhitespaceWidth(RGraphics graphics) + { + if (_whitespaceWidth < 0) + { + _whitespaceWidth = graphics.MeasureString(" ", this).Width; + } + return _whitespaceWidth; + } + + /// + /// Set font metrics to be cached for the font for future use. + /// + /// the full height of the font + /// the vertical offset of the font underline location from the top of the font. + internal void SetMetrics(int height, int underlineOffset) + { + _height = height; + _underlineOffset = underlineOffset; + } + } +} \ No newline at end of file diff --git a/Source/HtmlRenderer.SkiaSharp/Adapters/FontFamilyAdapter.cs b/Source/HtmlRenderer.SkiaSharp/Adapters/FontFamilyAdapter.cs new file mode 100644 index 000000000..d53c11a59 --- /dev/null +++ b/Source/HtmlRenderer.SkiaSharp/Adapters/FontFamilyAdapter.cs @@ -0,0 +1,49 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using TheArtOfDev.HtmlRenderer.Adapters; + + +namespace TheArtOfDev.HtmlRenderer.SkiaSharp.Adapters +{ + /// + /// Adapter for WinForms Font object for core. + /// + internal sealed class FontFamilyAdapter : RFontFamily + { + /// + /// the underline win-forms font. + /// + private readonly string _fontFamily; + + /// + /// Init. + /// + public FontFamilyAdapter(string fontFamily) + { + _fontFamily = fontFamily; + } + + /// + /// the underline win-forms font family. + /// + public string FontFamily + { + get { return _fontFamily; } + } + + public override string Name + { + get { return _fontFamily; } + } + } +} \ No newline at end of file diff --git a/Source/HtmlRenderer.SkiaSharp/Adapters/GraphicsAdapter.cs b/Source/HtmlRenderer.SkiaSharp/Adapters/GraphicsAdapter.cs new file mode 100644 index 000000000..6ec065bc4 --- /dev/null +++ b/Source/HtmlRenderer.SkiaSharp/Adapters/GraphicsAdapter.cs @@ -0,0 +1,244 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using SkiaSharp; +using System; +using TheArtOfDev.HtmlRenderer.Adapters; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; +using TheArtOfDev.HtmlRenderer.Core.Utils; +using TheArtOfDev.HtmlRenderer.SkiaSharp.Utilities; + +namespace TheArtOfDev.HtmlRenderer.SkiaSharp.Adapters +{ + /// + /// Adapter for Skia Graphics for core. + /// + internal sealed class GraphicsAdapter : RGraphics + { + #region Fields and Consts + + /// + /// The wrapped SkiaSharp graphics object + /// + private readonly SKCanvas _g; + + /// + /// if to release the graphics object on dispose + /// + private readonly bool _releaseGraphics; + + /// + /// Used to measure and draw strings + /// + private static readonly SKTextAlign _stringFormat; + + #endregion + + + static GraphicsAdapter() + { + _stringFormat = new SKTextAlign(); + //_stringFormat.Alignment = XStringAlignment.Near; + //_stringFormat.LineAlignment = XLineAlignment.Near; + _stringFormat = SKTextAlign.Left; + } + + /// + /// Init. + /// + /// the win forms graphics object to use + /// optional: if to release the graphics object on dispose (default - false) + public GraphicsAdapter(SKCanvas g, bool releaseGraphics = false) + : base(SkiaSharpAdapter.Instance, new RRect(0, 0, double.MaxValue, double.MaxValue)) + { + ArgChecker.AssertArgNotNull(g, "g"); + + _g = g; + _releaseGraphics = releaseGraphics; + } + + public override void PopClip() + { + _clipStack.Pop(); + _g.Restore(); + } + + public override void PushClip(RRect rect) + { + _clipStack.Push(rect); + _g.Save(); + _g.ClipRect(Utils.Convert(rect)); + } + + public override void PushClipExclude(RRect rect) + { } + + bool _antiAlias = true; + public override Object SetAntiAliasSmoothingMode() + { + /* + var prevMode = _; + _g.SmoothingMode = XSmoothingMode.AntiAlias; + + return prevMode; + */ + + var prevMode = _antiAlias; + _antiAlias = true; + return prevMode; + } + + public override void ReturnPreviousSmoothingMode(Object prevMode) + { + /* + if (prevMode != null) + { + _g.SmoothingMode = (XSmoothingMode)prevMode; + }*/ + if (prevMode != null) + { + _antiAlias = (bool)prevMode; + } + } + + public override RSize MeasureString(string str, RFont font) + { + var fontAdapter = (FontAdapter)font; + var realFont = fontAdapter.Font; + var p = new SKPaint(realFont); + var boundingRect = new SKRect(); + var measuredWidth = p.MeasureText(str, ref boundingRect); + + if (font.Height < 0) + { + var height = realFont.Metrics.XMax + realFont.Metrics.XMin; + var descent = realFont.Metrics.Descent; + fontAdapter.SetMetrics((int)Math.Round(height, MidpointRounding.AwayFromZero), (int)Math.Round((height - descent + 1f), MidpointRounding.AwayFromZero)); + } + + return new RSize(measuredWidth, boundingRect.Height); + } + + public override void MeasureString(string str, RFont font, double maxWidth, out int charFit, out double charFitWidth) + { + // there is no need for it - used for text selection + throw new NotSupportedException(); + } + + public override void DrawString(string str, RFont font, RColor color, RPoint point, RSize size, bool rtl) + { + //var xBrush = ((BrushAdapter)_adapter.GetSolidBrush(color)).Brush; + var skiaFont = ((FontAdapter)font).Font; + var p = new SKPaint + { + IsAntialias = _antiAlias, + FilterQuality = SKFilterQuality.Medium, + Color = Utils.Convert(color) + }; + _g.DrawText(str, (float)point.X, (float)point.Y - skiaFont.Metrics.Ascent, skiaFont, p); + } + + public override RBrush GetTextureBrush(RImage image, RRect dstRect, RPoint translateTransformLocation) + { + return new BrushAdapter(new XTextureBrush(((ImageAdapter)image).Image, Utils.Convert(dstRect), Utils.Convert(translateTransformLocation))); + } + + public override RGraphicsPath GetGraphicsPath() + { + return new GraphicsPathAdapter(); + } + + public override void Dispose() + { + if (_releaseGraphics) + _g.Dispose(); + } + + + #region Delegate graphics methods + + public override void DrawLine(RPen pen, double x1, double y1, double x2, double y2) + { + _g.DrawLine((float)x1, (float)y1, (float)x2, (float)y2, GetPaint(pen)); + } + + public override void DrawRectangle(RPen pen, double x, double y, double width, double height) + { + _g.DrawRect((float)x, (float)y, (float)width, (float)height, GetPaint(pen)); + } + + public override void DrawRectangle(RBrush brush, double x, double y, double width, double height) + { + var untypedBrush = ((BrushAdapter)brush).Brush; + if (untypedBrush is XTextureBrush textureBrush) + { + textureBrush.DrawRectangle(_g, (float)x, (float)y, (float)width, (float)height); + } + else if (untypedBrush is SKBrush skBrush) + { + var p = skBrush.GetPaint().Clone(); + p.IsAntialias = _antiAlias; + _g.DrawRect((float)x, (float)y, (float)width, (float)height, p); + } + } + + public override void DrawImage(RImage image, RRect destRect, RRect srcRect) + { + ((ImageAdapter)image).DrawImage(_g, Utils.Convert(destRect), Utils.Convert(srcRect)); + } + + public override void DrawImage(RImage image, RRect destRect) + { + ((ImageAdapter)image).DrawImage(_g, Utils.Convert(destRect)); + } + + public override void DrawPath(RPen pen, RGraphicsPath path) + { + _g.DrawPath(((GraphicsPathAdapter)path).GraphicsPath, GetPaint(pen)); + } + + public override void DrawPath(RBrush brush, RGraphicsPath path) + { + _g.DrawPath(((GraphicsPathAdapter)path).GraphicsPath, GetPaint(brush)); + } + + public override void DrawPolygon(RBrush brush, RPoint[] points) + { + var p = GetPaint(brush); + + if (points != null && points.Length > 0) + { + //(XBrush)((BrushAdapter)brush).Brush + var path = new SKPath(); + path.AddPoly(Utils.Convert(points)); + _g.DrawPath(path, p); + } + } + + private SKPaint GetPaint(RBrush brush) + { + SKBrush skBrush = (SKBrush)((BrushAdapter)brush).Brush; + var p = skBrush.GetPaint().Clone(); + p.IsAntialias = _antiAlias; + return p; + } + + private SKPaint GetPaint(RPen pen) + { + var skPaint = ((PenAdapter)pen).Pen.Clone(); + skPaint.IsAntialias = _antiAlias; + return skPaint; + } + + #endregion + } +} \ No newline at end of file diff --git a/Source/HtmlRenderer.SkiaSharp/Adapters/GraphicsPathAdapter.cs b/Source/HtmlRenderer.SkiaSharp/Adapters/GraphicsPathAdapter.cs new file mode 100644 index 000000000..466bd08eb --- /dev/null +++ b/Source/HtmlRenderer.SkiaSharp/Adapters/GraphicsPathAdapter.cs @@ -0,0 +1,97 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using SkiaSharp; +using System; +using TheArtOfDev.HtmlRenderer.Adapters; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; + + +namespace TheArtOfDev.HtmlRenderer.SkiaSharp.Adapters +{ + /// + /// Adapter for Skia graphics path object for core. + /// + internal sealed class GraphicsPathAdapter : RGraphicsPath + { + /// + /// The actual SKPath graphics path instance. + /// + private readonly SKPath _graphicsPath = new(); + + /// + /// the last point added to the path to begin next segment from + /// + private RPoint _lastPoint; + + /// + /// The actual SKPath graphics path instance. + /// + public SKPath GraphicsPath + { + get { return _graphicsPath; } + } + + public override void Start(double x, double y) + { + _lastPoint = new RPoint(x, y); + _graphicsPath.MoveTo((float)x, (float)y); + } + + public override void LineTo(double x, double y) + { + _graphicsPath.LineTo((float)x, (float)y); + _lastPoint = new RPoint(x, y); + } + + public override void ArcTo(double x, double y, double size, Corner corner) + { + float left = (float)(Math.Min(x, _lastPoint.X) - (corner == Corner.TopRight || corner == Corner.BottomRight ? size : 0)); + float top = (float)(Math.Min(y, _lastPoint.Y) - (corner == Corner.BottomLeft || corner == Corner.BottomRight ? size : 0)); + + var rect = SKRect.Create(left, top, (float)size * 2, (float)size * 2); + _graphicsPath.ArcTo(rect, GetStartAngle(corner), 90f, false); + _lastPoint = new RPoint(x, y); + } + + public override void Dispose() + { + _graphicsPath.Dispose(); + } + + /// + /// Get arc start angle for the given corner. + /// + private static int GetStartAngle(Corner corner) + { + int startAngle; + switch (corner) + { + case Corner.TopLeft: + startAngle = 180; + break; + case Corner.TopRight: + startAngle = 270; + break; + case Corner.BottomLeft: + startAngle = 90; + break; + case Corner.BottomRight: + startAngle = 0; + break; + default: + throw new ArgumentOutOfRangeException("corner"); + } + return startAngle; + } + } +} \ No newline at end of file diff --git a/Source/HtmlRenderer.SkiaSharp/Adapters/ImageAdapter.cs b/Source/HtmlRenderer.SkiaSharp/Adapters/ImageAdapter.cs new file mode 100644 index 000000000..1c7575ff7 --- /dev/null +++ b/Source/HtmlRenderer.SkiaSharp/Adapters/ImageAdapter.cs @@ -0,0 +1,100 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using SkiaSharp; +using TheArtOfDev.HtmlRenderer.Adapters; +using Svg.Skia; + +namespace TheArtOfDev.HtmlRenderer.SkiaSharp.Adapters +{ + /// + /// Adapter for SkiaSharp Image object for core. + /// + internal sealed class ImageAdapter : RImage + { + /// + /// the underlying image. This may be either a bitmap (_image) or an svg (_svg). + /// + private SKImage? _image; + private readonly SKSvg? _svg; + + /// + /// Initializes a new instance of the class. + /// + public ImageAdapter(SKImage image) + { + _image = image; + } + + public ImageAdapter(SKSvg svg) + { + _svg = svg; + } + + /// + /// the underline SkiaSharp image. + /// + public SKImage Image + { + get + { + if (_image == null && _svg?.Picture != null) + { + //Render the image from the picture, as this is being used in a texture brush. + _image = SKImage.FromPicture(_svg.Picture, _svg.Picture.CullRect.Size.ToSizeI()); + } + + return _image; + } + } + + public override double Width + { + get { return _image?.Width ?? _svg?.Picture?.CullRect.Width ?? 0; } + } + + public override double Height + { + get { return _image?.Height ?? _svg?.Picture?.CullRect.Height ?? 0; } + } + + public override void Dispose() + { + _image?.Dispose(); + _svg?.Picture?.Dispose(); + } + + internal void DrawImage(SKCanvas canvas, SKRect dstRect, SKRect? srcRect = null) + { + if (_svg != null) + { + //TODO: support the overload that passes a source rect. Using Matrix overload perhaps?.. + var matrix = SKMatrix.CreateTranslation(dstRect.Left, dstRect.Top); + matrix.ScaleX = dstRect.Width / _svg.Picture.CullRect.Width; + matrix.ScaleY = dstRect.Height / _svg.Picture.CullRect.Height; + + canvas.DrawPicture(_svg.Picture, ref matrix); + } + else + { + if (srcRect != null) + { + canvas.DrawImage(_image, dstRect, srcRect.Value); + } + else + { + canvas.DrawImage(_image, dstRect); + } + } + } + } +} \ No newline at end of file diff --git a/Source/HtmlRenderer.SkiaSharp/Adapters/PenAdapter.cs b/Source/HtmlRenderer.SkiaSharp/Adapters/PenAdapter.cs new file mode 100644 index 000000000..42390d079 --- /dev/null +++ b/Source/HtmlRenderer.SkiaSharp/Adapters/PenAdapter.cs @@ -0,0 +1,96 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using TheArtOfDev.HtmlRenderer.Adapters; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; +using SkiaSharp; +using System.Security.Cryptography.X509Certificates; + +namespace TheArtOfDev.HtmlRenderer.SkiaSharp.Adapters +{ + /// + /// Adapter for a Pen. Skia contains pen information in the SKPaint info, so this also wraps + /// an SKPaint. + /// + internal sealed class PenAdapter : RPen + { + /// + /// The skia equiv of a 'pen'. + /// + private readonly SKPaint _pen; + + /// + /// Init. + /// + public PenAdapter(SKPaint pen) + { + _pen = pen; + } + + /// + /// The actual WinForms brush instance. + /// + public SKPaint Pen + { + get { return _pen; } + } + + public override double Width + { + get { return _pen.StrokeWidth; } + set { _pen.StrokeWidth = (float)value; } + } + + public override RDashStyle DashStyle + { + set + { + switch (value) + { + case RDashStyle.Solid: + _pen.PathEffect = null; + //_pen.DashStyle = XDashStyle.Solid; + break; + case RDashStyle.Dash: + _pen.PathEffect = SKPathEffect.CreateDash(new float[] { 10, 10 }, 0); + if (Width < 2) + { + _pen.PathEffect = SKPathEffect.CreateDash(new float[] { 4, 4 }, 0); + } + //_pen.DashStyle = XDashStyle.Dash; + //if (Width < 2) + // _pen.DashPattern = new[] { 4, 4d }; // better looking + break; + case RDashStyle.Dot: + _pen.PathEffect = SKPathEffect.CreateDash(new float[] { 2, 10 }, 5); + //_pen.DashStyle = XDashStyle.Dot; + break; + + //TODO: support these. + //case RDashStyle.DashDot: + // _pen.DashStyle = XDashStyle.DashDot; + // break; + //case RDashStyle.DashDotDot: + // _pen.DashStyle = XDashStyle.DashDotDot; + // break; + //case RDashStyle.Custom: + // _pen.DashStyle = XDashStyle.Custom; + // break; + default: + _pen.PathEffect = null; + //_pen.DashStyle = XDashStyle.Solid + break; + } + } + } + } +} \ No newline at end of file diff --git a/Source/HtmlRenderer.SkiaSharp/Adapters/SkiaSharpAdapter.cs b/Source/HtmlRenderer.SkiaSharp/Adapters/SkiaSharpAdapter.cs new file mode 100644 index 000000000..4b6951f03 --- /dev/null +++ b/Source/HtmlRenderer.SkiaSharp/Adapters/SkiaSharpAdapter.cs @@ -0,0 +1,161 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using SkiaSharp; +using System.Drawing; +using System.Drawing.Text; +using System.IO; +using TheArtOfDev.HtmlRenderer.Adapters; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; +using TheArtOfDev.HtmlRenderer.SkiaSharp.Utilities; + +namespace TheArtOfDev.HtmlRenderer.SkiaSharp.Adapters +{ + /// + /// Adapter for SkiaSharp library platform. + /// + internal sealed class SkiaSharpAdapter : RAdapter + { + #region Fields and Consts + + /// + /// Singleton instance of global adapter. + /// + private static readonly SkiaSharpAdapter _instance = new SkiaSharpAdapter(); + + #endregion + + + /// + /// Init color resolve. + /// + private SkiaSharpAdapter() + { + AddFontFamilyMapping("monospace", "Courier New"); + AddFontFamilyMapping("Helvetica", "Arial"); + + var manager = SKFontManager.Default; + var families = manager.GetFontFamilies(); + + foreach (var family in families) + { + AddFontFamily(new FontFamilyAdapter(family)); + } + } + + /// + /// Singleton instance of global adapter. + /// + public static SkiaSharpAdapter Instance + { + get { return _instance; } + } + + protected override RColor GetColorInt(string colorName) + { + try + { + var color = Color.FromKnownColor((KnownColor)System.Enum.Parse(typeof(KnownColor), colorName, true)); + return Utils.Convert(color); + } + catch + { + return RColor.Empty; + } + } + + protected override RPen CreatePen(RColor color) + { + return new PenAdapter(new SKPaint { Color = Utils.Convert(color), IsStroke = true }); + } + + protected override RBrush CreateSolidBrush(RColor color) + { + SKBrush solidBrush; + if (color == RColor.White) + solidBrush = SKBrush.White; + else if (color == RColor.Black) + solidBrush = SKBrush.Black; + else if (color.A < 1) + solidBrush = SKBrush.Transparent; + else + solidBrush = new SKBrush(Utils.Convert(color)); + + return new BrushAdapter(solidBrush); + } + + protected override RBrush CreateLinearGradientBrush(RRect rect, RColor color1, RColor color2, double angle) + { + //XLinearGradientMode mode; + //if (angle < 45) + // mode = XLinearGradientMode.ForwardDiagonal; + //else if (angle < 90) + // mode = XLinearGradientMode.Vertical; + //else if (angle < 135) + // mode = XLinearGradientMode.BackwardDiagonal; + //else + // mode = XLinearGradientMode.Horizontal; + return new BrushAdapter(new SKBrush(Utils.Convert(rect), Utils.Convert(color1), Utils.Convert(color2), (float)angle)); + } + + protected override RImage ConvertImageInt(object image) + { + return image != null ? new ImageAdapter((SKImage)image) : null; + } + + protected override RImage ImageFromStreamInt(Stream memoryStream) + { + var image = SKImage.FromEncodedData(memoryStream); + if (image == null) + { + //Maybe an SVG? In future, let's make the html renderer pass media type if it's available. + memoryStream.Seek(0, SeekOrigin.Begin); + var skSvg = new Svg.Skia.SKSvg(); + skSvg.Load(memoryStream); + return new ImageAdapter(skSvg); + } + else + { + return new ImageAdapter(image); + } + } + + protected override RFont CreateFontInt(string family, double size, RFontStyle style) + { + SKFontStyle fontStyle; + + switch(style) + { + case RFontStyle.Bold: fontStyle = SKFontStyle.Bold; break; + case RFontStyle.Italic: fontStyle = SKFontStyle.Italic; break; + + case RFontStyle.Regular: + default: + fontStyle = SKFontStyle.Normal; break; + } + + var typeface = SKTypeface.FromFamilyName(family, fontStyle); + + var skFont = new SKFont(typeface, (float)size); + skFont.LinearMetrics = true; + skFont.Subpixel = true; + + + return new FontAdapter(skFont); + } + + protected override RFont CreateFontInt(RFontFamily family, double size, RFontStyle style) + { + return this.CreateFontInt(((FontFamilyAdapter)family).FontFamily, size, style); + } + } +} \ No newline at end of file diff --git a/Source/HtmlRenderer.SkiaSharp/Adapters/XTextureBrush.cs b/Source/HtmlRenderer.SkiaSharp/Adapters/XTextureBrush.cs new file mode 100644 index 000000000..e580e0c39 --- /dev/null +++ b/Source/HtmlRenderer.SkiaSharp/Adapters/XTextureBrush.cs @@ -0,0 +1,77 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + + +using SkiaSharp; + +namespace TheArtOfDev.HtmlRenderer.SkiaSharp.Adapters +{ + /// + /// Because PdfSharp doesn't support texture brush we need to implement it ourselves. + /// + internal sealed class XTextureBrush + { + #region Fields/Consts + + /// + /// The image to draw in the brush + /// + private readonly SKImage _image; + + /// + /// the + /// + private readonly SKRect _dstRect; + + /// + /// the transform the location of the image to handle center alignment + /// + private readonly SKPoint _translateTransformLocation; + + #endregion + + + /// + /// Init. + /// + public XTextureBrush(SKImage image, SKRect dstRect, SKPoint translateTransformLocation) + { + _image = image; + _dstRect = dstRect; + _translateTransformLocation = translateTransformLocation; + } + + /// + /// Draw the texture image in the given graphics at the given location. + /// + public void DrawRectangle(SKCanvas g, float x, float y, float width, float height) + { + var prevState = g.Save(); + g.ClipRect(new SKRect(x, y, width, height)); + + float rx = _translateTransformLocation.X; + float w = _image.Width, h = _image.Height; + while (rx < x + width) + { + float ry = _translateTransformLocation.Y; + while (ry < y + height) + { + g.DrawImage(_image, new SKRect(rx, ry, w, h)); + ry += h; + } + rx += w; + } + + g.Restore(); + } + } +} \ No newline at end of file diff --git a/Source/HtmlRenderer.SkiaSharp/HtmlContainer.cs b/Source/HtmlRenderer.SkiaSharp/HtmlContainer.cs new file mode 100644 index 000000000..974e78296 --- /dev/null +++ b/Source/HtmlRenderer.SkiaSharp/HtmlContainer.cs @@ -0,0 +1,356 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using SkiaSharp; +using System; +using System.Collections.Generic; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; +using TheArtOfDev.HtmlRenderer.Core; +using TheArtOfDev.HtmlRenderer.Core.Entities; +using TheArtOfDev.HtmlRenderer.Core.Utils; +using TheArtOfDev.HtmlRenderer.SkiaSharp.Adapters; +using TheArtOfDev.HtmlRenderer.SkiaSharp.Utilities; + +namespace TheArtOfDev.HtmlRenderer.SkiaSharp +{ + /// + /// Low level handling of Html Renderer logic, this class is used by . + /// + /// + public sealed class HtmlContainer : IDisposable + { + #region Fields and Consts + + /// + /// The internal core html container + /// + private readonly HtmlContainerInt _htmlContainerInt; + + #endregion + + + /// + /// Init. + /// + public HtmlContainer() + { + _htmlContainerInt = new HtmlContainerInt(SkiaSharpAdapter.Instance); + _htmlContainerInt.AvoidAsyncImagesLoading = true; + _htmlContainerInt.AvoidImagesLateLoading = true; + } + + /// + /// Raised when the set html document has been fully loaded.
+ /// Allows manipulation of the html dom, scroll position, etc. + ///
+ public event EventHandler LoadComplete + { + add { _htmlContainerInt.LoadComplete += value; } + remove { _htmlContainerInt.LoadComplete -= value; } + } + + /// + /// Raised when an error occurred during html rendering.
+ ///
+ /// + /// There is no guarantee that the event will be raised on the main thread, it can be raised on thread-pool thread. + /// + public event EventHandler RenderError + { + add { _htmlContainerInt.RenderError += value; } + remove { _htmlContainerInt.RenderError -= value; } + } + + /// + /// Raised when a stylesheet is about to be loaded by file path or URI by link element.
+ /// This event allows to provide the stylesheet manually or provide new source (file or Uri) to load from.
+ /// If no alternative data is provided the original source will be used.
+ ///
+ public event EventHandler StylesheetLoad + { + add { _htmlContainerInt.StylesheetLoad += value; } + remove { _htmlContainerInt.StylesheetLoad -= value; } + } + + /// + /// Raised when an image is about to be loaded by file path or URI.
+ /// This event allows to provide the image manually, if not handled the image will be loaded from file or download from URI. + ///
+ public event EventHandler ImageLoad + { + add { _htmlContainerInt.ImageLoad += value; } + remove { _htmlContainerInt.ImageLoad -= value; } + } + + /// + /// The internal core html container + /// + internal HtmlContainerInt HtmlContainerInt + { + get { return _htmlContainerInt; } + } + + /// + /// the parsed stylesheet data used for handling the html + /// + public CssData CssData + { + get { return _htmlContainerInt.CssData; } + } + + /// + /// Gets or sets a value indicating if anti-aliasing should be avoided for geometry like backgrounds and borders (default - false). + /// + public bool AvoidGeometryAntialias + { + get { return _htmlContainerInt.AvoidGeometryAntialias; } + set { _htmlContainerInt.AvoidGeometryAntialias = value; } + } + + /// + /// The scroll offset of the html.
+ /// This will adjust the rendered html by the given offset so the content will be "scrolled".
+ ///
+ /// + /// Element that is rendered at location (50,100) with offset of (0,200) will not be rendered as it + /// will be at -100 therefore outside the client rectangle. + /// + public SKPoint ScrollOffset + { + get { return Utils.Convert(_htmlContainerInt.ScrollOffset); } + set { _htmlContainerInt.ScrollOffset = Utils.Convert(value); } + } + + /// + /// The top-left most location of the rendered html.
+ /// This will offset the top-left corner of the rendered html. + ///
+ public SKPoint Location + { + get { return Utils.Convert(_htmlContainerInt.Location); } + set { _htmlContainerInt.Location = Utils.Convert(value); } + } + + /// + /// The max width and height of the rendered html.
+ /// The max width will effect the html layout wrapping lines, resize images and tables where possible.
+ /// The max height does NOT effect layout, but will not render outside it (clip).
+ /// can be exceed the max size by layout restrictions (unwrappable line, set image size, etc.).
+ /// Set zero for unlimited (width\height separately).
+ ///
+ public SKSize MaxSize + { + get { return Utils.Convert(_htmlContainerInt.MaxSize); } + set { _htmlContainerInt.MaxSize = Utils.Convert(value); } + } + + /// + /// The actual size of the rendered html (after layout) + /// + public SKSize ActualSize + { + get { return Utils.Convert(_htmlContainerInt.ActualSize); } + internal set { _htmlContainerInt.ActualSize = Utils.Convert(value); } + } + + public SKSize PageSize { + get + { + return new SKSize((float)_htmlContainerInt.PageSize.Width, (float)_htmlContainerInt.PageSize.Height); + } + set + { + _htmlContainerInt.PageSize = new RSize(value.Width, value.Height); + } + } + + /// + /// the top margin between the page start and the text + /// + public int MarginTop + { + get { return _htmlContainerInt.MarginTop; } + set + { + if (value > -1) + _htmlContainerInt.MarginTop = value; + } + } + + /// + /// the bottom margin between the page end and the text + /// + public int MarginBottom + { + get { return _htmlContainerInt.MarginBottom; } + set + { + if (value > -1) + _htmlContainerInt.MarginBottom = value; + } + } + + /// + /// the left margin between the page start and the text + /// + public int MarginLeft + { + get { return _htmlContainerInt.MarginLeft; } + set + { + if (value > -1) + _htmlContainerInt.MarginLeft = value; + } + } + + /// + /// the right margin between the page end and the text + /// + public int MarginRight + { + get { return _htmlContainerInt.MarginRight; } + set + { + if (value > -1) + _htmlContainerInt.MarginRight = value; + } + } + + /// + /// Set all 4 margins to the given value. + /// + /// + public void SetMargins(int value) + { + if (value > -1) + _htmlContainerInt.SetMargins(value); + } + + /// + /// Get the currently selected text segment in the html. + /// + public string SelectedText + { + get { return _htmlContainerInt.SelectedText; } + } + + /// + /// Copy the currently selected html segment with style. + /// + public string SelectedHtml + { + get { return _htmlContainerInt.SelectedHtml; } + } + + /// + /// Init with optional document and stylesheet. + /// + /// the html to init with, init empty if not given + /// optional: the stylesheet to init with, init default if not given + public async Task SetHtml(string htmlSource, CssData baseCssData = null) + { + await _htmlContainerInt.SetHtml(htmlSource, baseCssData); + } + + /// + /// Get html from the current DOM tree with style if requested. + /// + /// Optional: controls the way styles are generated when html is generated (default: ) + /// generated html + public string GetHtml(HtmlGenerationStyle styleGen = HtmlGenerationStyle.Inline) + { + return _htmlContainerInt.GetHtml(styleGen); + } + + /// + /// Get attribute value of element at the given x,y location by given key.
+ /// If more than one element exist with the attribute at the location the inner most is returned. + ///
+ /// the location to find the attribute at + /// the attribute key to get value by + /// found attribute value or null if not found + public string GetAttributeAt(SKPoint location, string attribute) + { + return _htmlContainerInt.GetAttributeAt(Utils.Convert(location), attribute); + } + + /// + /// Get all the links in the HTML with the element rectangle and href data. + /// + /// collection of all the links in the HTML + public List> GetLinks() + { + var linkElements = new List>(); + foreach (var link in HtmlContainerInt.GetLinks()) + { + linkElements.Add(new LinkElementData(link.Id, link.Href, Utils.Convert(link.Rectangle))); + } + return linkElements; + } + + /// + /// Get css link href at the given x,y location. + /// + /// the location to find the link at + /// css link href if exists or null + public string GetLinkAt(SKPoint location) + { + return _htmlContainerInt.GetLinkAt(Utils.Convert(location)); + } + + /// + /// Get the rectangle of html element as calculated by html layout.
+ /// Element if found by id (id attribute on the html element).
+ /// Note: to get the screen rectangle you need to adjust by the hosting control.
+ ///
+ /// the id of the element to get its rectangle + /// the rectangle of the element or null if not found + public SKRect? GetElementRectangle(string elementId) + { + var r = _htmlContainerInt.GetElementRectangle(elementId); + return r.HasValue ? Utils.Convert(r.Value) : (SKRect?)null; + } + + /// + /// Measures the bounds of box and children, recursively. + /// + /// Device context to draw + public async Task PerformLayout(SKCanvas g) + { + ArgChecker.AssertArgNotNull(g, "g"); + + using (var ig = new GraphicsAdapter(g)) + { + await _htmlContainerInt.PerformLayout(ig); + } + } + + /// + /// Render the html using the given device. + /// + /// the device to use to render + public async Task PerformPaint(SKCanvas g) + { + ArgChecker.AssertArgNotNull(g, "g"); + + using (var ig = new GraphicsAdapter(g)) + { + await _htmlContainerInt.PerformPaint(ig); + } + } + + public void Dispose() + { + _htmlContainerInt.Dispose(); + } + } +} \ No newline at end of file diff --git a/Source/HtmlRenderer.SkiaSharp/HtmlRenderer.SkiaSharp.csproj b/Source/HtmlRenderer.SkiaSharp/HtmlRenderer.SkiaSharp.csproj new file mode 100644 index 000000000..7967eb004 --- /dev/null +++ b/Source/HtmlRenderer.SkiaSharp/HtmlRenderer.SkiaSharp.csproj @@ -0,0 +1,21 @@ + + + + net7.0 + enable + enable + ThreeCS.HtmlRenderer.SkiaSharp + Skia Sharp target for HtmlRenderer. + https://github.com/mstancombe/HTML-Renderer/tree/features/net60 + + + + + + + + + + + + diff --git a/Source/HtmlRenderer.SkiaSharp/PdfGenerateConfig.cs b/Source/HtmlRenderer.SkiaSharp/PdfGenerateConfig.cs new file mode 100644 index 000000000..aa7ff9586 --- /dev/null +++ b/Source/HtmlRenderer.SkiaSharp/PdfGenerateConfig.cs @@ -0,0 +1,234 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using SkiaSharp; + +namespace TheArtOfDev.HtmlRenderer.SkiaSharp +{ + + public enum PageSize + { + Undefined = 0, + A0 = 1, + A1 = 2, + A2 = 3, + A3 = 4, + A4 = 5, + A5 = 6, + RA0 = 7, + RA1 = 8, + RA2 = 9, + RA3 = 10, + RA4 = 11, + RA5 = 12, + B0 = 13, + B1 = 14, + B2 = 0xF, + B3 = 0x10, + B4 = 17, + B5 = 18, + A6 = 19, + Quarto = 100, + Foolscap = 101, + Executive = 102, + GovernmentLetter = 103, + Letter = 104, + Legal = 105, + Ledger = 106, + Tabloid = 107, + Post = 108, + Crown = 109, + LargePost = 110, + Demy = 111, + Medium = 112, + Royal = 113, + Elephant = 114, + DoubleDemy = 115, + QuadDemy = 116, + STMT = 117, + Folio = 120, + Statement = 121, + Size10x14 = 122 + } + + public enum PageOrientation + { + Unknown = 0, + Portrait = 1, + Landscape = 2 + } + + public enum PageDirection + { + Downwards, + //[Obsolete("Not implemeted - yagni")] + //Upwards + } + + /// + /// The settings for generating PDF using + /// + public sealed class PdfGenerateConfig + { + #region Fields/Consts + + /// + /// the page size to use for each page in the generated pdf + /// + private PageSize _pageSize; + + /// + /// if the page size is undefined this allow you to set manually the page size + /// + private SKSize _xsize; + + /// + /// the orientation of each page of the generated pdf + /// + private PageOrientation _pageOrientation; + + /// + /// the top margin between the page start and the text + /// + private int _marginTop; + + /// + /// the bottom margin between the page end and the text + /// + private int _marginBottom; + + /// + /// the left margin between the page start and the text + /// + private int _marginLeft; + + /// + /// the right margin between the page end and the text + /// + private int _marginRight; + + #endregion + + /// + /// the page size to use for each page in the generated pdf + /// + public PageSize PageSize + { + get { return _pageSize; } + set { _pageSize = value; } + } + + /// + /// if the page size is undefined this allow you to set manually the page size + /// + public SKSize ManualPageSize { + get { return _xsize; } + set { _xsize = value; } + } + + /// + /// the orientation of each page of the generated pdf + /// + public PageOrientation PageOrientation + { + get { return _pageOrientation; } + set { _pageOrientation = value; } + } + + + /// + /// the top margin between the page start and the text + /// + public int MarginTop + { + get { return _marginTop; } + set + { + if (value > -1) + _marginTop = value; + } + } + + /// + /// the bottom margin between the page end and the text + /// + public int MarginBottom + { + get { return _marginBottom; } + set + { + if (value > -1) + _marginBottom = value; + } + } + + /// + /// the left margin between the page start and the text + /// + public int MarginLeft + { + get { return _marginLeft; } + set + { + if (value > -1) + _marginLeft = value; + } + } + + /// + /// the right margin between the page end and the text + /// + public int MarginRight + { + get { return _marginRight; } + set + { + if (value > -1) + _marginRight = value; + } + } + + /// + /// Set all 4 margins to the given value. + /// + /// + public void SetMargins(int value) + { + if (value > -1) + _marginBottom = _marginLeft = _marginTop = _marginRight = value; + } + + // The international definitions are: + // 1 inch == 25.4 mm + // 1 inch == 72 point + + /// + /// Convert the units passed in milimiters to the units used in SkiaSharp + /// + /// + /// + /// + public static SKSize MilimitersToUnits(float width, float height) { + return new SKSize(width / 25.4f * 72, height / 25.4f * 72); + } + + /// + /// Convert the units passed in inches to the units used in SkiaSharp + /// + /// + /// + /// + public static SKSize InchesToUnits(float width, float height) { + return new SKSize(width * 72, height * 72); + } + } +} \ No newline at end of file diff --git a/Source/HtmlRenderer.SkiaSharp/PdfGenerator.cs b/Source/HtmlRenderer.SkiaSharp/PdfGenerator.cs new file mode 100644 index 000000000..357bbf5c7 --- /dev/null +++ b/Source/HtmlRenderer.SkiaSharp/PdfGenerator.cs @@ -0,0 +1,274 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using HtmlRenderer.Core.Dom; +using SkiaSharp; +using System; +using TheArtOfDev.HtmlRenderer.Core; +using TheArtOfDev.HtmlRenderer.Core.Entities; +using TheArtOfDev.HtmlRenderer.Core.Utils; +using TheArtOfDev.HtmlRenderer.SkiaSharp.Adapters; +using TheArtOfDev.HtmlRenderer.SkiaSharp.Utilities; + +namespace TheArtOfDev.HtmlRenderer.SkiaSharp +{ + /// + /// TODO:a add doc + /// + public static class PdfGenerator + { + public static readonly float DefaultDPI = 72f; + + /// + /// Adds a font mapping from to iff the is not found.
+ /// When the font is used in rendered html and is not found in existing + /// fonts (installed or added) it will be replaced by .
+ ///
+ /// + /// This fonts mapping can be used as a fallback in case the requested font is not installed in the client system. + /// + /// the font family to replace + /// the font family to replace with + public static void AddFontFamilyMapping(string fromFamily, string toFamily) + { + ArgChecker.AssertArgNotNullOrEmpty(fromFamily, "fromFamily"); + ArgChecker.AssertArgNotNullOrEmpty(toFamily, "toFamily"); + + SkiaSharpAdapter.Instance.AddFontFamilyMapping(fromFamily, toFamily); + } + + /// + /// Parse the given stylesheet to object.
+ /// If is true the parsed css blocks are added to the + /// default css data (as defined by W3), merged if class name already exists. If false only the data in the given stylesheet is returned. + ///
+ /// + /// the stylesheet source to parse + /// true - combine the parsed css data with default css data, false - return only the parsed css data + /// the parsed css data + public static CssData ParseStyleSheet(string stylesheet, bool combineWithDefault = true) + { + return CssData.Parse(SkiaSharpAdapter.Instance, stylesheet, combineWithDefault); + } + + /// + /// Create PDF document from given HTML.
+ ///
+ /// HTML source to create PDF from + /// the page size to use for each page in the generated pdf + /// the margin to use between the HTML and the edges of each page + /// optional: the style to use for html rendering (default - use W3 default style) + /// optional: can be used to overwrite stylesheet resolution logic + /// optional: can be used to overwrite image resolution logic + /// the generated image of the html + public static async Task GeneratePdfAsync( + string html, + Stream outputStream, + int margin = 20, + CssData cssData = null, + EventHandler stylesheetLoad = null, + EventHandler imageLoad = null) + { + + var config = new PdfGenerateConfig(); + config.PageSize = PageSize.A4; + config.PageOrientation = PageOrientation.Portrait; + + return await GeneratePdfAsync(html, outputStream, config, cssData, stylesheetLoad, imageLoad); + } + + /// + /// Create PDF document from given HTML.
+ ///
+ /// HTML source to create PDF from + /// the configuration to use for the PDF generation (page size/page orientation/margins/etc.) + /// optional: the style to use for html rendering (default - use W3 default style) + /// optional: can be used to overwrite stylesheet resolution logic + /// optional: can be used to overwrite image resolution logic + /// the generated image of the html + public static async Task GeneratePdfAsync( + string html, + Stream outputStream, + PdfGenerateConfig config, + CssData cssData = null, + EventHandler stylesheetLoad = null, + EventHandler imageLoad = null) + { + // create PDF document to render the HTML into + var document = SKDocument.CreatePdf(outputStream, DefaultDPI); + + // add rendered PDF pages to document + await AddPdfPagesAsync(document, html, config, cssData, stylesheetLoad, imageLoad); + + return document; + } + + /// + /// Create PDF pages from given HTML and appends them to the provided PDF document.
+ ///
+ /// PDF document to append pages to + /// HTML source to create PDF from + /// the page size to use for each page in the generated pdf + /// the margin to use between the HTML and the edges of each page + /// optional: the style to use for html rendering (default - use W3 default style) + /// optional: can be used to overwrite stylesheet resolution logic + /// optional: can be used to overwrite image resolution logic + /// the generated image of the html + public static async Task AddPdfPages(SKDocument document, string html, PageSize pageSize, int margin = 20, CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) + { + var config = new PdfGenerateConfig(); + config.PageSize = pageSize; + config.SetMargins(margin); + await AddPdfPagesAsync(document, html, config, cssData, stylesheetLoad, imageLoad); + } + + /// + /// Create PDF pages from given HTML and appends them to the provided PDF document.
+ ///
+ /// PDF document to append pages to + /// HTML source to create PDF from + /// the configuration to use for the PDF generation (page size/page orientation/margins/etc.) + /// optional: the style to use for html rendering (default - use W3 default style) + /// optional: can be used to overwrite stylesheet resolution logic + /// optional: can be used to overwrite image resolution logic + /// the generated image of the html + public static async Task AddPdfPagesAsync( + SKDocument document, + string html, + PdfGenerateConfig config, + CssData cssData = null, + EventHandler stylesheetLoad = null, + EventHandler imageLoad = null) + { + //TODO: https://github.com/mono/SkiaSharp/issues/848 + //Perhaps we could subset the fonts so the pdf's generated weren't as large. Success has been reported + //with this aproach: + //https://github.com/mono/SkiaSharp/issues/848#issuecomment-1013134644 + + SKSize orgPageSize; + // get the size of each page to layout the HTML in + if (config.PageSize == PageSize.A4) + //210 * 297 + orgPageSize = new SKSize( + CssUnitConversion.Convert(210f, Core.Dom.CssUnit.Milimeters, Core.Dom.CssUnit.Inches) * DefaultDPI, + CssUnitConversion.Convert(297f, Core.Dom.CssUnit.Milimeters, Core.Dom.CssUnit.Inches) * DefaultDPI); + else + orgPageSize = config.ManualPageSize; + + if (config.PageOrientation == PageOrientation.Landscape) + { + // invert pagesize for landscape + orgPageSize = new SKSize(orgPageSize.Height, orgPageSize.Width); + } + + var pageSize = new SKSize(orgPageSize.Width - config.MarginLeft - config.MarginRight, orgPageSize.Height - config.MarginTop - config.MarginBottom); + + if (!string.IsNullOrEmpty(html)) + { + using (var container = new HtmlContainer()) + { + if (stylesheetLoad != null) + container.StylesheetLoad += stylesheetLoad; + if (imageLoad != null) + container.ImageLoad += imageLoad; + + container.Location = new SKPoint(config.MarginLeft, config.MarginTop); + container.MaxSize = new SKSize(pageSize.Width, 0); + await container.SetHtml(html, cssData); + container.PageSize = pageSize; + container.MarginBottom = config.MarginBottom; + container.MarginLeft = config.MarginLeft; + container.MarginRight = config.MarginRight; + container.MarginTop = config.MarginTop; + + // layout the HTML with the page width restriction to know how many pages are required + var docImageInfo = new SKImageInfo((int)pageSize.Width, (int)pageSize.Height); + using (var s = SKSurface.Create(docImageInfo)) + using (var g = s.Canvas) + { + await container.PerformLayout(g); + } + + // while there is un-rendered HTML, create another PDF page and render with proper offset for the next page + double scrollOffset = 0; + while (scrollOffset > -container.ActualSize.Height) + { + using (var pageCanvas = document.BeginPage(orgPageSize.Width, orgPageSize.Height)) + { + pageCanvas.ClipRect(new SKRect(config.MarginLeft, config.MarginTop, config.MarginLeft + pageSize.Width, config.MarginTop + pageSize.Height)); + + container.ScrollOffset = new SKPoint(0, (float)scrollOffset); + + await container.PerformPaint(pageCanvas); + + pageCanvas.Flush(); + document.EndPage(); + } + scrollOffset -= pageSize.Height; + } + + // add web links and anchors + HandleLinks(document, container, orgPageSize, pageSize); + + document.Close(); + } + } + } + + + + #region Private/Protected methods + + /// + /// Handle HTML links by create PDF Documents link either to external URL or to another page in the document. + /// + private static void HandleLinks(SKDocument document, HtmlContainer container, SKSize orgPageSize, SKSize pageSize) + { + //TODO: Annotations might work for this.. + //https://learn.microsoft.com/en-us/dotnet/api/skiasharp.skcanvas.drawannotation?view=skiasharp-2.88 + + /* + foreach (var link in container.GetLinks()) + { + int i = (int)(link.Rectangle.Top / pageSize.Height); + for (; i < document.Pages.Count && pageSize.Height * i < link.Rectangle.Bottom; i++) + { + var offset = pageSize.Height * i; + + // fucking position is from the bottom of the page + var xRect = new XRect(link.Rectangle.Left, orgPageSize.Height - (link.Rectangle.Height + link.Rectangle.Top - offset), link.Rectangle.Width, link.Rectangle.Height); + + if (link.IsAnchor) + { + // create link to another page in the document + var anchorRect = container.GetElementRectangle(link.AnchorId); + if (anchorRect.HasValue) + { + // document links to the same page as the link is not allowed + int anchorPageIdx = (int)(anchorRect.Value.Top / pageSize.Height); + if (i != anchorPageIdx) + document.Pages[i].AddDocumentLink(new PdfRectangle(xRect), anchorPageIdx); + } + } + else + { + // create link to URL + document.Pages[i].AddWebLink(new PdfRectangle(xRect), link.Href); + } + } + } + */ + } + + #endregion + } +} \ No newline at end of file diff --git a/Source/HtmlRenderer.SkiaSharp/Utilities/Utils.cs b/Source/HtmlRenderer.SkiaSharp/Utilities/Utils.cs new file mode 100644 index 000000000..e3191eae3 --- /dev/null +++ b/Source/HtmlRenderer.SkiaSharp/Utilities/Utils.cs @@ -0,0 +1,100 @@ +// "Therefore those skilled at the unorthodox +// are infinite as heaven and earth, +// inexhaustible as the great rivers. +// When they come to an end, +// they begin again, +// like the days and months; +// they die and are reborn, +// like the four seasons." +// +// - Sun Tsu, +// "The Art of War" + +using SkiaSharp; +using System.Drawing; +using TheArtOfDev.HtmlRenderer.Adapters.Entities; + +namespace TheArtOfDev.HtmlRenderer.SkiaSharp.Utilities +{ + /// + /// Utilities for converting SkiaSharp entities to HtmlRenderer core entities. + /// + internal static class Utils + { + /// + /// Convert from SkiaSharp point to core point. + /// + public static RPoint Convert(SKPoint p) + { + return new RPoint(p.X, p.Y); + } + + /// + /// Convert from SkiaSharp point to core point. + /// + public static SKPoint[] Convert(RPoint[] points) + { + SKPoint[] myPoints = new SKPoint[points.Length]; + for (int i = 0; i < points.Length; i++) + myPoints[i] = Convert(points[i]); + return myPoints; + } + + /// + /// Convert from core point to SkiaSharp point. + /// + public static SKPoint Convert(RPoint p) + { + return new SKPoint((float)p.X, (float)p.Y); + } + + /// + /// Convert from SkiaSharp size to core size. + /// + public static RSize Convert(SKSize s) + { + return new RSize(s.Width, s.Height); + } + + /// + /// Convert from core size to SkiaSharp size. + /// + public static SKSize Convert(RSize s) + { + return new SKSize((float)s.Width, (float)s.Height); + } + + /// + /// Convert from SkiaSharp rectangle to core rectangle. + /// + public static RRect Convert(SKRect r) + { + return new RRect(r.Left, r.Top, r.Width, r.Height); + } + + /// + /// Convert from core rectangle to SkiaSharp rectangle. + /// + public static SKRect Convert(RRect r) + { + return new SKRect((float)r.X, (float)r.Y, (float)(r.X + r.Width), (float)(r.Y + r.Height)); + } + + /// + /// Convert from core color to SkiaSharp color. + /// + public static SKColor Convert(RColor c) + { + return new SKColor(c.R, c.G, c.B, c.A); + } + + /// + /// Convert from color to SkiaSharp color. + /// + public static RColor Convert(Color c) + { + return RColor.FromArgb(c.A, c.R, c.G, c.B); + } + + } +} \ No newline at end of file diff --git a/Source/HtmlRenderer.WPF/HtmlLabel.cs b/Source/HtmlRenderer.WPF/HtmlLabel.cs index 01429c872..c4d362802 100644 --- a/Source/HtmlRenderer.WPF/HtmlLabel.cs +++ b/Source/HtmlRenderer.WPF/HtmlLabel.cs @@ -79,27 +79,32 @@ public virtual bool AutoSizeHeightOnly ///
protected override Size MeasureOverride(Size constraint) { - if (_htmlContainer != null) + Task.Run(async () => { - using (var ig = new GraphicsAdapter()) + if (_htmlContainer != null) { - var horizontal = Padding.Left + Padding.Right + BorderThickness.Left + BorderThickness.Right; - var vertical = Padding.Top + Padding.Bottom + BorderThickness.Top + BorderThickness.Bottom; + using (var ig = new GraphicsAdapter()) + { + var horizontal = Padding.Left + Padding.Right + BorderThickness.Left + BorderThickness.Right; + var vertical = Padding.Top + Padding.Bottom + BorderThickness.Top + BorderThickness.Bottom; - var size = new RSize(constraint.Width < Double.PositiveInfinity ? constraint.Width - horizontal : 0, constraint.Height < Double.PositiveInfinity ? constraint.Height - vertical : 0); - var minSize = new RSize(MinWidth < Double.PositiveInfinity ? MinWidth - horizontal : 0, MinHeight < Double.PositiveInfinity ? MinHeight - vertical : 0); - var maxSize = new RSize(MaxWidth < Double.PositiveInfinity ? MaxWidth - horizontal : 0, MaxHeight < Double.PositiveInfinity ? MaxHeight - vertical : 0); + var size = new RSize(constraint.Width < Double.PositiveInfinity ? constraint.Width - horizontal : 0, constraint.Height < Double.PositiveInfinity ? constraint.Height - vertical : 0); + var minSize = new RSize(MinWidth < Double.PositiveInfinity ? MinWidth - horizontal : 0, MinHeight < Double.PositiveInfinity ? MinHeight - vertical : 0); + var maxSize = new RSize(MaxWidth < Double.PositiveInfinity ? MaxWidth - horizontal : 0, MaxHeight < Double.PositiveInfinity ? MaxHeight - vertical : 0); - var newSize = HtmlRendererUtils.Layout(ig, _htmlContainer.HtmlContainerInt, size, minSize, maxSize, AutoSize, AutoSizeHeightOnly); + var newSize = await HtmlRendererUtils.LayoutAsync(ig, _htmlContainer.HtmlContainerInt, size, minSize, maxSize, AutoSize, AutoSizeHeightOnly); - constraint = new Size(newSize.Width + horizontal, newSize.Height + vertical); + constraint = new Size(newSize.Width + horizontal, newSize.Height + vertical); + } } - } - if (double.IsPositiveInfinity(constraint.Width) || double.IsPositiveInfinity(constraint.Height)) - constraint = Size.Empty; + if (double.IsPositiveInfinity(constraint.Width) || double.IsPositiveInfinity(constraint.Height)) + constraint = Size.Empty; + + return constraint; + }); - return constraint; + return default; } /// diff --git a/Source/HtmlRenderer.WPF/HtmlRender.cs b/Source/HtmlRenderer.WPF/HtmlRender.cs index 77eb4a046..ca9595f58 100644 --- a/Source/HtmlRenderer.WPF/HtmlRender.cs +++ b/Source/HtmlRenderer.WPF/HtmlRender.cs @@ -255,10 +255,10 @@ public static BitmapFrame RenderToImage(string html, Size size, CssData cssData /// optional: can be used to overwrite stylesheet resolution logic /// optional: can be used to overwrite image resolution logic /// the generated image of the html - public static BitmapFrame RenderToImage(string html, int maxWidth = 0, int maxHeight = 0, Color backgroundColor = new Color(), CssData cssData = null, + public static async Task RenderToImageAsync(string html, int maxWidth = 0, int maxHeight = 0, Color backgroundColor = new Color(), CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) { - return RenderToImage(html, Size.Empty, new Size(maxWidth, maxHeight), backgroundColor, cssData, stylesheetLoad, imageLoad); + return await RenderToImageAsync(html, Size.Empty, new Size(maxWidth, maxHeight), backgroundColor, cssData, stylesheetLoad, imageLoad); } /// @@ -281,7 +281,7 @@ public static BitmapFrame RenderToImage(string html, Size size, CssData cssData /// optional: can be used to overwrite stylesheet resolution logic /// optional: can be used to overwrite image resolution logic /// the generated image of the html - public static BitmapFrame RenderToImage(string html, Size minSize, Size maxSize, Color backgroundColor = new Color(), CssData cssData = null, + public static async Task RenderToImageAsync(string html, Size minSize, Size maxSize, Color backgroundColor = new Color(), CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) { RenderTargetBitmap renderTarget; @@ -298,7 +298,7 @@ public static BitmapFrame RenderToImage(string html, Size size, CssData cssData container.ImageLoad += imageLoad; container.SetHtml(html, cssData); - var finalSize = MeasureHtmlByRestrictions(container, minSize, maxSize); + var finalSize = await MeasureHtmlByRestrictionsAsync(container, minSize, maxSize); container.MaxSize = finalSize; renderTarget = new RenderTargetBitmap((int)finalSize.Width, (int)finalSize.Height, 96, 96, PixelFormats.Pbgra32); @@ -332,12 +332,12 @@ public static BitmapFrame RenderToImage(string html, Size size, CssData cssData /// the minimal size of the rendered html (zero - not limit the width/height) /// the maximum size of the rendered html, if not zero and html cannot be layout within the limit it will be clipped (zero - not limit the width/height) /// return: the size of the html to be rendered within the min/max limits - private static Size MeasureHtmlByRestrictions(HtmlContainer htmlContainer, Size minSize, Size maxSize) + private static async Task MeasureHtmlByRestrictionsAsync(HtmlContainer htmlContainer, Size minSize, Size maxSize) { // use desktop created graphics to measure the HTML using (var mg = new GraphicsAdapter()) { - var sizeInt = HtmlRendererUtils.MeasureHtmlByRestrictions(mg, htmlContainer.HtmlContainerInt, Utils.Convert(minSize), Utils.Convert(maxSize)); + var sizeInt = await HtmlRendererUtils.MeasureHtmlByRestrictionsAsync(mg, htmlContainer.HtmlContainerInt, Utils.Convert(minSize), Utils.Convert(maxSize)); if (maxSize.Width < 1 && sizeInt.Width > 4096) sizeInt.Width = 4096; return Utils.ConvertRound(sizeInt); diff --git a/Source/HtmlRenderer.WPF/HtmlRenderer.WPF.csproj b/Source/HtmlRenderer.WPF/HtmlRenderer.WPF.csproj index 80c4b97f9..aa37ed031 100644 --- a/Source/HtmlRenderer.WPF/HtmlRenderer.WPF.csproj +++ b/Source/HtmlRenderer.WPF/HtmlRenderer.WPF.csproj @@ -1,85 +1,15 @@ - - - + + - Debug - AnyCPU - {7E4E8DB5-85AD-4388-BDCB-38C6F423B8B0} - library - Properties - TheArtOfDev.HtmlRenderer.WPF - HtmlRenderer.WPF - v3.0 - 512 - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 4 - - + net7.0-windows + enable + disable + true + true - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release.WPF.Net35\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - {fe611685-391f-4e3e-b27e-d3150e51e49b} - HtmlRenderer - - + - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - + - - - \ No newline at end of file + + diff --git a/Source/HtmlRenderer.WinForms/Adapters/ContextMenuAdapter.cs b/Source/HtmlRenderer.WinForms/Adapters/ContextMenuAdapter.cs index ca0c83b7e..7fdc987f5 100644 --- a/Source/HtmlRenderer.WinForms/Adapters/ContextMenuAdapter.cs +++ b/Source/HtmlRenderer.WinForms/Adapters/ContextMenuAdapter.cs @@ -11,7 +11,6 @@ // "The Art of War" using System; -using System.Windows.Forms; using TheArtOfDev.HtmlRenderer.Adapters.Entities; using TheArtOfDev.HtmlRenderer.Core.Utils; using TheArtOfDev.HtmlRenderer.Adapters; diff --git a/Source/HtmlRenderer.WinForms/HtmlLabel.cs b/Source/HtmlRenderer.WinForms/HtmlLabel.cs index 8853490d2..da5c05dd5 100644 --- a/Source/HtmlRenderer.WinForms/HtmlLabel.cs +++ b/Source/HtmlRenderer.WinForms/HtmlLabel.cs @@ -487,23 +487,26 @@ protected override void OnLayout(LayoutEventArgs levent) { if (_htmlContainer != null) { - Graphics g = Utils.CreateGraphics(this); - if (g != null) - { - using (g) - using (var ig = new GraphicsAdapter(g, _htmlContainer.UseGdiPlusTextRendering)) + Task.Run(async () => { + Graphics g = Utils.CreateGraphics(this); + if (g != null) { - var newSize = HtmlRendererUtils.Layout(ig, - _htmlContainer.HtmlContainerInt, - new RSize(ClientSize.Width - Padding.Horizontal, ClientSize.Height - Padding.Vertical), - new RSize(MinimumSize.Width - Padding.Horizontal, MinimumSize.Height - Padding.Vertical), - new RSize(MaximumSize.Width - Padding.Horizontal, MaximumSize.Height - Padding.Vertical), - AutoSize, - AutoSizeHeightOnly); - ClientSize = Utils.ConvertRound(new RSize(newSize.Width + Padding.Horizontal, newSize.Height + Padding.Vertical)); + using (g) + using (var ig = new GraphicsAdapter(g, _htmlContainer.UseGdiPlusTextRendering)) + { + var newSize = await HtmlRendererUtils.LayoutAsync(ig, + _htmlContainer.HtmlContainerInt, + new RSize(ClientSize.Width - Padding.Horizontal, ClientSize.Height - Padding.Vertical), + new RSize(MinimumSize.Width - Padding.Horizontal, MinimumSize.Height - Padding.Vertical), + new RSize(MaximumSize.Width - Padding.Horizontal, MaximumSize.Height - Padding.Vertical), + AutoSize, + AutoSizeHeightOnly); + ClientSize = Utils.ConvertRound(new RSize(newSize.Width + Padding.Horizontal, newSize.Height + Padding.Vertical)); + } } - } + }); } + base.OnLayout(levent); } diff --git a/Source/HtmlRenderer.WinForms/HtmlRender.cs b/Source/HtmlRenderer.WinForms/HtmlRender.cs index 3c6ad3ca9..ed8057ca5 100644 --- a/Source/HtmlRenderer.WinForms/HtmlRender.cs +++ b/Source/HtmlRenderer.WinForms/HtmlRender.cs @@ -435,10 +435,10 @@ public static void RenderToImage(Image image, string html, PointF location, Size /// optional: can be used to overwrite image resolution logic /// the generated image of the html /// if is . - public static Image RenderToImage(string html, int maxWidth = 0, int maxHeight = 0, Color backgroundColor = new Color(), CssData cssData = null, + public static async Task RenderToImageAsync(string html, int maxWidth = 0, int maxHeight = 0, Color backgroundColor = new Color(), CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) { - return RenderToImage(html, Size.Empty, new Size(maxWidth, maxHeight), backgroundColor, cssData, stylesheetLoad, imageLoad); + return await RenderToImageAsync(html, Size.Empty, new Size(maxWidth, maxHeight), backgroundColor, cssData, stylesheetLoad, imageLoad); } /// @@ -462,7 +462,7 @@ public static void RenderToImage(Image image, string html, PointF location, Size /// optional: can be used to overwrite image resolution logic /// the generated image of the html /// if is . - public static Image RenderToImage(string html, Size minSize, Size maxSize, Color backgroundColor = new Color(), CssData cssData = null, + public static async Task RenderToImageAsync(string html, Size minSize, Size maxSize, Color backgroundColor = new Color(), CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) { if (backgroundColor == Color.Transparent) @@ -482,7 +482,7 @@ public static void RenderToImage(Image image, string html, PointF location, Size container.ImageLoad += imageLoad; container.SetHtml(html, cssData); - var finalSize = MeasureHtmlByRestrictions(container, minSize, maxSize); + var finalSize = await MeasureHtmlByRestrictionsAsync(container, minSize, maxSize); container.MaxSize = finalSize; // create the final image to render into by measured size @@ -559,10 +559,10 @@ public static Image RenderToImageGdiPlus(string html, Size size, TextRenderingHi /// optional: can be used to overwrite stylesheet resolution logic /// optional: can be used to overwrite image resolution logic /// the generated image of the html - public static Image RenderToImageGdiPlus(string html, int maxWidth = 0, int maxHeight = 0, TextRenderingHint textRenderingHint = TextRenderingHint.AntiAlias, CssData cssData = null, + public static async Task RenderToImageGdiPlusAsync(string html, int maxWidth = 0, int maxHeight = 0, TextRenderingHint textRenderingHint = TextRenderingHint.AntiAlias, CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) { - return RenderToImageGdiPlus(html, Size.Empty, new Size(maxWidth, maxHeight), textRenderingHint, cssData, stylesheetLoad, imageLoad); + return await RenderToImageGdiPlusAsync(html, Size.Empty, new Size(maxWidth, maxHeight), textRenderingHint, cssData, stylesheetLoad, imageLoad); } /// @@ -584,7 +584,7 @@ public static Image RenderToImageGdiPlus(string html, int maxWidth = 0, int maxH /// optional: can be used to overwrite stylesheet resolution logic /// optional: can be used to overwrite image resolution logic /// the generated image of the html - public static Image RenderToImageGdiPlus(string html, Size minSize, Size maxSize, TextRenderingHint textRenderingHint = TextRenderingHint.AntiAlias, CssData cssData = null, + public static async Task RenderToImageGdiPlusAsync(string html, Size minSize, Size maxSize, TextRenderingHint textRenderingHint = TextRenderingHint.AntiAlias, CssData cssData = null, EventHandler stylesheetLoad = null, EventHandler imageLoad = null) { if (string.IsNullOrEmpty(html)) @@ -602,7 +602,7 @@ public static Image RenderToImageGdiPlus(string html, Size minSize, Size maxSize container.ImageLoad += imageLoad; container.SetHtml(html, cssData); - var finalSize = MeasureHtmlByRestrictions(container, minSize, maxSize); + var finalSize = await MeasureHtmlByRestrictionsAsync(container, minSize, maxSize); container.MaxSize = finalSize; // create the final image to render into by measured size @@ -667,13 +667,13 @@ private static SizeF Measure(Graphics g, string html, float maxWidth, CssData cs /// the minimal size of the rendered html (zero - not limit the width/height) /// the maximum size of the rendered html, if not zero and html cannot be layout within the limit it will be clipped (zero - not limit the width/height) /// return: the size of the html to be rendered within the min/max limits - private static Size MeasureHtmlByRestrictions(HtmlContainer htmlContainer, Size minSize, Size maxSize) + private static async Task MeasureHtmlByRestrictionsAsync(HtmlContainer htmlContainer, Size minSize, Size maxSize) { // use desktop created graphics to measure the HTML using (var g = Graphics.FromHwnd(IntPtr.Zero)) using (var mg = new GraphicsAdapter(g, htmlContainer.UseGdiPlusTextRendering)) { - var sizeInt = HtmlRendererUtils.MeasureHtmlByRestrictions(mg, htmlContainer.HtmlContainerInt, Utils.Convert(minSize), Utils.Convert(maxSize)); + var sizeInt = await HtmlRendererUtils.MeasureHtmlByRestrictionsAsync(mg, htmlContainer.HtmlContainerInt, Utils.Convert(minSize), Utils.Convert(maxSize)); if (maxSize.Width < 1 && sizeInt.Width > 4096) sizeInt.Width = 4096; return Utils.ConvertRound(sizeInt); diff --git a/Source/HtmlRenderer.WinForms/HtmlRenderer.WinForms.csproj b/Source/HtmlRenderer.WinForms/HtmlRenderer.WinForms.csproj index ce1a98759..24947287d 100644 --- a/Source/HtmlRenderer.WinForms/HtmlRenderer.WinForms.csproj +++ b/Source/HtmlRenderer.WinForms/HtmlRenderer.WinForms.csproj @@ -1,126 +1,18 @@ - - + + - Debug - AnyCPU - 8.0.50727 - 2.0 - {1B058920-24B4-4140-8AE7-C8C6C38CA52D} - Library - Properties - TheArtOfDev.HtmlRenderer.WinForms - HtmlRenderer.WinForms - - - v2.0 - - - - - 2.0 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - + net7.0-windows + enable + disable + true - - true - full - false - bin\DebugNet20\ - DEBUG;TRACE - prompt - 4 - false - AllRules.ruleset - - - pdbonly - true - bin\ReleaseNet20\ - TRACE - prompt - 4 - AllRules.ruleset - - - - - - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - Component - - - Component - - - - Component - - - - - - + - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - + + - - {fe611685-391f-4e3e-b27e-d3150e51e49b} - HtmlRenderer - + - - - \ No newline at end of file + + diff --git a/Source/HtmlRenderer.WinForms/HtmlToolTip.cs b/Source/HtmlRenderer.WinForms/HtmlToolTip.cs index 40d7ab6ca..25a3988a3 100644 --- a/Source/HtmlRenderer.WinForms/HtmlToolTip.cs +++ b/Source/HtmlRenderer.WinForms/HtmlToolTip.cs @@ -18,6 +18,7 @@ using TheArtOfDev.HtmlRenderer.Core; using TheArtOfDev.HtmlRenderer.Core.Entities; using TheArtOfDev.HtmlRenderer.WinForms.Utilities; +using Timer = System.Windows.Forms.Timer; namespace TheArtOfDev.HtmlRenderer.WinForms { diff --git a/Source/HtmlRenderer.sln b/Source/HtmlRenderer.sln index cf7aaa634..ff45b31b1 100644 --- a/Source/HtmlRenderer.sln +++ b/Source/HtmlRenderer.sln @@ -1,118 +1,80 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.30501.0 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33103.201 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Demo", "Demo", "{E263EA16-2E6A-4269-A319-AA2F97ADA8E1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlRenderer", "HtmlRenderer\HtmlRenderer.csproj", "{CC492ED6-C849-4703-BCB8-3680B2B7E014}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HtmlRenderer.Demo.Common", "Demo\Common\HtmlRenderer.Demo.Common.csproj", "{2390B71F-9400-47F4-B23A-7F2649C87D35}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlRenderer.PdfSharp", "HtmlRenderer.PdfSharp\HtmlRenderer.PdfSharp.csproj", "{C0C1CD37-272F-4659-B7E6-953F86BEEEC7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HtmlRenderer.Demo.WinForms", "Demo\WinForms\HtmlRenderer.Demo.WinForms.csproj", "{8AD34FE8-8382-4A8A-B3AA-A0392ED42423}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlRenderer.WinForms", "HtmlRenderer.WinForms\HtmlRenderer.WinForms.csproj", "{2847DA9E-DE87-4B4F-8597-9165ECAA6D58}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HtmlRenderer.Demo.WPF", "Demo\WPF\HtmlRenderer.Demo.WPF.csproj", "{F02E0216-4AE3-474F-9381-FCB93411CDB0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlRenderer.WPF", "HtmlRenderer.WPF\HtmlRenderer.WPF.csproj", "{620AC72F-BC10-44F4-8387-250F3FE765C4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HtmlRenderer.WinForms", "HtmlRenderer.WinForms\HtmlRenderer.WinForms.csproj", "{1B058920-24B4-4140-8AE7-C8C6C38CA52D}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Demos", "Demos", "{CF4F888A-71EE-4EDC-99BA-8A02B4B841F0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HtmlRenderer.WPF", "HtmlRenderer.WPF\HtmlRenderer.WPF.csproj", "{7E4E8DB5-85AD-4388-BDCB-38C6F423B8B0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlRenderer.Demo.Common", "Demos\HtmlRenderer.Demo.Common\HtmlRenderer.Demo.Common.csproj", "{22D87EB2-87B0-4A83-BB9F-CFAFD7EC26D4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HtmlRenderer", "HtmlRenderer\HtmlRenderer.csproj", "{FE611685-391F-4E3E-B27E-D3150E51E49B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlRenderer.Demo.WinForms", "Demos\HtmlRenderer.Demo.WinForms\HtmlRenderer.Demo.WinForms.csproj", "{1A66CBC4-0297-4928-AECC-35E3A4205609}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HtmlRenderer.PdfSharp", "HtmlRenderer.PdfSharp\HtmlRenderer.PdfSharp.csproj", "{CA249F5D-9285-40A6-B217-5889EF79FD7E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlRenderer.Demo.WPF", "Demos\HtmlRenderer.Demo.WPF\HtmlRenderer.Demo.WPF.csproj", "{46175F41-83B5-4E4E-BA90-775BA6AC144A}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{AA47D163-2ECF-45FB-8798-2432681396B5}" - ProjectSection(SolutionItems) = preProject - .nuget\NuGet.Config = .nuget\NuGet.Config - .nuget\NuGet.exe = .nuget\NuGet.exe - .nuget\NuGet.targets = .nuget\NuGet.targets - EndProjectSection +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlRenderer.SkiaSharp", "HtmlRenderer.SkiaSharp\HtmlRenderer.SkiaSharp.csproj", "{B1054D40-9825-42B5-9BE0-55EDE79BC00B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlRenderer.Demo.SkiaSharp", "Demos\HtmlRenderer.Demo.SkiaSharp\HtmlRenderer.Demo.SkiaSharp.csproj", "{5E5E2495-4F7A-4C36-B7DF-3EBE71A5108A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HtmlRenderer.Demo.Console", "Demos\HtmlRenderer.Demo.Console\HtmlRenderer.Demo.Console.csproj", "{7E5B30E9-34C6-4123-B8A6-B50AC078DA53}" EndProject Global 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 - {2390B71F-9400-47F4-B23A-7F2649C87D35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2390B71F-9400-47F4-B23A-7F2649C87D35}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2390B71F-9400-47F4-B23A-7F2649C87D35}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {2390B71F-9400-47F4-B23A-7F2649C87D35}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {2390B71F-9400-47F4-B23A-7F2649C87D35}.Debug|x86.ActiveCfg = Debug|Any CPU - {2390B71F-9400-47F4-B23A-7F2649C87D35}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2390B71F-9400-47F4-B23A-7F2649C87D35}.Release|Any CPU.Build.0 = Release|Any CPU - {2390B71F-9400-47F4-B23A-7F2649C87D35}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {2390B71F-9400-47F4-B23A-7F2649C87D35}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {2390B71F-9400-47F4-B23A-7F2649C87D35}.Release|x86.ActiveCfg = Release|Any CPU - {8AD34FE8-8382-4A8A-B3AA-A0392ED42423}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8AD34FE8-8382-4A8A-B3AA-A0392ED42423}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8AD34FE8-8382-4A8A-B3AA-A0392ED42423}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {8AD34FE8-8382-4A8A-B3AA-A0392ED42423}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {8AD34FE8-8382-4A8A-B3AA-A0392ED42423}.Debug|x86.ActiveCfg = Debug|Any CPU - {8AD34FE8-8382-4A8A-B3AA-A0392ED42423}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8AD34FE8-8382-4A8A-B3AA-A0392ED42423}.Release|Any CPU.Build.0 = Release|Any CPU - {8AD34FE8-8382-4A8A-B3AA-A0392ED42423}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {8AD34FE8-8382-4A8A-B3AA-A0392ED42423}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {8AD34FE8-8382-4A8A-B3AA-A0392ED42423}.Release|x86.ActiveCfg = Release|Any CPU - {F02E0216-4AE3-474F-9381-FCB93411CDB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F02E0216-4AE3-474F-9381-FCB93411CDB0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F02E0216-4AE3-474F-9381-FCB93411CDB0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {F02E0216-4AE3-474F-9381-FCB93411CDB0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {F02E0216-4AE3-474F-9381-FCB93411CDB0}.Debug|x86.ActiveCfg = Debug|Any CPU - {F02E0216-4AE3-474F-9381-FCB93411CDB0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F02E0216-4AE3-474F-9381-FCB93411CDB0}.Release|Any CPU.Build.0 = Release|Any CPU - {F02E0216-4AE3-474F-9381-FCB93411CDB0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {F02E0216-4AE3-474F-9381-FCB93411CDB0}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {F02E0216-4AE3-474F-9381-FCB93411CDB0}.Release|x86.ActiveCfg = Release|Any CPU - {1B058920-24B4-4140-8AE7-C8C6C38CA52D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1B058920-24B4-4140-8AE7-C8C6C38CA52D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1B058920-24B4-4140-8AE7-C8C6C38CA52D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {1B058920-24B4-4140-8AE7-C8C6C38CA52D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {1B058920-24B4-4140-8AE7-C8C6C38CA52D}.Debug|x86.ActiveCfg = Debug|Any CPU - {1B058920-24B4-4140-8AE7-C8C6C38CA52D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1B058920-24B4-4140-8AE7-C8C6C38CA52D}.Release|Any CPU.Build.0 = Release|Any CPU - {1B058920-24B4-4140-8AE7-C8C6C38CA52D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {1B058920-24B4-4140-8AE7-C8C6C38CA52D}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {1B058920-24B4-4140-8AE7-C8C6C38CA52D}.Release|x86.ActiveCfg = Release|Any CPU - {7E4E8DB5-85AD-4388-BDCB-38C6F423B8B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7E4E8DB5-85AD-4388-BDCB-38C6F423B8B0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7E4E8DB5-85AD-4388-BDCB-38C6F423B8B0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {7E4E8DB5-85AD-4388-BDCB-38C6F423B8B0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {7E4E8DB5-85AD-4388-BDCB-38C6F423B8B0}.Debug|x86.ActiveCfg = Debug|Any CPU - {7E4E8DB5-85AD-4388-BDCB-38C6F423B8B0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7E4E8DB5-85AD-4388-BDCB-38C6F423B8B0}.Release|Any CPU.Build.0 = Release|Any CPU - {7E4E8DB5-85AD-4388-BDCB-38C6F423B8B0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {7E4E8DB5-85AD-4388-BDCB-38C6F423B8B0}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {7E4E8DB5-85AD-4388-BDCB-38C6F423B8B0}.Release|x86.ActiveCfg = Release|Any CPU - {FE611685-391F-4E3E-B27E-D3150E51E49B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FE611685-391F-4E3E-B27E-D3150E51E49B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FE611685-391F-4E3E-B27E-D3150E51E49B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {FE611685-391F-4E3E-B27E-D3150E51E49B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {FE611685-391F-4E3E-B27E-D3150E51E49B}.Debug|x86.ActiveCfg = Debug|Any CPU - {FE611685-391F-4E3E-B27E-D3150E51E49B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FE611685-391F-4E3E-B27E-D3150E51E49B}.Release|Any CPU.Build.0 = Release|Any CPU - {FE611685-391F-4E3E-B27E-D3150E51E49B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {FE611685-391F-4E3E-B27E-D3150E51E49B}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {FE611685-391F-4E3E-B27E-D3150E51E49B}.Release|x86.ActiveCfg = Release|Any CPU - {CA249F5D-9285-40A6-B217-5889EF79FD7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CA249F5D-9285-40A6-B217-5889EF79FD7E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CA249F5D-9285-40A6-B217-5889EF79FD7E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {CA249F5D-9285-40A6-B217-5889EF79FD7E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {CA249F5D-9285-40A6-B217-5889EF79FD7E}.Debug|x86.ActiveCfg = Debug|Any CPU - {CA249F5D-9285-40A6-B217-5889EF79FD7E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CA249F5D-9285-40A6-B217-5889EF79FD7E}.Release|Any CPU.Build.0 = Release|Any CPU - {CA249F5D-9285-40A6-B217-5889EF79FD7E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {CA249F5D-9285-40A6-B217-5889EF79FD7E}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {CA249F5D-9285-40A6-B217-5889EF79FD7E}.Release|x86.ActiveCfg = Release|Any CPU + {CC492ED6-C849-4703-BCB8-3680B2B7E014}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CC492ED6-C849-4703-BCB8-3680B2B7E014}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CC492ED6-C849-4703-BCB8-3680B2B7E014}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CC492ED6-C849-4703-BCB8-3680B2B7E014}.Release|Any CPU.Build.0 = Release|Any CPU + {C0C1CD37-272F-4659-B7E6-953F86BEEEC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C0C1CD37-272F-4659-B7E6-953F86BEEEC7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C0C1CD37-272F-4659-B7E6-953F86BEEEC7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C0C1CD37-272F-4659-B7E6-953F86BEEEC7}.Release|Any CPU.Build.0 = Release|Any CPU + {2847DA9E-DE87-4B4F-8597-9165ECAA6D58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2847DA9E-DE87-4B4F-8597-9165ECAA6D58}.Release|Any CPU.ActiveCfg = Release|Any CPU + {620AC72F-BC10-44F4-8387-250F3FE765C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {620AC72F-BC10-44F4-8387-250F3FE765C4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {22D87EB2-87B0-4A83-BB9F-CFAFD7EC26D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {22D87EB2-87B0-4A83-BB9F-CFAFD7EC26D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {22D87EB2-87B0-4A83-BB9F-CFAFD7EC26D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {22D87EB2-87B0-4A83-BB9F-CFAFD7EC26D4}.Release|Any CPU.Build.0 = Release|Any CPU + {1A66CBC4-0297-4928-AECC-35E3A4205609}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1A66CBC4-0297-4928-AECC-35E3A4205609}.Release|Any CPU.ActiveCfg = Release|Any CPU + {46175F41-83B5-4E4E-BA90-775BA6AC144A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {46175F41-83B5-4E4E-BA90-775BA6AC144A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1054D40-9825-42B5-9BE0-55EDE79BC00B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B1054D40-9825-42B5-9BE0-55EDE79BC00B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B1054D40-9825-42B5-9BE0-55EDE79BC00B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B1054D40-9825-42B5-9BE0-55EDE79BC00B}.Release|Any CPU.Build.0 = Release|Any CPU + {5E5E2495-4F7A-4C36-B7DF-3EBE71A5108A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5E5E2495-4F7A-4C36-B7DF-3EBE71A5108A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5E5E2495-4F7A-4C36-B7DF-3EBE71A5108A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E5E2495-4F7A-4C36-B7DF-3EBE71A5108A}.Release|Any CPU.Build.0 = Release|Any CPU + {7E5B30E9-34C6-4123-B8A6-B50AC078DA53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7E5B30E9-34C6-4123-B8A6-B50AC078DA53}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7E5B30E9-34C6-4123-B8A6-B50AC078DA53}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7E5B30E9-34C6-4123-B8A6-B50AC078DA53}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {2390B71F-9400-47F4-B23A-7F2649C87D35} = {E263EA16-2E6A-4269-A319-AA2F97ADA8E1} - {8AD34FE8-8382-4A8A-B3AA-A0392ED42423} = {E263EA16-2E6A-4269-A319-AA2F97ADA8E1} - {F02E0216-4AE3-474F-9381-FCB93411CDB0} = {E263EA16-2E6A-4269-A319-AA2F97ADA8E1} + {22D87EB2-87B0-4A83-BB9F-CFAFD7EC26D4} = {CF4F888A-71EE-4EDC-99BA-8A02B4B841F0} + {1A66CBC4-0297-4928-AECC-35E3A4205609} = {CF4F888A-71EE-4EDC-99BA-8A02B4B841F0} + {46175F41-83B5-4E4E-BA90-775BA6AC144A} = {CF4F888A-71EE-4EDC-99BA-8A02B4B841F0} + {5E5E2495-4F7A-4C36-B7DF-3EBE71A5108A} = {CF4F888A-71EE-4EDC-99BA-8A02B4B841F0} + {7E5B30E9-34C6-4123-B8A6-B50AC078DA53} = {CF4F888A-71EE-4EDC-99BA-8A02B4B841F0} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B4ABBC6A-EFE0-46EB-BEED-7C8017BA004C} EndGlobalSection EndGlobal diff --git a/Source/HtmlRenderer/Adapters/RAdapter.cs b/Source/HtmlRenderer/Adapters/RAdapter.cs index 6b13459c1..0ed190d7e 100644 --- a/Source/HtmlRenderer/Adapters/RAdapter.cs +++ b/Source/HtmlRenderer/Adapters/RAdapter.cs @@ -150,7 +150,14 @@ public RBrush GetLinearGradientBrush(RRect rect, RColor color1, RColor color2, d public RImage ConvertImage(object image) { // TODO:a remove this by creating better API. - return ConvertImageInt(image); + if (image is Stream imageStream) + { + return ImageFromStream(imageStream); + } + else + { + return ConvertImageInt(image); + } } /// @@ -213,7 +220,7 @@ public RImage GetLoadingImage() { if (_loadImage == null) { - var stream = typeof(HtmlRendererUtils).Assembly.GetManifestResourceStream("TheArtOfDev.HtmlRenderer.Core.Utils.ImageLoad.png"); + var stream = typeof(HtmlRendererUtils).Assembly.GetManifestResourceStream("HtmlRenderer.Core.Utils.ImageLoad.png"); if (stream != null) _loadImage = ImageFromStream(stream); } @@ -227,7 +234,7 @@ public RImage GetLoadingFailedImage() { if (_errorImage == null) { - var stream = typeof(HtmlRendererUtils).Assembly.GetManifestResourceStream("TheArtOfDev.HtmlRenderer.Core.Utils.ImageError.png"); + var stream = typeof(HtmlRendererUtils).Assembly.GetManifestResourceStream("HtmlRenderer.Core.Utils.ImageError.png"); if (stream != null) _errorImage = ImageFromStream(stream); } diff --git a/Source/HtmlRenderer/Core/CssDefaults.cs b/Source/HtmlRenderer/Core/CssDefaults.cs index bb313c223..9fb24e34d 100644 --- a/Source/HtmlRenderer/Core/CssDefaults.cs +++ b/Source/HtmlRenderer/Core/CssDefaults.cs @@ -99,7 +99,6 @@ internal static class CssDefaults *[DIR=""rtl""] { direction: rtl; unicode-bidi: embed } @media print { - h1 { page-break-before: always } h1, h2, h3, h4, h5, h6 { page-break-after: avoid } ul, ol, dl { page-break-before: avoid } diff --git a/Source/HtmlRenderer/Core/Dom/CssBox.cs b/Source/HtmlRenderer/Core/Dom/CssBox.cs index b2cd3d984..bdab4f4d6 100644 --- a/Source/HtmlRenderer/Core/Dom/CssBox.cs +++ b/Source/HtmlRenderer/Core/Dom/CssBox.cs @@ -13,6 +13,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Text; using TheArtOfDev.HtmlRenderer.Adapters; using TheArtOfDev.HtmlRenderer.Adapters.Entities; using TheArtOfDev.HtmlRenderer.Core.Entities; @@ -441,11 +442,11 @@ public static CssBox CreateBlock(CssBox parent, HtmlTag tag = null, CssBox befor /// Performs layout of the DOM structure creating lines by set bounds restrictions. /// /// Device context to use - public void PerformLayout(RGraphics g) + public async Task PerformLayoutAsync(RGraphics g) { try { - PerformLayoutImp(g); + await PerformLayoutImpAsync(g); } catch (Exception ex) { @@ -457,7 +458,7 @@ public void PerformLayout(RGraphics g) /// Paints the fragment /// /// Device context to use - public void Paint(RGraphics g) + public async Task PaintAsync(RGraphics g) { try { @@ -489,7 +490,7 @@ public void Paint(RGraphics g) } if (visible) - PaintImp(g); + await PaintImpAsync(g); // Restore clips if (this.Position == CssConstants.Fixed) @@ -610,12 +611,12 @@ public virtual void Dispose() /// Performs layout of the DOM structure creating lines by set bounds restrictions.
///
/// Device context to use - protected virtual void PerformLayoutImp(RGraphics g) + protected virtual async Task PerformLayoutImpAsync(RGraphics g) { if (Display != CssConstants.None) { RectanglesReset(); - MeasureWordsSize(g); + await MeasureWordsSizeAsync(g); } if (IsBlock || Display == CssConstants.ListItem || Display == CssConstants.Table || Display == CssConstants.InlineTable || Display == CssConstants.TableCell) @@ -652,16 +653,32 @@ protected virtual void PerformLayoutImp(RGraphics g) else { left = ContainingBlock.Location.X + ContainingBlock.ActualPaddingLeft + ActualMarginLeft + ContainingBlock.ActualBorderLeftWidth; - top = (prevSibling == null && ParentBox != null ? ParentBox.ClientTop : ParentBox == null ? Location.Y : 0) + MarginTopCollapse(prevSibling) + (prevSibling != null ? prevSibling.ActualBottom + prevSibling.ActualBorderBottomWidth : 0); + top = (prevSibling == null && ParentBox != null + ? ParentBox.ClientTop + : ParentBox == null + ? Location.Y + : 0) + + MarginTopCollapse(prevSibling) + + (prevSibling != null + ? prevSibling.ActualBottom + prevSibling.ActualBorderBottomWidth + : 0); + Location = new RPoint(left, top); - ActualBottom = top; + + if (this.PageBreakBefore == CssConstants.Always || prevSibling?.PageBreakAfter == CssConstants.Always) + { + this.BreakPage(true); + } + + //Start with the assumption this is zero height. + ActualBottom = Location.Y; } } //If we're talking about a table here.. if (Display == CssConstants.Table || Display == CssConstants.InlineTable) { - CssLayoutEngineTable.PerformLayout(g, this); + await CssLayoutEngineTable.PerformLayoutAsync(g, this); } else { @@ -669,13 +686,13 @@ protected virtual void PerformLayoutImp(RGraphics g) if (DomUtils.ContainsInlinesOnly(this)) { ActualBottom = Location.Y; - CssLayoutEngine.CreateLineBoxes(g, this); //This will automatically set the bottom of this block + await CssLayoutEngine.CreateLineBoxesAsync(g, this); //This will automatically set the bottom of this block } else if (_boxes.Count > 0) { foreach (var childBox in Boxes) { - childBox.PerformLayout(g); + await childBox.PerformLayoutAsync(g); } ActualRight = CalculateActualRight(); ActualBottom = MarginBottomCollapse(); @@ -694,7 +711,7 @@ protected virtual void PerformLayoutImp(RGraphics g) } ActualBottom = Math.Max(ActualBottom, Location.Y + ActualHeight); - CreateListItemBox(g); + await CreateListItemBoxAsync(g); if (!IsFixed) { @@ -707,14 +724,14 @@ protected virtual void PerformLayoutImp(RGraphics g) /// Assigns words its width and height ///
/// - internal virtual void MeasureWordsSize(RGraphics g) + internal virtual async Task MeasureWordsSizeAsync(RGraphics g) { if (!_wordsSizeMeasured) { if (BackgroundImage != CssConstants.None && _imageLoadHandler == null) { _imageLoadHandler = new ImageLoadHandler(HtmlContainer, OnImageLoadComplete); - _imageLoadHandler.LoadImage(BackgroundImage, HtmlTag != null ? HtmlTag.Attributes : null); + await _imageLoadHandler.LoadImageAsync(BackgroundImage, HtmlTag != null ? HtmlTag.Attributes : null); } MeasureWordSpacing(g); @@ -782,7 +799,7 @@ private int GetIndexForList() /// Creates the ///
/// - private void CreateListItemBox(RGraphics g) + private async Task CreateListItemBoxAsync(RGraphics g) { if (Display == CssConstants.ListItem && ListStyleType != CssConstants.None) { @@ -820,7 +837,7 @@ private void CreateListItemBox(RGraphics g) _listItemBox.ParseToWords(); - _listItemBox.PerformLayoutImp(g); + await _listItemBox.PerformLayoutImpAsync(g); _listItemBox.Size = new RSize(_listItemBox.Words[0].Width, _listItemBox.Words[0].Height); } _listItemBox.Words[0].Left = Location.X - _listItemBox.Size.Width - 5; @@ -1118,24 +1135,33 @@ protected double MarginTopCollapse(CssBoxProperties prevSibling) return value; } - public bool BreakPage() + public bool BreakPage(bool force = false) { var container = this.HtmlContainer; + bool shouldBreakToNextPage; + if (this.Size.Height >= container.PageSize.Height) - return false; + shouldBreakToNextPage = false; + else + { + var remTop = (this.Location.Y - container.MarginTop) % container.PageSize.Height; + var remBottom = (this.ActualBottom - container.MarginTop) % container.PageSize.Height; - var remTop = (this.Location.Y - container.MarginTop) % container.PageSize.Height; - var remBottom = (this.ActualBottom - container.MarginTop) % container.PageSize.Height; + shouldBreakToNextPage = remTop > remBottom; + } - if (remTop > remBottom) + if (force || shouldBreakToNextPage) { + var remTop = (this.Location.Y - container.MarginTop) % container.PageSize.Height; var diff = container.PageSize.Height - remTop; this.Location = new RPoint(this.Location.X, this.Location.Y + diff + 1); return true; } - - return false; + else + { + return false; + } } /// @@ -1210,7 +1236,7 @@ internal void OffsetTop(double amount) /// Paints the fragment /// /// the device to draw to - protected virtual void PaintImp(RGraphics g) + protected virtual async Task PaintImpAsync(RGraphics g) { if (Display != CssConstants.None && (Display != CssConstants.TableCell || EmptyCells != CssConstants.Hide || !IsSpaceOrEmpty)) { @@ -1254,17 +1280,17 @@ protected virtual void PaintImp(RGraphics g) foreach (CssBox b in Boxes) { if (b.Position != CssConstants.Absolute && !b.IsFixed) - b.Paint(g); + await b.PaintAsync(g); } foreach (CssBox b in Boxes) { if (b.Position == CssConstants.Absolute) - b.Paint(g); + await b.PaintAsync(g); } foreach (CssBox b in Boxes) { if (b.IsFixed) - b.Paint(g); + await b.PaintAsync(g); } if (clipped) @@ -1272,7 +1298,7 @@ protected virtual void PaintImp(RGraphics g) if (_listItemBox != null) { - _listItemBox.Paint(g); + await _listItemBox.PaintAsync(g); } } } @@ -1320,7 +1346,7 @@ protected void PaintBackground(RGraphics g, RRect rect, bool isFirst, bool isLas RGraphicsPath roundrect = null; if (IsRounded) { - roundrect = RenderUtils.GetRoundRect(g, rect, ActualCornerNw, ActualCornerNe, ActualCornerSe, ActualCornerSw); + roundrect = RenderUtils.GetRoundRect(g, rect, ActualBorderRadiusTopLeft, ActualBorderRadiusTopRight, ActualBorderRadiusBottomRight, ActualBorderRadiusBottomLeft); } Object prevMode = null; diff --git a/Source/HtmlRenderer/Core/Dom/CssBoxFrame.cs b/Source/HtmlRenderer/Core/Dom/CssBoxFrame.cs index 7bb6ed57f..4bb8ddf8a 100644 --- a/Source/HtmlRenderer/Core/Dom/CssBoxFrame.cs +++ b/Source/HtmlRenderer/Core/Dom/CssBoxFrame.cs @@ -12,6 +12,7 @@ using System; using System.Net; +using System.Net.Http.Json; using System.Text; using System.Threading; using TheArtOfDev.HtmlRenderer.Adapters; @@ -142,16 +143,17 @@ public override void Dispose() ///
private void LoadYoutubeDataAsync(Uri uri) { - ThreadPool.QueueUserWorkItem(state => + ThreadPool.QueueUserWorkItem(async state => { try { var apiUri = new Uri(string.Format("http://gdata.youtube.com/feeds/api/videos/{0}?v=2&alt=json", uri.Segments[2])); - var client = new WebClient(); - client.Encoding = Encoding.UTF8; - client.DownloadStringCompleted += OnDownloadYoutubeApiCompleted; - client.DownloadStringAsync(apiUri); + var client = new HttpClient(); + //client.Encoding = Encoding.UTF8; + var response = await client.GetAsync(apiUri); + //client.DownloadStringCompleted += OnDownloadYoutubeApiCompleted; + //client.DownloadStringAsync(apiUri); } catch (Exception ex) { @@ -278,16 +280,17 @@ private void OnDownloadYoutubeApiCompleted(object sender, DownloadStringComplete /// private void LoadVimeoDataAsync(Uri uri) { - ThreadPool.QueueUserWorkItem(state => + ThreadPool.QueueUserWorkItem(async state => { try { var apiUri = new Uri(string.Format("http://vimeo.com/api/v2/video/{0}.json", uri.Segments[2])); - var client = new WebClient(); - client.Encoding = Encoding.UTF8; - client.DownloadStringCompleted += OnDownloadVimeoApiCompleted; - client.DownloadStringAsync(apiUri); + var client = new HttpClient(); + var response = await client.GetAsync(apiUri); + //client.Encoding = Encoding.UTF8; + //client.DownloadStringCompleted += OnDownloadVimeoApiCompleted; + //client.DownloadStringAsync(apiUri); } catch (Exception ex) { @@ -441,12 +444,12 @@ private void HandlePostApiCall(object sender) /// Paints the fragment /// /// the device to draw to - protected override void PaintImp(RGraphics g) + protected override async Task PaintImpAsync(RGraphics g) { if (_videoImageUrl != null && _imageLoadHandler == null) { _imageLoadHandler = new ImageLoadHandler(HtmlContainer, OnLoadImageComplete); - _imageLoadHandler.LoadImage(_videoImageUrl, HtmlTag != null ? HtmlTag.Attributes : null); + await _imageLoadHandler.LoadImageAsync(_videoImageUrl, HtmlTag != null ? HtmlTag.Attributes : null); } var rects = CommonUtils.GetFirstValueOrDefault(Rectangles); @@ -554,7 +557,7 @@ private void DrawPlay(RGraphics g, RRect rect) /// Assigns words its width and height /// /// the device to use - internal override void MeasureWordsSize(RGraphics g) + internal override async Task MeasureWordsSizeAsync(RGraphics g) { if (!_wordsSizeMeasured) { diff --git a/Source/HtmlRenderer/Core/Dom/CssBoxHr.cs b/Source/HtmlRenderer/Core/Dom/CssBoxHr.cs index 8280f47c3..a6eeade17 100644 --- a/Source/HtmlRenderer/Core/Dom/CssBoxHr.cs +++ b/Source/HtmlRenderer/Core/Dom/CssBoxHr.cs @@ -39,7 +39,7 @@ public CssBoxHr(CssBox parent, HtmlTag tag) /// Performs layout of the DOM structure creating lines by set bounds restrictions. /// /// Device context to use - protected override void PerformLayoutImp(RGraphics g) + protected override async Task PerformLayoutImpAsync(RGraphics g) { if (Display == CssConstants.None) return; @@ -93,7 +93,7 @@ protected override void PerformLayoutImp(RGraphics g) /// Paints the fragment /// /// the device to draw to - protected override void PaintImp(RGraphics g) + protected override async Task PaintImpAsync(RGraphics g) { var offset = (HtmlContainer != null && !IsFixed) ? HtmlContainer.ScrollOffset : RPoint.Empty; var rect = new RRect(Bounds.X + offset.X, Bounds.Y + offset.Y, Bounds.Width, Bounds.Height); diff --git a/Source/HtmlRenderer/Core/Dom/CssBoxImage.cs b/Source/HtmlRenderer/Core/Dom/CssBoxImage.cs index a33627c83..d0a547936 100644 --- a/Source/HtmlRenderer/Core/Dom/CssBoxImage.cs +++ b/Source/HtmlRenderer/Core/Dom/CssBoxImage.cs @@ -67,13 +67,13 @@ public RImage Image /// Paints the fragment /// /// the device to draw to - protected override void PaintImp(RGraphics g) + protected override async Task PaintImpAsync(RGraphics g) { // load image if it is in visible rectangle if (_imageLoadHandler == null) { _imageLoadHandler = new ImageLoadHandler(HtmlContainer, OnLoadImageComplete); - _imageLoadHandler.LoadImage(GetAttribute("src"), HtmlTag != null ? HtmlTag.Attributes : null); + await _imageLoadHandler.LoadImageAsync(GetAttribute("src"), HtmlTag != null ? HtmlTag.Attributes : null); } var rect = CommonUtils.GetFirstValueOrDefault(Rectangles); @@ -135,7 +135,7 @@ protected override void PaintImp(RGraphics g) /// Assigns words its width and height /// /// the device to use - internal override void MeasureWordsSize(RGraphics g) + internal override async Task MeasureWordsSizeAsync(RGraphics g) { if (!_wordsSizeMeasured) { @@ -144,9 +144,9 @@ internal override void MeasureWordsSize(RGraphics g) _imageLoadHandler = new ImageLoadHandler(HtmlContainer, OnLoadImageComplete); if (this.Content != null && this.Content != CssConstants.Normal) - _imageLoadHandler.LoadImage(this.Content, HtmlTag != null ? HtmlTag.Attributes : null); + await _imageLoadHandler.LoadImageAsync(this.Content, HtmlTag != null ? HtmlTag.Attributes : null); else - _imageLoadHandler.LoadImage(GetAttribute("src"), HtmlTag != null ? HtmlTag.Attributes : null); + await _imageLoadHandler.LoadImageAsync(GetAttribute("src"), HtmlTag != null ? HtmlTag.Attributes : null); } MeasureWordSpacing(g); diff --git a/Source/HtmlRenderer/Core/Dom/CssBoxProperties.cs b/Source/HtmlRenderer/Core/Dom/CssBoxProperties.cs index 7abfb53ed..215e6c6b7 100644 --- a/Source/HtmlRenderer/Core/Dom/CssBoxProperties.cs +++ b/Source/HtmlRenderer/Core/Dom/CssBoxProperties.cs @@ -54,11 +54,11 @@ internal abstract class CssBoxProperties private string _bottom; private string _color = "black"; private string _content = "normal"; - private string _cornerNwRadius = "0"; - private string _cornerNeRadius = "0"; - private string _cornerSeRadius = "0"; - private string _cornerSwRadius = "0"; - private string _cornerRadius = "0"; + private string _borderTopLeftRadius = "0"; + private string _borderTopRightRadius = "0"; + private string _borderBottomRightRadius = "0"; + private string _borderBottomLeftRadius = "0"; + private string _borderRadius = "0"; private string _emptyCells = "show"; private string _direction = "ltr"; private string _display = "inline"; @@ -84,6 +84,8 @@ internal abstract class CssBoxProperties private string _paddingBottom = "0"; private string _paddingRight = "0"; private string _paddingTop = "0"; + private string _pageBreakBefore = CssConstants.Auto; + private string _pageBreakAfter = CssConstants.Auto; private string _pageBreakInside = CssConstants.Auto; private string _right; private string _textAlign = string.Empty; @@ -114,10 +116,10 @@ internal abstract class CssBoxProperties /// private RSize _size; - private double _actualCornerNw = double.NaN; - private double _actualCornerNe = double.NaN; - private double _actualCornerSw = double.NaN; - private double _actualCornerSe = double.NaN; + private double _actualBorderRadiusTopLeft = double.NaN; + private double _actualBorderRadiusTopRight = double.NaN; + private double _actualBorderRadiusBottomLeft = double.NaN; + private double _actualBorderRadiusBottomRight = double.NaN; private RColor _actualColor = RColor.Empty; private double _actualBackgroundGradientAngle = double.NaN; private double _actualHeight = double.NaN; @@ -274,66 +276,71 @@ public string BorderCollapse set { _borderCollapse = value; } } - public string CornerRadius + public string BorderRadius { - get { return _cornerRadius; } + get { return _borderRadius; } set { MatchCollection r = RegexParserUtils.Match(RegexParserUtils.CssLength, value); switch (r.Count) { - case 1: - CornerNeRadius = r[0].Value; - CornerNwRadius = r[0].Value; - CornerSeRadius = r[0].Value; - CornerSwRadius = r[0].Value; + // Radius is set for all 4 sides + case 1: + BorderTopRightRadius = r[0].Value; + BorderTopLeftRadius = r[0].Value; + BorderBottomRightRadius = r[0].Value; + BorderBottomLeftRadius = r[0].Value; break; - case 2: - CornerNeRadius = r[0].Value; - CornerNwRadius = r[0].Value; - CornerSeRadius = r[1].Value; - CornerSwRadius = r[1].Value; + // top-left-and-bottom-right | top-right-and-bottom-left + case 2: + BorderTopLeftRadius = r[0].Value; + BorderBottomRightRadius = r[0].Value; + BorderTopRightRadius = r[1].Value; + BorderBottomLeftRadius = r[1].Value; break; - case 3: - CornerNeRadius = r[0].Value; - CornerNwRadius = r[1].Value; - CornerSeRadius = r[2].Value; + // top-left | top-right-and-bottom-left | bottom-right + case 3: + BorderTopLeftRadius = r[0].Value; + BorderTopRightRadius = r[1].Value; + BorderBottomLeftRadius = r[1].Value; + BorderBottomRightRadius = r[2].Value; break; - case 4: - CornerNeRadius = r[0].Value; - CornerNwRadius = r[1].Value; - CornerSeRadius = r[2].Value; - CornerSwRadius = r[3].Value; + // top-left | top-right | bottom-right | bottom-left + case 4: + BorderTopLeftRadius = r[0].Value; + BorderTopRightRadius = r[1].Value; + BorderBottomRightRadius = r[2].Value; + BorderBottomLeftRadius = r[3].Value; break; } - _cornerRadius = value; + _borderRadius = value; } } - public string CornerNwRadius + public string BorderTopLeftRadius { - get { return _cornerNwRadius; } - set { _cornerNwRadius = value; } + get { return _borderTopLeftRadius; } + set { _borderTopLeftRadius = value; } } - public string CornerNeRadius + public string BorderTopRightRadius { - get { return _cornerNeRadius; } - set { _cornerNeRadius = value; } + get { return _borderTopRightRadius; } + set { _borderTopRightRadius = value; } } - public string CornerSeRadius + public string BorderBottomRightRadius { - get { return _cornerSeRadius; } - set { _cornerSeRadius = value; } + get { return _borderBottomRightRadius; } + set { _borderBottomRightRadius = value; } } - public string CornerSwRadius + public string BorderBottomLeftRadius { - get { return _cornerSwRadius; } - set { _cornerSwRadius = value; } + get { return _borderBottomLeftRadius; } + set { _borderBottomLeftRadius = value; } } public string MarginBottom @@ -400,6 +407,24 @@ public string PaddingTop } } + public string PageBreakBefore + { + get { return _pageBreakBefore; } + set + { + _pageBreakBefore = value; + } + } + + public string PageBreakAfter + { + get { return _pageBreakAfter; } + set + { + _pageBreakAfter = value; + } + } + public string PageBreakInside { get { return _pageBreakInside; } @@ -1105,62 +1130,62 @@ public RColor ActualBorderRightColor } /// - /// Gets the actual length of the north west corner + /// Gets the actual length of the top left border /// - public double ActualCornerNw + public double ActualBorderRadiusTopLeft { get { - if (double.IsNaN(_actualCornerNw)) + if (double.IsNaN(_actualBorderRadiusTopLeft)) { - _actualCornerNw = CssValueParser.ParseLength(CornerNwRadius, 0, this); + _actualBorderRadiusTopLeft = CssValueParser.ParseLength(BorderTopLeftRadius, 0, this); } - return _actualCornerNw; + return _actualBorderRadiusTopLeft; } } /// - /// Gets the actual length of the north east corner + /// Gets the actual length of the top right border /// - public double ActualCornerNe + public double ActualBorderRadiusTopRight { get { - if (double.IsNaN(_actualCornerNe)) + if (double.IsNaN(_actualBorderRadiusTopRight)) { - _actualCornerNe = CssValueParser.ParseLength(CornerNeRadius, 0, this); + _actualBorderRadiusTopRight = CssValueParser.ParseLength(BorderTopRightRadius, 0, this); } - return _actualCornerNe; + return _actualBorderRadiusTopRight; } } /// - /// Gets the actual length of the south east corner + /// Gets the actual length of the bottom right border /// - public double ActualCornerSe + public double ActualBorderRadiusBottomRight { get { - if (double.IsNaN(_actualCornerSe)) + if (double.IsNaN(_actualBorderRadiusBottomRight)) { - _actualCornerSe = CssValueParser.ParseLength(CornerSeRadius, 0, this); + _actualBorderRadiusBottomRight = CssValueParser.ParseLength(BorderBottomRightRadius, 0, this); } - return _actualCornerSe; + return _actualBorderRadiusBottomRight; } } /// - /// Gets the actual length of the south west corner + /// Gets the actual length of the bottom left border /// - public double ActualCornerSw + public double ActualBorderRadiusBottomLeft { get { - if (double.IsNaN(_actualCornerSw)) + if (double.IsNaN(_actualBorderRadiusBottomLeft)) { - _actualCornerSw = CssValueParser.ParseLength(CornerSwRadius, 0, this); + _actualBorderRadiusBottomLeft = CssValueParser.ParseLength(BorderBottomLeftRadius, 0, this); } - return _actualCornerSw; + return _actualBorderRadiusBottomLeft; } } @@ -1169,7 +1194,7 @@ public double ActualCornerSw /// public bool IsRounded { - get { return ActualCornerNe > 0f || ActualCornerNw > 0f || ActualCornerSe > 0f || ActualCornerSw > 0f; } + get { return ActualBorderRadiusTopRight > 0f || ActualBorderRadiusTopLeft > 0f || ActualBorderRadiusBottomRight > 0f || ActualBorderRadiusBottomLeft > 0f; } } /// @@ -1534,11 +1559,11 @@ protected void InheritStyle(CssBox p, bool everything) _borderBottomStyle = p._borderBottomStyle; _borderLeftStyle = p._borderLeftStyle; _bottom = p._bottom; - _cornerNwRadius = p._cornerNwRadius; - _cornerNeRadius = p._cornerNeRadius; - _cornerSeRadius = p._cornerSeRadius; - _cornerSwRadius = p._cornerSwRadius; - _cornerRadius = p._cornerRadius; + _borderTopLeftRadius = p._borderTopLeftRadius; + _borderTopRightRadius = p._borderTopRightRadius; + _borderBottomRightRadius = p._borderBottomRightRadius; + _borderBottomLeftRadius = p._borderBottomLeftRadius; + _borderRadius = p._borderRadius; _display = p._display; _float = p._float; _height = p._height; diff --git a/Source/HtmlRenderer/Core/Dom/CssLayoutEngine.cs b/Source/HtmlRenderer/Core/Dom/CssLayoutEngine.cs index a24f9e708..498f987dc 100644 --- a/Source/HtmlRenderer/Core/Dom/CssLayoutEngine.cs +++ b/Source/HtmlRenderer/Core/Dom/CssLayoutEngine.cs @@ -117,7 +117,7 @@ public static void MeasureImageSize(CssRectImage imageWord) /// /// /// - public static void CreateLineBoxes(RGraphics g, CssBox blockBox) + public static async Task CreateLineBoxesAsync(RGraphics g, CssBox blockBox) { ArgChecker.AssertArgNotNull(g, "g"); ArgChecker.AssertArgNotNull(blockBox, "blockBox"); @@ -140,7 +140,7 @@ public static void CreateLineBoxes(RGraphics g, CssBox blockBox) CssLineBox line = new CssLineBox(blockBox); //Flow words and boxes - FlowBox(g, blockBox, blockBox, limitRight, 0, startx, ref line, ref curx, ref cury, ref maxRight, ref maxBottom); + (line, curx, cury, maxRight, maxBottom) = await FlowBoxAsync(g, blockBox, blockBox, limitRight, 0, startx, line, curx, cury, maxRight, maxBottom); // if width is not restricted we need to lower it to the actual width if (blockBox.ActualRight >= 90999) @@ -239,7 +239,14 @@ public static void ApplyCellVerticalAlignment(RGraphics g, CssBox cell) /// Current y coordinate that will be the top of the next word /// Maximum right reached so far /// Maximum bottom reached so far - private static void FlowBox(RGraphics g, CssBox blockbox, CssBox box, double limitRight, double linespacing, double startx, ref CssLineBox line, ref double curx, ref double cury, ref double maxRight, ref double maxbottom) + private static async Task<(CssLineBox line, double curx, double cury, double maxRight, double maxbottom)> FlowBoxAsync( + RGraphics g, + CssBox blockbox, + CssBox box, + double limitRight, + double linespacing, + double startx, + CssLineBox line, double curx, double cury, double maxRight, double maxbottom) { var startX = curx; var startY = cury; @@ -254,7 +261,7 @@ private static void FlowBox(RGraphics g, CssBox blockbox, CssBox box, double lim double rightspacing = (b.Position != CssConstants.Absolute && b.Position != CssConstants.Fixed) ? b.ActualMarginRight + b.ActualBorderRightWidth + b.ActualPaddingRight : 0; b.RectanglesReset(); - b.MeasureWordsSize(g); + await b.MeasureWordsSizeAsync(g); curx += leftspacing; @@ -323,7 +330,7 @@ private static void FlowBox(RGraphics g, CssBox blockbox, CssBox box, double lim } else { - FlowBox(g, blockbox, b, limitRight, linespacing, startx, ref line, ref curx, ref cury, ref maxRight, ref maxbottom); + (line, curx, cury, maxRight, maxbottom) = await FlowBoxAsync(g, blockbox, b, limitRight, linespacing, startx, line, curx, cury, maxRight, maxbottom); } curx += rightspacing; @@ -359,6 +366,8 @@ private static void FlowBox(RGraphics g, CssBox blockbox, CssBox box, double lim } box.LastHostingLineBox = line; + + return (line, curx, cury, maxRight, maxbottom); } /// diff --git a/Source/HtmlRenderer/Core/Dom/CssLayoutEngineTable.cs b/Source/HtmlRenderer/Core/Dom/CssLayoutEngineTable.cs index 79627161a..ddaf8b0f7 100644 --- a/Source/HtmlRenderer/Core/Dom/CssLayoutEngineTable.cs +++ b/Source/HtmlRenderer/Core/Dom/CssLayoutEngineTable.cs @@ -121,7 +121,7 @@ public static double GetTableSpacing(CssBox tableBox) /// /// /// - public static void PerformLayout(RGraphics g, CssBox tableBox) + public static async Task PerformLayoutAsync(RGraphics g, CssBox tableBox) { ArgChecker.AssertArgNotNull(g, "g"); ArgChecker.AssertArgNotNull(tableBox, "tableBox"); @@ -129,7 +129,7 @@ public static void PerformLayout(RGraphics g, CssBox tableBox) try { var table = new CssLayoutEngineTable(tableBox); - table.Layout(g); + await table.LayoutAsync(g); } catch (Exception ex) { @@ -144,9 +144,9 @@ public static void PerformLayout(RGraphics g, CssBox tableBox) /// Analyzes the Table and assigns values to this CssTable object. /// To be called from the constructor /// - private void Layout(RGraphics g) + private async Task LayoutAsync(RGraphics g) { - MeasureWords(_tableBox, g); + await MeasureWordsAsync(_tableBox, g); // get the table boxes into the proper fields AssignBoxKinds(); @@ -169,7 +169,7 @@ private void Layout(RGraphics g) _tableBox.PaddingLeft = _tableBox.PaddingTop = _tableBox.PaddingRight = _tableBox.PaddingBottom = "0"; //Actually layout cells! - LayoutCells(g); + await LayoutCellsAsync(g); } /// @@ -604,7 +604,7 @@ private void EnforceMinimumSize() /// Layout the cells by the calculated table layout /// /// - private void LayoutCells(RGraphics g) + private async Task LayoutCellsAsync(RGraphics g) { double startx = Math.Max(_tableBox.ClientLeft + GetHorizontalSpacing(), 0); double starty = Math.Max(_tableBox.ClientTop + GetVerticalSpacing(), 0); @@ -642,7 +642,7 @@ private void LayoutCells(RGraphics g) double width = GetCellWidth(columnIndex, cell); cell.Location = new RPoint(curx, cury); cell.Size = new RSize(width, 0f); - cell.PerformLayout(g); //That will automatically set the bottom of the cell + await cell.PerformLayoutAsync(g); //That will automatically set the bottom of the cell //Alter max bottom only if row is cell's row + cell's rowspan - 1 CssSpacingBox sb = cell as CssSpacingBox; @@ -808,14 +808,14 @@ private static int GetRowSpan(CssBox b) /// /// the box to measure /// Device to use - private static void MeasureWords(CssBox box, RGraphics g) + private static async Task MeasureWordsAsync(CssBox box, RGraphics g) { if (box != null) { foreach (var childBox in box.Boxes) { - childBox.MeasureWordsSize(g); - MeasureWords(childBox, g); + await childBox.MeasureWordsSizeAsync(g); + await MeasureWordsAsync(childBox, g); } } } diff --git a/Source/HtmlRenderer/Core/Dom/CssUnit.cs b/Source/HtmlRenderer/Core/Dom/CssUnit.cs index 269893e8d..c8baa6347 100644 --- a/Source/HtmlRenderer/Core/Dom/CssUnit.cs +++ b/Source/HtmlRenderer/Core/Dom/CssUnit.cs @@ -18,7 +18,7 @@ namespace TheArtOfDev.HtmlRenderer.Core.Dom /// /// http://www.w3.org/TR/CSS21/syndata.html#length-units /// - internal enum CssUnit + public enum CssUnit { None, Ems, diff --git a/Source/HtmlRenderer/Core/Dom/CssUnitConversion.cs b/Source/HtmlRenderer/Core/Dom/CssUnitConversion.cs new file mode 100644 index 000000000..3a3c4fe54 --- /dev/null +++ b/Source/HtmlRenderer/Core/Dom/CssUnitConversion.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlTypes; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using TheArtOfDev.HtmlRenderer.Core.Dom; + +namespace HtmlRenderer.Core.Dom +{ + public class CssUnitConversion + { + /// + /// TODO: fully implement, and use in the core as well. + /// + /// + /// Some extra thought needed here as conversion from size to px needs to know DPI. + /// + public static T Convert(T value, CssUnit from, CssUnit to) + where T : IFloatingPoint + { + var valueInMm = from switch + { + CssUnit.Milimeters => value, + CssUnit.Centimeters => value * (T)T.CreateChecked(10), + CssUnit.Inches => value * T.CreateChecked(2.54) * T.CreateChecked(10), + _ => throw new NotImplementedException(), + }; + var valueInDest = to switch + { + CssUnit.Centimeters => valueInMm * T.CreateChecked(10), + CssUnit.Milimeters => valueInMm, + CssUnit.Inches => valueInMm / T.CreateChecked(10) / T.CreateChecked(2.54), + _ => throw new NotImplementedException(), + }; + return valueInDest; + } + } +} diff --git a/Source/HtmlRenderer/Core/Entities/HtmlImageLoadEventArgs.cs b/Source/HtmlRenderer/Core/Entities/HtmlImageLoadEventArgs.cs index 5d5a4c5af..407da4e04 100644 --- a/Source/HtmlRenderer/Core/Entities/HtmlImageLoadEventArgs.cs +++ b/Source/HtmlRenderer/Core/Entities/HtmlImageLoadEventArgs.cs @@ -26,7 +26,7 @@ namespace TheArtOfDev.HtmlRenderer.Core.Entities /// the path to the image to load (file path or URL) /// the image to use /// optional: limit to specific rectangle in the loaded image - public delegate void HtmlImageLoadCallback(string path, Object image, RRect imageRectangle); + public delegate Task HtmlImageLoadCallbackAsync(string path, Object image, RRect imageRectangle); /// /// Invoked when an image is about to be loaded by file path, URL or inline data in 'img' element or background-image CSS style.
@@ -59,7 +59,7 @@ public sealed class HtmlImageLoadEventArgs : EventArgs /// /// Callback used to allow setting image externally and async. /// - private readonly HtmlImageLoadCallback _callback; + private readonly HtmlImageLoadCallbackAsync _callback; #endregion @@ -70,7 +70,7 @@ public sealed class HtmlImageLoadEventArgs : EventArgs /// the source of the image (file path or Uri) /// collection of all the attributes that are defined on the image element /// Callback used to allow setting image externally and async. - internal HtmlImageLoadEventArgs(string src, Dictionary attributes, HtmlImageLoadCallback callback) + internal HtmlImageLoadEventArgs(string src, Dictionary attributes, HtmlImageLoadCallbackAsync callback) { _src = src; _attributes = attributes; diff --git a/Source/HtmlRenderer/Core/Entities/HtmlRenderErrorEventArgs.cs b/Source/HtmlRenderer/Core/Entities/HtmlRenderErrorEventArgs.cs index 4696ed3b9..ee84efa41 100644 --- a/Source/HtmlRenderer/Core/Entities/HtmlRenderErrorEventArgs.cs +++ b/Source/HtmlRenderer/Core/Entities/HtmlRenderErrorEventArgs.cs @@ -39,8 +39,14 @@ public sealed class HtmlRenderErrorEventArgs : EventArgs ///
/// the type of error to report /// the error message - /// optional: the exception that occurred - public HtmlRenderErrorEventArgs(HtmlRenderErrorType type, string message, Exception exception = null) + public HtmlRenderErrorEventArgs(HtmlRenderErrorType type, string message) + { + _type = type; + _message = message; + _exception = default; + } + + public HtmlRenderErrorEventArgs(HtmlRenderErrorType type, string message, Exception exception) { _type = type; _message = message; diff --git a/Source/HtmlRenderer/Core/Handlers/BordersDrawHandler.cs b/Source/HtmlRenderer/Core/Handlers/BordersDrawHandler.cs index b20c331cb..f52bd9426 100644 --- a/Source/HtmlRenderer/Core/Handlers/BordersDrawHandler.cs +++ b/Source/HtmlRenderer/Core/Handlers/BordersDrawHandler.cs @@ -206,69 +206,69 @@ private static RGraphicsPath GetRoundedBorderPath(RGraphics g, Border border, Cs switch (border) { case Border.Top: - if (b.ActualCornerNw > 0 || b.ActualCornerNe > 0) + if (b.ActualBorderRadiusTopLeft > 0 || b.ActualBorderRadiusTopRight > 0) { path = g.GetGraphicsPath(); - path.Start(r.Left + b.ActualBorderLeftWidth / 2, r.Top + b.ActualBorderTopWidth / 2 + b.ActualCornerNw); + path.Start(r.Left + b.ActualBorderLeftWidth / 2, r.Top + b.ActualBorderTopWidth / 2 + b.ActualBorderRadiusTopLeft); - if (b.ActualCornerNw > 0) - path.ArcTo(r.Left + b.ActualBorderLeftWidth / 2 + b.ActualCornerNw, r.Top + b.ActualBorderTopWidth / 2, b.ActualCornerNw, RGraphicsPath.Corner.TopLeft); + if (b.ActualBorderRadiusTopLeft > 0) + path.ArcTo(r.Left + b.ActualBorderLeftWidth / 2 + b.ActualBorderRadiusTopLeft, r.Top + b.ActualBorderTopWidth / 2, b.ActualBorderRadiusTopLeft, RGraphicsPath.Corner.TopLeft); - path.LineTo(r.Right - b.ActualBorderRightWidth / 2 - b.ActualCornerNe, r.Top + b.ActualBorderTopWidth / 2); + path.LineTo(r.Right - b.ActualBorderRightWidth / 2 - b.ActualBorderRadiusTopRight, r.Top + b.ActualBorderTopWidth / 2); - if (b.ActualCornerNe > 0) - path.ArcTo(r.Right - b.ActualBorderRightWidth / 2, r.Top + b.ActualBorderTopWidth / 2 + b.ActualCornerNe, b.ActualCornerNe, RGraphicsPath.Corner.TopRight); + if (b.ActualBorderRadiusTopRight > 0) + path.ArcTo(r.Right - b.ActualBorderRightWidth / 2, r.Top + b.ActualBorderTopWidth / 2 + b.ActualBorderRadiusTopRight, b.ActualBorderRadiusTopRight, RGraphicsPath.Corner.TopRight); } break; case Border.Bottom: - if (b.ActualCornerSw > 0 || b.ActualCornerSe > 0) + if (b.ActualBorderRadiusBottomLeft > 0 || b.ActualBorderRadiusBottomRight > 0) { path = g.GetGraphicsPath(); - path.Start(r.Right - b.ActualBorderRightWidth / 2, r.Bottom - b.ActualBorderBottomWidth / 2 - b.ActualCornerSe); + path.Start(r.Right - b.ActualBorderRightWidth / 2, r.Bottom - b.ActualBorderBottomWidth / 2 - b.ActualBorderRadiusBottomRight); - if (b.ActualCornerSe > 0) - path.ArcTo(r.Right - b.ActualBorderRightWidth / 2 - b.ActualCornerSe, r.Bottom - b.ActualBorderBottomWidth / 2, b.ActualCornerSe, RGraphicsPath.Corner.BottomRight); + if (b.ActualBorderRadiusBottomRight > 0) + path.ArcTo(r.Right - b.ActualBorderRightWidth / 2 - b.ActualBorderRadiusBottomRight, r.Bottom - b.ActualBorderBottomWidth / 2, b.ActualBorderRadiusBottomRight, RGraphicsPath.Corner.BottomRight); - path.LineTo(r.Left + b.ActualBorderLeftWidth / 2 + b.ActualCornerSw, r.Bottom - b.ActualBorderBottomWidth / 2); + path.LineTo(r.Left + b.ActualBorderLeftWidth / 2 + b.ActualBorderRadiusBottomLeft, r.Bottom - b.ActualBorderBottomWidth / 2); - if (b.ActualCornerSw > 0) - path.ArcTo(r.Left + b.ActualBorderLeftWidth / 2, r.Bottom - b.ActualBorderBottomWidth / 2 - b.ActualCornerSw, b.ActualCornerSw, RGraphicsPath.Corner.BottomLeft); + if (b.ActualBorderRadiusBottomLeft > 0) + path.ArcTo(r.Left + b.ActualBorderLeftWidth / 2, r.Bottom - b.ActualBorderBottomWidth / 2 - b.ActualBorderRadiusBottomLeft, b.ActualBorderRadiusBottomLeft, RGraphicsPath.Corner.BottomLeft); } break; case Border.Right: - if (b.ActualCornerNe > 0 || b.ActualCornerSe > 0) + if (b.ActualBorderRadiusTopRight > 0 || b.ActualBorderRadiusBottomRight > 0) { path = g.GetGraphicsPath(); bool noTop = b.BorderTopStyle == CssConstants.None || b.BorderTopStyle == CssConstants.Hidden; bool noBottom = b.BorderBottomStyle == CssConstants.None || b.BorderBottomStyle == CssConstants.Hidden; - path.Start(r.Right - b.ActualBorderRightWidth / 2 - (noTop ? b.ActualCornerNe : 0), r.Top + b.ActualBorderTopWidth / 2 + (noTop ? 0 : b.ActualCornerNe)); + path.Start(r.Right - b.ActualBorderRightWidth / 2 - (noTop ? b.ActualBorderRadiusTopRight : 0), r.Top + b.ActualBorderTopWidth / 2 + (noTop ? 0 : b.ActualBorderRadiusTopRight)); - if (b.ActualCornerNe > 0 && noTop) - path.ArcTo(r.Right - b.ActualBorderLeftWidth / 2, r.Top + b.ActualBorderTopWidth / 2 + b.ActualCornerNe, b.ActualCornerNe, RGraphicsPath.Corner.TopRight); + if (b.ActualBorderRadiusTopRight > 0 && noTop) + path.ArcTo(r.Right - b.ActualBorderLeftWidth / 2, r.Top + b.ActualBorderTopWidth / 2 + b.ActualBorderRadiusTopRight, b.ActualBorderRadiusTopRight, RGraphicsPath.Corner.TopRight); - path.LineTo(r.Right - b.ActualBorderRightWidth / 2, r.Bottom - b.ActualBorderBottomWidth / 2 - b.ActualCornerSe); + path.LineTo(r.Right - b.ActualBorderRightWidth / 2, r.Bottom - b.ActualBorderBottomWidth / 2 - b.ActualBorderRadiusBottomRight); - if (b.ActualCornerSe > 0 && noBottom) - path.ArcTo(r.Right - b.ActualBorderRightWidth / 2 - b.ActualCornerSe, r.Bottom - b.ActualBorderBottomWidth / 2, b.ActualCornerSe, RGraphicsPath.Corner.BottomRight); + if (b.ActualBorderRadiusBottomRight > 0 && noBottom) + path.ArcTo(r.Right - b.ActualBorderRightWidth / 2 - b.ActualBorderRadiusBottomRight, r.Bottom - b.ActualBorderBottomWidth / 2, b.ActualBorderRadiusBottomRight, RGraphicsPath.Corner.BottomRight); } break; case Border.Left: - if (b.ActualCornerNw > 0 || b.ActualCornerSw > 0) + if (b.ActualBorderRadiusTopLeft > 0 || b.ActualBorderRadiusBottomLeft > 0) { path = g.GetGraphicsPath(); bool noTop = b.BorderTopStyle == CssConstants.None || b.BorderTopStyle == CssConstants.Hidden; bool noBottom = b.BorderBottomStyle == CssConstants.None || b.BorderBottomStyle == CssConstants.Hidden; - path.Start(r.Left + b.ActualBorderLeftWidth / 2 + (noBottom ? b.ActualCornerSw : 0), r.Bottom - b.ActualBorderBottomWidth / 2 - (noBottom ? 0 : b.ActualCornerSw)); + path.Start(r.Left + b.ActualBorderLeftWidth / 2 + (noBottom ? b.ActualBorderRadiusBottomLeft : 0), r.Bottom - b.ActualBorderBottomWidth / 2 - (noBottom ? 0 : b.ActualBorderRadiusBottomLeft)); - if (b.ActualCornerSw > 0 && noBottom) - path.ArcTo(r.Left + b.ActualBorderLeftWidth / 2, r.Bottom - b.ActualBorderBottomWidth / 2 - b.ActualCornerSw, b.ActualCornerSw, RGraphicsPath.Corner.BottomLeft); + if (b.ActualBorderRadiusBottomLeft > 0 && noBottom) + path.ArcTo(r.Left + b.ActualBorderLeftWidth / 2, r.Bottom - b.ActualBorderBottomWidth / 2 - b.ActualBorderRadiusBottomLeft, b.ActualBorderRadiusBottomLeft, RGraphicsPath.Corner.BottomLeft); - path.LineTo(r.Left + b.ActualBorderLeftWidth / 2, r.Top + b.ActualBorderTopWidth / 2 + b.ActualCornerNw); + path.LineTo(r.Left + b.ActualBorderLeftWidth / 2, r.Top + b.ActualBorderTopWidth / 2 + b.ActualBorderRadiusTopLeft); - if (b.ActualCornerNw > 0 && noTop) - path.ArcTo(r.Left + b.ActualBorderLeftWidth / 2 + b.ActualCornerNw, r.Top + b.ActualBorderTopWidth / 2, b.ActualCornerNw, RGraphicsPath.Corner.TopLeft); + if (b.ActualBorderRadiusTopLeft > 0 && noTop) + path.ArcTo(r.Left + b.ActualBorderLeftWidth / 2 + b.ActualBorderRadiusTopLeft, r.Top + b.ActualBorderTopWidth / 2, b.ActualBorderRadiusTopLeft, RGraphicsPath.Corner.TopLeft); } break; } diff --git a/Source/HtmlRenderer/Core/Handlers/ImageDownloader.cs b/Source/HtmlRenderer/Core/Handlers/ImageDownloader.cs index 2f8b0f5e6..3cbfb13e8 100644 --- a/Source/HtmlRenderer/Core/Handlers/ImageDownloader.cs +++ b/Source/HtmlRenderer/Core/Handlers/ImageDownloader.cs @@ -41,7 +41,7 @@ internal sealed class ImageDownloader : IDisposable /// /// the web client used to download image from URL (to cancel on dispose) /// - private readonly List _clients = new List(); + private readonly List _clients = new List(); /// /// dictionary of image cache path to callbacks of download to handle multiple requests to download the same image @@ -60,7 +60,7 @@ public ImageDownloader() /// the path on disk to download the file to /// is to download the file sync or async (true-async) /// This callback will be called with local file path. If something went wrong in the download it will return null. - public void DownloadImage(Uri imageUri, string filePath, bool async, DownloadFileAsyncCallback cachedFileCallback) + public async Task DownloadImageAsync(Uri imageUri, string filePath, bool async, DownloadFileAsyncCallback cachedFileCallback) { ArgChecker.AssertArgNotNull(imageUri, "imageUri"); ArgChecker.AssertArgNotNull(cachedFileCallback, "cachedFileCallback"); @@ -84,9 +84,12 @@ public void DownloadImage(Uri imageUri, string filePath, bool async, DownloadFil { var tempPath = Path.GetTempFileName(); if (async) - ThreadPool.QueueUserWorkItem(DownloadImageFromUrlAsync, new DownloadData(imageUri, tempPath, filePath)); + { + //Don't wait for the image to be downloaded, just start the task. TODO: cancellation tokens. + var task = DownloadImageFromUrl(imageUri, tempPath, filePath); + } else - DownloadImageFromUrl(imageUri, tempPath, filePath); + await DownloadImageFromUrl(imageUri, tempPath, filePath); } } @@ -103,86 +106,66 @@ public void Dispose() /// /// Download the requested file in the URI to the given file path.
- /// Use async sockets API to download from web, . ///
- private void DownloadImageFromUrl(Uri source, string tempPath, string filePath) + private async Task DownloadImageFromUrl(Uri source, string tempPath, string filePath) { try { - using (var client = new WebClient()) + using (var client = new HttpClient()) { _clients.Add(client); - client.DownloadFile(source, tempPath); - OnDownloadImageCompleted(client, source, tempPath, filePath, null, false); + var response = await client.GetAsync(source); + await OnDownloadImageCompleted(response, source, tempPath, filePath); + _clients.Remove(client); } } - catch (Exception ex) + catch (TaskCanceledException) { - OnDownloadImageCompleted(null, source, tempPath, filePath, ex, false); + //If the download was cancelled, don't bother raising this. + return; } } /// - /// Download the requested file in the URI to the given file path.
- /// Use async sockets API to download from web, . + /// Checks if the file was downloaded and raises the cachedFileCallback from ///
- /// key value pair of URL and file info to download the file to - private void DownloadImageFromUrlAsync(object data) + private async Task OnDownloadImageCompleted(HttpResponseMessage response, Uri source, string tempPath, string filePath) { - var downloadData = (DownloadData)data; - try - { - var client = new WebClient(); - _clients.Add(client); - client.DownloadFileCompleted += OnDownloadImageAsyncCompleted; - client.DownloadFileAsync(downloadData._uri, downloadData._tempPath, downloadData); - } - catch (Exception ex) - { - OnDownloadImageCompleted(null, downloadData._uri, downloadData._tempPath, downloadData._filePath, ex, false); - } - } + Exception error = null; + bool cancelled = false; - /// - /// On download image complete to local file.
- /// If the download canceled do nothing, if failed report error. - ///
- private void OnDownloadImageAsyncCompleted(object sender, AsyncCompletedEventArgs e) - { - var downloadData = (DownloadData)e.UserState; try { - using (var client = (WebClient)sender) - { - client.DownloadFileCompleted -= OnDownloadImageAsyncCompleted; - OnDownloadImageCompleted(client, downloadData._uri, downloadData._tempPath, downloadData._filePath, e.Error, e.Cancelled); - } + response.EnsureSuccessStatusCode(); } - catch (Exception ex) + catch (TaskCanceledException) { - OnDownloadImageCompleted(null, downloadData._uri, downloadData._tempPath, downloadData._filePath, ex, false); + cancelled = true; + } + catch(Exception ex) + { + error = ex; } - } - /// - /// Checks if the file was downloaded and raises the cachedFileCallback from - /// - private void OnDownloadImageCompleted(WebClient client, Uri source, string tempPath, string filePath, Exception error, bool cancelled) - { if (!cancelled) { if (error == null) { - var contentType = CommonUtils.GetResponseContentType(client); - if (contentType == null || !contentType.StartsWith("image", StringComparison.OrdinalIgnoreCase)) + var mediaType = response.Content.Headers.ContentType?.MediaType; + if (mediaType == null || !mediaType.StartsWith("image", StringComparison.OrdinalIgnoreCase)) { - error = new Exception("Failed to load image, not image content type: " + contentType); + error = new Exception("Failed to load image, not image content type: " + mediaType); } - } + //Save the content to the temp path. + using (var responseStream = response.Content.ReadAsStream()) + { + using (var tempFile = File.OpenWrite(tempPath)) + { + await responseStream.CopyToAsync(tempFile); + } + } - if (error == null) - { if (File.Exists(tempPath)) { try @@ -231,7 +214,7 @@ private void ReleaseObjects() try { var client = _clients[0]; - client.CancelAsync(); + client.CancelPendingRequests(); client.Dispose(); _clients.RemoveAt(0); } diff --git a/Source/HtmlRenderer/Core/Handlers/ImageLoadHandler.cs b/Source/HtmlRenderer/Core/Handlers/ImageLoadHandler.cs index eb9ace4fd..5a7901163 100644 --- a/Source/HtmlRenderer/Core/Handlers/ImageLoadHandler.cs +++ b/Source/HtmlRenderer/Core/Handlers/ImageLoadHandler.cs @@ -131,11 +131,11 @@ public RRect Rectangle /// the source of the image to load /// the collection of attributes on the element to use in event /// the image object (null if failed) - public void LoadImage(string src, Dictionary attributes) + public async Task LoadImageAsync(string src, Dictionary attributes) { try { - var args = new HtmlImageLoadEventArgs(src, attributes, OnHtmlImageLoadEventCallback); + var args = new HtmlImageLoadEventArgs(src, attributes, OnHtmlImageLoadEventCallbackAsync); _htmlContainer.RaiseHtmlImageLoadEvent(args); _asyncCallback = !_htmlContainer.AvoidAsyncImagesLoading; @@ -149,7 +149,7 @@ public void LoadImage(string src, Dictionary attributes) } else { - SetImageFromPath(src); + await SetImageFromPathAsync(src); } } else @@ -183,7 +183,7 @@ public void Dispose() /// the path to the image to load (file path or uri) /// the image to load /// optional: limit to specific rectangle of the image and not all of it - private void OnHtmlImageLoadEventCallback(string path, object image, RRect imageRectangle) + private async Task OnHtmlImageLoadEventCallbackAsync(string path, object image, RRect imageRectangle) { if (!_disposed) { @@ -196,7 +196,7 @@ private void OnHtmlImageLoadEventCallback(string path, object image, RRect image } else if (!string.IsNullOrEmpty(path)) { - SetImageFromPath(path); + await SetImageFromPathAsync(path); } else { @@ -251,12 +251,12 @@ private RImage GetImageFromData(string src) /// Load image from path of image file or URL. ///
/// the file path or uri to load image from - private void SetImageFromPath(string path) + private async Task SetImageFromPathAsync(string path) { var uri = CommonUtils.TryGetUri(path); if (uri != null && uri.Scheme != "file") { - SetImageFromUrl(uri); + await SetImageFromUrlAsync(uri); } else { @@ -323,7 +323,7 @@ private void LoadImageFromFile(string source) /// Create local file name in temp folder from the URI, if the file already exists use it as it has already been downloaded. /// If not download the file. /// - private void SetImageFromUrl(Uri source) + private async Task SetImageFromUrlAsync(Uri source) { var filePath = CommonUtils.GetLocalfileName(source); if (filePath.Exists && filePath.Length > 0) @@ -332,7 +332,7 @@ private void SetImageFromUrl(Uri source) } else { - _htmlContainer.GetImageDownloader().DownloadImage(source, filePath.FullName, !_htmlContainer.AvoidAsyncImagesLoading, OnDownloadImageCompleted); + await _htmlContainer.GetImageDownloader().DownloadImageAsync(source, filePath.FullName, !_htmlContainer.AvoidAsyncImagesLoading, OnDownloadImageCompleted); } } diff --git a/Source/HtmlRenderer/Core/Handlers/StylesheetLoadHandler.cs b/Source/HtmlRenderer/Core/Handlers/StylesheetLoadHandler.cs index 719f3cebb..fd3c552cb 100644 --- a/Source/HtmlRenderer/Core/Handlers/StylesheetLoadHandler.cs +++ b/Source/HtmlRenderer/Core/Handlers/StylesheetLoadHandler.cs @@ -35,12 +35,12 @@ internal static class StylesheetLoadHandler /// the attributes of the link element /// return the stylesheet string that has been loaded (null if failed or is given) /// return stylesheet data object that was provided by overwrite (null if failed or is given) - public static void LoadStylesheet(HtmlContainerInt htmlContainer, string src, Dictionary attributes, out string stylesheet, out CssData stylesheetData) + public static async Task<(string, CssData)> LoadStylesheetAsync(HtmlContainerInt htmlContainer, string src, Dictionary attributes) { ArgChecker.AssertArgNotNull(htmlContainer, "htmlContainer"); - stylesheet = null; - stylesheetData = null; + string stylesheet = null; + CssData stylesheetData = null; try { var args = new HtmlStylesheetLoadEventArgs(src, attributes); @@ -56,17 +56,19 @@ public static void LoadStylesheet(HtmlContainerInt htmlContainer, string src, Di } else if (args.SetSrc != null) { - stylesheet = LoadStylesheet(htmlContainer, args.SetSrc); + stylesheet = await LoadStylesheetAsync(htmlContainer, args.SetSrc); } else { - stylesheet = LoadStylesheet(htmlContainer, src); + stylesheet = await LoadStylesheetAsync(htmlContainer, src); } } catch (Exception ex) { htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Exception in handling stylesheet source", ex); } + + return (stylesheet, stylesheetData); } @@ -78,7 +80,7 @@ public static void LoadStylesheet(HtmlContainerInt htmlContainer, string src, Di /// the container of the html to handle load stylesheet for /// the file path or uri to load the stylesheet from /// the stylesheet string - private static string LoadStylesheet(HtmlContainerInt htmlContainer, string src) + private static async Task LoadStylesheetAsync(HtmlContainerInt htmlContainer, string src) { var uri = CommonUtils.TryGetUri(src); if (uri == null || uri.Scheme == "file") @@ -87,7 +89,7 @@ private static string LoadStylesheet(HtmlContainerInt htmlContainer, string src) } else { - return LoadStylesheetFromUri(htmlContainer, uri); + return await LoadStylesheetFromUriAsync(htmlContainer, uri); } } @@ -127,19 +129,28 @@ private static string LoadStylesheetFromFile(HtmlContainerInt htmlContainer, str /// the container of the html to handle load stylesheet for /// the uri to download from /// the loaded stylesheet string - private static string LoadStylesheetFromUri(HtmlContainerInt htmlContainer, Uri uri) + private static async Task LoadStylesheetFromUriAsync(HtmlContainerInt htmlContainer, Uri uri) { - using (var client = new WebClient()) + using (var client = new HttpClient()) { - var stylesheet = client.DownloadString(uri); + //var stylesheet = client.DownloadString(uri); + string stylesheet = default; + var response = await client.GetAsync(uri); + if (response == null || !response.IsSuccessStatusCode) + { + htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Error in retrieving stylesheet"); + } + try { + stylesheet = await response.Content.ReadAsStringAsync(); stylesheet = CorrectRelativeUrls(stylesheet, uri); } catch (Exception ex) { htmlContainer.ReportError(HtmlRenderErrorType.CssParsing, "Error in correcting relative URL in loaded stylesheet", ex); } + return stylesheet; } } diff --git a/Source/HtmlRenderer/Core/HtmlContainerInt.cs b/Source/HtmlRenderer/Core/HtmlContainerInt.cs index 1d71de9fb..780bcaf58 100644 --- a/Source/HtmlRenderer/Core/HtmlContainerInt.cs +++ b/Source/HtmlRenderer/Core/HtmlContainerInt.cs @@ -504,7 +504,7 @@ internal RColor SelectionBackColor /// /// the html to init with, init empty if not given /// optional: the stylesheet to init with, init default if not given - public void SetHtml(string htmlSource, CssData baseCssData = null) + public async Task SetHtml(string htmlSource, CssData baseCssData = null) { Clear(); if (!string.IsNullOrEmpty(htmlSource)) @@ -513,7 +513,7 @@ public void SetHtml(string htmlSource, CssData baseCssData = null) _cssData = baseCssData ?? _adapter.DefaultCssData; DomParser parser = new DomParser(_cssParser); - _root = parser.GenerateCssTree(htmlSource, this, ref _cssData); + (_root, _cssData) = await parser.GenerateCssTreeAsync(htmlSource, this, _cssData); if (_root != null) { _selectionHandler = new SelectionHandler(_root); @@ -628,7 +628,7 @@ public string GetLinkAt(RPoint location) /// Measures the bounds of box and children, recursively. /// /// Device context to draw - public void PerformLayout(RGraphics g) + public async Task PerformLayout(RGraphics g) { ArgChecker.AssertArgNotNull(g, "g"); @@ -638,14 +638,14 @@ public void PerformLayout(RGraphics g) // if width is not restricted we set it to large value to get the actual later _root.Size = new RSize(_maxSize.Width > 0 ? _maxSize.Width : 99999, 0); _root.Location = _location; - _root.PerformLayout(g); + await _root.PerformLayoutAsync(g); if (_maxSize.Width <= 0.1) { // in case the width is not restricted we need to double layout, first will find the width so second can layout by it (center alignment) _root.Size = new RSize((int)Math.Ceiling(_actualSize.Width), 0); _actualSize = RSize.Empty; - _root.PerformLayout(g); + await _root.PerformLayoutAsync(g); } if (!_loadComplete) @@ -662,7 +662,7 @@ public void PerformLayout(RGraphics g) /// Render the html using the given device. /// /// the device to use to render - public void PerformPaint(RGraphics g) + public async Task PerformPaint(RGraphics g) { ArgChecker.AssertArgNotNull(g, "g"); @@ -677,7 +677,7 @@ public void PerformPaint(RGraphics g) if (_root != null) { - _root.Paint(g); + await _root.PaintAsync(g); } g.PopClip(); diff --git a/Source/HtmlRenderer/Core/HtmlRendererUtils.cs b/Source/HtmlRenderer/Core/HtmlRendererUtils.cs index 9a414a7fe..caed22fcc 100644 --- a/Source/HtmlRenderer/Core/HtmlRendererUtils.cs +++ b/Source/HtmlRenderer/Core/HtmlRendererUtils.cs @@ -29,16 +29,16 @@ public static class HtmlRendererUtils /// the minimal size of the rendered html (zero - not limit the width/height) /// the maximum size of the rendered html, if not zero and html cannot be layout within the limit it will be clipped (zero - not limit the width/height) /// return: the size of the html to be rendered within the min/max limits - public static RSize MeasureHtmlByRestrictions(RGraphics g, HtmlContainerInt htmlContainer, RSize minSize, RSize maxSize) + public static async Task MeasureHtmlByRestrictionsAsync(RGraphics g, HtmlContainerInt htmlContainer, RSize minSize, RSize maxSize) { // first layout without size restriction to know html actual size - htmlContainer.PerformLayout(g); + await htmlContainer.PerformLayout(g); if (maxSize.Width > 0 && maxSize.Width < htmlContainer.ActualSize.Width) { // to allow the actual size be smaller than max we need to set max size only if it is really larger htmlContainer.MaxSize = new RSize(maxSize.Width, 0); - htmlContainer.PerformLayout(g); + await htmlContainer.PerformLayout(g); } // restrict the final size by min/max @@ -48,7 +48,7 @@ public static RSize MeasureHtmlByRestrictions(RGraphics g, HtmlContainerInt html if (finalWidth > htmlContainer.ActualSize.Width) { htmlContainer.MaxSize = new RSize(finalWidth, 0); - htmlContainer.PerformLayout(g); + await htmlContainer.PerformLayout(g); } var finalHeight = Math.Max(maxSize.Height > 0 ? Math.Min(maxSize.Height, (int)htmlContainer.ActualSize.Height) : (int)htmlContainer.ActualSize.Height, minSize.Height); @@ -72,7 +72,7 @@ public static RSize MeasureHtmlByRestrictions(RGraphics g, HtmlContainerInt html /// the max size restriction - can be empty for no restriction /// if to modify the size (width and height) by html content layout /// if to modify the height by html content layout - public static RSize Layout(RGraphics g, HtmlContainerInt htmlContainer, RSize size, RSize minSize, RSize maxSize, bool autoSize, bool autoSizeHeightOnly) + public static async Task LayoutAsync(RGraphics g, HtmlContainerInt htmlContainer, RSize size, RSize minSize, RSize maxSize, bool autoSize, bool autoSizeHeightOnly) { if (autoSize) htmlContainer.MaxSize = new RSize(0, 0); @@ -81,7 +81,7 @@ public static RSize Layout(RGraphics g, HtmlContainerInt htmlContainer, RSize si else htmlContainer.MaxSize = size; - htmlContainer.PerformLayout(g); + await htmlContainer.PerformLayout(g); RSize newSize = size; if (autoSize || autoSizeHeightOnly) @@ -92,13 +92,13 @@ public static RSize Layout(RGraphics g, HtmlContainerInt htmlContainer, RSize si { // to allow the actual size be smaller than max we need to set max size only if it is really larger htmlContainer.MaxSize = maxSize; - htmlContainer.PerformLayout(g); + await htmlContainer.PerformLayout(g); } else if (minSize.Width > 0 && minSize.Width > htmlContainer.ActualSize.Width) { // if min size is larger than the actual we need to re-layout so all 100% layouts will be correct htmlContainer.MaxSize = new RSize(minSize.Width, 0); - htmlContainer.PerformLayout(g); + await htmlContainer.PerformLayout(g); } newSize = htmlContainer.ActualSize; } @@ -113,7 +113,7 @@ public static RSize Layout(RGraphics g, HtmlContainerInt htmlContainer, RSize si // handle if changing the height of the label affects the desired width and those require re-layout if (Math.Abs(prevWidth - size.Width) > 0.01) - return Layout(g, htmlContainer, size, minSize, maxSize, false, true); + return await LayoutAsync(g, htmlContainer, size, minSize, maxSize, false, true); } } diff --git a/Source/HtmlRenderer/Core/Parse/DomParser.cs b/Source/HtmlRenderer/Core/Parse/DomParser.cs index d841485f0..4c213c34e 100644 --- a/Source/HtmlRenderer/Core/Parse/DomParser.cs +++ b/Source/HtmlRenderer/Core/Parse/DomParser.cs @@ -52,7 +52,7 @@ public DomParser(CssParser cssParser) /// the html container to use for reference resolve /// the css data to use /// the root of the generated tree - public CssBox GenerateCssTree(string html, HtmlContainerInt htmlContainer, ref CssData cssData) + public async Task<(CssBox, CssData)> GenerateCssTreeAsync(string html, HtmlContainerInt htmlContainer, CssData cssData) { var root = HtmlParser.ParseDocument(html); if (root != null) @@ -60,7 +60,7 @@ public CssBox GenerateCssTree(string html, HtmlContainerInt htmlContainer, ref C root.HtmlContainer = htmlContainer; bool cssDataChanged = false; - CascadeParseStyles(root, htmlContainer, ref cssData, ref cssDataChanged); + (cssData, cssDataChanged) = await CascadeParseStyles(root, htmlContainer, cssData, cssDataChanged); CascadeApplyStyles(root, cssData); @@ -79,7 +79,7 @@ public CssBox GenerateCssTree(string html, HtmlContainerInt htmlContainer, ref C CorrectInlineBoxesParent(root); } - return root; + return (root, cssData); } @@ -94,7 +94,7 @@ public CssBox GenerateCssTree(string html, HtmlContainerInt htmlContainer, ref C /// the html container to use for reference resolve /// the style data to fill with found styles /// check if the css data has been modified by the handled html not to change the base css data - private void CascadeParseStyles(CssBox box, HtmlContainerInt htmlContainer, ref CssData cssData, ref bool cssDataChanged) + private async Task<(CssData, bool)> CascadeParseStyles(CssBox box, HtmlContainerInt htmlContainer, CssData cssData, bool cssDataChanged) { if (box.HtmlTag != null) { @@ -105,7 +105,7 @@ private void CascadeParseStyles(CssBox box, HtmlContainerInt htmlContainer, ref CloneCssData(ref cssData, ref cssDataChanged); string stylesheet; CssData stylesheetData; - StylesheetLoadHandler.LoadStylesheet(htmlContainer, box.GetAttribute("href", string.Empty), box.HtmlTag.Attributes, out stylesheet, out stylesheetData); + (stylesheet, stylesheetData) = await StylesheetLoadHandler.LoadStylesheetAsync(htmlContainer, box.GetAttribute("href", string.Empty), box.HtmlTag.Attributes); if (stylesheet != null) _cssParser.ParseStyleSheet(cssData, stylesheet); else if (stylesheetData != null) @@ -123,8 +123,10 @@ private void CascadeParseStyles(CssBox box, HtmlContainerInt htmlContainer, ref foreach (var childBox in box.Boxes) { - CascadeParseStyles(childBox, htmlContainer, ref cssData, ref cssDataChanged); + (cssData, cssDataChanged) = await CascadeParseStyles(childBox, htmlContainer, cssData, cssDataChanged); } + + return (cssData, cssDataChanged); } diff --git a/Source/HtmlRenderer/Core/Utils/CommonUtils.cs b/Source/HtmlRenderer/Core/Utils/CommonUtils.cs index 12c03ad32..fa0827706 100644 --- a/Source/HtmlRenderer/Core/Utils/CommonUtils.cs +++ b/Source/HtmlRenderer/Core/Utils/CommonUtils.cs @@ -191,21 +191,6 @@ public static FileInfo TryGetFileInfo(string path) return null; } - /// - /// Get web client response content type. - /// - /// the web client to get the response content type from - /// response content type or null - public static string GetResponseContentType(WebClient client) - { - foreach (string header in client.ResponseHeaders) - { - if (header.Equals("Content-Type", StringComparison.InvariantCultureIgnoreCase)) - return client.ResponseHeaders[header]; - } - return null; - } - /// /// Gets the representation of the online uri on the local disk. /// diff --git a/Source/HtmlRenderer/Core/Utils/CssConstants.cs b/Source/HtmlRenderer/Core/Utils/CssConstants.cs index 655849256..46b7f31ef 100644 --- a/Source/HtmlRenderer/Core/Utils/CssConstants.cs +++ b/Source/HtmlRenderer/Core/Utils/CssConstants.cs @@ -18,6 +18,7 @@ namespace TheArtOfDev.HtmlRenderer.Core.Utils internal static class CssConstants { public const string Absolute = "absolute"; + public const string Always = "always"; public const string Auto = "auto"; public const string Avoid = "avoid"; public const string Baseline = "baseline"; diff --git a/Source/HtmlRenderer/Core/Utils/CssUtils.cs b/Source/HtmlRenderer/Core/Utils/CssUtils.cs index 69f949390..e51f73238 100644 --- a/Source/HtmlRenderer/Core/Utils/CssUtils.cs +++ b/Source/HtmlRenderer/Core/Utils/CssUtils.cs @@ -96,16 +96,16 @@ public static string GetPropertyValue(CssBox cssBox, string propName) return cssBox.BorderSpacing; case "border-collapse": return cssBox.BorderCollapse; - case "corner-radius": - return cssBox.CornerRadius; - case "corner-nw-radius": - return cssBox.CornerNwRadius; - case "corner-ne-radius": - return cssBox.CornerNeRadius; - case "corner-se-radius": - return cssBox.CornerSeRadius; - case "corner-sw-radius": - return cssBox.CornerSwRadius; + case "border-radius": + return cssBox.BorderRadius; + case "border-top-left-radius": + return cssBox.BorderTopLeftRadius; + case "border-top-right-radius": + return cssBox.BorderTopRightRadius; + case "border-bottom-right-radius": + return cssBox.BorderBottomRightRadius; + case "border-bottom-left-radius": + return cssBox.BorderBottomLeftRadius; case "margin-bottom": return cssBox.MarginBottom; case "margin-left": @@ -122,6 +122,10 @@ public static string GetPropertyValue(CssBox cssBox, string propName) return cssBox.PaddingRight; case "padding-top": return cssBox.PaddingTop; + case "page-break-before": + return cssBox.PageBreakBefore; + case "page-break-after": + return cssBox.PageBreakAfter; case "page-break-inside": return cssBox.PageBreakInside; case "left": @@ -255,20 +259,20 @@ public static void SetPropertyValue(CssBox cssBox, string propName, string value case "border-collapse": cssBox.BorderCollapse = value; break; - case "corner-radius": - cssBox.CornerRadius = value; + case "border-radius": + cssBox.BorderRadius = value; break; - case "corner-nw-radius": - cssBox.CornerNwRadius = value; + case "border-top-left-radius": + cssBox.BorderTopLeftRadius = value; break; - case "corner-ne-radius": - cssBox.CornerNeRadius = value; + case "border-top-right-radius": + cssBox.BorderTopRightRadius = value; break; - case "corner-se-radius": - cssBox.CornerSeRadius = value; + case "border-bottom-right-radius": + cssBox.BorderBottomRightRadius = value; break; - case "corner-sw-radius": - cssBox.CornerSwRadius = value; + case "border-bottom-left-radius": + cssBox.BorderBottomLeftRadius = value; break; case "margin-bottom": cssBox.MarginBottom = value; @@ -294,6 +298,12 @@ public static void SetPropertyValue(CssBox cssBox, string propName, string value case "padding-top": cssBox.PaddingTop = value; break; + case "page-break-before": + cssBox.PageBreakBefore = value; + break; + case "page-break-after": + cssBox.PageBreakAfter = value; + break; case "page-break-inside": cssBox.PageBreakInside = value; break; diff --git a/Source/HtmlRenderer/Core/Utils/RenderUtils.cs b/Source/HtmlRenderer/Core/Utils/RenderUtils.cs index 2726b5fb2..5a0f5928b 100644 --- a/Source/HtmlRenderer/Core/Utils/RenderUtils.cs +++ b/Source/HtmlRenderer/Core/Utils/RenderUtils.cs @@ -96,43 +96,43 @@ public static void DrawImageErrorIcon(RGraphics g, HtmlContainerInt htmlContaine /// /// Creates a rounded rectangle using the specified corner radius
- /// NW-----NE + /// TL------TR /// | | /// | | - /// SW-----SE + /// BL------BR ///
/// the device to draw into /// Rectangle to round - /// Radius of the north east corner - /// Radius of the north west corner - /// Radius of the south east corner - /// Radius of the south west corner + /// Radius of the top left corner + /// Radius of the top right corner + /// Radius of the bottom right corner + /// Radius of the bottom left corner /// GraphicsPath with the lines of the rounded rectangle ready to be painted - public static RGraphicsPath GetRoundRect(RGraphics g, RRect rect, double nwRadius, double neRadius, double seRadius, double swRadius) + public static RGraphicsPath GetRoundRect(RGraphics g, RRect rect, double topLeftRadius, double topRightRadius, double bottomRightRadius, double bottomLeftRadius) { var path = g.GetGraphicsPath(); - path.Start(rect.Left + nwRadius, rect.Top); + path.Start(rect.Left + topLeftRadius, rect.Top); - path.LineTo(rect.Right - neRadius, rect.Y); + path.LineTo(rect.Right - topRightRadius, rect.Y); - if (neRadius > 0f) - path.ArcTo(rect.Right, rect.Top + neRadius, neRadius, RGraphicsPath.Corner.TopRight); + if (topRightRadius > 0f) + path.ArcTo(rect.Right, rect.Top + topRightRadius, topRightRadius, RGraphicsPath.Corner.TopRight); - path.LineTo(rect.Right, rect.Bottom - seRadius); + path.LineTo(rect.Right, rect.Bottom - bottomRightRadius); - if (seRadius > 0f) - path.ArcTo(rect.Right - seRadius, rect.Bottom, seRadius, RGraphicsPath.Corner.BottomRight); + if (bottomRightRadius > 0f) + path.ArcTo(rect.Right - bottomRightRadius, rect.Bottom, bottomRightRadius, RGraphicsPath.Corner.BottomRight); - path.LineTo(rect.Left + swRadius, rect.Bottom); + path.LineTo(rect.Left + bottomLeftRadius, rect.Bottom); - if (swRadius > 0f) - path.ArcTo(rect.Left, rect.Bottom - swRadius, swRadius, RGraphicsPath.Corner.BottomLeft); + if (bottomLeftRadius > 0f) + path.ArcTo(rect.Left, rect.Bottom - bottomLeftRadius, bottomLeftRadius, RGraphicsPath.Corner.BottomLeft); - path.LineTo(rect.Left, rect.Top + nwRadius); + path.LineTo(rect.Left, rect.Top + topLeftRadius); - if (nwRadius > 0f) - path.ArcTo(rect.Left + nwRadius, rect.Top, nwRadius, RGraphicsPath.Corner.TopLeft); + if (topLeftRadius > 0f) + path.ArcTo(rect.Left + topLeftRadius, rect.Top, topLeftRadius, RGraphicsPath.Corner.TopLeft); return path; } diff --git a/Source/HtmlRenderer/HtmlRenderer.csproj b/Source/HtmlRenderer/HtmlRenderer.csproj index 74549b41d..3c53ff4d1 100644 --- a/Source/HtmlRenderer/HtmlRenderer.csproj +++ b/Source/HtmlRenderer/HtmlRenderer.csproj @@ -1,129 +1,26 @@ - - - - - Debug - AnyCPU - {FE611685-391F-4E3E-B27E-D3150E51E49B} - Library - Properties - TheArtOfDev.HtmlRenderer - HtmlRenderer - v2.0 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - Properties\SharedAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + net7.0 + enable + disable + ThreeCS.HtmlRenderer + 'new' .net port of HtmlRenderer. Would be nice to merge back to arthub one day. + https://github.com/mstancombe/HTML-Renderer/tree/features/net60 + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + + diff --git a/Source/SharedAssemblyInfo.cs b/Source/SharedAssemblyInfo.cs index d5336037f..ffa168faf 100644 --- a/Source/SharedAssemblyInfo.cs +++ b/Source/SharedAssemblyInfo.cs @@ -8,7 +8,7 @@ [assembly: AssemblyTitle("HTML Renderer")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Open source hosted on CodePlex")] +[assembly: AssemblyCompany("Open source hosted on Github")] [assembly: AssemblyProduct("HTML Renderer")] [assembly: AssemblyCopyright("Copyright © 2008")] [assembly: AssemblyTrademark("")]