From 5858399c84f5fa2f2b06b2858fbf310c7d0d3245 Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Fri, 31 Oct 2014 16:03:36 +0800 Subject: [PATCH 001/134] Updated project references to CEF 2171.1899 --- CefSharp.Core/CefSharp.Core.vcxproj | 4 ++-- CefSharp.Core/packages.config | 2 +- CefSharp.Test/CefSharp.Test.csproj | 8 ++++---- CefSharp.Test/packages.config | 4 ++-- .../CefSharp.WinForms.Example.csproj | 8 ++++---- CefSharp.WinForms.Example/packages.config | 4 ++-- CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj | 8 ++++---- CefSharp.Wpf.Example/packages.config | 4 ++-- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/CefSharp.Core/CefSharp.Core.vcxproj b/CefSharp.Core/CefSharp.Core.vcxproj index c49046cb78..e18785d9fb 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj +++ b/CefSharp.Core/CefSharp.Core.vcxproj @@ -1,6 +1,6 @@  - + Debug @@ -285,6 +285,6 @@ 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/CefSharp.Core/packages.config b/CefSharp.Core/packages.config index 03ee03d3d3..96bfbf846f 100644 --- a/CefSharp.Core/packages.config +++ b/CefSharp.Core/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/CefSharp.Test/CefSharp.Test.csproj b/CefSharp.Test/CefSharp.Test.csproj index f24312825e..b5ab0cc2d6 100644 --- a/CefSharp.Test/CefSharp.Test.csproj +++ b/CefSharp.Test/CefSharp.Test.csproj @@ -141,9 +141,9 @@ 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/CefSharp.Test/packages.config b/CefSharp.Test/packages.config index 0f1da60830..5900dbeeca 100644 --- a/CefSharp.Test/packages.config +++ b/CefSharp.Test/packages.config @@ -2,8 +2,8 @@ - - + + \ No newline at end of file diff --git a/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj b/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj index b46a2bc08c..29af0b563e 100644 --- a/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj +++ b/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj @@ -150,9 +150,9 @@ 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/CefSharp.WinForms.Example/packages.config b/CefSharp.WinForms.Example/packages.config index 711f25de0c..740f5addb9 100644 --- a/CefSharp.WinForms.Example/packages.config +++ b/CefSharp.WinForms.Example/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file diff --git a/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj b/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj index 6a94d60af2..60618ea1f4 100644 --- a/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj +++ b/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj @@ -168,9 +168,9 @@ 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/CefSharp.Wpf.Example/packages.config b/CefSharp.Wpf.Example/packages.config index 711f25de0c..740f5addb9 100644 --- a/CefSharp.Wpf.Example/packages.config +++ b/CefSharp.Wpf.Example/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file From 0cccb2a1e6d211359d646f417d90d0fa1fd82a2e Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Fri, 31 Oct 2014 16:04:45 +0800 Subject: [PATCH 002/134] Fixed missing parameter for `ShowDevTools()` method, which now supports parameter `Inspect Element At` which is not yet implemented in CEFSharp. --- CefSharp.Core/Internals/RenderClientAdapter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index c552474750..6caefea9c7 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -137,7 +137,7 @@ namespace CefSharp windowInfo.SetAsPopup(cefHost->GetWindowHandle(), "DevTools"); - cefHost->ShowDevTools(windowInfo, this, settings); + cefHost->ShowDevTools(windowInfo, this, settings, CefPoint()); } } From c61bc9a762a6ac5ad5e7af159237846ae16cfbe5 Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Sun, 2 Nov 2014 21:16:52 +0800 Subject: [PATCH 003/134] Updated build.ps1 version to 2171.1899 --- build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.ps1 b/build.ps1 index 63ca6c512e..349e4feac9 100644 --- a/build.ps1 +++ b/build.ps1 @@ -5,7 +5,7 @@ param( [Parameter(Position = 1)] [string] $Version = "37.0.0", [Parameter(Position = 2)] - [string] $RedistVersion = "3.2062.1876" + [string] $RedistVersion = "3.2171.1899" ) $WorkingDir = split-path -parent $MyInvocation.MyCommand.Definition From a51d46463fab2bca72e68604e5627063fec2a284 Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 3 Nov 2014 18:18:12 +1000 Subject: [PATCH 004/134] Whitespace fix --- CefSharp.Core/Internals/RenderClientAdapter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index 6caefea9c7..a7729e7dce 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -137,7 +137,7 @@ namespace CefSharp windowInfo.SetAsPopup(cefHost->GetWindowHandle(), "DevTools"); - cefHost->ShowDevTools(windowInfo, this, settings, CefPoint()); + cefHost->ShowDevTools(windowInfo, this, settings, CefPoint()); } } From 49fa5abaddec32db01800f5207ec8af0c39e4636 Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 3 Nov 2014 18:19:11 +1000 Subject: [PATCH 005/134] Update to correct redist -pre version --- build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.ps1 b/build.ps1 index 349e4feac9..67a677417a 100644 --- a/build.ps1 +++ b/build.ps1 @@ -5,7 +5,7 @@ param( [Parameter(Position = 1)] [string] $Version = "37.0.0", [Parameter(Position = 2)] - [string] $RedistVersion = "3.2171.1899" + [string] $RedistVersion = "3.2171.1899-pre0" ) $WorkingDir = split-path -parent $MyInvocation.MyCommand.Definition From d62bd687ba58c3934fe58f94edea48ab550ca66e Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 3 Nov 2014 18:19:39 +1000 Subject: [PATCH 006/134] Untabify --- build.ps1 | 62 +++++++++++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/build.ps1 b/build.ps1 index 67a677417a..285c8833fb 100644 --- a/build.ps1 +++ b/build.ps1 @@ -56,8 +56,8 @@ function Die ) Write-Host - Write-Error $Message - exit 1 + Write-Error $Message + exit 1 } function Warn @@ -68,8 +68,8 @@ function Warn ) Write-Host - Write-Host $Message -ForegroundColor Yellow - Write-Host + Write-Host $Message -ForegroundColor Yellow + Write-Host } function TernaryReturn @@ -220,38 +220,38 @@ function Nupkg # Build packages . $nuget pack nuget\CefSharp.Common.nuspec -NoPackageAnalysis -Version $Version -OutputDirectory nuget -Properties "RedistVersion=$RedistVersion" - . $nuget pack nuget\CefSharp.Wpf.nuspec -NoPackageAnalysis -Version $Version -OutputDirectory nuget - . $nuget pack nuget\CefSharp.WinForms.nuspec -NoPackageAnalysis -Version $Version -OutputDirectory nuget + . $nuget pack nuget\CefSharp.Wpf.nuspec -NoPackageAnalysis -Version $Version -OutputDirectory nuget + . $nuget pack nuget\CefSharp.WinForms.nuspec -NoPackageAnalysis -Version $Version -OutputDirectory nuget - # Invoke `AfterBuild` script if available (ie. upload packages to myget) - if(-not (Test-Path $WorkingDir\AfterBuild.ps1)) { - return - } + # Invoke `AfterBuild` script if available (ie. upload packages to myget) + if(-not (Test-Path $WorkingDir\AfterBuild.ps1)) { + return + } - . $WorkingDir\AfterBuild.ps1 -Version $Version + . $WorkingDir\AfterBuild.ps1 -Version $Version } function DownloadNuget() { - $nuget = Join-Path $env:LOCALAPPDATA .\nuget\NuGet.exe + $nuget = Join-Path $env:LOCALAPPDATA .\nuget\NuGet.exe if(-not (Test-Path $nuget)) - { - $client = New-Object System.Net.WebClient; - $client.DownloadFile('http://nuget.org/nuget.exe', $nuget); - } + { + $client = New-Object System.Net.WebClient; + $client.DownloadFile('http://nuget.org/nuget.exe', $nuget); + } } function WriteAssemblyVersion { - param() - - $Filename = Join-Path $WorkingDir CefSharp\Properties\AssemblyInfo.cs - $Regex = 'public const string AssemblyVersion = "(.*)"'; - - $AssemblyInfo = Get-Content $Filename - $NewString = $AssemblyInfo -replace $Regex, "public const string AssemblyVersion = ""$Version""" - - $NewString | Set-Content $Filename -Encoding UTF8 + param() + + $Filename = Join-Path $WorkingDir CefSharp\Properties\AssemblyInfo.cs + $Regex = 'public const string AssemblyVersion = "(.*)"'; + + $AssemblyInfo = Get-Content $Filename + $NewString = $AssemblyInfo -replace $Regex, "public const string AssemblyVersion = ""$Version""" + + $NewString | Set-Content $Filename -Encoding UTF8 } DownloadNuget @@ -262,21 +262,21 @@ WriteAssemblyVersion switch -Exact ($Target) { "nupkg" - { - VSX v120 + { + VSX v120 VSX v110 Nupkg } - "nupkg-only" - { + "nupkg-only" + { Nupkg } "vs2013" - { + { VSX v120 } "vs2012" - { + { VSX v110 } } \ No newline at end of file From e2f2b11ed6dba14621e4ca28a4744b9cf4ae2f61 Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 3 Nov 2014 19:58:15 +1000 Subject: [PATCH 007/134] Manually apply remaining changes from https://github.com/cefsharp/CefSharp/pull/507 --- CefSharp/Properties/AssemblyInfo.cs | 4 ++-- NuGet/pack.bat | 4 ---- build.ps1 | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) delete mode 100644 NuGet/pack.bat diff --git a/CefSharp/Properties/AssemblyInfo.cs b/CefSharp/Properties/AssemblyInfo.cs index afbe14223b..5f87404e98 100644 --- a/CefSharp/Properties/AssemblyInfo.cs +++ b/CefSharp/Properties/AssemblyInfo.cs @@ -32,8 +32,8 @@ public static class AssemblyInfo public const bool ComVisible = false; public const string AssemblyCompany = "The CefSharp Authors"; public const string AssemblyProduct = "CefSharp"; - public const string AssemblyVersion = "37.0.0.0"; - public const string AssemblyFileVersion = "37.0.0.0"; + public const string AssemblyVersion = "39.0.0.0"; + public const string AssemblyFileVersion = "39.0.0.0"; public const string AssemblyCopyright = "Copyright © The CefSharp Authors 2010-2014"; public const string CefSharpCoreProject = "CefSharp.Core, PublicKey=" + PublicKey; public const string CefSharpBrowserSubprocessProject = "CefSharp.BrowserSubprocess, PublicKey=" + PublicKey; diff --git a/NuGet/pack.bat b/NuGet/pack.bat deleted file mode 100644 index 8358fc925e..0000000000 --- a/NuGet/pack.bat +++ /dev/null @@ -1,4 +0,0 @@ -set version=37.0.0 -NuGet pack CefSharp.Common.nuspec -NoPackageAnalysis -Version %version% -NuGet pack CefSharp.Wpf.nuspec -NoPackageAnalysis -Version %version% -NuGet pack CefSharp.WinForms.nuspec -NoPackageAnalysis -Version %version% diff --git a/build.ps1 b/build.ps1 index 285c8833fb..b6ecb84d84 100644 --- a/build.ps1 +++ b/build.ps1 @@ -3,7 +3,7 @@ param( [Parameter(Position = 0)] [string] $Target = "nupkg", [Parameter(Position = 1)] - [string] $Version = "37.0.0", + [string] $Version = "39.0.0", [Parameter(Position = 2)] [string] $RedistVersion = "3.2171.1899-pre0" ) From 705da02d7fe8fc44f6a978d63b20b825c40778af Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Tue, 30 Sep 2014 15:23:50 +0800 Subject: [PATCH 008/134] Added overridable OnRendering method, to allow parent app to know when the browser is redrawing/updating --- CefSharp.Wpf/CefSharp.Wpf.csproj | 2 ++ CefSharp.Wpf/ChromiumWebBrowser.cs | 21 +++++++++++ CefSharp.Wpf/RenderingEventArgs.cs | 26 ++++++++++++++ CefSharp.Wpf/RenderingEventHandler.cs | 13 +++++++ patch.diff | 50 +++++++++++++++++++++++++++ 5 files changed, 112 insertions(+) create mode 100644 CefSharp.Wpf/RenderingEventArgs.cs create mode 100644 CefSharp.Wpf/RenderingEventHandler.cs create mode 100644 patch.diff diff --git a/CefSharp.Wpf/CefSharp.Wpf.csproj b/CefSharp.Wpf/CefSharp.Wpf.csproj index 24a145998c..88ccec3932 100644 --- a/CefSharp.Wpf/CefSharp.Wpf.csproj +++ b/CefSharp.Wpf/CefSharp.Wpf.csproj @@ -99,6 +99,8 @@ + + diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 602b0476cc..7a621d4dac 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -57,6 +57,11 @@ public class ChromiumWebBrowser : ContentControl, IRenderWebBrowser, IWpfWebBrow public event EventHandler FrameLoadEnd; public event EventHandler LoadError; + /// + /// Raised before each render cycle, and allows you to adjust the bitmap before it's rendered/applied + /// + public event RenderingEventHandler Rendering; + public ICommand BackCommand { get; private set; } public ICommand ForwardCommand { get; private set; } public ICommand ReloadCommand { get; private set; } @@ -455,6 +460,7 @@ public ChromiumWebBrowser() disposables.Add(managedCefBrowserAdapter); disposables.Add(new DisposableEventWrapper(this, ActualHeightProperty, OnActualSizeChanged)); disposables.Add(new DisposableEventWrapper(this, ActualWidthProperty, OnActualSizeChanged)); + } ~ChromiumWebBrowser() @@ -1200,10 +1206,25 @@ void IRenderWebBrowser.ClearBitmap(BitmapInfo bitmapInfo) bitmapInfo.InteropBitmap = null; } + /// + /// Raises Rendering event + /// + protected virtual void OnRendering(object sender, RenderingEventArgs eventArgs) + { + if (Rendering != null) + { + Rendering(this, eventArgs); + } + } + void IRenderWebBrowser.SetBitmap(BitmapInfo bitmapInfo) { lock (bitmapInfo.BitmapLock) { + // Inform parents that the browser rendering is updating + OnRendering(this, new RenderingEventArgs(bitmapInfo)); + + // Now update the WPF image if (bitmapInfo.IsPopup) { bitmapInfo.InteropBitmap = SetBitmapHelper(bitmapInfo, diff --git a/CefSharp.Wpf/RenderingEventArgs.cs b/CefSharp.Wpf/RenderingEventArgs.cs new file mode 100644 index 0000000000..e0957aa0ca --- /dev/null +++ b/CefSharp.Wpf/RenderingEventArgs.cs @@ -0,0 +1,26 @@ +// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +using System; +using CefSharp.Internals; + +namespace CefSharp.Wpf +{ + /// + /// Event arguments to the Rendering event handler set up in IWebBrowser. + /// + public class RenderingEventArgs : EventArgs + { + public RenderingEventArgs(BitmapInfo bitmapInfo) + { + BitmapInfo = bitmapInfo; + } + + /// + /// The bitmap info being rendered. + /// + public BitmapInfo BitmapInfo { get; private set; } + + } +} diff --git a/CefSharp.Wpf/RenderingEventHandler.cs b/CefSharp.Wpf/RenderingEventHandler.cs new file mode 100644 index 0000000000..b8c5ff6c88 --- /dev/null +++ b/CefSharp.Wpf/RenderingEventHandler.cs @@ -0,0 +1,13 @@ +// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +namespace CefSharp.Wpf +{ + /// + /// A delegate type used to listen to Rendgering messages. + /// + /// The object that raised the event. + /// The event arguments. + public delegate void RenderingEventHandler(object sender, RenderingEventArgs e); +} \ No newline at end of file diff --git a/patch.diff b/patch.diff new file mode 100644 index 0000000000..2e153aedbf --- /dev/null +++ b/patch.diff @@ -0,0 +1,50 @@ +From fbc5bf970a720677f8bb5cceb08eeee4d9e5b488 Mon Sep 17 00:00:00 2001 +From: Bodekaer +Date: Wed, 17 Sep 2014 14:56:59 +0200 +Subject: [PATCH] Fixed #482 WCF timeout issue + +--- + CefSharp/Internals/BrowserProcessServiceHost.cs | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/CefSharp/Internals/BrowserProcessServiceHost.cs b/CefSharp/Internals/BrowserProcessServiceHost.cs +index 3a97971..efbd413 100644 +--- a/CefSharp/Internals/BrowserProcessServiceHost.cs ++++ b/CefSharp/Internals/BrowserProcessServiceHost.cs +@@ -5,6 +5,7 @@ + using System; + using System.Net.Security; + using System.ServiceModel; ++using System.ServiceModel.Channels; + using System.ServiceModel.Description; + using System.Threading.Tasks; + +@@ -66,11 +67,22 @@ namespace CefSharp.Internals + operationContextTaskCompletionSource = null; + } + +- public static NetNamedPipeBinding CreateBinding() ++ public static CustomBinding CreateBinding() + { + var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None); + binding.MaxReceivedMessageSize = SixteenMegaBytesInBytes; +- return binding; ++ binding.ReceiveTimeout = TimeSpan.MaxValue; ++ binding.SendTimeout = TimeSpan.MaxValue; ++ binding.OpenTimeout = TimeSpan.MaxValue; ++ binding.CloseTimeout = TimeSpan.MaxValue; ++ ++ // Ensure binding connection stays open indefinitely until closed ++ var customBinding = new CustomBinding(binding); ++ var connectionSettings = customBinding.Elements.Find().ConnectionPoolSettings; ++ connectionSettings.IdleTimeout = TimeSpan.MaxValue; ++ connectionSettings.MaxOutboundConnectionsPerEndpoint = 0; ++ ++ return customBinding; + } + } + } +\ No newline at end of file +-- +1.8.3.msysgit.0 + From beb3897141bcfcc8d12510275994f9d3ea9f4bfa Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Tue, 4 Nov 2014 12:29:56 +0800 Subject: [PATCH 009/134] Fixed url load issue when assigning URL before browser is fully loaded --- CefSharp.Core/ManagedCefBrowserAdapter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index fac53f31db..62a83a0d21 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -58,7 +58,7 @@ namespace CefSharp HWND hwnd = HWND(); CefWindowInfo window; window.SetAsWindowless(hwnd, TRUE); - CefString addressNative = StringUtils::ToNative("about:blank"); + CefString addressNative = StringUtils::ToNative(_address); if (!CefBrowserHost::CreateBrowser(window, _renderClientAdapter.get(), addressNative, *(CefBrowserSettings*) browserSettings->_internalBrowserSettings, NULL)) From 88b7619901212a54e56548d4fd61428215e54391 Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Tue, 4 Nov 2014 12:38:57 +0800 Subject: [PATCH 010/134] Cleanup tabs into spaces #beb3897141bcfcc8d12510275994f9d3ea9f4bfa --- CefSharp.Core/ManagedCefBrowserAdapter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 62a83a0d21..225ba67029 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -58,7 +58,7 @@ namespace CefSharp HWND hwnd = HWND(); CefWindowInfo window; window.SetAsWindowless(hwnd, TRUE); - CefString addressNative = StringUtils::ToNative(_address); + CefString addressNative = StringUtils::ToNative(_address); if (!CefBrowserHost::CreateBrowser(window, _renderClientAdapter.get(), addressNative, *(CefBrowserSettings*) browserSettings->_internalBrowserSettings, NULL)) From a1e5335d6a937156373687da81658504b8b538bb Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Tue, 4 Nov 2014 14:15:25 +0800 Subject: [PATCH 011/134] Revert BrowserSubprocess.Core 2062 merge update to match 2171 --- .../CefSharp.BrowserSubprocess.Core.vcxproj | 6 +++--- CefSharp.BrowserSubprocess.Core/packages.config | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj index 6a9e7882ce..2fb2f63c72 100644 --- a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj +++ b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj @@ -1,6 +1,6 @@  - + Debug @@ -66,7 +66,7 @@ - 598202e1 + f6c01df1 true @@ -198,6 +198,6 @@ 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/CefSharp.BrowserSubprocess.Core/packages.config b/CefSharp.BrowserSubprocess.Core/packages.config index f9dacf6924..96bfbf846f 100644 --- a/CefSharp.BrowserSubprocess.Core/packages.config +++ b/CefSharp.BrowserSubprocess.Core/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file From 35b3bac9d564fb5c5ed7b38cde1e54f6a0a5b216 Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Tue, 4 Nov 2014 19:02:23 +0800 Subject: [PATCH 012/134] Added support for context menu in WPF --- CefSharp.Core/Internals/ClientAdapter.cpp | 6 +++--- CefSharp.Wpf/ChromiumWebBrowser.cs | 1 + CefSharp/IWebBrowser.cs | 5 +++++ CefSharp/IWinFormsWebBrowser.cs | 1 - 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CefSharp.Core/Internals/ClientAdapter.cpp b/CefSharp.Core/Internals/ClientAdapter.cpp index 8cf9f81b4c..1ee292fda6 100644 --- a/CefSharp.Core/Internals/ClientAdapter.cpp +++ b/CefSharp.Core/Internals/ClientAdapter.cpp @@ -382,10 +382,10 @@ namespace CefSharp CefRefPtr params, CefRefPtr model) { // Something like this... - auto winFormsWebBrowserControl = dynamic_cast((IWebBrowserInternal^)_browserControl); - if (winFormsWebBrowserControl == nullptr) return; + auto webBrowserControl = dynamic_cast((IWebBrowserInternal^)_browserControl); + if (webBrowserControl == nullptr) return; - IMenuHandler^ handler = winFormsWebBrowserControl->MenuHandler; + IMenuHandler^ handler = webBrowserControl->MenuHandler; if (handler == nullptr) return; auto result = handler->OnBeforeContextMenu(_browserControl); diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 7a621d4dac..35571aa3ce 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -50,6 +50,7 @@ public class ChromiumWebBrowser : ContentControl, IRenderWebBrowser, IWpfWebBrow public IRequestHandler RequestHandler { get; set; } public IDownloadHandler DownloadHandler { get; set; } public ILifeSpanHandler LifeSpanHandler { get; set; } + public IMenuHandler MenuHandler { get; set; } public event EventHandler ConsoleMessage; public event EventHandler StatusMessage; diff --git a/CefSharp/IWebBrowser.cs b/CefSharp/IWebBrowser.cs index a5192010d1..4b467ea14e 100644 --- a/CefSharp/IWebBrowser.cs +++ b/CefSharp/IWebBrowser.cs @@ -105,6 +105,11 @@ public interface IWebBrowser : IDisposable /// IDownloadHandler DownloadHandler { get; set; } + /// + /// Implement and assign to handle events related to the browser context menu + /// + IMenuHandler MenuHandler { get; set; } + /// /// A flag that indicates whether the WebBrowser is initialized (true) or not (false). /// diff --git a/CefSharp/IWinFormsWebBrowser.cs b/CefSharp/IWinFormsWebBrowser.cs index 78290aa7e1..322efb48ce 100644 --- a/CefSharp/IWinFormsWebBrowser.cs +++ b/CefSharp/IWinFormsWebBrowser.cs @@ -10,7 +10,6 @@ namespace CefSharp // so the dependency would go the wrong way... Has to be here for the time being. public interface IWinFormsWebBrowser : IWebBrowser { - IMenuHandler MenuHandler { get; set; } event EventHandler NavStateChanged; event EventHandler TitleChanged; event EventHandler AddressChanged; From 901438da055e931c294d4b004378cf794d29323f Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Tue, 4 Nov 2014 19:03:02 +0800 Subject: [PATCH 013/134] Added support for context menu parameters. All supports new spell check feature #222 --- CefSharp.Core/CefSharp.Core.vcxproj | 2 + CefSharp.Core/CefSharp.Core.vcxproj.filters | 6 + .../Internals/CefContextMenuParamsWrapper.cpp | 111 ++++++++++++++++++ .../Internals/CefContextMenuParamsWrapper.h | 59 ++++++++++ CefSharp.Core/Internals/ClientAdapter.cpp | 6 +- CefSharp.WinForms.Example/MenuHandler.cs | 2 +- .../CefSharp.Wpf.Example.csproj | 1 + CefSharp.Wpf.Example/Handlers/MenuHandler.cs | 23 ++++ .../Views/BrowserTabView.xaml.cs | 8 +- CefSharp/CefSharp.csproj | 1 + CefSharp/IContextMenuParams.cs | 52 ++++++++ CefSharp/IMenuHandler.cs | 2 +- 12 files changed, 268 insertions(+), 5 deletions(-) create mode 100644 CefSharp.Core/Internals/CefContextMenuParamsWrapper.cpp create mode 100644 CefSharp.Core/Internals/CefContextMenuParamsWrapper.h create mode 100644 CefSharp.Wpf.Example/Handlers/MenuHandler.cs create mode 100644 CefSharp/IContextMenuParams.cs diff --git a/CefSharp.Core/CefSharp.Core.vcxproj b/CefSharp.Core/CefSharp.Core.vcxproj index 554ce62ee4..f8a74eca6e 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj +++ b/CefSharp.Core/CefSharp.Core.vcxproj @@ -217,6 +217,7 @@ + @@ -240,6 +241,7 @@ + diff --git a/CefSharp.Core/CefSharp.Core.vcxproj.filters b/CefSharp.Core/CefSharp.Core.vcxproj.filters index e1a242f196..ef7967b7f0 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj.filters +++ b/CefSharp.Core/CefSharp.Core.vcxproj.filters @@ -53,6 +53,9 @@ Source Files + + Source Files + @@ -124,6 +127,9 @@ Header Files + + Header Files + diff --git a/CefSharp.Core/Internals/CefContextMenuParamsWrapper.cpp b/CefSharp.Core/Internals/CefContextMenuParamsWrapper.cpp new file mode 100644 index 0000000000..bd6a44f887 --- /dev/null +++ b/CefSharp.Core/Internals/CefContextMenuParamsWrapper.cpp @@ -0,0 +1,111 @@ +// Copyright © 2010-2014 The CefSharp Project. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +#include "Stdafx.h" +#include "CefContextMenuParamsWrapper.h" + +namespace CefSharp +{ + namespace Internals + { + + + int CefContextMenuParamsWrapper::YCoord::get() + { + return _wrappedInfo->GetYCoord(); + } + + int CefContextMenuParamsWrapper::XCoord::get() + { + return _wrappedInfo->GetXCoord(); + } + + + //// TODO: Implement: + ////virtual TypeFlags GetTypeFlags() OVERRIDE; + + + String^ CefContextMenuParamsWrapper::LinkUrl::get() + { + return StringUtils::ToClr(_wrappedInfo->GetLinkUrl()); + } + + + String^ CefContextMenuParamsWrapper::UnfilteredLinkUrl::get() + { + return StringUtils::ToClr(_wrappedInfo->GetUnfilteredLinkUrl()); + } + + + String^ CefContextMenuParamsWrapper::SourceUrl::get() + { + return StringUtils::ToClr(_wrappedInfo->GetSourceUrl()); + } + + + bool CefContextMenuParamsWrapper::HasImageContents::get() + { + return _wrappedInfo->HasImageContents(); + } + + + String^ CefContextMenuParamsWrapper::PageUrl::get() + { + return StringUtils::ToClr(_wrappedInfo->GetPageUrl()); + } + + + String^ CefContextMenuParamsWrapper::FrameUrl::get() + { + return StringUtils::ToClr(_wrappedInfo->GetFrameUrl()); + } + String^ CefContextMenuParamsWrapper::FrameCharset::get() + { + return StringUtils::ToClr(_wrappedInfo->GetFrameCharset()); + } + + + //// TODO: Implement: + ////virtual MediaType GetMediaType() OVERRIDE; + ////virtual MediaStateFlags GetMediaStateFlags() OVERRIDE; + + + String^ CefContextMenuParamsWrapper::SelectionText::get() + { + return StringUtils::ToClr(_wrappedInfo->GetSelectionText()); + } + + + String^ CefContextMenuParamsWrapper::MisspelledWord::get() + { + return StringUtils::ToClr(_wrappedInfo->GetMisspelledWord()); + } + + int CefContextMenuParamsWrapper::MisspellingHash::get() + { + return _wrappedInfo->GetMisspellingHash(); + } + + + //// TODO: Implement: + ////virtual bool GetDictionarySuggestions(std::vector& suggestions) OVERRIDE; + + + bool CefContextMenuParamsWrapper::IsEditable::get() + { + return _wrappedInfo->IsEditable(); + } + + bool CefContextMenuParamsWrapper::IsSpellCheckEnabled::get() + { + return _wrappedInfo->IsSpellCheckEnabled(); + } + + + //// TODO: Implement: + ////virtual EditStateFlags GetEditStateFlags() OVERRIDE; + + + } +} diff --git a/CefSharp.Core/Internals/CefContextMenuParamsWrapper.h b/CefSharp.Core/Internals/CefContextMenuParamsWrapper.h new file mode 100644 index 0000000000..0c2c40b71a --- /dev/null +++ b/CefSharp.Core/Internals/CefContextMenuParamsWrapper.h @@ -0,0 +1,59 @@ +// Copyright © 2010-2014 The CefSharp Project. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +#pragma once + +#include "Stdafx.h" +#include "MCefRefPtr.h" + +using namespace System; +using namespace System::Collections::Generic; + +namespace CefSharp +{ + namespace Internals + { + ref class CefContextMenuParamsWrapper : public IContextMenuParams + { + MCefRefPtr _wrappedInfo; + + internal: + CefContextMenuParamsWrapper(CefRefPtr cefParams) : _wrappedInfo(cefParams) {} + + public: + virtual property int YCoord { int get(); } + virtual property int XCoord { int get(); } + + // TODO: Implement: + //virtual TypeFlags GetTypeFlags() OVERRIDE; + virtual property String^ LinkUrl { String^ get(); } + virtual property String^ UnfilteredLinkUrl { String^ get(); } + virtual property String^ SourceUrl { String^ get(); } + virtual property bool HasImageContents { bool get(); } + virtual property String^ PageUrl { String^ get(); } + virtual property String^ FrameUrl { String^ get(); } + virtual property String^ FrameCharset { String^ get(); } + + // TODO: Implement: + //virtual MediaType GetMediaType() OVERRIDE; + //virtual MediaStateFlags GetMediaStateFlags() OVERRIDE; + + virtual property String^ SelectionText { String^ get(); } + virtual property String^ MisspelledWord { String^ get(); } + virtual property int MisspellingHash { int get(); } + + // TODO: Implement: + //virtual property bool GetDictionarySuggestions { String^ get(); } + //virtual bool GetDictionarySuggestions(std::vector& suggestions) OVERRIDE; + + virtual property bool IsEditable { bool get(); } + virtual property bool IsSpellCheckEnabled { bool get(); } + + // TODO: Implement: + //virtual EditStateFlags GetEditStateFlags() OVERRIDE; + + + }; + } +} diff --git a/CefSharp.Core/Internals/ClientAdapter.cpp b/CefSharp.Core/Internals/ClientAdapter.cpp index 1ee292fda6..83e66bcd91 100644 --- a/CefSharp.Core/Internals/ClientAdapter.cpp +++ b/CefSharp.Core/Internals/ClientAdapter.cpp @@ -6,6 +6,7 @@ #include "Internals/CefRequestWrapper.h" #include "Internals/CefWebPluginInfoWrapper.h" +#include "Internals/CefContextMenuParamsWrapper.h" #include "Internals/JavascriptBinding/BindingHandler.h" #include "Internals/RequestResponse.h" #include "ClientAdapter.h" @@ -388,7 +389,10 @@ namespace CefSharp IMenuHandler^ handler = webBrowserControl->MenuHandler; if (handler == nullptr) return; - auto result = handler->OnBeforeContextMenu(_browserControl); + // Context menu params + CefContextMenuParamsWrapper^ contextMenuParamsWrapper = gcnew CefContextMenuParamsWrapper(params); + + auto result = handler->OnBeforeContextMenu(_browserControl, contextMenuParamsWrapper); if (!result) { // The only way I found for preventing the context menu to be displayed is by removing all items. :-) while (model->GetCount() > 0) { diff --git a/CefSharp.WinForms.Example/MenuHandler.cs b/CefSharp.WinForms.Example/MenuHandler.cs index 43b603df17..0850262264 100644 --- a/CefSharp.WinForms.Example/MenuHandler.cs +++ b/CefSharp.WinForms.Example/MenuHandler.cs @@ -6,7 +6,7 @@ namespace CefSharp.WinForms.Example { internal class MenuHandler : IMenuHandler { - public bool OnBeforeContextMenu(IWebBrowser browser) + public bool OnBeforeContextMenu(IWebBrowser browser, IContextMenuParams parameters) { // Return false if you want to disable the context menu. return true; diff --git a/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj b/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj index bdd08c05fd..c758b17b92 100644 --- a/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj +++ b/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj @@ -99,6 +99,7 @@ Designer + diff --git a/CefSharp.Wpf.Example/Handlers/MenuHandler.cs b/CefSharp.Wpf.Example/Handlers/MenuHandler.cs new file mode 100644 index 0000000000..2a14de61d8 --- /dev/null +++ b/CefSharp.Wpf.Example/Handlers/MenuHandler.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace CefSharp.Wpf.Example.Handlers +{ + + public class MenuHandler : IMenuHandler + { + + public bool OnBeforeContextMenu(IWebBrowser browser, IContextMenuParams parameters) + { + + Console.WriteLine("Context menu opened"); + Console.WriteLine(parameters.MisspelledWord); + + return true; + } + + + } +} diff --git a/CefSharp.Wpf.Example/Views/BrowserTabView.xaml.cs b/CefSharp.Wpf.Example/Views/BrowserTabView.xaml.cs index de1be99857..b395b17aa7 100644 --- a/CefSharp.Wpf.Example/Views/BrowserTabView.xaml.cs +++ b/CefSharp.Wpf.Example/Views/BrowserTabView.xaml.cs @@ -2,6 +2,7 @@ // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. +using System; using System.Windows.Controls; using System.Windows.Input; using CefSharp.Example; @@ -16,18 +17,21 @@ public BrowserTabView() browser.RequestHandler = new RequestHandler(); browser.RegisterJsObject("bound", new BoundObject()); + + browser.MenuHandler = new Handlers.MenuHandler(); } private void OnTextBoxGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { - var textBox = (TextBox) sender; + var textBox = (TextBox)sender; textBox.SelectAll(); } private void OnTextBoxGotMouseCapture(object sender, MouseEventArgs e) { - var textBox = (TextBox) sender; + var textBox = (TextBox)sender; textBox.SelectAll(); } + } } diff --git a/CefSharp/CefSharp.csproj b/CefSharp/CefSharp.csproj index 1a2b963eb6..cead85d646 100644 --- a/CefSharp/CefSharp.csproj +++ b/CefSharp/CefSharp.csproj @@ -100,6 +100,7 @@ + diff --git a/CefSharp/IContextMenuParams.cs b/CefSharp/IContextMenuParams.cs new file mode 100644 index 0000000000..210e93696a --- /dev/null +++ b/CefSharp/IContextMenuParams.cs @@ -0,0 +1,52 @@ +// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +namespace CefSharp +{ + /// + /// Wrapper for the CEF3 CefWebPluginInfo + /// + public interface IContextMenuParams + { + int YCoord { get; } + + int XCoord { get; } + + + // TODO: Implement: + //virtual TypeFlags GetTypeFlags() OVERRIDE; + + + string LinkUrl { get; } + string UnfilteredLinkUrl { get; } + string SourceUrl { get; } + bool HasImageContents { get; } + string PageUrl { get; } + string FrameUrl { get; } + string FrameCharset { get; } + + + // TODO: Implement: + //virtual MediaType GetMediaType() OVERRIDE; + //virtual MediaStateFlags GetMediaStateFlags() OVERRIDE; + + + string SelectionText { get; } + string MisspelledWord { get; } + int MisspellingHash { get; } + + // TODO: Implement: + //virtual property bool GetDictionarySuggestions { String^ get(); } + //virtual bool GetDictionarySuggestions(std::vector& suggestions) OVERRIDE; + bool IsEditable { get; } + bool IsSpellCheckEnabled { get; } + + + // TODO: Implement: + //virtual EditStateFlags GetEditStateFlags() OVERRIDE; + + + + } +} diff --git a/CefSharp/IMenuHandler.cs b/CefSharp/IMenuHandler.cs index 05c3d3316e..b1fbbc080d 100644 --- a/CefSharp/IMenuHandler.cs +++ b/CefSharp/IMenuHandler.cs @@ -6,6 +6,6 @@ namespace CefSharp { public interface IMenuHandler { - bool OnBeforeContextMenu(IWebBrowser browser); + bool OnBeforeContextMenu(IWebBrowser browser, IContextMenuParams parameters); } } From e0984a6aa29ab33d4e30b92927a4052682725d2b Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Tue, 4 Nov 2014 19:51:09 +0800 Subject: [PATCH 014/134] Added support for dictionary suggestions in the context menu #222 --- .../Internals/CefContextMenuParamsWrapper.cpp | 12 ++++++++++++ .../Internals/CefContextMenuParamsWrapper.h | 5 +++-- CefSharp/IContextMenuParams.cs | 7 ++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/CefSharp.Core/Internals/CefContextMenuParamsWrapper.cpp b/CefSharp.Core/Internals/CefContextMenuParamsWrapper.cpp index bd6a44f887..c61055aae8 100644 --- a/CefSharp.Core/Internals/CefContextMenuParamsWrapper.cpp +++ b/CefSharp.Core/Internals/CefContextMenuParamsWrapper.cpp @@ -60,6 +60,7 @@ namespace CefSharp { return StringUtils::ToClr(_wrappedInfo->GetFrameUrl()); } + String^ CefContextMenuParamsWrapper::FrameCharset::get() { return StringUtils::ToClr(_wrappedInfo->GetFrameCharset()); @@ -92,6 +93,17 @@ namespace CefSharp ////virtual bool GetDictionarySuggestions(std::vector& suggestions) OVERRIDE; + List^ CefContextMenuParamsWrapper::DictionarySuggestions::get() + { + std::vector& dictionarySuggestions = std::vector(); + bool result = _wrappedInfo->GetDictionarySuggestions(dictionarySuggestions); + + return StringUtils::ToClr(dictionarySuggestions); + } + + + + bool CefContextMenuParamsWrapper::IsEditable::get() { return _wrappedInfo->IsEditable(); diff --git a/CefSharp.Core/Internals/CefContextMenuParamsWrapper.h b/CefSharp.Core/Internals/CefContextMenuParamsWrapper.h index 0c2c40b71a..85d4d79631 100644 --- a/CefSharp.Core/Internals/CefContextMenuParamsWrapper.h +++ b/CefSharp.Core/Internals/CefContextMenuParamsWrapper.h @@ -43,8 +43,9 @@ namespace CefSharp virtual property String^ MisspelledWord { String^ get(); } virtual property int MisspellingHash { int get(); } - // TODO: Implement: - //virtual property bool GetDictionarySuggestions { String^ get(); } + virtual property List^ DictionarySuggestions { List^ get(); } + + //virtual bool GetDictionarySuggestions(std::vector& suggestions) OVERRIDE; virtual property bool IsEditable { bool get(); } diff --git a/CefSharp/IContextMenuParams.cs b/CefSharp/IContextMenuParams.cs index 210e93696a..71be16e5b6 100644 --- a/CefSharp/IContextMenuParams.cs +++ b/CefSharp/IContextMenuParams.cs @@ -2,6 +2,8 @@ // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. +using System.Collections.Generic; + namespace CefSharp { /// @@ -36,9 +38,8 @@ public interface IContextMenuParams string MisspelledWord { get; } int MisspellingHash { get; } - // TODO: Implement: - //virtual property bool GetDictionarySuggestions { String^ get(); } - //virtual bool GetDictionarySuggestions(std::vector& suggestions) OVERRIDE; + List DictionarySuggestions { get; } + bool IsEditable { get; } bool IsSpellCheckEnabled { get; } From 7b84ac23087178e62c354d9de20ae6e3d13faee3 Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Tue, 4 Nov 2014 21:58:39 +0800 Subject: [PATCH 015/134] Added support for new Browser.ReplaceMisspelling to allow you to replace the currently misspelled word with a new one --- CefSharp.Core/ManagedCefBrowserAdapter.h | 14 ++++++++++++++ CefSharp.WinForms/ChromiumWebBrowser.cs | 7 +++++++ CefSharp.Wpf/ChromiumWebBrowser.cs | 6 ++++++ CefSharp/IWebBrowser.cs | 10 +++++++++- 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 1bdaf8da97..ac1e32297d 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -494,5 +494,19 @@ namespace CefSharp { _javaScriptObjectRepository->Register(name, object); } + + + void ReplaceMisspelling(String^ word) + { + auto cefHost = _renderClientAdapter->TryGetCefHost(); + + if (cefHost != nullptr) + { + CefString wordNative = StringUtils::ToNative(word); + cefHost->ReplaceMisspelling(wordNative); + } + } + + }; } diff --git a/CefSharp.WinForms/ChromiumWebBrowser.cs b/CefSharp.WinForms/ChromiumWebBrowser.cs index 570436820a..fd6f5d947b 100644 --- a/CefSharp.WinForms/ChromiumWebBrowser.cs +++ b/CefSharp.WinForms/ChromiumWebBrowser.cs @@ -353,5 +353,12 @@ private void OnPaint(object sender, PaintEventArgs e) managedCefBrowserAdapter.OnPaint(Handle); } } + + + public void ReplaceMisspelling(string word) + { + managedCefBrowserAdapter.ReplaceMisspelling(word); + } + } } diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 35571aa3ce..ccadfc6e69 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -1284,5 +1284,11 @@ public Task GetTextAsync() managedCefBrowserAdapter.GetText(taskStringVisitor); return taskStringVisitor.Task; } + + public void ReplaceMisspelling(string word) + { + managedCefBrowserAdapter.ReplaceMisspelling(word); + } + } } diff --git a/CefSharp/IWebBrowser.cs b/CefSharp/IWebBrowser.cs index 4b467ea14e..60b1a55df9 100644 --- a/CefSharp/IWebBrowser.cs +++ b/CefSharp/IWebBrowser.cs @@ -256,6 +256,14 @@ public interface IWebBrowser : IDisposable /// /// Explicitly close the developer tools window if one exists for this browser instance. /// - void CloseDevTools(); + void CloseDevTools(); + + /// + /// If a misspelled word is currently selected in an editable node calling + /// this method will replace it with the specified |word|. + /// + /// The new word that will replace the currently selected word. + void ReplaceMisspelling(string word); + } } From e4ca157790e313f9efb10469b8d178308f70f03d Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Tue, 4 Nov 2014 21:59:37 +0800 Subject: [PATCH 016/134] Added Browser.AddWordToDictionary() support, to allow adding custom word to the spell checker dictionary --- CefSharp.Core/ManagedCefBrowserAdapter.h | 10 ++++++++++ CefSharp.Wpf/ChromiumWebBrowser.cs | 5 +++++ CefSharp/IWebBrowser.cs | 11 ++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index ac1e32297d..ef8848842b 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -507,6 +507,16 @@ namespace CefSharp } } + void AddWordToDictionary(String^ word){ + auto cefHost = _renderClientAdapter->TryGetCefHost(); + + if (cefHost != nullptr) + { + CefString wordNative = StringUtils::ToNative(word); + cefHost->AddWordToDictionary(wordNative); + } + } + }; } diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index ccadfc6e69..1e236021fe 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -1290,5 +1290,10 @@ public void ReplaceMisspelling(string word) managedCefBrowserAdapter.ReplaceMisspelling(word); } + public void AddWordToDictionary(string word) + { + managedCefBrowserAdapter.AddWordToDictionary(word); + } + } } diff --git a/CefSharp/IWebBrowser.cs b/CefSharp/IWebBrowser.cs index 60b1a55df9..cf44956d0d 100644 --- a/CefSharp/IWebBrowser.cs +++ b/CefSharp/IWebBrowser.cs @@ -260,10 +260,19 @@ public interface IWebBrowser : IDisposable /// /// If a misspelled word is currently selected in an editable node calling - /// this method will replace it with the specified |word|. + /// this method will replace it with the specified word. /// /// The new word that will replace the currently selected word. void ReplaceMisspelling(string word); + /// + /// Add the specified word to the spelling dictionary. + /// + /// The new word that will be added to the dictionary. + void AddWordToDictionary(string word); + + + + } } From 2583a40c25218782d8d8a369d3e1ee87772f82b5 Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Tue, 4 Nov 2014 22:03:23 +0800 Subject: [PATCH 017/134] Added new AddWordToDictionary to WinForms as well (previously only in WPF) --- CefSharp.WinForms/ChromiumWebBrowser.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CefSharp.WinForms/ChromiumWebBrowser.cs b/CefSharp.WinForms/ChromiumWebBrowser.cs index fd6f5d947b..01acf4dfab 100644 --- a/CefSharp.WinForms/ChromiumWebBrowser.cs +++ b/CefSharp.WinForms/ChromiumWebBrowser.cs @@ -360,5 +360,11 @@ public void ReplaceMisspelling(string word) managedCefBrowserAdapter.ReplaceMisspelling(word); } + public void AddWordToDictionary(string word) + { + managedCefBrowserAdapter.AddWordToDictionary(word); + } + + } } From f7b8bbea59b689a4478567270822e03827c8f97a Mon Sep 17 00:00:00 2001 From: amaitland Date: Wed, 5 Nov 2014 11:33:07 +1000 Subject: [PATCH 018/134] Remove patch.diff --- patch.diff | 50 -------------------------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 patch.diff diff --git a/patch.diff b/patch.diff deleted file mode 100644 index 2e153aedbf..0000000000 --- a/patch.diff +++ /dev/null @@ -1,50 +0,0 @@ -From fbc5bf970a720677f8bb5cceb08eeee4d9e5b488 Mon Sep 17 00:00:00 2001 -From: Bodekaer -Date: Wed, 17 Sep 2014 14:56:59 +0200 -Subject: [PATCH] Fixed #482 WCF timeout issue - ---- - CefSharp/Internals/BrowserProcessServiceHost.cs | 16 ++++++++++++++-- - 1 file changed, 14 insertions(+), 2 deletions(-) - -diff --git a/CefSharp/Internals/BrowserProcessServiceHost.cs b/CefSharp/Internals/BrowserProcessServiceHost.cs -index 3a97971..efbd413 100644 ---- a/CefSharp/Internals/BrowserProcessServiceHost.cs -+++ b/CefSharp/Internals/BrowserProcessServiceHost.cs -@@ -5,6 +5,7 @@ - using System; - using System.Net.Security; - using System.ServiceModel; -+using System.ServiceModel.Channels; - using System.ServiceModel.Description; - using System.Threading.Tasks; - -@@ -66,11 +67,22 @@ namespace CefSharp.Internals - operationContextTaskCompletionSource = null; - } - -- public static NetNamedPipeBinding CreateBinding() -+ public static CustomBinding CreateBinding() - { - var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None); - binding.MaxReceivedMessageSize = SixteenMegaBytesInBytes; -- return binding; -+ binding.ReceiveTimeout = TimeSpan.MaxValue; -+ binding.SendTimeout = TimeSpan.MaxValue; -+ binding.OpenTimeout = TimeSpan.MaxValue; -+ binding.CloseTimeout = TimeSpan.MaxValue; -+ -+ // Ensure binding connection stays open indefinitely until closed -+ var customBinding = new CustomBinding(binding); -+ var connectionSettings = customBinding.Elements.Find().ConnectionPoolSettings; -+ connectionSettings.IdleTimeout = TimeSpan.MaxValue; -+ connectionSettings.MaxOutboundConnectionsPerEndpoint = 0; -+ -+ return customBinding; - } - } - } -\ No newline at end of file --- -1.8.3.msysgit.0 - From 5f0277033eb770e216ed37fefa7668cfc40e4a7e Mon Sep 17 00:00:00 2001 From: amaitland Date: Wed, 5 Nov 2014 11:40:42 +1000 Subject: [PATCH 019/134] Remove RenderingEventHandler and replace with generic EventHandler Take reference to EventHandler in OnRendering before null check - best practice --- CefSharp.Wpf/CefSharp.Wpf.csproj | 1 - CefSharp.Wpf/ChromiumWebBrowser.cs | 7 ++++--- CefSharp.Wpf/RenderingEventHandler.cs | 13 ------------- 3 files changed, 4 insertions(+), 17 deletions(-) delete mode 100644 CefSharp.Wpf/RenderingEventHandler.cs diff --git a/CefSharp.Wpf/CefSharp.Wpf.csproj b/CefSharp.Wpf/CefSharp.Wpf.csproj index 88ccec3932..3bfe48f298 100644 --- a/CefSharp.Wpf/CefSharp.Wpf.csproj +++ b/CefSharp.Wpf/CefSharp.Wpf.csproj @@ -100,7 +100,6 @@ - diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 1e236021fe..f37d926bc3 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -61,7 +61,7 @@ public class ChromiumWebBrowser : ContentControl, IRenderWebBrowser, IWpfWebBrow /// /// Raised before each render cycle, and allows you to adjust the bitmap before it's rendered/applied /// - public event RenderingEventHandler Rendering; + public event EventHandler Rendering; public ICommand BackCommand { get; private set; } public ICommand ForwardCommand { get; private set; } @@ -1212,9 +1212,10 @@ void IRenderWebBrowser.ClearBitmap(BitmapInfo bitmapInfo) /// protected virtual void OnRendering(object sender, RenderingEventArgs eventArgs) { - if (Rendering != null) + var rendering = Rendering; + if (rendering != null) { - Rendering(this, eventArgs); + rendering(this, eventArgs); } } diff --git a/CefSharp.Wpf/RenderingEventHandler.cs b/CefSharp.Wpf/RenderingEventHandler.cs deleted file mode 100644 index b8c5ff6c88..0000000000 --- a/CefSharp.Wpf/RenderingEventHandler.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. - -namespace CefSharp.Wpf -{ - /// - /// A delegate type used to listen to Rendgering messages. - /// - /// The object that raised the event. - /// The event arguments. - public delegate void RenderingEventHandler(object sender, RenderingEventArgs e); -} \ No newline at end of file From 66d953d2b3efc25e44c7d98ec8809022cef78d67 Mon Sep 17 00:00:00 2001 From: amaitland Date: Wed, 5 Nov 2014 13:03:00 +1000 Subject: [PATCH 020/134] Split RequestResponse into Request and Response objects --- CefSharp.Core/Internals/ClientAdapter.cpp | 12 +++++------ CefSharp.Core/Internals/RequestResponse.h | 8 ++------ CefSharp.Example/RequestHandler.cs | 5 ++--- CefSharp/CefSharp.csproj | 2 +- CefSharp/IRequestHandler.cs | 5 +++-- CefSharp/IRequestResponse.cs | 25 ----------------------- CefSharp/IResponse.cs | 20 ++++++++++++++++++ 7 files changed, 34 insertions(+), 43 deletions(-) delete mode 100644 CefSharp/IRequestResponse.cs create mode 100644 CefSharp/IResponse.cs diff --git a/CefSharp.Core/Internals/ClientAdapter.cpp b/CefSharp.Core/Internals/ClientAdapter.cpp index 5393b104a3..83641fa0b5 100644 --- a/CefSharp.Core/Internals/ClientAdapter.cpp +++ b/CefSharp.Core/Internals/ClientAdapter.cpp @@ -258,16 +258,16 @@ namespace CefSharp return false; } - CefRequestWrapper^ wrapper = gcnew CefRequestWrapper(request); - RequestResponse^ requestResponse = gcnew RequestResponse(wrapper); + auto requestWrapper = gcnew CefRequestWrapper(request); + auto response = gcnew RequestResponse(); - bool ret = handler->OnBeforeResourceLoad(_browserControl, requestResponse); + bool ret = handler->OnBeforeResourceLoad(_browserControl, requestWrapper, response); - if (requestResponse->Action == ResponseAction::Redirect) + if (response->Action == ResponseAction::Redirect) { - request->SetURL(StringUtils::ToNative(requestResponse->RedirectUrl)); + request->SetURL(StringUtils::ToNative(response->RedirectUrl)); } - else if (requestResponse->Action == ResponseAction::Respond) + else if (response->Action == ResponseAction::Respond) { throw gcnew NotImplementedException("Respond is not yet supported."); diff --git a/CefSharp.Core/Internals/RequestResponse.h b/CefSharp.Core/Internals/RequestResponse.h index 2486a646f6..adf3bbfb2d 100644 --- a/CefSharp.Core/Internals/RequestResponse.h +++ b/CefSharp.Core/Internals/RequestResponse.h @@ -22,9 +22,8 @@ namespace CefSharp Respond }; - private ref class RequestResponse : IRequestResponse + private ref class RequestResponse : IResponse { - IRequest^ _request; Stream^ _responseStream; String^ _mimeType; String^ _redirectUrl; @@ -34,9 +33,7 @@ namespace CefSharp NameValueCollection^ _responseHeaders; internal: - RequestResponse(IRequest^ request) : - _action(ResponseAction::Continue), - _request(request) + RequestResponse() : _action(ResponseAction::Continue) { } @@ -50,7 +47,6 @@ namespace CefSharp public: virtual void Cancel(); - virtual property IRequest^ Request { IRequest^ get() { return _request; } } virtual void Redirect(String^ url); virtual void RespondWith(Stream^ stream, String^ mimeType); virtual void RespondWith(Stream^ stream, String^ mimeType, String^ statusText, int statusCode, NameValueCollection^ responseHeaders); diff --git a/CefSharp.Example/RequestHandler.cs b/CefSharp.Example/RequestHandler.cs index d4853f011d..dc29bfb325 100644 --- a/CefSharp.Example/RequestHandler.cs +++ b/CefSharp.Example/RequestHandler.cs @@ -21,14 +21,13 @@ void IRequestHandler.OnPluginCrashed(IWebBrowser browser, string pluginPath) // TODO: Add your own code here for handling scenarios where a plugin crashed, for one reason or another. } - bool IRequestHandler.OnBeforeResourceLoad(IWebBrowser browser, IRequestResponse requestResponse) + bool IRequestHandler.OnBeforeResourceLoad(IWebBrowser browser, IRequest request, IResponse response) { - IRequest request = requestResponse.Request; if (request.Url.StartsWith(ResourceUrl.ToString())) { Stream resourceStream = new MemoryStream(Encoding.UTF8.GetBytes( "

Success

This document is loaded from a System.IO.Stream

")); - requestResponse.RespondWith(resourceStream, "text/html"); + response.RespondWith(resourceStream, "text/html"); } return false; diff --git a/CefSharp/CefSharp.csproj b/CefSharp/CefSharp.csproj index cead85d646..295db772a3 100644 --- a/CefSharp/CefSharp.csproj +++ b/CefSharp/CefSharp.csproj @@ -89,6 +89,7 @@
+ @@ -130,7 +131,6 @@ - diff --git a/CefSharp/IRequestHandler.cs b/CefSharp/IRequestHandler.cs index df10479fe6..1681737dfd 100644 --- a/CefSharp/IRequestHandler.cs +++ b/CefSharp/IRequestHandler.cs @@ -29,9 +29,10 @@ public interface IRequestHandler /// Called before a resource request is loaded. /// /// the browser object - /// the request response object - can be modified in this callback + /// the request + /// the response - can be modified in this callback /// To cancel loading of the resource return true or false o allow the resource to load normally. - bool OnBeforeResourceLoad(IWebBrowser browser, IRequestResponse requestResponse); + bool OnBeforeResourceLoad(IWebBrowser browser, IRequest request, IResponse response); // TODO: Investigate how we can support in CEF3. //void OnResourceResponse(IWebBrowser browser, string url, int status, string statusText, string mimeType, WebHeaderCollection headers); diff --git a/CefSharp/IRequestResponse.cs b/CefSharp/IRequestResponse.cs deleted file mode 100644 index d50bf3958c..0000000000 --- a/CefSharp/IRequestResponse.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. - -using System.IO; - -namespace CefSharp -{ - public interface IRequestResponse - { - // TODO: Improve these comments. - - /// cancel the request, return nothing - void Cancel(); - - /// the current request - IRequest Request { get; } - - /// respond with redirection to the provided URL - void Redirect(string url); - - /// respond with data from Stream - void RespondWith(Stream stream, string mimeType); - } -} diff --git a/CefSharp/IResponse.cs b/CefSharp/IResponse.cs new file mode 100644 index 0000000000..6fe18230b3 --- /dev/null +++ b/CefSharp/IResponse.cs @@ -0,0 +1,20 @@ +// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +using System.IO; + +namespace CefSharp +{ + public interface IResponse + { + /// cancel the request, return nothing + void Cancel(); + + /// respond with redirection to the provided URL + void Redirect(string url); + + /// respond with data from Stream + void RespondWith(Stream stream, string mimeType); + } +} From 2d262f68815910b7d4fb2364c54ac0b7538a9d99 Mon Sep 17 00:00:00 2001 From: amaitland Date: Wed, 5 Nov 2014 13:04:41 +1000 Subject: [PATCH 021/134] Rename RequestResponse to Response --- CefSharp.Core/CefSharp.Core.vcxproj | 4 ++-- CefSharp.Core/CefSharp.Core.vcxproj.filters | 12 ++++++------ CefSharp.Core/Internals/ClientAdapter.cpp | 4 ++-- .../Internals/{RequestResponse.cpp => Response.cpp} | 10 +++++----- .../Internals/{RequestResponse.h => Response.h} | 4 ++-- 5 files changed, 17 insertions(+), 17 deletions(-) rename CefSharp.Core/Internals/{RequestResponse.cpp => Response.cpp} (75%) rename CefSharp.Core/Internals/{RequestResponse.h => Response.h} (93%) diff --git a/CefSharp.Core/CefSharp.Core.vcxproj b/CefSharp.Core/CefSharp.Core.vcxproj index f8a74eca6e..6f9d469470 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj +++ b/CefSharp.Core/CefSharp.Core.vcxproj @@ -224,7 +224,7 @@ - + @@ -253,7 +253,7 @@ - + diff --git a/CefSharp.Core/CefSharp.Core.vcxproj.filters b/CefSharp.Core/CefSharp.Core.vcxproj.filters index ef7967b7f0..235bda890f 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj.filters +++ b/CefSharp.Core/CefSharp.Core.vcxproj.filters @@ -41,9 +41,6 @@ Source Files - - Source Files - Source Files @@ -56,6 +53,9 @@ Source Files + + Source Files + @@ -115,9 +115,6 @@ Header Files - - Header Files - Header Files @@ -130,6 +127,9 @@ Header Files + + Header Files + diff --git a/CefSharp.Core/Internals/ClientAdapter.cpp b/CefSharp.Core/Internals/ClientAdapter.cpp index 83641fa0b5..6fe00694fd 100644 --- a/CefSharp.Core/Internals/ClientAdapter.cpp +++ b/CefSharp.Core/Internals/ClientAdapter.cpp @@ -8,7 +8,7 @@ #include "Internals/CefWebPluginInfoWrapper.h" #include "Internals/CefContextMenuParamsWrapper.h" #include "Internals/JavascriptBinding/BindingHandler.h" -#include "Internals/RequestResponse.h" +#include "Internals/Response.h" #include "ClientAdapter.h" #include "Cef.h" #include "DownloadAdapter.h" @@ -259,7 +259,7 @@ namespace CefSharp } auto requestWrapper = gcnew CefRequestWrapper(request); - auto response = gcnew RequestResponse(); + auto response = gcnew Response(); bool ret = handler->OnBeforeResourceLoad(_browserControl, requestWrapper, response); diff --git a/CefSharp.Core/Internals/RequestResponse.cpp b/CefSharp.Core/Internals/Response.cpp similarity index 75% rename from CefSharp.Core/Internals/RequestResponse.cpp rename to CefSharp.Core/Internals/Response.cpp index 9e1a8b97c0..1223a987a6 100644 --- a/CefSharp.Core/Internals/RequestResponse.cpp +++ b/CefSharp.Core/Internals/Response.cpp @@ -3,29 +3,29 @@ // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. #include "Stdafx.h" -#include "RequestResponse.h" +#include "Response.h" namespace CefSharp { namespace Internals { - void RequestResponse::Cancel() + void Response::Cancel() { _action = ResponseAction::Cancel; } - void RequestResponse::Redirect(String^ url) + void Response::Redirect(String^ url) { _redirectUrl = url; _action = ResponseAction::Redirect; } - void RequestResponse::RespondWith(Stream^ stream, String^ mimeType) + void Response::RespondWith(Stream^ stream, String^ mimeType) { RespondWith(stream, mimeType, "OK", 200, nullptr); } - void RequestResponse::RespondWith(Stream^ stream, String^ mimeType, String^ statusText, int statusCode, NameValueCollection^ responseHeaders) + void Response::RespondWith(Stream^ stream, String^ mimeType, String^ statusText, int statusCode, NameValueCollection^ responseHeaders) { if (String::IsNullOrEmpty(mimeType)) { diff --git a/CefSharp.Core/Internals/RequestResponse.h b/CefSharp.Core/Internals/Response.h similarity index 93% rename from CefSharp.Core/Internals/RequestResponse.h rename to CefSharp.Core/Internals/Response.h index adf3bbfb2d..f06bfff5da 100644 --- a/CefSharp.Core/Internals/RequestResponse.h +++ b/CefSharp.Core/Internals/Response.h @@ -22,7 +22,7 @@ namespace CefSharp Respond }; - private ref class RequestResponse : IResponse + private ref class Response : IResponse { Stream^ _responseStream; String^ _mimeType; @@ -33,7 +33,7 @@ namespace CefSharp NameValueCollection^ _responseHeaders; internal: - RequestResponse() : _action(ResponseAction::Continue) + Response() : _action(ResponseAction::Continue) { } From 13349a93cfbcfd45893abdbc9bfb4eff3dabccc1 Mon Sep 17 00:00:00 2001 From: amaitland Date: Wed, 5 Nov 2014 13:54:50 +1000 Subject: [PATCH 022/134] Revert "Split RequestResponse into Request and Response objects" This reverts commit 66d953d2b3efc25e44c7d98ec8809022cef78d67. --- CefSharp.Core/CefSharp.Core.vcxproj | 4 +-- CefSharp.Core/CefSharp.Core.vcxproj.filters | 12 ++++----- CefSharp.Core/Internals/ClientAdapter.cpp | 14 +++++------ .../{Response.cpp => RequestResponse.cpp} | 10 ++++---- .../{Response.h => RequestResponse.h} | 8 ++++-- CefSharp.Example/RequestHandler.cs | 5 ++-- CefSharp/CefSharp.csproj | 2 +- CefSharp/IRequestHandler.cs | 5 ++-- CefSharp/IRequestResponse.cs | 25 +++++++++++++++++++ CefSharp/IResponse.cs | 20 --------------- 10 files changed, 57 insertions(+), 48 deletions(-) rename CefSharp.Core/Internals/{Response.cpp => RequestResponse.cpp} (75%) rename CefSharp.Core/Internals/{Response.h => RequestResponse.h} (84%) create mode 100644 CefSharp/IRequestResponse.cs delete mode 100644 CefSharp/IResponse.cs diff --git a/CefSharp.Core/CefSharp.Core.vcxproj b/CefSharp.Core/CefSharp.Core.vcxproj index 6f9d469470..f8a74eca6e 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj +++ b/CefSharp.Core/CefSharp.Core.vcxproj @@ -224,7 +224,7 @@ - + @@ -253,7 +253,7 @@ - + diff --git a/CefSharp.Core/CefSharp.Core.vcxproj.filters b/CefSharp.Core/CefSharp.Core.vcxproj.filters index 235bda890f..ef7967b7f0 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj.filters +++ b/CefSharp.Core/CefSharp.Core.vcxproj.filters @@ -41,6 +41,9 @@ Source Files + + Source Files + Source Files @@ -53,9 +56,6 @@ Source Files - - Source Files - @@ -115,6 +115,9 @@ Header Files + + Header Files + Header Files @@ -127,9 +130,6 @@ Header Files - - Header Files - diff --git a/CefSharp.Core/Internals/ClientAdapter.cpp b/CefSharp.Core/Internals/ClientAdapter.cpp index 6fe00694fd..5393b104a3 100644 --- a/CefSharp.Core/Internals/ClientAdapter.cpp +++ b/CefSharp.Core/Internals/ClientAdapter.cpp @@ -8,7 +8,7 @@ #include "Internals/CefWebPluginInfoWrapper.h" #include "Internals/CefContextMenuParamsWrapper.h" #include "Internals/JavascriptBinding/BindingHandler.h" -#include "Internals/Response.h" +#include "Internals/RequestResponse.h" #include "ClientAdapter.h" #include "Cef.h" #include "DownloadAdapter.h" @@ -258,16 +258,16 @@ namespace CefSharp return false; } - auto requestWrapper = gcnew CefRequestWrapper(request); - auto response = gcnew Response(); + CefRequestWrapper^ wrapper = gcnew CefRequestWrapper(request); + RequestResponse^ requestResponse = gcnew RequestResponse(wrapper); - bool ret = handler->OnBeforeResourceLoad(_browserControl, requestWrapper, response); + bool ret = handler->OnBeforeResourceLoad(_browserControl, requestResponse); - if (response->Action == ResponseAction::Redirect) + if (requestResponse->Action == ResponseAction::Redirect) { - request->SetURL(StringUtils::ToNative(response->RedirectUrl)); + request->SetURL(StringUtils::ToNative(requestResponse->RedirectUrl)); } - else if (response->Action == ResponseAction::Respond) + else if (requestResponse->Action == ResponseAction::Respond) { throw gcnew NotImplementedException("Respond is not yet supported."); diff --git a/CefSharp.Core/Internals/Response.cpp b/CefSharp.Core/Internals/RequestResponse.cpp similarity index 75% rename from CefSharp.Core/Internals/Response.cpp rename to CefSharp.Core/Internals/RequestResponse.cpp index 1223a987a6..9e1a8b97c0 100644 --- a/CefSharp.Core/Internals/Response.cpp +++ b/CefSharp.Core/Internals/RequestResponse.cpp @@ -3,29 +3,29 @@ // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. #include "Stdafx.h" -#include "Response.h" +#include "RequestResponse.h" namespace CefSharp { namespace Internals { - void Response::Cancel() + void RequestResponse::Cancel() { _action = ResponseAction::Cancel; } - void Response::Redirect(String^ url) + void RequestResponse::Redirect(String^ url) { _redirectUrl = url; _action = ResponseAction::Redirect; } - void Response::RespondWith(Stream^ stream, String^ mimeType) + void RequestResponse::RespondWith(Stream^ stream, String^ mimeType) { RespondWith(stream, mimeType, "OK", 200, nullptr); } - void Response::RespondWith(Stream^ stream, String^ mimeType, String^ statusText, int statusCode, NameValueCollection^ responseHeaders) + void RequestResponse::RespondWith(Stream^ stream, String^ mimeType, String^ statusText, int statusCode, NameValueCollection^ responseHeaders) { if (String::IsNullOrEmpty(mimeType)) { diff --git a/CefSharp.Core/Internals/Response.h b/CefSharp.Core/Internals/RequestResponse.h similarity index 84% rename from CefSharp.Core/Internals/Response.h rename to CefSharp.Core/Internals/RequestResponse.h index f06bfff5da..2486a646f6 100644 --- a/CefSharp.Core/Internals/Response.h +++ b/CefSharp.Core/Internals/RequestResponse.h @@ -22,8 +22,9 @@ namespace CefSharp Respond }; - private ref class Response : IResponse + private ref class RequestResponse : IRequestResponse { + IRequest^ _request; Stream^ _responseStream; String^ _mimeType; String^ _redirectUrl; @@ -33,7 +34,9 @@ namespace CefSharp NameValueCollection^ _responseHeaders; internal: - Response() : _action(ResponseAction::Continue) + RequestResponse(IRequest^ request) : + _action(ResponseAction::Continue), + _request(request) { } @@ -47,6 +50,7 @@ namespace CefSharp public: virtual void Cancel(); + virtual property IRequest^ Request { IRequest^ get() { return _request; } } virtual void Redirect(String^ url); virtual void RespondWith(Stream^ stream, String^ mimeType); virtual void RespondWith(Stream^ stream, String^ mimeType, String^ statusText, int statusCode, NameValueCollection^ responseHeaders); diff --git a/CefSharp.Example/RequestHandler.cs b/CefSharp.Example/RequestHandler.cs index dc29bfb325..d4853f011d 100644 --- a/CefSharp.Example/RequestHandler.cs +++ b/CefSharp.Example/RequestHandler.cs @@ -21,13 +21,14 @@ void IRequestHandler.OnPluginCrashed(IWebBrowser browser, string pluginPath) // TODO: Add your own code here for handling scenarios where a plugin crashed, for one reason or another. } - bool IRequestHandler.OnBeforeResourceLoad(IWebBrowser browser, IRequest request, IResponse response) + bool IRequestHandler.OnBeforeResourceLoad(IWebBrowser browser, IRequestResponse requestResponse) { + IRequest request = requestResponse.Request; if (request.Url.StartsWith(ResourceUrl.ToString())) { Stream resourceStream = new MemoryStream(Encoding.UTF8.GetBytes( "

Success

This document is loaded from a System.IO.Stream

")); - response.RespondWith(resourceStream, "text/html"); + requestResponse.RespondWith(resourceStream, "text/html"); } return false; diff --git a/CefSharp/CefSharp.csproj b/CefSharp/CefSharp.csproj index 295db772a3..cead85d646 100644 --- a/CefSharp/CefSharp.csproj +++ b/CefSharp/CefSharp.csproj @@ -89,7 +89,6 @@
- @@ -131,6 +130,7 @@ + diff --git a/CefSharp/IRequestHandler.cs b/CefSharp/IRequestHandler.cs index 1681737dfd..df10479fe6 100644 --- a/CefSharp/IRequestHandler.cs +++ b/CefSharp/IRequestHandler.cs @@ -29,10 +29,9 @@ public interface IRequestHandler /// Called before a resource request is loaded. /// /// the browser object - /// the request - /// the response - can be modified in this callback + /// the request response object - can be modified in this callback /// To cancel loading of the resource return true or false o allow the resource to load normally. - bool OnBeforeResourceLoad(IWebBrowser browser, IRequest request, IResponse response); + bool OnBeforeResourceLoad(IWebBrowser browser, IRequestResponse requestResponse); // TODO: Investigate how we can support in CEF3. //void OnResourceResponse(IWebBrowser browser, string url, int status, string statusText, string mimeType, WebHeaderCollection headers); diff --git a/CefSharp/IRequestResponse.cs b/CefSharp/IRequestResponse.cs new file mode 100644 index 0000000000..d50bf3958c --- /dev/null +++ b/CefSharp/IRequestResponse.cs @@ -0,0 +1,25 @@ +// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +using System.IO; + +namespace CefSharp +{ + public interface IRequestResponse + { + // TODO: Improve these comments. + + /// cancel the request, return nothing + void Cancel(); + + /// the current request + IRequest Request { get; } + + /// respond with redirection to the provided URL + void Redirect(string url); + + /// respond with data from Stream + void RespondWith(Stream stream, string mimeType); + } +} diff --git a/CefSharp/IResponse.cs b/CefSharp/IResponse.cs deleted file mode 100644 index 6fe18230b3..0000000000 --- a/CefSharp/IResponse.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. - -using System.IO; - -namespace CefSharp -{ - public interface IResponse - { - /// cancel the request, return nothing - void Cancel(); - - /// respond with redirection to the provided URL - void Redirect(string url); - - /// respond with data from Stream - void RespondWith(Stream stream, string mimeType); - } -} From 3b9de609a3376bd67c524007d12e058317068f0a Mon Sep 17 00:00:00 2001 From: amaitland Date: Thu, 6 Nov 2014 14:30:27 +1000 Subject: [PATCH 023/134] Update build.ps1 to include param for AssemblyVersion - has problem with -pre tag --- CefSharp/Properties/AssemblyInfo.cs | 2 +- build.ps1 | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CefSharp/Properties/AssemblyInfo.cs b/CefSharp/Properties/AssemblyInfo.cs index 5a97b884d8..ac717d4749 100644 --- a/CefSharp/Properties/AssemblyInfo.cs +++ b/CefSharp/Properties/AssemblyInfo.cs @@ -33,7 +33,7 @@ public static class AssemblyInfo public const bool ComVisible = false; public const string AssemblyCompany = "The CefSharp Authors"; public const string AssemblyProduct = "CefSharp"; - public const string AssemblyVersion = "39.0.0.0"; + public const string AssemblyVersion = "39.0.0"; public const string AssemblyFileVersion = "39.0.0.0"; public const string AssemblyCopyright = "Copyright © The CefSharp Authors 2010-2014"; public const string CefSharpCoreProject = "CefSharp.Core, PublicKey=" + PublicKey; diff --git a/build.ps1 b/build.ps1 index b6ecb84d84..d95440387f 100644 --- a/build.ps1 +++ b/build.ps1 @@ -3,8 +3,10 @@ param( [Parameter(Position = 0)] [string] $Target = "nupkg", [Parameter(Position = 1)] - [string] $Version = "39.0.0", - [Parameter(Position = 2)] + [string] $Version = "39.0.0-pre01", + [Parameter(Position = 2)] + [string] $AssemblyVersion = "39.0.0", + [Parameter(Position = 3)] [string] $RedistVersion = "3.2171.1899-pre0" ) @@ -249,7 +251,7 @@ function WriteAssemblyVersion $Regex = 'public const string AssemblyVersion = "(.*)"'; $AssemblyInfo = Get-Content $Filename - $NewString = $AssemblyInfo -replace $Regex, "public const string AssemblyVersion = ""$Version""" + $NewString = $AssemblyInfo -replace $Regex, "public const string AssemblyVersion = ""$AssemblyVersion""" $NewString | Set-Content $Filename -Encoding UTF8 } From 38380582c678d69688a3313f0230ff5ccdd89859 Mon Sep 17 00:00:00 2001 From: amaitland Date: Thu, 6 Nov 2014 14:31:00 +1000 Subject: [PATCH 024/134] Fix mistake in CefSharp.Common.nuspec - packages were incorrect --- NuGet/CefSharp.Common.nuspec | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/NuGet/CefSharp.Common.nuspec b/NuGet/CefSharp.Common.nuspec index 424648e4d2..67fdc052a6 100644 --- a/NuGet/CefSharp.Common.nuspec +++ b/NuGet/CefSharp.Common.nuspec @@ -12,10 +12,8 @@ chrome browser Copyright © 2010-2014 The CefSharp Authors - - - - + + From 7783769eadeb56aff41fb9379a638d59af6ba42e Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 14 Nov 2014 09:13:04 +1000 Subject: [PATCH 025/134] Update build version and feed url in appveyor.yml --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 9401ba970e..3014dab01f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ environment: VisualStudioVersion: 11.0 -version: 37.0.0-CI{build} +version: 39.0.0-CI{build} shallow_clone: true @@ -19,7 +19,7 @@ artifacts: # Publish to myget.org feed deploy: provider: NuGet - server: https://www.myget.org/F/cefsharp/ + server: https://www.myget.org/F/cefsharp-2171/ api_key: secure: T3yoLSioRwXa7byUvu17t4I88RTQTvICh2j+KplLb1YVimd1IYy2m2akGqgOMJhY skip_symbols: true From acfad1fcbf35d36d7e901158c2c9330c5e32f6bd Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 14 Nov 2014 09:15:29 +1000 Subject: [PATCH 026/134] Untabify --- build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.ps1 b/build.ps1 index b16e0f533b..4b83c1524f 100644 --- a/build.ps1 +++ b/build.ps1 @@ -4,7 +4,7 @@ param( [string] $Target = "nupkg", [Parameter(Position = 1)] [string] $Version = "39.0.0-pre01", - [Parameter(Position = 2)] + [Parameter(Position = 2)] [string] $AssemblyVersion = "39.0.0", [Parameter(Position = 3)] [string] $RedistVersion = "3.2171.1899-pre0" From 065bb055f08680af2f3062af34538efba43873b9 Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 14 Nov 2014 09:36:35 +1000 Subject: [PATCH 027/134] Cleanup managedCefBrowserAdapter address property, can now be set directly when creating the offscreen browser --- CefSharp.Core/ManagedCefBrowserAdapter.h | 14 ++------------ CefSharp.Wpf/ChromiumWebBrowser.cs | 2 +- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 09327c8aba..416b9411c0 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -23,7 +23,6 @@ namespace CefSharp MCefRefPtr _renderClientAdapter; BrowserProcessServiceHost^ _browserProcessServiceHost; IWebBrowserInternal^ _webBrowserInternal; - String^ _address; JavascriptObjectRepository^ _javaScriptObjectRepository; protected: @@ -39,7 +38,6 @@ namespace CefSharp } _webBrowserInternal = nullptr; - _address = nullptr; _javaScriptObjectRepository = nullptr; DisposableResource::DoDispose(isDisposing); @@ -53,12 +51,12 @@ namespace CefSharp _javaScriptObjectRepository = gcnew JavascriptObjectRepository(); } - void CreateOffscreenBrowser(BrowserSettings^ browserSettings) + void CreateOffscreenBrowser(BrowserSettings^ browserSettings, String^ address) { HWND hwnd = HWND(); CefWindowInfo window; window.SetAsWindowless(hwnd, TRUE); - CefString addressNative = StringUtils::ToNative(_address); + CefString addressNative = StringUtils::ToNative(address); if (!CefBrowserHost::CreateBrowser(window, _renderClientAdapter.get(), addressNative, *(CefBrowserSettings*) browserSettings->_internalBrowserSettings, NULL)) @@ -79,7 +77,6 @@ namespace CefSharp void LoadUrl(String^ address) { - _address = address; auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); if (cefFrame != nullptr) @@ -96,13 +93,6 @@ namespace CefSharp if(_webBrowserInternal != nullptr) { _webBrowserInternal->OnInitialized(); - - auto address = _address; - - if (address != nullptr) - { - LoadUrl(address); - } } } diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 641b24ada4..b7c8e1d290 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -476,7 +476,7 @@ private void CreateOffscreenBrowserWhenActualSizeChanged() return; } - managedCefBrowserAdapter.CreateOffscreenBrowser(BrowserSettings ?? new BrowserSettings()); + managedCefBrowserAdapter.CreateOffscreenBrowser(BrowserSettings ?? new BrowserSettings(), Address); browserCreated = true; } From 76c002aac94a889127fbe22665cbc378d6e55bf2 Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 14 Nov 2014 09:38:43 +1000 Subject: [PATCH 028/134] Cleanup OnPreviewKey --- CefSharp.Wpf/ChromiumWebBrowser.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index b7c8e1d290..7e8073f824 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -857,19 +857,16 @@ private void OnPreviewKey(KeyEventArgs e) // we have to handle these extra keys here. Hooking the Tab key like this makes the tab focusing in essence work like // KeyboardNavigation.TabNavigation="Cycle"; you will never be able to Tab out of the web browser control. var modifiers = GetModifiers(e); + var sendKey = KeysToSendtoBrowser.Contains(e.Key); - if (KeysToSendtoBrowser.Contains(e.Key) || modifiers > 0) + if (sendKey || modifiers > 0) { var message = (int)(e.IsDown ? WM.KEYDOWN : WM.KEYUP); var virtualKey = KeyInterop.VirtualKeyFromKey(e.Key); managedCefBrowserAdapter.SendKeyEvent(message, virtualKey, modifiers); - if (KeysToSendtoBrowser.Contains(e.Key)) - { - e.Handled = true; - } - + e.Handled = sendKey; } } From 7058a9bc2972b90c682c75754e3782c33815f8db Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 18 Nov 2014 13:53:55 +1000 Subject: [PATCH 029/134] Update `OffScreen` browser to support `2171` --- .../CefSharp.OffScreen.Example.csproj | 8 ++++---- CefSharp.OffScreen.Example/Program.cs | 5 +---- CefSharp.OffScreen.Example/packages.config | 4 ++-- CefSharp.OffScreen/ChromiumWebBrowser.cs | 17 ++++++++++++++--- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj b/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj index 16bf7a69c2..f5b2a1a5bb 100644 --- a/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj +++ b/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj @@ -88,9 +88,9 @@ 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/CefSharp.OffScreen.Example/Program.cs b/CefSharp.OffScreen.Example/Program.cs index cd57525a62..592af442ac 100644 --- a/CefSharp.OffScreen.Example/Program.cs +++ b/CefSharp.OffScreen.Example/Program.cs @@ -25,15 +25,12 @@ public static void Main(string[] args) CefExample.Init(); // Create the offscreen Chromium browser. - browser = new ChromiumWebBrowser(); + browser = new ChromiumWebBrowser(testUrl); // An event that is fired when the first page is finished loading. // This returns to us from another thread. browser.FrameLoadEnd += BrowserFrameLoadEnd; - // Start loading the test URL in Chrome's thread. - browser.Load(testUrl); - // We have to wait for something, otherwise the process will exit too soon. Console.ReadKey(); diff --git a/CefSharp.OffScreen.Example/packages.config b/CefSharp.OffScreen.Example/packages.config index 084feef8ea..08fe3cd2d4 100644 --- a/CefSharp.OffScreen.Example/packages.config +++ b/CefSharp.OffScreen.Example/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index 3c938db125..b8943c9223 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -35,17 +35,18 @@ public class ChromiumWebBrowser : IRenderWebBrowser /// This must be set to something other than 0x0 otherwise Chromium will not render, /// and the ScreenshotAsync task will deadlock. private System.Drawing.Size size = new System.Drawing.Size(1366, 768); - + /// /// Create a new offscreen Chromium with the initial URL of "about:blank". /// + /// Initial address (url) to load /// The browser settings to use. If null, the default settings are used. - public ChromiumWebBrowser(BrowserSettings browserSettings = null) + public ChromiumWebBrowser(string address, BrowserSettings browserSettings = null) { Cef.AddDisposable(this); managedCefBrowserAdapter = new ManagedCefBrowserAdapter(this); - managedCefBrowserAdapter.CreateOffscreenBrowser(browserSettings ?? new BrowserSettings()); + managedCefBrowserAdapter.CreateOffscreenBrowser(browserSettings ?? new BrowserSettings(), address); } public void Dispose() @@ -195,6 +196,16 @@ public void CloseDevTools() throw new NotImplementedException(); } + public void ReplaceMisspelling(string word) + { + throw new NotImplementedException(); + } + + public void AddWordToDictionary(string word) + { + throw new NotImplementedException(); + } + public string Address { get; set; } public bool CanGoBack { get; private set; } From e9defe152373b4b7f748b9cb26c77bc65f97b4f1 Mon Sep 17 00:00:00 2001 From: amaitland Date: Wed, 19 Nov 2014 22:58:46 +1000 Subject: [PATCH 030/134] Update to 3.2171.1902-pre packages --- .../CefSharp.BrowserSubprocess.Core.vcxproj | 6 +++--- CefSharp.BrowserSubprocess.Core/packages.config | 2 +- CefSharp.Core/CefSharp.Core.vcxproj | 6 +++--- CefSharp.Core/packages.config | 2 +- .../CefSharp.OffScreen.Example.csproj | 9 +++++---- CefSharp.OffScreen.Example/packages.config | 4 ++-- CefSharp.Test/CefSharp.Test.csproj | 10 +++++----- CefSharp.Test/packages.config | 4 ++-- .../CefSharp.WinForms.Example.csproj | 10 +++++----- CefSharp.WinForms.Example/packages.config | 4 ++-- CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj | 10 +++++----- CefSharp.Wpf.Example/packages.config | 4 ++-- 12 files changed, 36 insertions(+), 35 deletions(-) diff --git a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj index 2fb2f63c72..23f21248cf 100644 --- a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj +++ b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj @@ -1,6 +1,6 @@  - + Debug @@ -66,7 +66,7 @@ - f6c01df1 + e7e3cc55 true @@ -198,6 +198,6 @@ 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/CefSharp.BrowserSubprocess.Core/packages.config b/CefSharp.BrowserSubprocess.Core/packages.config index 96bfbf846f..29df00376a 100644 --- a/CefSharp.BrowserSubprocess.Core/packages.config +++ b/CefSharp.BrowserSubprocess.Core/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/CefSharp.Core/CefSharp.Core.vcxproj b/CefSharp.Core/CefSharp.Core.vcxproj index b1644c5d4f..8e592415a9 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj +++ b/CefSharp.Core/CefSharp.Core.vcxproj @@ -1,6 +1,6 @@  - + Debug @@ -66,7 +66,7 @@ <_ProjectFileVersion>11.0.51106.1 - 3c9e3304 + 35b130a2 bin\$(Configuration)\ @@ -280,6 +280,6 @@ 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/CefSharp.Core/packages.config b/CefSharp.Core/packages.config index 96bfbf846f..29df00376a 100644 --- a/CefSharp.Core/packages.config +++ b/CefSharp.Core/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj b/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj index f5b2a1a5bb..52a4335c8f 100644 --- a/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj +++ b/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj @@ -12,6 +12,7 @@ v4.0 512 Client + 62ab0abb true @@ -88,9 +89,9 @@ 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/CefSharp.OffScreen.Example/packages.config b/CefSharp.OffScreen.Example/packages.config index 08fe3cd2d4..b71b02da62 100644 --- a/CefSharp.OffScreen.Example/packages.config +++ b/CefSharp.OffScreen.Example/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file diff --git a/CefSharp.Test/CefSharp.Test.csproj b/CefSharp.Test/CefSharp.Test.csproj index c4733404e7..0d7d0d6d9a 100644 --- a/CefSharp.Test/CefSharp.Test.csproj +++ b/CefSharp.Test/CefSharp.Test.csproj @@ -19,7 +19,7 @@ 3.5 Client - afff917a + e8407935 true @@ -142,9 +142,9 @@ 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/CefSharp.Test/packages.config b/CefSharp.Test/packages.config index 3de428da91..2fb56cd67a 100644 --- a/CefSharp.Test/packages.config +++ b/CefSharp.Test/packages.config @@ -2,8 +2,8 @@ - - + + \ No newline at end of file diff --git a/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj b/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj index d72cf3c54b..3f63e8c899 100644 --- a/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj +++ b/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj @@ -21,7 +21,7 @@ 3.5 Client - d2750ac0 + da768d66 x64 @@ -150,9 +150,9 @@ 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/CefSharp.WinForms.Example/packages.config b/CefSharp.WinForms.Example/packages.config index 740f5addb9..1a95f9f5a3 100644 --- a/CefSharp.WinForms.Example/packages.config +++ b/CefSharp.WinForms.Example/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file diff --git a/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj b/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj index c758b17b92..b7c20a44a7 100644 --- a/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj +++ b/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj @@ -21,7 +21,7 @@ 3.5 Client - 1f156171 + afb6365a true @@ -166,9 +166,9 @@ 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/CefSharp.Wpf.Example/packages.config b/CefSharp.Wpf.Example/packages.config index 740f5addb9..1a95f9f5a3 100644 --- a/CefSharp.Wpf.Example/packages.config +++ b/CefSharp.Wpf.Example/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file From 9e5c0707c890c00b173f669e95a5ad2ed4c42ad3 Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Thu, 27 Nov 2014 23:29:51 +0100 Subject: [PATCH 031/134] Updated cef redist to 3.2171.1902-pre0 --- build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.ps1 b/build.ps1 index 66069ad2c1..696463bdcc 100644 --- a/build.ps1 +++ b/build.ps1 @@ -7,7 +7,7 @@ param( [Parameter(Position = 2)] [string] $AssemblyVersion = "39.0.0", [Parameter(Position = 3)] - [string] $RedistVersion = "3.2171.1899-pre0" + [string] $RedistVersion = "3.2171.1902-pre0" ) $WorkingDir = split-path -parent $MyInvocation.MyCommand.Definition From 81532639e22bd5005c3dcae9bcf625d454118614 Mon Sep 17 00:00:00 2001 From: Bodekaer Date: Thu, 27 Nov 2014 23:30:24 +0100 Subject: [PATCH 032/134] Cleaner naming of CefSharp dll references when automatically imported from NuGet to VS --- NuGet/CefSharp.Common.props | 21 ++++++++++++--------- NuGet/CefSharp.Wpf.props | 11 ++++++----- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/NuGet/CefSharp.Common.props b/NuGet/CefSharp.Common.props index 8533dae14e..08de47cc0b 100644 --- a/NuGet/CefSharp.Common.props +++ b/NuGet/CefSharp.Common.props @@ -1,14 +1,17 @@ - - - - - + + $(MSBuildThisFileDirectory)..\CefSharp\x86\CefSharp.dll + + + $(MSBuildThisFileDirectory)..\CefSharp\x64\CefSharp.dll + + + $(MSBuildThisFileDirectory)..\CefSharp\x86\CefSharp.Core.dll + + + $(MSBuildThisFileDirectory)..\CefSharp\x64\CefSharp.Core.dll + diff --git a/NuGet/CefSharp.Wpf.props b/NuGet/CefSharp.Wpf.props index ed206ec0b7..d80635b327 100644 --- a/NuGet/CefSharp.Wpf.props +++ b/NuGet/CefSharp.Wpf.props @@ -1,10 +1,11 @@ - - - + + $(MSBuildThisFileDirectory)..\CefSharp\x86\CefSharp.Wpf.dll + + + $(MSBuildThisFileDirectory)..\CefSharp\x64\CefSharp.Wpf.dll + From a0b2a8a59018316ed7310726466a1e49b62e2c87 Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 28 Nov 2014 11:49:33 +1000 Subject: [PATCH 033/134] Update project references in nuget props files --- NuGet/CefSharp.OffScreen.props | 12 +++++++----- NuGet/CefSharp.WinForms.props | 11 ++++++----- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/NuGet/CefSharp.OffScreen.props b/NuGet/CefSharp.OffScreen.props index 6689b254c2..05638713c1 100644 --- a/NuGet/CefSharp.OffScreen.props +++ b/NuGet/CefSharp.OffScreen.props @@ -1,10 +1,12 @@ - - - + + $(MSBuildThisFileDirectory)..\CefSharp\x86\CefSharp.OffScreen.dll + + + $(MSBuildThisFileDirectory)..\CefSharp\x64\CefSharp.OffScreen.dll + + diff --git a/NuGet/CefSharp.WinForms.props b/NuGet/CefSharp.WinForms.props index 05acaa7145..c340077edc 100644 --- a/NuGet/CefSharp.WinForms.props +++ b/NuGet/CefSharp.WinForms.props @@ -1,10 +1,11 @@ - - - + + $(MSBuildThisFileDirectory)..\CefSharp\x86\CefSharp.WinForms.dll + + + $(MSBuildThisFileDirectory)..\CefSharp\x64\CefSharp.WinForms.dll + From d38118393b9e698ebc37316130eb0d6bf0359eca Mon Sep 17 00:00:00 2001 From: amaitland Date: Wed, 3 Dec 2014 11:21:22 +1000 Subject: [PATCH 034/134] Release handlers used for InteropBitmap when disposing of RenderClientAdapter --- CefSharp.Core/Internals/RenderClientAdapter.h | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index 9e2cf767b4..c564cf6c4c 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -41,13 +41,25 @@ namespace CefSharp _renderWebBrowser = nullptr; _webBrowserInternal = nullptr; + DisposeBitmapInfo(MainBitmapInfo); + delete MainBitmapInfo; MainBitmapInfo = nullptr; + DisposeBitmapInfo(PopupBitmapInfo); + delete PopupBitmapInfo; PopupBitmapInfo = nullptr; } + void DisposeBitmapInfo(BitmapInfo^ bitmapInfo) + { + auto backBufferHandle = (HANDLE)bitmapInfo->BackBufferHandle; + auto fileMappingHandle = (HANDLE)bitmapInfo->FileMappingHandle; + + ReleaseBitmapHandlers(&backBufferHandle, &fileMappingHandle); + } + // CefClient virtual CefRefPtr GetRenderHandler() OVERRIDE{ return this; }; @@ -186,17 +198,7 @@ namespace CefSharp { _renderWebBrowser->ClearBitmap(bitmapInfo); - if (*backBufferHandle != NULL) - { - UnmapViewOfFile(*backBufferHandle); - *backBufferHandle = NULL; - } - - if (*fileMappingHandle != NULL) - { - CloseHandle(*fileMappingHandle); - *fileMappingHandle = NULL; - } + ReleaseBitmapHandlers(backBufferHandle, fileMappingHandle); *fileMappingHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, numberOfBytes, NULL); if (*fileMappingHandle == NULL) @@ -221,6 +223,21 @@ namespace CefSharp CopyMemory(*backBufferHandle, (void*)buffer, numberOfBytes); }; + void ReleaseBitmapHandlers(HANDLE* backBufferHandle, HANDLE* fileMappingHandle) + { + if (*backBufferHandle != NULL) + { + UnmapViewOfFile(*backBufferHandle); + *backBufferHandle = NULL; + } + + if (*fileMappingHandle != NULL) + { + CloseHandle(*fileMappingHandle); + *fileMappingHandle = NULL; + } + } + IMPLEMENT_REFCOUNTING(RenderClientAdapter) }; } From 259b37d7f2128c8f96b2b020e3945a0fe8bba3e6 Mon Sep 17 00:00:00 2001 From: "treverj@tjdiversified.com" Date: Tue, 2 Dec 2014 22:47:18 -0600 Subject: [PATCH 035/134] Changed Resize function to better match the CefClient's Add NotifyMoveOrResizeStarted Method --- CefSharp.Core/ManagedCefBrowserAdapter.h | 38 ++++++++++++++++++++---- CefSharp.WinForms/ChromiumWebBrowser.cs | 7 +++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 67f72ec31f..c6685955f9 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -471,11 +471,39 @@ namespace CefSharp *(CefBrowserSettings*)browserSettings->_internalBrowserSettings, NULL); } - void Resize(int width, int height) - { - HWND browserHwnd = _renderClientAdapter->GetBrowserHwnd(); - SetWindowPos(browserHwnd, NULL, 0, 0, width, height, SWP_NOZORDER); - } + void Resize(int width, int height) + { + CefWindowHandle hwnd = _renderClientAdapter->TryGetCefHost()->GetWindowHandle(); + if (hwnd) { + if (width <= 0 && height <= 0) { + // For windowed browsers when the frame window is minimized set the + // browser window size to 0x0 to reduce resource usage. + SetWindowPos(hwnd, NULL, + 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); + } + else { + // Resize the window and address bar to match the new frame size. + RECT rect; + GetClientRect(hwnd, &rect); + HDWP hdwp = BeginDeferWindowPos(1); + hdwp = DeferWindowPos(hdwp, hwnd, NULL, + 0, 0, width, + height, SWP_NOZORDER); + EndDeferWindowPos(hdwp); + } + } + } + + void NotifyMoveOrResizeStarted() + { + auto cefHost = _renderClientAdapter->TryGetCefHost(); + + if (cefHost != nullptr) + { + cefHost->NotifyMoveOrResizeStarted(); + } + } + void RegisterJsObject(String^ name, Object^ object) { diff --git a/CefSharp.WinForms/ChromiumWebBrowser.cs b/CefSharp.WinForms/ChromiumWebBrowser.cs index 9d5a882c0b..559de14acc 100644 --- a/CefSharp.WinForms/ChromiumWebBrowser.cs +++ b/CefSharp.WinForms/ChromiumWebBrowser.cs @@ -360,6 +360,13 @@ private void ResizeBrowser() } } + public void NotifyMoveOrResizeStarted() + { + if (IsBrowserInitialized && managedCefBrowserAdapter != null) + { + managedCefBrowserAdapter.NotifyMoveOrResizeStarted(); + } + } public void ReplaceMisspelling(string word) { From 0ae0e68ba1ec53126b261e1757a07ed99e77953f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bjarte=20Skog=C3=B8y?= Date: Wed, 3 Dec 2014 09:35:25 +0100 Subject: [PATCH 036/134] Implemented WasHidden for the WPF ChromiumWebBrowser --- CefSharp.Core/ManagedCefBrowserAdapter.h | 10 ++++++++++ CefSharp.Wpf/ChromiumWebBrowser.cs | 3 +++ 2 files changed, 13 insertions(+) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 67f72ec31f..0a1914ec2e 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -116,6 +116,16 @@ namespace CefSharp } } + void WasHidden(bool hidden) + { + auto cefHost = _renderClientAdapter->TryGetCefHost(); + + if (cefHost != nullptr) + { + cefHost->WasHidden(hidden); + } + } + void SendFocusEvent(bool isFocused) { auto cefHost = _renderClientAdapter->TryGetCefHost(); diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 1bf851e207..c86224ea43 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -506,6 +506,9 @@ private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArg // If the control was not rendered yet when we tried to set up the source hook, it may have failed (since it couldn't // lookup the HwndSource), so we need to retry it whenever visibility changes. AddSourceHookIfNotAlreadyPresent(); + + var isVisible = (bool)args.NewValue; + managedCefBrowserAdapter.WasHidden(!isVisible); } private static void OnApplicationExit(object sender, ExitEventArgs e) From 4297893b616c0f3f9bf7917bcea5750564bfd732 Mon Sep 17 00:00:00 2001 From: "treverj@tjdiversified.com" Date: Wed, 3 Dec 2014 09:25:46 -0600 Subject: [PATCH 037/134] Code cleanup and changes based on comments --- CefSharp.Core/ManagedCefBrowserAdapter.h | 61 +++++++++++------------- CefSharp.WinForms/ChromiumWebBrowser.cs | 2 +- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index c6685955f9..b60ba5bdc5 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -26,6 +26,8 @@ namespace CefSharp JavascriptObjectRepository^ _javaScriptObjectRepository; protected: + + virtual void DoDispose(bool isDisposing) override { Close(); @@ -43,6 +45,7 @@ namespace CefSharp DisposableResource::DoDispose(isDisposing); }; + public: ManagedCefBrowserAdapter(IWebBrowserInternal^ webBrowserInternal) { @@ -471,38 +474,32 @@ namespace CefSharp *(CefBrowserSettings*)browserSettings->_internalBrowserSettings, NULL); } - void Resize(int width, int height) - { - CefWindowHandle hwnd = _renderClientAdapter->TryGetCefHost()->GetWindowHandle(); - if (hwnd) { - if (width <= 0 && height <= 0) { - // For windowed browsers when the frame window is minimized set the - // browser window size to 0x0 to reduce resource usage. - SetWindowPos(hwnd, NULL, - 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); - } - else { - // Resize the window and address bar to match the new frame size. - RECT rect; - GetClientRect(hwnd, &rect); - HDWP hdwp = BeginDeferWindowPos(1); - hdwp = DeferWindowPos(hdwp, hwnd, NULL, - 0, 0, width, - height, SWP_NOZORDER); - EndDeferWindowPos(hdwp); - } - } - } - - void NotifyMoveOrResizeStarted() - { - auto cefHost = _renderClientAdapter->TryGetCefHost(); - - if (cefHost != nullptr) - { - cefHost->NotifyMoveOrResizeStarted(); - } - } + void Resize(int width, int height) + { + HWND browserHwnd = _renderClientAdapter->GetBrowserHwnd(); + if (browserHwnd) { + if (width == 0 && height == 0) + { + // For windowed browsers when the frame window is minimized set the + // browser window size to 0x0 to reduce resource usage. + SetWindowPos(browserHwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); + } + else + { + SetWindowPos(browserHwnd, NULL, 0, 0, width, height, SWP_NOZORDER); + } + } + } + + void NotifyMoveOrResizeStarted() + { + auto cefHost = _renderClientAdapter->TryGetCefHost(); + + if (cefHost != nullptr) + { + cefHost->NotifyMoveOrResizeStarted(); + } + } void RegisterJsObject(String^ name, Object^ object) diff --git a/CefSharp.WinForms/ChromiumWebBrowser.cs b/CefSharp.WinForms/ChromiumWebBrowser.cs index 559de14acc..47bf407f11 100644 --- a/CefSharp.WinForms/ChromiumWebBrowser.cs +++ b/CefSharp.WinForms/ChromiumWebBrowser.cs @@ -34,6 +34,7 @@ public class ChromiumWebBrowser : Control, IWebBrowserInternal, IWinFormsWebBrow public bool CanReload { get; private set; } public bool IsBrowserInitialized { get; private set; } + public double ZoomLevel { get { return managedCefBrowserAdapter.GetZoomLevel(); } @@ -348,7 +349,6 @@ public Task GetTextAsync() protected override void OnSizeChanged(EventArgs e) { base.OnSizeChanged(e); - ResizeBrowser(); } From c425dd12e0f7ab69250ad4eb52040568ce22cdaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bjarte=20Skog=C3=B8y?= Date: Wed, 3 Dec 2014 20:25:20 +0100 Subject: [PATCH 038/134] Formatting --- CefSharp.Core/ManagedCefBrowserAdapter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 0a1914ec2e..ff4b81f640 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -122,7 +122,7 @@ namespace CefSharp if (cefHost != nullptr) { - cefHost->WasHidden(hidden); + cefHost->WasHidden(hidden); } } From 368267711ec565c26b2126ac83fbe26496c046b3 Mon Sep 17 00:00:00 2001 From: "treverj@tjdiversified.com" Date: Wed, 3 Dec 2014 09:25:46 -0600 Subject: [PATCH 039/134] Code cleanup and changes based on comments --- CefSharp.Core/ManagedCefBrowserAdapter.h | 72 +++++++++++++----------- CefSharp.WinForms/ChromiumWebBrowser.cs | 1 - 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index c6685955f9..2e45f116ac 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -18,14 +18,18 @@ using namespace System::Threading::Tasks; namespace CefSharp { + public ref class ManagedCefBrowserAdapter : public DisposableResource { MCefRefPtr _renderClientAdapter; BrowserProcessServiceHost^ _browserProcessServiceHost; IWebBrowserInternal^ _webBrowserInternal; JavascriptObjectRepository^ _javaScriptObjectRepository; - + + protected: + + virtual void DoDispose(bool isDisposing) override { Close(); @@ -43,7 +47,12 @@ namespace CefSharp DisposableResource::DoDispose(isDisposing); }; + public: + + + + ManagedCefBrowserAdapter(IWebBrowserInternal^ webBrowserInternal) { _renderClientAdapter = new RenderClientAdapter(webBrowserInternal, gcnew Action(this, &ManagedCefBrowserAdapter::OnAfterBrowserCreated)); @@ -460,6 +469,7 @@ namespace CefSharp void CreateBrowser(BrowserSettings^ browserSettings, IntPtr^ sourceHandle, String^ address) { + HWND hwnd = static_cast(sourceHandle->ToPointer()); RECT rect; GetClientRect(hwnd, &rect); @@ -469,40 +479,36 @@ namespace CefSharp CefBrowserHost::CreateBrowser(window, _renderClientAdapter.get(), addressNative, *(CefBrowserSettings*)browserSettings->_internalBrowserSettings, NULL); + } - void Resize(int width, int height) - { - CefWindowHandle hwnd = _renderClientAdapter->TryGetCefHost()->GetWindowHandle(); - if (hwnd) { - if (width <= 0 && height <= 0) { - // For windowed browsers when the frame window is minimized set the - // browser window size to 0x0 to reduce resource usage. - SetWindowPos(hwnd, NULL, - 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); - } - else { - // Resize the window and address bar to match the new frame size. - RECT rect; - GetClientRect(hwnd, &rect); - HDWP hdwp = BeginDeferWindowPos(1); - hdwp = DeferWindowPos(hdwp, hwnd, NULL, - 0, 0, width, - height, SWP_NOZORDER); - EndDeferWindowPos(hdwp); - } - } - } - - void NotifyMoveOrResizeStarted() - { - auto cefHost = _renderClientAdapter->TryGetCefHost(); - - if (cefHost != nullptr) - { - cefHost->NotifyMoveOrResizeStarted(); - } - } + void Resize(int width, int height) + { + HWND browserHwnd = _renderClientAdapter->GetBrowserHwnd(); + if (browserHwnd) + { + if (width == 0 && height == 0) + { + // For windowed browsers when the frame window is minimized set the + // browser window size to 0x0 to reduce resource usage. + SetWindowPos(browserHwnd, NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); + } + else + { + SetWindowPos(browserHwnd, NULL, 0, 0, width, height, SWP_NOZORDER); + } + } + } + + void NotifyMoveOrResizeStarted() + { + auto cefHost = _renderClientAdapter->TryGetCefHost(); + + if (cefHost != nullptr) + { + cefHost->NotifyMoveOrResizeStarted(); + } + } void RegisterJsObject(String^ name, Object^ object) diff --git a/CefSharp.WinForms/ChromiumWebBrowser.cs b/CefSharp.WinForms/ChromiumWebBrowser.cs index 559de14acc..c10b71d1b9 100644 --- a/CefSharp.WinForms/ChromiumWebBrowser.cs +++ b/CefSharp.WinForms/ChromiumWebBrowser.cs @@ -348,7 +348,6 @@ public Task GetTextAsync() protected override void OnSizeChanged(EventArgs e) { base.OnSizeChanged(e); - ResizeBrowser(); } From ad5795552c41b84d40115087c2b04561f46461d2 Mon Sep 17 00:00:00 2001 From: "treverj@tjdiversified.com" Date: Wed, 3 Dec 2014 20:34:35 -0600 Subject: [PATCH 040/134] Code clean up. --- CefSharp.Core/ManagedCefBrowserAdapter.h | 4 ---- CefSharp.WinForms/ChromiumWebBrowser.cs | 2 -- 2 files changed, 6 deletions(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 2e45f116ac..e0fa56bff9 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -51,8 +51,6 @@ namespace CefSharp public: - - ManagedCefBrowserAdapter(IWebBrowserInternal^ webBrowserInternal) { _renderClientAdapter = new RenderClientAdapter(webBrowserInternal, gcnew Action(this, &ManagedCefBrowserAdapter::OnAfterBrowserCreated)); @@ -510,13 +508,11 @@ namespace CefSharp } } - void RegisterJsObject(String^ name, Object^ object) { _javaScriptObjectRepository->Register(name, object); } - void ReplaceMisspelling(String^ word) { auto cefHost = _renderClientAdapter->TryGetCefHost(); diff --git a/CefSharp.WinForms/ChromiumWebBrowser.cs b/CefSharp.WinForms/ChromiumWebBrowser.cs index 47bf407f11..f31764738d 100644 --- a/CefSharp.WinForms/ChromiumWebBrowser.cs +++ b/CefSharp.WinForms/ChromiumWebBrowser.cs @@ -34,7 +34,6 @@ public class ChromiumWebBrowser : Control, IWebBrowserInternal, IWinFormsWebBrow public bool CanReload { get; private set; } public bool IsBrowserInitialized { get; private set; } - public double ZoomLevel { get { return managedCefBrowserAdapter.GetZoomLevel(); } @@ -378,6 +377,5 @@ public void AddWordToDictionary(string word) managedCefBrowserAdapter.AddWordToDictionary(word); } - } } From ed2b2f1f6495f13c2e00ef7ed8f9dba1cf82dd00 Mon Sep 17 00:00:00 2001 From: amaitland Date: Thu, 4 Dec 2014 14:46:30 +1000 Subject: [PATCH 041/134] Fix formatting introduced by PR #661 --- CefSharp.Core/ManagedCefBrowserAdapter.h | 16 +++------------- CefSharp.WinForms/ChromiumWebBrowser.cs | 2 +- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 6a378c3099..63a97a5791 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -18,18 +18,14 @@ using namespace System::Threading::Tasks; namespace CefSharp { - public ref class ManagedCefBrowserAdapter : public DisposableResource { MCefRefPtr _renderClientAdapter; BrowserProcessServiceHost^ _browserProcessServiceHost; IWebBrowserInternal^ _webBrowserInternal; JavascriptObjectRepository^ _javaScriptObjectRepository; - - + protected: - - virtual void DoDispose(bool isDisposing) override { Close(); @@ -47,10 +43,7 @@ namespace CefSharp DisposableResource::DoDispose(isDisposing); }; - public: - - ManagedCefBrowserAdapter(IWebBrowserInternal^ webBrowserInternal) { _renderClientAdapter = new RenderClientAdapter(webBrowserInternal, gcnew Action(this, &ManagedCefBrowserAdapter::OnAfterBrowserCreated)); @@ -477,7 +470,6 @@ namespace CefSharp void CreateBrowser(BrowserSettings^ browserSettings, IntPtr^ sourceHandle, String^ address) { - HWND hwnd = static_cast(sourceHandle->ToPointer()); RECT rect; GetClientRect(hwnd, &rect); @@ -487,7 +479,6 @@ namespace CefSharp CefBrowserHost::CreateBrowser(window, _renderClientAdapter.get(), addressNative, *(CefBrowserSettings*)browserSettings->_internalBrowserSettings, NULL); - } void Resize(int width, int height) @@ -534,7 +525,8 @@ namespace CefSharp } } - void AddWordToDictionary(String^ word){ + void AddWordToDictionary(String^ word) + { auto cefHost = _renderClientAdapter->TryGetCefHost(); if (cefHost != nullptr) @@ -543,7 +535,5 @@ namespace CefSharp cefHost->AddWordToDictionary(wordNative); } } - - }; } diff --git a/CefSharp.WinForms/ChromiumWebBrowser.cs b/CefSharp.WinForms/ChromiumWebBrowser.cs index 281fd61e0c..a1c5c0f4a0 100644 --- a/CefSharp.WinForms/ChromiumWebBrowser.cs +++ b/CefSharp.WinForms/ChromiumWebBrowser.cs @@ -374,6 +374,7 @@ public override bool Focused protected override void OnSizeChanged(EventArgs e) { base.OnSizeChanged(e); + ResizeBrowser(); } @@ -402,6 +403,5 @@ public void AddWordToDictionary(string word) { managedCefBrowserAdapter.AddWordToDictionary(word); } - } } From 9fcffab55393e102955ef6cf15e3e71e0776c16d Mon Sep 17 00:00:00 2001 From: dimas Date: Thu, 4 Dec 2014 16:44:09 +0700 Subject: [PATCH 042/134] Implementing invalidate --- CefSharp.Core/CefSharp.Core.vcxproj | 1 + CefSharp.Core/CefSharp.Core.vcxproj.filters | 3 +++ CefSharp.Core/ManagedCefBrowserAdapter.h | 13 ++++++++++++- CefSharp.Core/MouseButtonType.h | 3 ++- CefSharp.Core/PaintElementType.h | 14 ++++++++++++++ CefSharp.Wpf/ChromiumWebBrowser.cs | 3 +++ build.ps1 | 6 +++--- 7 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 CefSharp.Core/PaintElementType.h diff --git a/CefSharp.Core/CefSharp.Core.vcxproj b/CefSharp.Core/CefSharp.Core.vcxproj index 8e592415a9..0595589bda 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj +++ b/CefSharp.Core/CefSharp.Core.vcxproj @@ -250,6 +250,7 @@ + diff --git a/CefSharp.Core/CefSharp.Core.vcxproj.filters b/CefSharp.Core/CefSharp.Core.vcxproj.filters index 0879635f56..5d1f81a257 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj.filters +++ b/CefSharp.Core/CefSharp.Core.vcxproj.filters @@ -94,6 +94,9 @@ Header Files + + Header Files + Header Files diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 63a97a5791..ccecf1326d 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -7,6 +7,7 @@ #include "Stdafx.h" #include "BrowserSettings.h" #include "MouseButtonType.h" +#include "PaintElementType.h" #include "Internals/RenderClientAdapter.h" #include "Internals/MCefRefPtr.h" #include "Internals/StringVisitor.h" @@ -126,6 +127,16 @@ namespace CefSharp } } + void Invalidate(PaintElementType type) + { + auto cefHost = _renderClientAdapter->TryGetCefHost(); + + if (cefHost != nullptr) + { + cefHost->Invalidate((CefBrowserHost::PaintElementType)type); + } + } + void SendFocusEvent(bool isFocused) { auto cefHost = _renderClientAdapter->TryGetCefHost(); @@ -191,7 +202,7 @@ namespace CefSharp void OnMouseButton(int x, int y, MouseButtonType mouseButtonType, bool mouseUp, int clickCount, CefEventFlags modifiers) { auto cefHost = _renderClientAdapter->TryGetCefHost(); - + if (cefHost != nullptr) { CefMouseEvent mouseEvent; diff --git a/CefSharp.Core/MouseButtonType.h b/CefSharp.Core/MouseButtonType.h index 2a84dc7f0a..5add4099bc 100644 --- a/CefSharp.Core/MouseButtonType.h +++ b/CefSharp.Core/MouseButtonType.h @@ -10,6 +10,7 @@ namespace CefSharp { Left = CefBrowserHost::MouseButtonType::MBT_LEFT, Middle = CefBrowserHost::MouseButtonType::MBT_MIDDLE, - Right = CefBrowserHost::MouseButtonType::MBT_RIGHT + Right = CefBrowserHost::MouseButtonType::MBT_RIGHT, + Blabla }; } \ No newline at end of file diff --git a/CefSharp.Core/PaintElementType.h b/CefSharp.Core/PaintElementType.h new file mode 100644 index 0000000000..dd6481ce4b --- /dev/null +++ b/CefSharp.Core/PaintElementType.h @@ -0,0 +1,14 @@ +// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +#include "include/cef_browser.h" + +namespace CefSharp +{ + public enum class PaintElementType + { + View = CefBrowserHost::PaintElementType::PET_VIEW, + Popup = CefBrowserHost::PaintElementType::PET_POPUP + }; +} \ No newline at end of file diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index c86224ea43..fd5e7cc1c9 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -509,6 +509,9 @@ private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArg var isVisible = (bool)args.NewValue; managedCefBrowserAdapter.WasHidden(!isVisible); + + if (isVisible) + managedCefBrowserAdapter.Invalidate(PaintElementType.View); } private static void OnApplicationExit(object sender, ExitEventArgs e) diff --git a/build.ps1 b/build.ps1 index 696463bdcc..cdb9effeea 100644 --- a/build.ps1 +++ b/build.ps1 @@ -3,7 +3,7 @@ param( [Parameter(Position = 0)] [string] $Target = "nupkg", [Parameter(Position = 1)] - [string] $Version = "39.0.0-pre01", + [string] $Version = "39.0.0-pre01-MB3", [Parameter(Position = 2)] [string] $AssemblyVersion = "39.0.0", [Parameter(Position = 3)] @@ -284,8 +284,8 @@ WriteAssemblyVersion switch -Exact ($Target) { "nupkg" { - #VSX v120 - VSX v110 + VSX v120 + #VSX v110 Nupkg } "nupkg-only" From 094df1aab1df28654d371b2088bdd01fc722525a Mon Sep 17 00:00:00 2001 From: dimas Date: Thu, 4 Dec 2014 16:44:09 +0700 Subject: [PATCH 043/134] Implementing invalidate --- CefSharp.Core/CefSharp.Core.vcxproj | 1 + CefSharp.Core/CefSharp.Core.vcxproj.filters | 3 +++ CefSharp.Core/ManagedCefBrowserAdapter.h | 13 ++++++++++++- CefSharp.Core/PaintElementType.h | 14 ++++++++++++++ CefSharp.Wpf/ChromiumWebBrowser.cs | 3 +++ build.ps1 | 6 +++--- 6 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 CefSharp.Core/PaintElementType.h diff --git a/CefSharp.Core/CefSharp.Core.vcxproj b/CefSharp.Core/CefSharp.Core.vcxproj index 8e592415a9..07462f0f61 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj +++ b/CefSharp.Core/CefSharp.Core.vcxproj @@ -250,6 +250,7 @@ + diff --git a/CefSharp.Core/CefSharp.Core.vcxproj.filters b/CefSharp.Core/CefSharp.Core.vcxproj.filters index 0879635f56..5d1f81a257 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj.filters +++ b/CefSharp.Core/CefSharp.Core.vcxproj.filters @@ -94,6 +94,9 @@ Header Files + + Header Files + Header Files diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 63a97a5791..ccecf1326d 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -7,6 +7,7 @@ #include "Stdafx.h" #include "BrowserSettings.h" #include "MouseButtonType.h" +#include "PaintElementType.h" #include "Internals/RenderClientAdapter.h" #include "Internals/MCefRefPtr.h" #include "Internals/StringVisitor.h" @@ -126,6 +127,16 @@ namespace CefSharp } } + void Invalidate(PaintElementType type) + { + auto cefHost = _renderClientAdapter->TryGetCefHost(); + + if (cefHost != nullptr) + { + cefHost->Invalidate((CefBrowserHost::PaintElementType)type); + } + } + void SendFocusEvent(bool isFocused) { auto cefHost = _renderClientAdapter->TryGetCefHost(); @@ -191,7 +202,7 @@ namespace CefSharp void OnMouseButton(int x, int y, MouseButtonType mouseButtonType, bool mouseUp, int clickCount, CefEventFlags modifiers) { auto cefHost = _renderClientAdapter->TryGetCefHost(); - + if (cefHost != nullptr) { CefMouseEvent mouseEvent; diff --git a/CefSharp.Core/PaintElementType.h b/CefSharp.Core/PaintElementType.h new file mode 100644 index 0000000000..dd6481ce4b --- /dev/null +++ b/CefSharp.Core/PaintElementType.h @@ -0,0 +1,14 @@ +// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +#include "include/cef_browser.h" + +namespace CefSharp +{ + public enum class PaintElementType + { + View = CefBrowserHost::PaintElementType::PET_VIEW, + Popup = CefBrowserHost::PaintElementType::PET_POPUP + }; +} \ No newline at end of file diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index c86224ea43..fd5e7cc1c9 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -509,6 +509,9 @@ private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArg var isVisible = (bool)args.NewValue; managedCefBrowserAdapter.WasHidden(!isVisible); + + if (isVisible) + managedCefBrowserAdapter.Invalidate(PaintElementType.View); } private static void OnApplicationExit(object sender, ExitEventArgs e) diff --git a/build.ps1 b/build.ps1 index 696463bdcc..cdb9effeea 100644 --- a/build.ps1 +++ b/build.ps1 @@ -3,7 +3,7 @@ param( [Parameter(Position = 0)] [string] $Target = "nupkg", [Parameter(Position = 1)] - [string] $Version = "39.0.0-pre01", + [string] $Version = "39.0.0-pre01-MB3", [Parameter(Position = 2)] [string] $AssemblyVersion = "39.0.0", [Parameter(Position = 3)] @@ -284,8 +284,8 @@ WriteAssemblyVersion switch -Exact ($Target) { "nupkg" { - #VSX v120 - VSX v110 + VSX v120 + #VSX v110 Nupkg } "nupkg-only" From e6f7ab414c1111aabd115e9f52e101e44345d0b3 Mon Sep 17 00:00:00 2001 From: dimas Date: Thu, 4 Dec 2014 18:02:07 +0700 Subject: [PATCH 044/134] Removing test line, was committed by mistake --- CefSharp.Core/MouseButtonType.h | 1 - 1 file changed, 1 deletion(-) diff --git a/CefSharp.Core/MouseButtonType.h b/CefSharp.Core/MouseButtonType.h index 5add4099bc..85bd7cd8fa 100644 --- a/CefSharp.Core/MouseButtonType.h +++ b/CefSharp.Core/MouseButtonType.h @@ -11,6 +11,5 @@ namespace CefSharp Left = CefBrowserHost::MouseButtonType::MBT_LEFT, Middle = CefBrowserHost::MouseButtonType::MBT_MIDDLE, Right = CefBrowserHost::MouseButtonType::MBT_RIGHT, - Blabla }; } \ No newline at end of file From 519e4e86a0ab4a782920ecb748ddb674da6c9124 Mon Sep 17 00:00:00 2001 From: dimas Date: Thu, 4 Dec 2014 18:45:12 +0700 Subject: [PATCH 045/134] Adjusting formatting to use space instead of tab --- CefSharp.Core/ManagedCefBrowserAdapter.h | 17 ++++++++--------- CefSharp.Core/MouseButtonType.h | 2 +- CefSharp.Core/PaintElementType.h | 10 +++++----- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index ccecf1326d..2c4838fdbe 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -127,15 +127,15 @@ namespace CefSharp } } - void Invalidate(PaintElementType type) - { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + void Invalidate(PaintElementType type) + { + auto cefHost = _renderClientAdapter->TryGetCefHost(); - if (cefHost != nullptr) - { - cefHost->Invalidate((CefBrowserHost::PaintElementType)type); - } - } + if (cefHost != nullptr) + { + cefHost->Invalidate((CefBrowserHost::PaintElementType)type); + } + } void SendFocusEvent(bool isFocused) { @@ -202,7 +202,6 @@ namespace CefSharp void OnMouseButton(int x, int y, MouseButtonType mouseButtonType, bool mouseUp, int clickCount, CefEventFlags modifiers) { auto cefHost = _renderClientAdapter->TryGetCefHost(); - if (cefHost != nullptr) { CefMouseEvent mouseEvent; diff --git a/CefSharp.Core/MouseButtonType.h b/CefSharp.Core/MouseButtonType.h index 85bd7cd8fa..2a84dc7f0a 100644 --- a/CefSharp.Core/MouseButtonType.h +++ b/CefSharp.Core/MouseButtonType.h @@ -10,6 +10,6 @@ namespace CefSharp { Left = CefBrowserHost::MouseButtonType::MBT_LEFT, Middle = CefBrowserHost::MouseButtonType::MBT_MIDDLE, - Right = CefBrowserHost::MouseButtonType::MBT_RIGHT, + Right = CefBrowserHost::MouseButtonType::MBT_RIGHT }; } \ No newline at end of file diff --git a/CefSharp.Core/PaintElementType.h b/CefSharp.Core/PaintElementType.h index dd6481ce4b..703545ef43 100644 --- a/CefSharp.Core/PaintElementType.h +++ b/CefSharp.Core/PaintElementType.h @@ -6,9 +6,9 @@ namespace CefSharp { - public enum class PaintElementType - { - View = CefBrowserHost::PaintElementType::PET_VIEW, - Popup = CefBrowserHost::PaintElementType::PET_POPUP - }; + public enum class PaintElementType + { + View = CefBrowserHost::PaintElementType::PET_VIEW, + Popup = CefBrowserHost::PaintElementType::PET_POPUP + }; } \ No newline at end of file From 9a65bcb4b44321c4a4410f84e6dccc9db0320672 Mon Sep 17 00:00:00 2001 From: dimas Date: Thu, 4 Dec 2014 23:22:52 +0700 Subject: [PATCH 046/134] Reverting changes to build.ps1 file --- build.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.ps1 b/build.ps1 index cdb9effeea..696463bdcc 100644 --- a/build.ps1 +++ b/build.ps1 @@ -3,7 +3,7 @@ param( [Parameter(Position = 0)] [string] $Target = "nupkg", [Parameter(Position = 1)] - [string] $Version = "39.0.0-pre01-MB3", + [string] $Version = "39.0.0-pre01", [Parameter(Position = 2)] [string] $AssemblyVersion = "39.0.0", [Parameter(Position = 3)] @@ -284,8 +284,8 @@ WriteAssemblyVersion switch -Exact ($Target) { "nupkg" { - VSX v120 - #VSX v110 + #VSX v120 + VSX v110 Nupkg } "nupkg-only" From 698751cb1a150677693ef35353d183fc77f84340 Mon Sep 17 00:00:00 2001 From: dimas Date: Thu, 4 Dec 2014 23:26:30 +0700 Subject: [PATCH 047/134] Removing unnecessary whiteline changes --- CefSharp.Core/ManagedCefBrowserAdapter.h | 1 + 1 file changed, 1 insertion(+) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 2c4838fdbe..ee95ecf0f4 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -202,6 +202,7 @@ namespace CefSharp void OnMouseButton(int x, int y, MouseButtonType mouseButtonType, bool mouseUp, int clickCount, CefEventFlags modifiers) { auto cefHost = _renderClientAdapter->TryGetCefHost(); + if (cefHost != nullptr) { CefMouseEvent mouseEvent; From d68e99b1d21b88d7e4de6a24cf0a7ca02b01076d Mon Sep 17 00:00:00 2001 From: dimas Date: Thu, 4 Dec 2014 23:30:13 +0700 Subject: [PATCH 048/134] Changing copyright symbol to avoid encoding issue --- CefSharp.Core/PaintElementType.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CefSharp.Core/PaintElementType.h b/CefSharp.Core/PaintElementType.h index 703545ef43..d382ddc47b 100644 --- a/CefSharp.Core/PaintElementType.h +++ b/CefSharp.Core/PaintElementType.h @@ -1,4 +1,4 @@ -// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. +// Copyright (c) 2010-2014 The CefSharp Authors. All rights reserved. // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. From db517cc2dabfba5e32a6711746fc6add2b72ccd7 Mon Sep 17 00:00:00 2001 From: dimas Date: Thu, 4 Dec 2014 23:33:38 +0700 Subject: [PATCH 049/134] Removing Invalidate call from inside OnIsVisibleChanged, instead making it a method so it can be called from other place if necessary --- CefSharp.Wpf/ChromiumWebBrowser.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index fd5e7cc1c9..e1533b42f3 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -509,9 +509,6 @@ private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArg var isVisible = (bool)args.NewValue; managedCefBrowserAdapter.WasHidden(!isVisible); - - if (isVisible) - managedCefBrowserAdapter.Invalidate(PaintElementType.View); } private static void OnApplicationExit(object sender, ExitEventArgs e) @@ -1291,5 +1288,13 @@ public void AddWordToDictionary(string word) managedCefBrowserAdapter.AddWordToDictionary(word); } + // Invalidate the view. The browser will call CefRenderHandler::OnPaint + // asynchronously. This method is only used when window rendering is + // disabled. + public void Invalidate(PaintElementType type) + { + managedCefBrowserAdapter.Invalidate(type); + } + } } From 2011243ec37abe2119ad2951266d112f2633b606 Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 8 Dec 2014 12:12:48 +1000 Subject: [PATCH 050/134] Re-add copyright symbol --- CefSharp.Core/PaintElementType.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CefSharp.Core/PaintElementType.h b/CefSharp.Core/PaintElementType.h index d382ddc47b..703545ef43 100644 --- a/CefSharp.Core/PaintElementType.h +++ b/CefSharp.Core/PaintElementType.h @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2014 The CefSharp Authors. All rights reserved. +// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. From 414b2c00987533771d98db8ebd11b9c0bbf060a0 Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 8 Dec 2014 12:17:54 +1000 Subject: [PATCH 051/134] Improve Xml comment and add `Invalidate` method to IWpfWebBrowser interface --- CefSharp.Wpf/ChromiumWebBrowser.cs | 8 ++++---- CefSharp.Wpf/IWpfWebBrowser.cs | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index e1533b42f3..488fdbcfc5 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -1288,13 +1288,13 @@ public void AddWordToDictionary(string word) managedCefBrowserAdapter.AddWordToDictionary(word); } - // Invalidate the view. The browser will call CefRenderHandler::OnPaint - // asynchronously. This method is only used when window rendering is - // disabled. + /// + /// Invalidate the view. The browser will call CefRenderHandler::OnPaint asynchronously. + /// + /// indicates which surface to re-paint either View or Popup. public void Invalidate(PaintElementType type) { managedCefBrowserAdapter.Invalidate(type); } - } } diff --git a/CefSharp.Wpf/IWpfWebBrowser.cs b/CefSharp.Wpf/IWpfWebBrowser.cs index 72306d3c89..7d903808c7 100644 --- a/CefSharp.Wpf/IWpfWebBrowser.cs +++ b/CefSharp.Wpf/IWpfWebBrowser.cs @@ -90,5 +90,11 @@ public interface IWpfWebBrowser : IWebBrowser /// Redo last action. /// ICommand RedoCommand { get; } + + /// + /// Invalidate the view. The browser will call CefRenderHandler::OnPaint asynchronously. + /// + /// indicates which surface to re-paint either View or Popup. + void Invalidate(PaintElementType type); } } From 4dd032871262d6e6f660498ed70410fa989a26e7 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 19:42:49 +1000 Subject: [PATCH 052/134] Remove redundant `ClearBitmap` method from IRenderWebBrowser --- CefSharp.Core/Internals/RenderClientAdapter.h | 2 +- CefSharp.OffScreen/ChromiumWebBrowser.cs | 19 +++++++------------ CefSharp.Wpf/ChromiumWebBrowser.cs | 5 ----- CefSharp/Internals/IRenderWebBrowser.cs | 1 - 4 files changed, 8 insertions(+), 19 deletions(-) diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index c564cf6c4c..3c79015fbf 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -196,7 +196,7 @@ namespace CefSharp currentWidth != width || currentHeight != height) { - _renderWebBrowser->ClearBitmap(bitmapInfo); + bitmapInfo->InteropBitmap = nullptr; ReleaseBitmapHandlers(backBufferHandle, fileMappingHandle); diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index 4f4c747cf2..0a5698e67c 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -353,16 +353,6 @@ int IRenderWebBrowser.BytesPerPixel get { return 4; } } - void IRenderWebBrowser.ClearBitmap(BitmapInfo bitmapInfo) - { - lock (bitmapLock) - { - if (bitmap != null) - bitmap.Dispose(); - bitmap = null; - } - } - int IRenderWebBrowser.Width { get { return size.Width; } @@ -382,10 +372,15 @@ void IRenderWebBrowser.SetBitmap(BitmapInfo bitmapInfo) { lock (bitmapLock) { - ((IRenderWebBrowser)this).ClearBitmap(bitmapInfo); + if (bitmap != null) + { + bitmap.Dispose(); + bitmap = null; + } + lock (bitmapInfo.BitmapLock) { - var stride = bitmapInfo.Width * ((IRenderWebBrowser)this).BytesPerPixel; + var stride = bitmapInfo.Width*((IRenderWebBrowser)this).BytesPerPixel; bitmap = BitmapSourceToBitmap2(Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, bitmapInfo.Width, bitmapInfo.Height, PixelFormats.Bgra32, stride, 0)); diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index cf6c4f57fb..95161714f5 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -1213,11 +1213,6 @@ void IRenderWebBrowser.SetCursor(IntPtr handle) }); } - void IRenderWebBrowser.ClearBitmap(BitmapInfo bitmapInfo) - { - bitmapInfo.InteropBitmap = null; - } - /// /// Raises Rendering event /// diff --git a/CefSharp/Internals/IRenderWebBrowser.cs b/CefSharp/Internals/IRenderWebBrowser.cs index ef7e6f7182..433b966896 100644 --- a/CefSharp/Internals/IRenderWebBrowser.cs +++ b/CefSharp/Internals/IRenderWebBrowser.cs @@ -17,7 +17,6 @@ public interface IRenderWebBrowser : IWebBrowserInternal void SetCursor(IntPtr cursor); - void ClearBitmap(BitmapInfo bitmapInfo); void SetBitmap(BitmapInfo bitmapInfo); void SetPopupIsOpen(bool show); From da6e95e8983feb44d111a591d9eafe88483000fc Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 19:44:31 +1000 Subject: [PATCH 053/134] Remove redundant SetBitmap method from IRenderWebBrowser --- CefSharp.OffScreen/ChromiumWebBrowser.cs | 7 +------ CefSharp.Wpf/ChromiumWebBrowser.cs | 5 ++--- CefSharp/Internals/IRenderWebBrowser.cs | 2 -- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index 0a5698e67c..a0a6b0a7fc 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -364,11 +364,6 @@ int IRenderWebBrowser.Height } void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) - { - ((IRenderWebBrowser)this).SetBitmap(bitmapInfo); - } - - void IRenderWebBrowser.SetBitmap(BitmapInfo bitmapInfo) { lock (bitmapLock) { @@ -380,7 +375,7 @@ void IRenderWebBrowser.SetBitmap(BitmapInfo bitmapInfo) lock (bitmapInfo.BitmapLock) { - var stride = bitmapInfo.Width*((IRenderWebBrowser)this).BytesPerPixel; + var stride = bitmapInfo.Width * ((IRenderWebBrowser)this).BytesPerPixel; bitmap = BitmapSourceToBitmap2(Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, bitmapInfo.Width, bitmapInfo.Height, PixelFormats.Bgra32, stride, 0)); diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 95161714f5..002f5bbec6 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -662,8 +662,7 @@ private IntPtr SourceHook(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) { - IRenderWebBrowser renderer = this; - UiThreadRunAsync(() => renderer.SetBitmap(bitmapInfo), DispatcherPriority.Render); + UiThreadRunAsync(() => SetBitmap(bitmapInfo), DispatcherPriority.Render); } void IWebBrowserInternal.SetAddress(string address) @@ -1225,7 +1224,7 @@ protected virtual void OnRendering(object sender, RenderingEventArgs eventArgs) } } - void IRenderWebBrowser.SetBitmap(BitmapInfo bitmapInfo) + private void SetBitmap(BitmapInfo bitmapInfo) { lock (bitmapInfo.BitmapLock) { diff --git a/CefSharp/Internals/IRenderWebBrowser.cs b/CefSharp/Internals/IRenderWebBrowser.cs index 433b966896..223d3e93ff 100644 --- a/CefSharp/Internals/IRenderWebBrowser.cs +++ b/CefSharp/Internals/IRenderWebBrowser.cs @@ -17,8 +17,6 @@ public interface IRenderWebBrowser : IWebBrowserInternal void SetCursor(IntPtr cursor); - void SetBitmap(BitmapInfo bitmapInfo); - void SetPopupIsOpen(bool show); void SetPopupSizeAndPosition(int width, int height, int x, int y); }; From aaf676fa0919e2d56c45f651be2c540a7fa96483 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 19:48:08 +1000 Subject: [PATCH 054/134] Simplify SetBitmap by removing Action<> --- CefSharp.Wpf/ChromiumWebBrowser.cs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 002f5bbec6..c21e1252ec 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -1231,17 +1231,11 @@ private void SetBitmap(BitmapInfo bitmapInfo) // Inform parents that the browser rendering is updating OnRendering(this, new RenderingEventArgs(bitmapInfo)); + var img = bitmapInfo.IsPopup ? popupImage : image; // Now update the WPF image - if (bitmapInfo.IsPopup) - { - bitmapInfo.InteropBitmap = SetBitmapHelper(bitmapInfo, - (InteropBitmap)bitmapInfo.InteropBitmap, bitmap => popupImage.Source = bitmap); - } - else - { - bitmapInfo.InteropBitmap = SetBitmapHelper(bitmapInfo, - (InteropBitmap)bitmapInfo.InteropBitmap, bitmap => image.Source = bitmap); - } + + bitmapInfo.InteropBitmap = SetBitmapHelper(bitmapInfo, + (InteropBitmap)bitmapInfo.InteropBitmap, img); } } @@ -1253,18 +1247,18 @@ private Point GetPixelPosition(MouseEventArgs e) return pixelPosition; } - private object SetBitmapHelper(BitmapInfo bitmapInfo, InteropBitmap bitmap, Action imageSourceSetter) + private object SetBitmapHelper(BitmapInfo bitmapInfo, InteropBitmap bitmap, Image image) { if (bitmap == null) { - imageSourceSetter(null); + image.Source = null; GC.Collect(1); var stride = bitmapInfo.Width * ((IRenderWebBrowser)this).BytesPerPixel; bitmap = (InteropBitmap)Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, bitmapInfo.Width, bitmapInfo.Height, PixelFormat, stride, 0); - imageSourceSetter(bitmap); + image.Source = bitmap; } bitmap.Invalidate(); From 2824f3b225b10be4a3b964e496993332e66c6a06 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 20:23:05 +1000 Subject: [PATCH 055/134] Continued refactor of SetBitmapHelper --- CefSharp.Wpf/ChromiumWebBrowser.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index c21e1252ec..5fed32a129 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -1231,11 +1231,11 @@ private void SetBitmap(BitmapInfo bitmapInfo) // Inform parents that the browser rendering is updating OnRendering(this, new RenderingEventArgs(bitmapInfo)); + var bytesPerPixel = ((IRenderWebBrowser)this).BytesPerPixel; + var img = bitmapInfo.IsPopup ? popupImage : image; // Now update the WPF image - - bitmapInfo.InteropBitmap = SetBitmapHelper(bitmapInfo, - (InteropBitmap)bitmapInfo.InteropBitmap, img); + SetBitmapHelper(bitmapInfo, img, bytesPerPixel); } } @@ -1247,23 +1247,24 @@ private Point GetPixelPosition(MouseEventArgs e) return pixelPosition; } - private object SetBitmapHelper(BitmapInfo bitmapInfo, InteropBitmap bitmap, Image image) + private static void SetBitmapHelper(BitmapInfo bitmapInfo, Image img, int bytesPerPixel) { + var bitmap = bitmapInfo.InteropBitmap as InteropBitmap; if (bitmap == null) { - image.Source = null; + img.Source = null; GC.Collect(1); - var stride = bitmapInfo.Width * ((IRenderWebBrowser)this).BytesPerPixel; + var stride = bitmapInfo.Width * bytesPerPixel; bitmap = (InteropBitmap)Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, bitmapInfo.Width, bitmapInfo.Height, PixelFormat, stride, 0); - image.Source = bitmap; + img.Source = bitmap; } bitmap.Invalidate(); - return bitmap; + bitmapInfo.InteropBitmap = bitmap; } public void ViewSource() From 7c1bc144b6b5643786d424643f776f445a6405aa Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 20:24:04 +1000 Subject: [PATCH 056/134] Remove SetBitmapHelper method - call code inline for now --- CefSharp.Wpf/ChromiumWebBrowser.cs | 37 +++++++++++++----------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 5fed32a129..3facc08a7b 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -1235,7 +1235,22 @@ private void SetBitmap(BitmapInfo bitmapInfo) var img = bitmapInfo.IsPopup ? popupImage : image; // Now update the WPF image - SetBitmapHelper(bitmapInfo, img, bytesPerPixel); + var bitmap = bitmapInfo.InteropBitmap as InteropBitmap; + if (bitmap == null) + { + img.Source = null; + GC.Collect(1); + + var stride = bitmapInfo.Width * bytesPerPixel; + + bitmap = (InteropBitmap)Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, + bitmapInfo.Width, bitmapInfo.Height, PixelFormat, stride, 0); + img.Source = bitmap; + } + + bitmap.Invalidate(); + + bitmapInfo.InteropBitmap = bitmap; } } @@ -1247,26 +1262,6 @@ private Point GetPixelPosition(MouseEventArgs e) return pixelPosition; } - private static void SetBitmapHelper(BitmapInfo bitmapInfo, Image img, int bytesPerPixel) - { - var bitmap = bitmapInfo.InteropBitmap as InteropBitmap; - if (bitmap == null) - { - img.Source = null; - GC.Collect(1); - - var stride = bitmapInfo.Width * bytesPerPixel; - - bitmap = (InteropBitmap)Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, - bitmapInfo.Width, bitmapInfo.Height, PixelFormat, stride, 0); - img.Source = bitmap; - } - - bitmap.Invalidate(); - - bitmapInfo.InteropBitmap = bitmap; - } - public void ViewSource() { managedCefBrowserAdapter.ViewSource(); From 0bb35f8b27ec51053c347c404cace044179ae6e7 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 20:24:47 +1000 Subject: [PATCH 057/134] Only update the InteropBitmap reference when a new one is created --- CefSharp.Wpf/ChromiumWebBrowser.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 3facc08a7b..b772a07867 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -1246,11 +1246,11 @@ private void SetBitmap(BitmapInfo bitmapInfo) bitmap = (InteropBitmap)Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, bitmapInfo.Width, bitmapInfo.Height, PixelFormat, stride, 0); img.Source = bitmap; + + bitmapInfo.InteropBitmap = bitmap; } bitmap.Invalidate(); - - bitmapInfo.InteropBitmap = bitmap; } } From f6743870236c6646e41f305afd658a21c63bfdbd Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 20:25:38 +1000 Subject: [PATCH 058/134] Move rendering code inline --- CefSharp.Wpf/ChromiumWebBrowser.cs | 61 +++++++++++++++--------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index b772a07867..bd1c8f553e 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -662,7 +662,36 @@ private IntPtr SourceHook(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) { - UiThreadRunAsync(() => SetBitmap(bitmapInfo), DispatcherPriority.Render); + UiThreadRunAsync(delegate + { + lock (bitmapInfo.BitmapLock) + { + // Inform parents that the browser rendering is updating + OnRendering(this, new RenderingEventArgs(bitmapInfo)); + + var bytesPerPixel = ((IRenderWebBrowser)this).BytesPerPixel; + + var img = bitmapInfo.IsPopup ? popupImage : image; + // Now update the WPF image + var bitmap = bitmapInfo.InteropBitmap as InteropBitmap; + if (bitmap == null) + { + img.Source = null; + GC.Collect(1); + + var stride = bitmapInfo.Width * bytesPerPixel; + + bitmap = (InteropBitmap)Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, + bitmapInfo.Width, bitmapInfo.Height, PixelFormat, stride, 0); + img.Source = bitmap; + + bitmapInfo.InteropBitmap = bitmap; + } + + bitmap.Invalidate(); + } + }, + DispatcherPriority.Render); } void IWebBrowserInternal.SetAddress(string address) @@ -1224,36 +1253,6 @@ protected virtual void OnRendering(object sender, RenderingEventArgs eventArgs) } } - private void SetBitmap(BitmapInfo bitmapInfo) - { - lock (bitmapInfo.BitmapLock) - { - // Inform parents that the browser rendering is updating - OnRendering(this, new RenderingEventArgs(bitmapInfo)); - - var bytesPerPixel = ((IRenderWebBrowser)this).BytesPerPixel; - - var img = bitmapInfo.IsPopup ? popupImage : image; - // Now update the WPF image - var bitmap = bitmapInfo.InteropBitmap as InteropBitmap; - if (bitmap == null) - { - img.Source = null; - GC.Collect(1); - - var stride = bitmapInfo.Width * bytesPerPixel; - - bitmap = (InteropBitmap)Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, - bitmapInfo.Width, bitmapInfo.Height, PixelFormat, stride, 0); - img.Source = bitmap; - - bitmapInfo.InteropBitmap = bitmap; - } - - bitmap.Invalidate(); - } - } - private Point GetPixelPosition(MouseEventArgs e) { var deviceIndependentPosition = e.GetPosition(this); From a11ec84b2ba4b6a1bf46a3ef815398d2fb163fc0 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 20:27:35 +1000 Subject: [PATCH 059/134] Only get BytesPerPixel when generating a new InteropBitmap --- CefSharp.Wpf/ChromiumWebBrowser.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index bd1c8f553e..7127ff75b7 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -669,8 +669,6 @@ void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) // Inform parents that the browser rendering is updating OnRendering(this, new RenderingEventArgs(bitmapInfo)); - var bytesPerPixel = ((IRenderWebBrowser)this).BytesPerPixel; - var img = bitmapInfo.IsPopup ? popupImage : image; // Now update the WPF image var bitmap = bitmapInfo.InteropBitmap as InteropBitmap; @@ -679,6 +677,7 @@ void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) img.Source = null; GC.Collect(1); + var bytesPerPixel = ((IRenderWebBrowser)this).BytesPerPixel; var stride = bitmapInfo.Width * bytesPerPixel; bitmap = (InteropBitmap)Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, From e3f771883312516ee394dc08d2b9b2574b365011 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 20:48:21 +1000 Subject: [PATCH 060/134] Rename width and height variables --- CefSharp.Core/Internals/RenderClientAdapter.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index 3c79015fbf..af51cde14d 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -186,15 +186,15 @@ namespace CefSharp _renderWebBrowser->InvokeRenderAsync(bitmapInfo); }; - void SetBufferHelper(BitmapInfo^ bitmapInfo, int ¤tWidth, int& currentHeight, int width, int height, + void SetBufferHelper(BitmapInfo^ bitmapInfo, int ¤tWidth, int& currentHeight, int newWidth, int newHeight, HANDLE* fileMappingHandle, HANDLE* backBufferHandle, const void* buffer) { - int pixels = width * height; + int pixels = newWidth * newHeight; int numberOfBytes = pixels * _renderWebBrowser->BytesPerPixel; if (*backBufferHandle == NULL || - currentWidth != width || - currentHeight != height) + currentWidth != newWidth || + currentHeight != newHeight) { bitmapInfo->InteropBitmap = nullptr; @@ -216,8 +216,8 @@ namespace CefSharp return; } - currentWidth = width; - currentHeight = height; + currentWidth = newWidth; + currentHeight = newHeight; } CopyMemory(*backBufferHandle, (void*)buffer, numberOfBytes); From 325b7f19e207adc7315e63faf711a60b236aa7ac Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 20:50:14 +1000 Subject: [PATCH 061/134] Continue to cleanup width and height variables --- CefSharp.Core/Internals/RenderClientAdapter.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index af51cde14d..4d1fd2f4ff 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -180,13 +180,10 @@ namespace CefSharp bitmapInfo->FileMappingHandle = (IntPtr)fileMappingHandle; bitmapInfo->BackBufferHandle = (IntPtr)backBufferHandle; - bitmapInfo->Width = newWidth; - bitmapInfo->Height = newHeight; - _renderWebBrowser->InvokeRenderAsync(bitmapInfo); }; - void SetBufferHelper(BitmapInfo^ bitmapInfo, int ¤tWidth, int& currentHeight, int newWidth, int newHeight, + void SetBufferHelper(BitmapInfo^ bitmapInfo, int currentWidth, int currentHeight, int newWidth, int newHeight, HANDLE* fileMappingHandle, HANDLE* backBufferHandle, const void* buffer) { int pixels = newWidth * newHeight; @@ -215,11 +212,11 @@ namespace CefSharp // TODO: method call fails. return; } - - currentWidth = newWidth; - currentHeight = newHeight; } + bitmapInfo->Width = newWidth; + bitmapInfo->Height = newHeight; + CopyMemory(*backBufferHandle, (void*)buffer, numberOfBytes); }; From 96b300eaf2138f0e5653c0922ff480db2b90a69e Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 20:51:18 +1000 Subject: [PATCH 062/134] Move currentWidth and currentHeight into SetBufferHelper --- CefSharp.Core/Internals/RenderClientAdapter.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index 4d1fd2f4ff..89719e0498 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -169,12 +169,10 @@ namespace CefSharp { lock l(bitmapInfo->BitmapLock); - int currentWidth = bitmapInfo->Width, currentHeight = bitmapInfo->Height; - auto fileMappingHandle = (HANDLE)bitmapInfo->FileMappingHandle; auto backBufferHandle = (HANDLE)bitmapInfo->BackBufferHandle; - SetBufferHelper(bitmapInfo, currentWidth, currentHeight, newWidth, newHeight, &fileMappingHandle, + SetBufferHelper(bitmapInfo, newWidth, newHeight, &fileMappingHandle, &backBufferHandle, buffer); bitmapInfo->FileMappingHandle = (IntPtr)fileMappingHandle; @@ -183,9 +181,12 @@ namespace CefSharp _renderWebBrowser->InvokeRenderAsync(bitmapInfo); }; - void SetBufferHelper(BitmapInfo^ bitmapInfo, int currentWidth, int currentHeight, int newWidth, int newHeight, + void SetBufferHelper(BitmapInfo^ bitmapInfo, int newWidth, int newHeight, HANDLE* fileMappingHandle, HANDLE* backBufferHandle, const void* buffer) { + int currentWidth = bitmapInfo->Width; + int currentHeight = bitmapInfo->Height; + int pixels = newWidth * newHeight; int numberOfBytes = pixels * _renderWebBrowser->BytesPerPixel; From f1e50092241723946d3623b7983c91f44cd6d435 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 20:52:27 +1000 Subject: [PATCH 063/134] Remove redundant local variable declaration --- CefSharp.Core/Internals/RenderClientAdapter.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index 89719e0498..c8d437d44a 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -184,15 +184,12 @@ namespace CefSharp void SetBufferHelper(BitmapInfo^ bitmapInfo, int newWidth, int newHeight, HANDLE* fileMappingHandle, HANDLE* backBufferHandle, const void* buffer) { - int currentWidth = bitmapInfo->Width; - int currentHeight = bitmapInfo->Height; - int pixels = newWidth * newHeight; int numberOfBytes = pixels * _renderWebBrowser->BytesPerPixel; if (*backBufferHandle == NULL || - currentWidth != newWidth || - currentHeight != newHeight) + bitmapInfo->Width != newWidth || + bitmapInfo->Height != newHeight) { bitmapInfo->InteropBitmap = nullptr; From 6f5ce15847110556526bcb5bed647f9ea01db6d6 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 20:55:48 +1000 Subject: [PATCH 064/134] Simplify OnPaint --- CefSharp.Core/Internals/RenderClientAdapter.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index c8d437d44a..1e1e03cf00 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -98,14 +98,7 @@ namespace CefSharp virtual DECL void OnPaint(CefRefPtr browser, PaintElementType type, const RectList& dirtyRects, const void* buffer, int width, int height) OVERRIDE { - if (type == PET_VIEW) - { - SetBuffer(MainBitmapInfo, width, height, buffer); - } - else if (type == PET_POPUP) - { - SetBuffer(PopupBitmapInfo, width, height, buffer); - } + SetBuffer(type == PET_VIEW ? MainBitmapInfo : PopupBitmapInfo, width, height, buffer); }; virtual DECL void OnCursorChange(CefRefPtr browser, CefCursorHandle cursor) OVERRIDE From 166c898251afd273136619660c8f6cc64645b7f5 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 21:04:37 +1000 Subject: [PATCH 065/134] Add comments to SetBufferHelper --- CefSharp.Core/Internals/RenderClientAdapter.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index 1e1e03cf00..7102809c60 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -184,10 +184,13 @@ namespace CefSharp bitmapInfo->Width != newWidth || bitmapInfo->Height != newHeight) { + //Clear the reference to InteropBitmap so a new one is created in by InvokeRenderAsync bitmapInfo->InteropBitmap = nullptr; + //Release the current handles (if not null) ReleaseBitmapHandlers(backBufferHandle, fileMappingHandle); + // Create new fileMappingHandle *fileMappingHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, numberOfBytes, NULL); if (*fileMappingHandle == NULL) { From 013c3145c7c001ca0693135fa55d36e2f13bbbdd Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 21:05:29 +1000 Subject: [PATCH 066/134] Only create new RenderingEventArgs when EventHandler is attached (performance reasons, no need to create object unnecessarily) --- CefSharp.Wpf/ChromiumWebBrowser.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 7127ff75b7..245b607c70 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -667,7 +667,7 @@ void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) lock (bitmapInfo.BitmapLock) { // Inform parents that the browser rendering is updating - OnRendering(this, new RenderingEventArgs(bitmapInfo)); + OnRendering(this, bitmapInfo); var img = bitmapInfo.IsPopup ? popupImage : image; // Now update the WPF image @@ -1243,12 +1243,12 @@ void IRenderWebBrowser.SetCursor(IntPtr handle) /// /// Raises Rendering event /// - protected virtual void OnRendering(object sender, RenderingEventArgs eventArgs) + protected virtual void OnRendering(object sender, BitmapInfo bitmapInfo) { var rendering = Rendering; if (rendering != null) { - rendering(this, eventArgs); + rendering(sender, new RenderingEventArgs(bitmapInfo)); } } From 7bc7cd227a80ced6896524fa029222c19e49dec5 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 21:17:37 +1000 Subject: [PATCH 067/134] Improve comment --- CefSharp.Core/Internals/RenderClientAdapter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index 7102809c60..620f25405e 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -184,7 +184,7 @@ namespace CefSharp bitmapInfo->Width != newWidth || bitmapInfo->Height != newHeight) { - //Clear the reference to InteropBitmap so a new one is created in by InvokeRenderAsync + //Clear the reference to InteropBitmap so a new one is created by InvokeRenderAsync bitmapInfo->InteropBitmap = nullptr; //Release the current handles (if not null) From 25203c53278b04c86dc8aaafa37d0e174d5a18bd Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 21:24:55 +1000 Subject: [PATCH 068/134] Create BrowserSettings in ChromiumWebBrowser constructor and explicitly call Dispose (it references an unmanaged resource) --- CefSharp.Wpf/ChromiumWebBrowser.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 245b607c70..24dc9db8e7 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -338,6 +338,9 @@ public void Dispose() protected virtual void Dispose(bool isdisposing) { + BrowserSettings.Dispose(); + + BrowserSettings = null; ResourceHandler = null; Loaded -= OnLoaded; @@ -470,6 +473,7 @@ public ChromiumWebBrowser() disposables.Add(new DisposableEventWrapper(this, ActualWidthProperty, OnActualSizeChanged)); ResourceHandler = new DefaultResourceHandler(); + BrowserSettings = new BrowserSettings(); } ~ChromiumWebBrowser() @@ -484,7 +488,7 @@ private void CreateOffscreenBrowserWhenActualSizeChanged() return; } - managedCefBrowserAdapter.CreateOffscreenBrowser(BrowserSettings ?? new BrowserSettings(), Address); + managedCefBrowserAdapter.CreateOffscreenBrowser(BrowserSettings, Address); browserCreated = true; } From 40f3328b5b3650899ddc3c98f3686378cf76774a Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 21:42:09 +1000 Subject: [PATCH 069/134] Add simple JSON example to BindingTest.html --- CefSharp.Example/BoundObject.cs | 5 +++++ CefSharp.Example/Resources/BindingTest.html | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/CefSharp.Example/BoundObject.cs b/CefSharp.Example/BoundObject.cs index c48cb5a83e..50fc60a81b 100644 --- a/CefSharp.Example/BoundObject.cs +++ b/CefSharp.Example/BoundObject.cs @@ -194,6 +194,11 @@ public String lowercaseMethod() return "lowercase"; } + public string ReturnJsonEmployeeList() + { + return "{\"employees\":[{\"firstName\":\"John\", \"lastName\":\"Doe\"},{\"firstName\":\"Anna\", \"lastName\":\"Smith\"},{\"firstName\":\"Peter\", \"lastName\":\"Jones\"}]}"; + } + [JavascriptIgnore] public string IgnoredProperty { get; set; } diff --git a/CefSharp.Example/Resources/BindingTest.html b/CefSharp.Example/Resources/BindingTest.html index 41ecf32684..a4052deba8 100644 --- a/CefSharp.Example/Resources/BindingTest.html +++ b/CefSharp.Example/Resources/BindingTest.html @@ -45,6 +45,25 @@ document.write("Stress Test done with : " + stressTestCallCount + " call to bound.repeat(\"hi \", 5)");

+ +

+ JSON Serializer Test +
+ +

+ + Methods on bound object 'bound':
From 520349d6435db0012b39bee34d80c379d817c574 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 23:19:21 +1000 Subject: [PATCH 070/134] Make BitmapInfo abstract and implement a strongly typed version in WPF and OffScreen --- CefSharp.Core/Internals/RenderClientAdapter.h | 11 +++++------ CefSharp.OffScreen/CefSharp.OffScreen.csproj | 1 + CefSharp.OffScreen/ChromiumWebBrowser.cs | 5 +++++ CefSharp.OffScreen/GdiBitmapInfo.cs | 15 +++++++++++++++ CefSharp.Wpf/CefSharp.Wpf.csproj | 1 + CefSharp.Wpf/ChromiumWebBrowser.cs | 14 ++++++++++---- CefSharp.Wpf/InteropBitmapInfo.cs | 16 ++++++++++++++++ CefSharp.Wpf/RenderingEventArgs.cs | 5 ++--- CefSharp/Internals/BitmapInfo.cs | 7 +++---- CefSharp/Internals/IRenderWebBrowser.cs | 1 + 10 files changed, 59 insertions(+), 17 deletions(-) create mode 100644 CefSharp.OffScreen/GdiBitmapInfo.cs create mode 100644 CefSharp.Wpf/InteropBitmapInfo.cs diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index 620f25405e..1fd642eaf1 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -29,11 +29,10 @@ namespace CefSharp ClientAdapter(webBrowserInternal, onAfterBrowserCreated), _webBrowserInternal(webBrowserInternal) { - MainBitmapInfo = gcnew BitmapInfo(); - PopupBitmapInfo = gcnew BitmapInfo(); - PopupBitmapInfo->IsPopup = true; - _renderWebBrowser = dynamic_cast(webBrowserInternal); + + MainBitmapInfo = _renderWebBrowser->CreateBitmapInfo(false); + PopupBitmapInfo = _renderWebBrowser->CreateBitmapInfo(true); } ~RenderClientAdapter() @@ -184,8 +183,8 @@ namespace CefSharp bitmapInfo->Width != newWidth || bitmapInfo->Height != newHeight) { - //Clear the reference to InteropBitmap so a new one is created by InvokeRenderAsync - bitmapInfo->InteropBitmap = nullptr; + //Clear the reference to Bitmap so a new one is created by InvokeRenderAsync + bitmapInfo->ClearBitmap(); //Release the current handles (if not null) ReleaseBitmapHandlers(backBufferHandle, fileMappingHandle); diff --git a/CefSharp.OffScreen/CefSharp.OffScreen.csproj b/CefSharp.OffScreen/CefSharp.OffScreen.csproj index 9e5eac677a..7a2c28be10 100644 --- a/CefSharp.OffScreen/CefSharp.OffScreen.csproj +++ b/CefSharp.OffScreen/CefSharp.OffScreen.csproj @@ -64,6 +64,7 @@
+ diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index a0a6b0a7fc..b245225561 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -363,6 +363,11 @@ int IRenderWebBrowser.Height get { return size.Height; } } + public BitmapInfo CreateBitmapInfo(bool isPopup) + { + return new GdiBitmapInfo { IsPopup = isPopup }; + } + void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) { lock (bitmapLock) diff --git a/CefSharp.OffScreen/GdiBitmapInfo.cs b/CefSharp.OffScreen/GdiBitmapInfo.cs new file mode 100644 index 0000000000..968c72e6c5 --- /dev/null +++ b/CefSharp.OffScreen/GdiBitmapInfo.cs @@ -0,0 +1,15 @@ +using System.Drawing; +using CefSharp.Internals; + +namespace CefSharp.OffScreen +{ + public class GdiBitmapInfo : BitmapInfo + { + public Bitmap Bitmap { get; set; } + + public override void ClearBitmap() + { + Bitmap = null; + } + } +} diff --git a/CefSharp.Wpf/CefSharp.Wpf.csproj b/CefSharp.Wpf/CefSharp.Wpf.csproj index 3bfe48f298..0c7fa17114 100644 --- a/CefSharp.Wpf/CefSharp.Wpf.csproj +++ b/CefSharp.Wpf/CefSharp.Wpf.csproj @@ -93,6 +93,7 @@ + Code diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 24dc9db8e7..2cf66f1020 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -664,18 +664,24 @@ private IntPtr SourceHook(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam return IntPtr.Zero; } + public BitmapInfo CreateBitmapInfo(bool isPopup) + { + return new InteropBitmapInfo { IsPopup = isPopup }; + } + void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) { UiThreadRunAsync(delegate { lock (bitmapInfo.BitmapLock) { + var interopBitmapInfo = (InteropBitmapInfo)bitmapInfo; // Inform parents that the browser rendering is updating - OnRendering(this, bitmapInfo); + OnRendering(this, interopBitmapInfo); var img = bitmapInfo.IsPopup ? popupImage : image; // Now update the WPF image - var bitmap = bitmapInfo.InteropBitmap as InteropBitmap; + var bitmap = interopBitmapInfo.InteropBitmap; if (bitmap == null) { img.Source = null; @@ -688,7 +694,7 @@ void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) bitmapInfo.Width, bitmapInfo.Height, PixelFormat, stride, 0); img.Source = bitmap; - bitmapInfo.InteropBitmap = bitmap; + interopBitmapInfo.InteropBitmap = bitmap; } bitmap.Invalidate(); @@ -1247,7 +1253,7 @@ void IRenderWebBrowser.SetCursor(IntPtr handle) /// /// Raises Rendering event /// - protected virtual void OnRendering(object sender, BitmapInfo bitmapInfo) + protected virtual void OnRendering(object sender, InteropBitmapInfo bitmapInfo) { var rendering = Rendering; if (rendering != null) diff --git a/CefSharp.Wpf/InteropBitmapInfo.cs b/CefSharp.Wpf/InteropBitmapInfo.cs new file mode 100644 index 0000000000..20d0f7cab2 --- /dev/null +++ b/CefSharp.Wpf/InteropBitmapInfo.cs @@ -0,0 +1,16 @@ +using System.Windows.Interop; +using CefSharp.Internals; + +namespace CefSharp.Wpf +{ + public class InteropBitmapInfo : BitmapInfo + { + // Cannot be InteropBitmap since we really don't want CefSharp to be dependent on WPF libraries. + public InteropBitmap InteropBitmap { get; set; } + + public override void ClearBitmap() + { + InteropBitmap = null; + } + } +} diff --git a/CefSharp.Wpf/RenderingEventArgs.cs b/CefSharp.Wpf/RenderingEventArgs.cs index e0957aa0ca..d8d4e7ef3a 100644 --- a/CefSharp.Wpf/RenderingEventArgs.cs +++ b/CefSharp.Wpf/RenderingEventArgs.cs @@ -3,7 +3,6 @@ // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. using System; -using CefSharp.Internals; namespace CefSharp.Wpf { @@ -12,7 +11,7 @@ namespace CefSharp.Wpf /// public class RenderingEventArgs : EventArgs { - public RenderingEventArgs(BitmapInfo bitmapInfo) + public RenderingEventArgs(InteropBitmapInfo bitmapInfo) { BitmapInfo = bitmapInfo; } @@ -20,7 +19,7 @@ public RenderingEventArgs(BitmapInfo bitmapInfo) /// /// The bitmap info being rendered. /// - public BitmapInfo BitmapInfo { get; private set; } + public InteropBitmapInfo BitmapInfo { get; private set; } } } diff --git a/CefSharp/Internals/BitmapInfo.cs b/CefSharp/Internals/BitmapInfo.cs index a6b0a35017..4498b3ad87 100644 --- a/CefSharp/Internals/BitmapInfo.cs +++ b/CefSharp/Internals/BitmapInfo.cs @@ -6,7 +6,7 @@ namespace CefSharp.Internals { - public class BitmapInfo + public abstract class BitmapInfo { public object BitmapLock; public IntPtr BackBufferHandle; @@ -17,10 +17,9 @@ public class BitmapInfo public IntPtr FileMappingHandle { get; set; } - // Cannot be InteropBitmap since we really don't want CefSharp to be dependent on WPF libraries. - public object InteropBitmap; + public abstract void ClearBitmap(); - public BitmapInfo() + protected BitmapInfo() { BitmapLock = new object(); } diff --git a/CefSharp/Internals/IRenderWebBrowser.cs b/CefSharp/Internals/IRenderWebBrowser.cs index 223d3e93ff..354299b4c9 100644 --- a/CefSharp/Internals/IRenderWebBrowser.cs +++ b/CefSharp/Internals/IRenderWebBrowser.cs @@ -13,6 +13,7 @@ public interface IRenderWebBrowser : IWebBrowserInternal int Width { get; } int Height { get; } + BitmapInfo CreateBitmapInfo(bool isPopup); void InvokeRenderAsync(BitmapInfo bitmapInfo); void SetCursor(IntPtr cursor); From 33b0e4710e7a1e771d49baec831d98a8c55bcaab Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 23:35:31 +1000 Subject: [PATCH 071/134] Add TODO --- CefSharp.Wpf/ChromiumWebBrowser.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 2cf66f1020..326ede0ae3 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -694,6 +694,9 @@ void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) bitmapInfo.Width, bitmapInfo.Height, PixelFormat, stride, 0); img.Source = bitmap; + //TODO: Look into + //bitmap.CopyPixels + interopBitmapInfo.InteropBitmap = bitmap; } From 85c44f77547baaefe8a6eccf56a32f680493feef Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 16 Dec 2014 23:41:11 +1000 Subject: [PATCH 072/134] Move BytesPerPixel to BitmapInfo - simplifies code --- CefSharp.Core/Internals/RenderClientAdapter.h | 2 +- CefSharp.OffScreen/ChromiumWebBrowser.cs | 10 +++------- CefSharp.Wpf/ChromiumWebBrowser.cs | 17 ++++------------- CefSharp/Internals/BitmapInfo.cs | 2 ++ CefSharp/Internals/IRenderWebBrowser.cs | 2 -- 5 files changed, 10 insertions(+), 23 deletions(-) diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index 1fd642eaf1..7bd85e6adf 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -177,7 +177,7 @@ namespace CefSharp HANDLE* fileMappingHandle, HANDLE* backBufferHandle, const void* buffer) { int pixels = newWidth * newHeight; - int numberOfBytes = pixels * _renderWebBrowser->BytesPerPixel; + int numberOfBytes = pixels * bitmapInfo->BytesPerPixel; if (*backBufferHandle == NULL || bitmapInfo->Width != newWidth || diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index b245225561..d7e403387f 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -347,11 +347,6 @@ public void SendMouseWheelEvent(int x, int y, int deltaX, int deltaY) } #region IRenderWebBrowser (rendering to bitmap; derived from CefSharp.Wpf.ChromiumWebBrowser) - /// The bitmap buffer is 32 BPP. - int IRenderWebBrowser.BytesPerPixel - { - get { return 4; } - } int IRenderWebBrowser.Width { @@ -365,7 +360,8 @@ int IRenderWebBrowser.Height public BitmapInfo CreateBitmapInfo(bool isPopup) { - return new GdiBitmapInfo { IsPopup = isPopup }; + //The bitmap buffer is 32 BPP + return new GdiBitmapInfo { IsPopup = isPopup, BytesPerPixel = 4 }; } void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) @@ -380,7 +376,7 @@ void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) lock (bitmapInfo.BitmapLock) { - var stride = bitmapInfo.Width * ((IRenderWebBrowser)this).BytesPerPixel; + var stride = bitmapInfo.Width * bitmapInfo.BytesPerPixel; bitmap = BitmapSourceToBitmap2(Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, bitmapInfo.Width, bitmapInfo.Height, PixelFormats.Bgra32, stride, 0)); diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 326ede0ae3..9f97551556 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -21,6 +21,8 @@ namespace CefSharp.Wpf { public class ChromiumWebBrowser : ContentControl, IRenderWebBrowser, IWpfWebBrowser { + private static readonly PixelFormat PixelFormat = PixelFormats.Bgra32; + private static readonly int BytesPerPixel = PixelFormat.BitsPerPixel / 8; private static readonly Key[] KeysToSendtoBrowser = { Key.Tab, @@ -118,11 +120,6 @@ public bool CanReload #endregion - int IRenderWebBrowser.BytesPerPixel - { - get { return PixelFormat.BitsPerPixel / 8; } - } - int IRenderWebBrowser.Width { get { return (int)matrix.Transform(new Point(ActualWidth, ActualHeight)).X; } @@ -133,11 +130,6 @@ int IRenderWebBrowser.Height get { return (int)matrix.Transform(new Point(ActualWidth, ActualHeight)).Y; } } - private static PixelFormat PixelFormat - { - get { return PixelFormats.Bgra32; } - } - #region Address dependency property public string Address @@ -666,7 +658,7 @@ private IntPtr SourceHook(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam public BitmapInfo CreateBitmapInfo(bool isPopup) { - return new InteropBitmapInfo { IsPopup = isPopup }; + return new InteropBitmapInfo { IsPopup = isPopup, BytesPerPixel = BytesPerPixel }; } void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) @@ -687,8 +679,7 @@ void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) img.Source = null; GC.Collect(1); - var bytesPerPixel = ((IRenderWebBrowser)this).BytesPerPixel; - var stride = bitmapInfo.Width * bytesPerPixel; + var stride = bitmapInfo.Width * bitmapInfo.BytesPerPixel; bitmap = (InteropBitmap)Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, bitmapInfo.Width, bitmapInfo.Height, PixelFormat, stride, 0); diff --git a/CefSharp/Internals/BitmapInfo.cs b/CefSharp/Internals/BitmapInfo.cs index 4498b3ad87..7cb0194667 100644 --- a/CefSharp/Internals/BitmapInfo.cs +++ b/CefSharp/Internals/BitmapInfo.cs @@ -17,6 +17,8 @@ public abstract class BitmapInfo public IntPtr FileMappingHandle { get; set; } + public int BytesPerPixel { get; set; } + public abstract void ClearBitmap(); protected BitmapInfo() diff --git a/CefSharp/Internals/IRenderWebBrowser.cs b/CefSharp/Internals/IRenderWebBrowser.cs index 354299b4c9..e73fafa207 100644 --- a/CefSharp/Internals/IRenderWebBrowser.cs +++ b/CefSharp/Internals/IRenderWebBrowser.cs @@ -8,8 +8,6 @@ namespace CefSharp.Internals { public interface IRenderWebBrowser : IWebBrowserInternal { - int BytesPerPixel { get; } - int Width { get; } int Height { get; } From c7032ea83cb6c91e76eb87017ee961de9ec0cd9b Mon Sep 17 00:00:00 2001 From: amaitland Date: Thu, 18 Dec 2014 22:22:15 +1000 Subject: [PATCH 073/134] Upgrade to Cef 3.2171.1949 OnCursorChange Signature has changed --- .../CefSharp.BrowserSubprocess.Core.vcxproj | 6 +++--- CefSharp.BrowserSubprocess.Core/packages.config | 2 +- CefSharp.Core/CefSharp.Core.vcxproj | 6 +++--- CefSharp.Core/Internals/RenderClientAdapter.h | 3 ++- CefSharp.Core/packages.config | 2 +- .../CefSharp.OffScreen.Example.csproj | 10 +++++----- CefSharp.OffScreen.Example/packages.config | 4 ++-- CefSharp.Test/CefSharp.Test.csproj | 10 +++++----- CefSharp.Test/packages.config | 4 ++-- .../CefSharp.WinForms.Example.csproj | 10 +++++----- CefSharp.WinForms.Example/packages.config | 4 ++-- CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj | 10 +++++----- CefSharp.Wpf.Example/packages.config | 4 ++-- NuGet.config | 1 + build.ps1 | 2 +- 15 files changed, 40 insertions(+), 38 deletions(-) diff --git a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj index 23f21248cf..7743e9fdee 100644 --- a/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj +++ b/CefSharp.BrowserSubprocess.Core/CefSharp.BrowserSubprocess.Core.vcxproj @@ -1,6 +1,6 @@  - + Debug @@ -66,7 +66,7 @@ - e7e3cc55 + 03744085 true @@ -198,6 +198,6 @@ 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/CefSharp.BrowserSubprocess.Core/packages.config b/CefSharp.BrowserSubprocess.Core/packages.config index 29df00376a..e2fa03398d 100644 --- a/CefSharp.BrowserSubprocess.Core/packages.config +++ b/CefSharp.BrowserSubprocess.Core/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/CefSharp.Core/CefSharp.Core.vcxproj b/CefSharp.Core/CefSharp.Core.vcxproj index 71f3887230..5a28c9ece4 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj +++ b/CefSharp.Core/CefSharp.Core.vcxproj @@ -1,6 +1,6 @@  - + Debug @@ -66,7 +66,7 @@ <_ProjectFileVersion>11.0.51106.1 - 35b130a2 + 6edfce21 bin\$(Configuration)\ @@ -282,6 +282,6 @@ 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/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index c564cf6c4c..de533f87bf 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -108,7 +108,8 @@ namespace CefSharp } }; - virtual DECL void OnCursorChange(CefRefPtr browser, CefCursorHandle cursor) OVERRIDE + virtual DECL void OnCursorChange(CefRefPtr browser, CefCursorHandle cursor, CursorType type, + const CefCursorInfo& custom_cursor_info) OVERRIDE { _renderWebBrowser->SetCursor((IntPtr)cursor); }; diff --git a/CefSharp.Core/packages.config b/CefSharp.Core/packages.config index 29df00376a..e2fa03398d 100644 --- a/CefSharp.Core/packages.config +++ b/CefSharp.Core/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file diff --git a/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj b/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj index 52a4335c8f..0e663d886c 100644 --- a/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj +++ b/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj @@ -12,7 +12,7 @@ v4.0 512 Client - 62ab0abb + 320b0b24 true @@ -89,9 +89,9 @@ 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/CefSharp.OffScreen.Example/packages.config b/CefSharp.OffScreen.Example/packages.config index b71b02da62..a13e14422e 100644 --- a/CefSharp.OffScreen.Example/packages.config +++ b/CefSharp.OffScreen.Example/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file diff --git a/CefSharp.Test/CefSharp.Test.csproj b/CefSharp.Test/CefSharp.Test.csproj index 0d7d0d6d9a..d22a5bb564 100644 --- a/CefSharp.Test/CefSharp.Test.csproj +++ b/CefSharp.Test/CefSharp.Test.csproj @@ -19,7 +19,7 @@ 3.5 Client - e8407935 + 85aa022d true @@ -142,9 +142,9 @@ 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/CefSharp.Test/packages.config b/CefSharp.Test/packages.config index 2fb56cd67a..ecc64962e9 100644 --- a/CefSharp.Test/packages.config +++ b/CefSharp.Test/packages.config @@ -2,8 +2,8 @@ - - + + \ No newline at end of file diff --git a/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj b/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj index c5305b8980..196133da78 100644 --- a/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj +++ b/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj @@ -21,7 +21,7 @@ 3.5 Client - da768d66 + e79ac826 x64 @@ -155,9 +155,9 @@ 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/CefSharp.WinForms.Example/packages.config b/CefSharp.WinForms.Example/packages.config index 1a95f9f5a3..a97537c46b 100644 --- a/CefSharp.WinForms.Example/packages.config +++ b/CefSharp.WinForms.Example/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file diff --git a/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj b/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj index b7c20a44a7..37e8ff465a 100644 --- a/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj +++ b/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj @@ -21,7 +21,7 @@ 3.5 Client - afb6365a + eef213f7 true @@ -166,9 +166,9 @@ 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/CefSharp.Wpf.Example/packages.config b/CefSharp.Wpf.Example/packages.config index 1a95f9f5a3..a97537c46b 100644 --- a/CefSharp.Wpf.Example/packages.config +++ b/CefSharp.Wpf.Example/packages.config @@ -1,5 +1,5 @@  - - + + \ No newline at end of file diff --git a/NuGet.config b/NuGet.config index fdbce8603f..d9430d5a84 100644 --- a/NuGet.config +++ b/NuGet.config @@ -3,6 +3,7 @@ + diff --git a/build.ps1 b/build.ps1 index 696463bdcc..f40759b71a 100644 --- a/build.ps1 +++ b/build.ps1 @@ -7,7 +7,7 @@ param( [Parameter(Position = 2)] [string] $AssemblyVersion = "39.0.0", [Parameter(Position = 3)] - [string] $RedistVersion = "3.2171.1902-pre0" + [string] $RedistVersion = "3.2171.1949" ) $WorkingDir = split-path -parent $MyInvocation.MyCommand.Definition From 048ff475e5ac6d48c69cd96b1e2e7893f0498288 Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 19 Dec 2014 14:09:17 +1000 Subject: [PATCH 074/134] When OnTitleChange and browser IsPopup then set the Window title directly --- CefSharp.Core/Internals/ClientAdapter.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CefSharp.Core/Internals/ClientAdapter.cpp b/CefSharp.Core/Internals/ClientAdapter.cpp index 910f09411a..2497f05d45 100644 --- a/CefSharp.Core/Internals/ClientAdapter.cpp +++ b/CefSharp.Core/Internals/ClientAdapter.cpp @@ -77,7 +77,16 @@ namespace CefSharp void ClientAdapter::OnTitleChange(CefRefPtr browser, const CefString& title) { - _browserControl->SetTitle(StringUtils::ToClr(title)); + if(browser->IsPopup()) + { + // Set the popup window title + auto hwnd = browser->GetHost()->GetWindowHandle(); + SetWindowText(hwnd, std::wstring(title).c_str()); + } + else + { + _browserControl->SetTitle(StringUtils::ToClr(title)); + } } bool ClientAdapter::OnTooltip(CefRefPtr browser, CefString& text) From 450ee3995d1f6e9140ac6627399b2594d0ab0e72 Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 19 Dec 2014 16:30:59 +1000 Subject: [PATCH 075/134] Close open popups (if any) when ManagedCefBrowserAdapter is disposed --- CefSharp.Core/Internals/ClientAdapter.cpp | 38 ++++++++++++++++++++--- CefSharp.Core/Internals/ClientAdapter.h | 3 ++ CefSharp.Core/ManagedCefBrowserAdapter.h | 12 +++++-- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/CefSharp.Core/Internals/ClientAdapter.cpp b/CefSharp.Core/Internals/ClientAdapter.cpp index 2497f05d45..19678dc4e9 100644 --- a/CefSharp.Core/Internals/ClientAdapter.cpp +++ b/CefSharp.Core/Internals/ClientAdapter.cpp @@ -17,6 +17,19 @@ namespace CefSharp { namespace Internals { + void ClientAdapter::CloseAllPopups(bool forceClose) + { + if (!_popupBrowsers.empty()) + { + // Request that any popup browsers close. + auto it = _popupBrowsers.begin(); + for (; it != _popupBrowsers.end(); ++it) + { + (*it)->GetHost()->CloseBrowser(forceClose); + } + } + } + bool ClientAdapter::OnBeforePopup(CefRefPtr browser, CefRefPtr frame, const CefString& target_url, const CefString& target_frame_name, const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, CefRefPtr& client, CefBrowserSettings& settings, bool* no_javascript_access) @@ -34,7 +47,12 @@ namespace CefSharp void ClientAdapter::OnAfterCreated(CefRefPtr browser) { - if (!browser->IsPopup()) + if (browser->IsPopup()) + { + // Add to the list of popup browsers. + _popupBrowsers.push_back(browser); + } + else { _browserHwnd = browser->GetHost()->GetWindowHandle(); _cefBrowser = browser; @@ -49,7 +67,20 @@ namespace CefSharp void ClientAdapter::OnBeforeClose(CefRefPtr browser) { - if (_browserHwnd == browser->GetHost()->GetWindowHandle()) + if (browser->IsPopup()) + { + // Remove from the browser popup list. + auto it = _popupBrowsers.begin(); + for (; it != _popupBrowsers.end(); ++it) + { + if ((*it)->IsSame(browser)) + { + _popupBrowsers.erase(it); + break; + } + } + } + else if (_browserHwnd == browser->GetHost()->GetWindowHandle()) { ILifeSpanHandler^ handler = _browserControl->LifeSpanHandler; if (handler != nullptr) @@ -270,7 +301,7 @@ namespace CefSharp { auto mimeType = StringUtils::ToNative(resourceHandler->MimeType); auto statusText = StringUtils::ToNative(resourceHandler->StatusText); - + CefRefPtr streamAdapter = new StreamAdapter(resourceHandler->Stream); CefRefPtr stream = CefStreamReader::CreateForHandler(static_cast>(streamAdapter)); @@ -494,6 +525,5 @@ namespace CefSharp return handler->OnDragEnter(_browserControl, dragDataWrapper, (CefSharp::DragOperationsMask)mask); } - } } diff --git a/CefSharp.Core/Internals/ClientAdapter.h b/CefSharp.Core/Internals/ClientAdapter.h index 8ddcbfb026..272d03423a 100644 --- a/CefSharp.Core/Internals/ClientAdapter.h +++ b/CefSharp.Core/Internals/ClientAdapter.h @@ -5,6 +5,7 @@ #pragma once #include "Stdafx.h" +#include #include "include/cef_app.h" #include "include/cef_client.h" #include "include/cef_render_process_handler.h" @@ -36,6 +37,7 @@ namespace CefSharp gcroot^> _onAfterBrowserCreated; HWND _browserHwnd; CefRefPtr _cefBrowser; + std::list> _popupBrowsers; gcroot _tooltip; @@ -57,6 +59,7 @@ namespace CefSharp HWND GetBrowserHwnd() { return _browserHwnd; } CefRefPtr GetCefBrowser() { return _cefBrowser; } + void CloseAllPopups(bool forceClose); // CefClient virtual CefRefPtr GetLifeSpanHandler() OVERRIDE{ return this; } diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 6d6e7793af..10317fde4e 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -29,7 +29,8 @@ namespace CefSharp protected: virtual void DoDispose(bool isDisposing) override { - Close(); + CloseAllPopups(true); + Close(true); _renderClientAdapter = nullptr; if (_browserProcessServiceHost != nullptr) @@ -66,16 +67,21 @@ namespace CefSharp } } - void Close() + void Close(bool forceClose) { auto cefHost = _renderClientAdapter->TryGetCefHost(); if (cefHost != nullptr) { - cefHost->CloseBrowser(true); + cefHost->CloseBrowser(forceClose); } } + void CloseAllPopups(bool forceClose) + { + _renderClientAdapter->CloseAllPopups(forceClose); + } + void LoadUrl(String^ address) { auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); From 5543b21df5def33c4320108f07e31d9c80a64306 Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 22 Dec 2014 17:08:12 +1000 Subject: [PATCH 076/134] Whitespace fixes --- .../Internals/CefContextMenuParamsWrapper.cpp | 20 ------------------- .../Internals/CefContextMenuParamsWrapper.h | 4 +--- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/CefSharp.Core/Internals/CefContextMenuParamsWrapper.cpp b/CefSharp.Core/Internals/CefContextMenuParamsWrapper.cpp index c61055aae8..31507a7361 100644 --- a/CefSharp.Core/Internals/CefContextMenuParamsWrapper.cpp +++ b/CefSharp.Core/Internals/CefContextMenuParamsWrapper.cpp @@ -9,8 +9,6 @@ namespace CefSharp { namespace Internals { - - int CefContextMenuParamsWrapper::YCoord::get() { return _wrappedInfo->GetYCoord(); @@ -21,41 +19,34 @@ namespace CefSharp return _wrappedInfo->GetXCoord(); } - //// TODO: Implement: ////virtual TypeFlags GetTypeFlags() OVERRIDE; - String^ CefContextMenuParamsWrapper::LinkUrl::get() { return StringUtils::ToClr(_wrappedInfo->GetLinkUrl()); } - String^ CefContextMenuParamsWrapper::UnfilteredLinkUrl::get() { return StringUtils::ToClr(_wrappedInfo->GetUnfilteredLinkUrl()); } - String^ CefContextMenuParamsWrapper::SourceUrl::get() { return StringUtils::ToClr(_wrappedInfo->GetSourceUrl()); } - bool CefContextMenuParamsWrapper::HasImageContents::get() { return _wrappedInfo->HasImageContents(); } - String^ CefContextMenuParamsWrapper::PageUrl::get() { return StringUtils::ToClr(_wrappedInfo->GetPageUrl()); } - String^ CefContextMenuParamsWrapper::FrameUrl::get() { return StringUtils::ToClr(_wrappedInfo->GetFrameUrl()); @@ -66,18 +57,15 @@ namespace CefSharp return StringUtils::ToClr(_wrappedInfo->GetFrameCharset()); } - //// TODO: Implement: ////virtual MediaType GetMediaType() OVERRIDE; ////virtual MediaStateFlags GetMediaStateFlags() OVERRIDE; - String^ CefContextMenuParamsWrapper::SelectionText::get() { return StringUtils::ToClr(_wrappedInfo->GetSelectionText()); } - String^ CefContextMenuParamsWrapper::MisspelledWord::get() { return StringUtils::ToClr(_wrappedInfo->GetMisspelledWord()); @@ -88,11 +76,9 @@ namespace CefSharp return _wrappedInfo->GetMisspellingHash(); } - //// TODO: Implement: ////virtual bool GetDictionarySuggestions(std::vector& suggestions) OVERRIDE; - List^ CefContextMenuParamsWrapper::DictionarySuggestions::get() { std::vector& dictionarySuggestions = std::vector(); @@ -101,9 +87,6 @@ namespace CefSharp return StringUtils::ToClr(dictionarySuggestions); } - - - bool CefContextMenuParamsWrapper::IsEditable::get() { return _wrappedInfo->IsEditable(); @@ -114,10 +97,7 @@ namespace CefSharp return _wrappedInfo->IsSpellCheckEnabled(); } - //// TODO: Implement: ////virtual EditStateFlags GetEditStateFlags() OVERRIDE; - - } } diff --git a/CefSharp.Core/Internals/CefContextMenuParamsWrapper.h b/CefSharp.Core/Internals/CefContextMenuParamsWrapper.h index 85d4d79631..185bc941ba 100644 --- a/CefSharp.Core/Internals/CefContextMenuParamsWrapper.h +++ b/CefSharp.Core/Internals/CefContextMenuParamsWrapper.h @@ -45,7 +45,7 @@ namespace CefSharp virtual property List^ DictionarySuggestions { List^ get(); } - + // TODO: Implement: //virtual bool GetDictionarySuggestions(std::vector& suggestions) OVERRIDE; virtual property bool IsEditable { bool get(); } @@ -53,8 +53,6 @@ namespace CefSharp // TODO: Implement: //virtual EditStateFlags GetEditStateFlags() OVERRIDE; - - }; } } From e6e85f67eb20dc105e1b75dcbb3a8eb67d61d83d Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 22 Dec 2014 17:23:33 +1000 Subject: [PATCH 077/134] Add license disclaimer Cleanup formatting --- CefSharp.Wpf.Example/Handlers/MenuHandler.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/CefSharp.Wpf.Example/Handlers/MenuHandler.cs b/CefSharp.Wpf.Example/Handlers/MenuHandler.cs index 2a14de61d8..1df98e6a8c 100644 --- a/CefSharp.Wpf.Example/Handlers/MenuHandler.cs +++ b/CefSharp.Wpf.Example/Handlers/MenuHandler.cs @@ -1,23 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +using System; namespace CefSharp.Wpf.Example.Handlers { - public class MenuHandler : IMenuHandler { - public bool OnBeforeContextMenu(IWebBrowser browser, IContextMenuParams parameters) { - Console.WriteLine("Context menu opened"); Console.WriteLine(parameters.MisspelledWord); return true; } - - } } From 78bbc23bd22f15b0120d5c53f55afbc54bde704f Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 22 Dec 2014 17:24:07 +1000 Subject: [PATCH 078/134] Implement AddWordToDictionary and ReplaceMisspelling in CefSharp.Offscreen --- CefSharp.OffScreen/ChromiumWebBrowser.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index 7aff142d5d..34f1d41722 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -207,12 +207,12 @@ public void CloseDevTools() public void ReplaceMisspelling(string word) { - throw new NotImplementedException(); + managedCefBrowserAdapter.ReplaceMisspelling(word); } public void AddWordToDictionary(string word) { - throw new NotImplementedException(); + managedCefBrowserAdapter.AddWordToDictionary(word); } public string Address { get; set; } From 6ecd2239df5278ef99a1ad1cf43ab15ff446177e Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 22 Dec 2014 17:26:11 +1000 Subject: [PATCH 079/134] Remove testing localPackages entry from NuGet.config --- NuGet.config | 1 - 1 file changed, 1 deletion(-) diff --git a/NuGet.config b/NuGet.config index d9430d5a84..fdbce8603f 100644 --- a/NuGet.config +++ b/NuGet.config @@ -3,7 +3,6 @@ - From 48aa8181392917101bcbb84d0487c990c0a93fbd Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 22 Dec 2014 17:28:06 +1000 Subject: [PATCH 080/134] Remove old files (including nunit) --- clean.sh | 7 ------- nunit/nunit-console-runner.dll | Bin 36864 -> 0 bytes nunit/nunit-console-x86.exe | Bin 5120 -> 0 bytes nunit/nunit.core.dll | Bin 147456 -> 0 bytes nunit/nunit.core.interfaces.dll | Bin 57344 -> 0 bytes nunit/nunit.framework.dll | Bin 143360 -> 0 bytes nunit/nunit.util.dll | Bin 131072 -> 0 bytes test.sh | 8 -------- 8 files changed, 15 deletions(-) delete mode 100755 clean.sh delete mode 100644 nunit/nunit-console-runner.dll delete mode 100644 nunit/nunit-console-x86.exe delete mode 100644 nunit/nunit.core.dll delete mode 100644 nunit/nunit.core.interfaces.dll delete mode 100644 nunit/nunit.framework.dll delete mode 100644 nunit/nunit.util.dll delete mode 100644 test.sh diff --git a/clean.sh b/clean.sh deleted file mode 100755 index 07171770d2..0000000000 --- a/clean.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -# -# Purpose: Utility script which makes it easier to switch between VS2010 and VS2012 (since they share the same output folder) -# -rm -rf $(gfind -iname bin -or -iname obj) -rm -f Debug/CefSharp*.* -rm -f Release/CefSharp*.* diff --git a/nunit/nunit-console-runner.dll b/nunit/nunit-console-runner.dll deleted file mode 100644 index 057145566545140479a265c8ff856985d6404e26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36864 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 diff --git a/nunit/nunit-console-x86.exe b/nunit/nunit-console-x86.exe deleted file mode 100644 index 06279acb54f6d4aefa7482e6d20f04e69581fd39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5120 zcmeHKO>88^6@G1djn})j%#t8hh^2N+zzd%Ccx)Dj*zC-Xz2L=vc*ZvQ6K?mEXFBfb z9;$o%lLPXFNKquThloR@NIB*ZMM<;~hzKEWIRt6XNQpQn2NWqeB!`giy`J%mV>?=; zNZ~-)_3G!ndiA|mue#nWe(Mf(6HyQ9XP*(hiL#ohr>0yd2*OxxX=NIL@&YxxTvWBNtnGn;{wJEMSLTQotZw@FQG2|0NwRj4^sCJIegf*U=-&n+FIVxCJk<=!M3lK*zw93~<(1-(V?=ZH2R zXij!En?x5o$M@S;3H+9LAI2}W259YA@5g9=+zX;m+14g*^rR?2vQ1=Mj09T_oerO1 zBqay*w$XkFLBYC-Y1VZKwWH*SZgvc%TW7zbFt#o_M|DN?`*Z9&B8!O8eXjCQ#u5xz z`yh3V4B!C!pP}BTuXK$JqW|>G;_aIjYer$LyIDJ9Kbv_j`y9`lBOmlG*u!tYEwEt- zb+{NCFQ`N;kwKuc3x?N8XjM0_8A?|bMPfdd+BAGg)?H>0{xNDp9}p^=*L3;E_BFZnQKCqg}!A4 zRxkZh=%1`vXzlHKO7th%6MqbmqNm^i9<3;5zfG%xpemyuJhB066TIJrb2sQKbXn+C zq1S|t3;nv#ywG`}uL%7n=w)(1hsYE9y6kaY`ifk-LN+~v)~1K30QxA+gAUWHpcg0u zIzf+HHh8x{Uly4nZJ_^c+O$Tg=a7BJVbeVZg7OC#nRqi9Tl5X-bV?1=UlUglO)rM! zhOb|spb>a++6{v!^mTfF>bkA>H5Gg(ipFVa4NSX`FjpHvpbga`H#EMtMa6?C)-_t* z`kr=UT6DaCY&Q-KIR-(LaP3vS?St)w0p+7e*S7qFk{A0rA0ybd8nHf_p4E|SygG}X zWER3&-3bm(GFA-iaO0DVLRddAUZr{pt7M$At~qAsz5}#`5|sh-(!OivwD;S{M=9pT_~*(Q3@qN`$t!h`InxD{9`+*Tdd4q0>|YhTAFcs!e#cosgh z$xqVm54Z!h*dyz$(&3A(j=MC;F?wu^H_odBwtq_{IeJ$5g zuB_H}+2`**GLWy4%1Q4_^8fHam%OJ6vHu9RpGvZ+4j{=(wQ|OM^^|#DeAuBO=_Vih zI~e>dM|2PGcB|Bp5B@n}%hbJ|Nwn+8(Ov_c!)sNgs0v$1 za37yjG=kY{_}DP23~0L98wXMaUKQF5PbJw#G@Uzui2I2>lJ9 zSFl#o9_>KC0UgE6BKofEtFbR*V7U^cLgDAd>uj}$`Mhw~!851 zOFOOzLUz~_mlQQUas&CnSF zM*}AkcSL3>A(%k_>D7@S}Wa3Po-28J3-m;!$8lZ4s?{d@xnm=G*VwlR238i(M+mg zg6AW*ij*-**F4vRQMk=1bM1L2s@c2aDOGatB4RUn2b9d*I*Ecmq)Y diff --git a/nunit/nunit.core.dll b/nunit/nunit.core.dll deleted file mode 100644 index 5a727d5dcc28df5106df9df2d4a31f38370001f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147456 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%0D~zdgx%xM0c^&Hu>0viCtV^g8^r!fae1@gCc(c7 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 Y3~XXx69bzV*u=ml1~xJ9|0D+fH)&6#=Kufz diff --git a/nunit/nunit.core.interfaces.dll b/nunit/nunit.core.interfaces.dll deleted file mode 100644 index 47aa177ee8b9217e77c428d872400c16a0bf6e90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 57344 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 U6$z|JU_}Be5?GPI|3eA4pEWoSqY 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 F{{V^2iOv83 diff --git a/test.sh b/test.sh deleted file mode 100644 index e7aae369b7..0000000000 --- a/test.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -CONF=$1 - -for dll in `ls $CONF/*.Test.dll` -do - ./nunit/nunit-console-x86.exe -domain=None $dll -done From 4baa1d65dccde60c250eaf57f923429776a28a29 Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 22 Dec 2014 22:00:00 +1000 Subject: [PATCH 081/134] Remove "--type=renderer" check as the rendering is done by the browsersubprocess --- CefSharp.Example/CefExample.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/CefSharp.Example/CefExample.cs b/CefSharp.Example/CefExample.cs index 6a00fac224..f2dca272c4 100644 --- a/CefSharp.Example/CefExample.cs +++ b/CefSharp.Example/CefExample.cs @@ -35,14 +35,7 @@ public static void Init() if (!Cef.Initialize(settings)) { - if (Environment.GetCommandLineArgs().Contains("--type=renderer")) - { - Environment.Exit(0); - } - else - { - return; - } + throw new Exception("Unable to Initialize Cef"); } } From d366634f1856b0c386e4acf40432f412b2e72232 Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 22 Dec 2014 22:07:25 +1000 Subject: [PATCH 082/134] Remove unnecessary call to CefExecuteProcess. Relevant upstream comment "It can be used to run secondary processes from the browser client executable (default behavior) or from a separate executable specified by the CefSettings.browser_subprocess_path value" We use a separate browsersubprocess which has the relevant call. --- CefSharp.Core/Cef.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/CefSharp.Core/Cef.h b/CefSharp.Core/Cef.h index 920312a99c..5e7928b355 100644 --- a/CefSharp.Core/Cef.h +++ b/CefSharp.Core/Cef.h @@ -146,15 +146,6 @@ namespace CefSharp CefMainArgs main_args; CefRefPtr app(new CefSharpApp(cefSettings)); - int exitCode = CefExecuteProcess(main_args, app.get(), NULL); - - if (exitCode >= 0) - { - // Something went "wrong", but it may also be caused in the case where we are the secondary process, so we - // can't really throw exceptions or anything like that. - return false; - } - success = CefInitialize(main_args, *(cefSettings->_cefSettings), app.get(), NULL); app->CompleteSchemeRegistrations(); _initialized = success; From 48c362552360f5ebb8e6246bfb8610dbbf74d8f3 Mon Sep 17 00:00:00 2001 From: amaitland Date: Thu, 18 Dec 2014 12:29:16 +1000 Subject: [PATCH 083/134] Import keyboard SourceHook code from cefclient to comprehensively handle key modifiers Simplified OnPreviewKey so that it only deals with keys that would have been handled by WPF --- CefSharp.Core/ManagedCefBrowserAdapter.h | 128 +++++++++++++++++++---- CefSharp.Wpf/ChromiumWebBrowser.cs | 51 ++++----- 2 files changed, 135 insertions(+), 44 deletions(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 10317fde4e..8f8f3d52df 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -163,7 +163,7 @@ namespace CefSharp } } - bool SendKeyEvent(int message, int wParam, CefEventFlags modifiers) + bool SendKeyEvent(int message, int wParam, int lParam) { auto cefHost = _renderClientAdapter->TryGetCefHost(); @@ -171,27 +171,117 @@ namespace CefSharp { return false; } - else - { - CefKeyEvent keyEvent; - if (message == WM_CHAR) - keyEvent.type = KEYEVENT_CHAR; - else if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN) - keyEvent.type = KEYEVENT_KEYDOWN; - else if (message == WM_KEYUP || message == WM_SYSKEYUP) - keyEvent.type = KEYEVENT_KEYUP; - keyEvent.windows_key_code = keyEvent.native_key_code = wParam; - keyEvent.is_system_key = - message == WM_SYSKEYDOWN || - message == WM_SYSKEYUP || - message == WM_SYSCHAR; + CefKeyEvent keyEvent; + keyEvent.windows_key_code = wParam; + keyEvent.native_key_code = lParam; + keyEvent.is_system_key = message == WM_SYSCHAR || + message == WM_SYSKEYDOWN || + message == WM_SYSKEYUP; - keyEvent.modifiers = (uint32)modifiers; - - cefHost->SendKeyEvent(keyEvent); - return true; + if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN) + { + keyEvent.type = KEYEVENT_RAWKEYDOWN; } + else if (message == WM_KEYUP || message == WM_SYSKEYUP) + { + keyEvent.type = KEYEVENT_KEYUP; + } + else + { + keyEvent.type = KEYEVENT_CHAR; + } + keyEvent.modifiers = GetCefKeyboardModifiers(wParam, lParam); + + cefHost->SendKeyEvent(keyEvent); + + return true; + } + + bool isKeyDown(WPARAM wparam) + { + return (GetKeyState(wparam) & 0x8000) != 0; + } + + int GetCefKeyboardModifiers(WPARAM wparam, LPARAM lparam) + { + int modifiers = 0; + if (isKeyDown(VK_SHIFT)) + modifiers |= EVENTFLAG_SHIFT_DOWN; + if (isKeyDown(VK_CONTROL)) + modifiers |= EVENTFLAG_CONTROL_DOWN; + if (isKeyDown(VK_MENU)) + modifiers |= EVENTFLAG_ALT_DOWN; + + // Low bit set from GetKeyState indicates "toggled". + if (::GetKeyState(VK_NUMLOCK) & 1) + modifiers |= EVENTFLAG_NUM_LOCK_ON; + if (::GetKeyState(VK_CAPITAL) & 1) + modifiers |= EVENTFLAG_CAPS_LOCK_ON; + + switch (wparam) { + case VK_RETURN: + if ((lparam >> 16) & KF_EXTENDED) + modifiers |= EVENTFLAG_IS_KEY_PAD; + break; + case VK_INSERT: + case VK_DELETE: + case VK_HOME: + case VK_END: + case VK_PRIOR: + case VK_NEXT: + case VK_UP: + case VK_DOWN: + case VK_LEFT: + case VK_RIGHT: + if (!((lparam >> 16) & KF_EXTENDED)) + modifiers |= EVENTFLAG_IS_KEY_PAD; + break; + case VK_NUMLOCK: + case VK_NUMPAD0: + case VK_NUMPAD1: + case VK_NUMPAD2: + case VK_NUMPAD3: + case VK_NUMPAD4: + case VK_NUMPAD5: + case VK_NUMPAD6: + case VK_NUMPAD7: + case VK_NUMPAD8: + case VK_NUMPAD9: + case VK_DIVIDE: + case VK_MULTIPLY: + case VK_SUBTRACT: + case VK_ADD: + case VK_DECIMAL: + case VK_CLEAR: + modifiers |= EVENTFLAG_IS_KEY_PAD; + break; + case VK_SHIFT: + if (isKeyDown(VK_LSHIFT)) + modifiers |= EVENTFLAG_IS_LEFT; + else if (isKeyDown(VK_RSHIFT)) + modifiers |= EVENTFLAG_IS_RIGHT; + break; + case VK_CONTROL: + if (isKeyDown(VK_LCONTROL)) + modifiers |= EVENTFLAG_IS_LEFT; + else if (isKeyDown(VK_RCONTROL)) + modifiers |= EVENTFLAG_IS_RIGHT; + break; + case VK_MENU: + if (isKeyDown(VK_LMENU)) + modifiers |= EVENTFLAG_IS_LEFT; + else if (isKeyDown(VK_RMENU)) + modifiers |= EVENTFLAG_IS_RIGHT; + break; + case VK_LWIN: + modifiers |= EVENTFLAG_IS_LEFT; + break; + case VK_RWIN: + modifiers |= EVENTFLAG_IS_RIGHT; + break; + } + return modifiers; } void OnMouseMove(int x, int y, bool mouseLeave, CefEventFlags modifiers) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index af7095448d..bb860493c6 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -7,7 +7,6 @@ using Microsoft.Win32.SafeHandles; using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; @@ -21,14 +20,6 @@ namespace CefSharp.Wpf { public class ChromiumWebBrowser : ContentControl, IRenderWebBrowser, IWpfWebBrowser { - private static readonly Key[] KeysToSendtoBrowser = - { - Key.Tab, - Key.Home, Key.End, - Key.Left, Key.Right, - Key.Up, Key.Down - }; - private HwndSource source; private HwndSourceHook sourceHook; private DispatcherTimer tooltipTimer; @@ -636,6 +627,7 @@ private IntPtr SourceHook(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam case WM.KEYUP: case WM.CHAR: case WM.IME_CHAR: + { if (!IsKeyboardFocused) { break; @@ -649,12 +641,10 @@ private IntPtr SourceHook(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam return IntPtr.Zero; } - if (managedCefBrowserAdapter.SendKeyEvent(message, wParam.ToInt32(), 0)) - { - handled = true; - } - + handled = managedCefBrowserAdapter.SendKeyEvent(message, wParam.ToInt32(), lParam.ToInt32()); + break; + } } return IntPtr.Zero; @@ -860,30 +850,41 @@ private void OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) protected override void OnPreviewKeyDown(KeyEventArgs e) { - OnPreviewKey(e); + if (e.Handled) + { + base.OnPreviewKeyDown(e); + } + else + { + OnPreviewKey(e); + } } protected override void OnPreviewKeyUp(KeyEventArgs e) { - OnPreviewKey(e); + if (e.Handled) + { + base.OnPreviewKeyUp(e); + } + else + { + OnPreviewKey(e); + } } private void OnPreviewKey(KeyEventArgs e) { - // For some reason, not all kinds of keypresses triggers the appropriate WM_ messages handled by our SourceHook, so - // we have to handle these extra keys here. Hooking the Tab key like this makes the tab focusing in essence work like + // As KeyDown and KeyUp bubble, it appears they're being handled before they get a chance to + // trigger the appropriate WM_ messages handled by our SourceHook, so we have to handle these extra keys here. + // Hooking the Tab key like this makes the tab focusing in essence work like // KeyboardNavigation.TabNavigation="Cycle"; you will never be able to Tab out of the web browser control. - var modifiers = GetModifiers(e); - var sendKey = KeysToSendtoBrowser.Contains(e.Key); - - if (sendKey || modifiers > 0) + if (e.Key == Key.Tab || e.Key == Key.Home || e.Key == Key.End || e.Key == Key.Up || e.Key == Key.Down) { + var modifiers = GetModifiers(e); var message = (int)(e.IsDown ? WM.KEYDOWN : WM.KEYUP); var virtualKey = KeyInterop.VirtualKeyFromKey(e.Key); - managedCefBrowserAdapter.SendKeyEvent(message, virtualKey, modifiers); - - e.Handled = sendKey; + e.Handled = managedCefBrowserAdapter.SendKeyEvent(message, virtualKey, (int)modifiers); } } From 1f5c5a974073346be16d1ff3516c5d5ae9d38169 Mon Sep 17 00:00:00 2001 From: amaitland Date: Thu, 18 Dec 2014 12:30:40 +1000 Subject: [PATCH 084/134] Cleanup Adding/Removing of SourceHook by using PresentationSourceChangedHandler --- CefSharp.Wpf/ChromiumWebBrowser.cs | 77 +++++++++++++----------------- 1 file changed, 32 insertions(+), 45 deletions(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index bb860493c6..ffc065c036 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -329,10 +329,11 @@ public void Dispose() protected virtual void Dispose(bool isdisposing) { + PresentationSource.RemoveSourceChangedHandler(this, PresentationSourceChangedHandler); + ResourceHandler = null; Loaded -= OnLoaded; - Unloaded -= OnUnloaded; GotKeyboardFocus -= OnGotKeyboardFocus; LostKeyboardFocus -= OnLostKeyboardFocus; @@ -341,8 +342,6 @@ protected virtual void Dispose(bool isdisposing) Cef.RemoveDisposable(this); - RemoveSourceHook(); - foreach (var disposable in disposables) { disposable.Dispose(); @@ -424,7 +423,6 @@ public ChromiumWebBrowser() Dispatcher.BeginInvoke((Action)(() => WebBrowser = this)); Loaded += OnLoaded; - Unloaded += OnUnloaded; GotKeyboardFocus += OnGotKeyboardFocus; LostKeyboardFocus += OnLostKeyboardFocus; @@ -436,7 +434,6 @@ public ChromiumWebBrowser() toolTip.Visibility = Visibility.Collapsed; toolTip.Closed += OnTooltipClosed; - BackCommand = new DelegateCommand(Back, () => CanGoBack); ForwardCommand = new DelegateCommand(Forward, () => CanGoForward); ReloadCommand = new DelegateCommand(Reload, () => CanReload); @@ -461,6 +458,8 @@ public ChromiumWebBrowser() disposables.Add(new DisposableEventWrapper(this, ActualWidthProperty, OnActualSizeChanged)); ResourceHandler = new DefaultResourceHandler(); + + PresentationSource.AddSourceChangedHandler(this, PresentationSourceChangedHandler); } ~ChromiumWebBrowser() @@ -468,6 +467,31 @@ public ChromiumWebBrowser() Dispose(false); } + private void PresentationSourceChangedHandler(object sender, SourceChangedEventArgs args) + { + if (args.NewSource != null) + { + var newSource = (HwndSource)args.NewSource; + + source = newSource; + + if (source != null) + { + matrix = source.CompositionTarget.TransformToDevice; + sourceHook = SourceHook; + source.AddHook(sourceHook); + } + } + else if (args.OldSource != null) + { + if (source != null && sourceHook != null) + { + source.RemoveHook(sourceHook); + source = null; + } + } + } + private void CreateOffscreenBrowserWhenActualSizeChanged() { if (browserCreated || System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) @@ -500,10 +524,6 @@ private void OnActualSizeChanged(object sender, EventArgs e) private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs args) { - // If the control was not rendered yet when we tried to set up the source hook, it may have failed (since it couldn't - // lookup the HwndSource), so we need to retry it whenever visibility changes. - AddSourceHookIfNotAlreadyPresent(); - var isVisible = (bool)args.NewValue; managedCefBrowserAdapter.WasHidden(!isVisible); } @@ -519,21 +539,12 @@ private void OnLoaded(object sender, RoutedEventArgs routedEventArgs) { CleanupElement = Window.GetWindow(this); } - - AddSourceHookIfNotAlreadyPresent(); - } - - private void OnUnloaded(object sender, RoutedEventArgs routedEventArgs) - { - RemoveSourceHook(); } public override void OnApplyTemplate() { base.OnApplyTemplate(); - AddSourceHookIfNotAlreadyPresent(); - CheckIsNonStandardDpi(); // Create main window @@ -587,36 +598,12 @@ private void CheckIsNonStandardDpi() ); } - private void AddSourceHookIfNotAlreadyPresent() - { - if (source != null) - { - return; - } - - source = (HwndSource)PresentationSource.FromVisual(this); - - if (source != null) - { - matrix = source.CompositionTarget.TransformToDevice; - sourceHook = SourceHook; - source.AddHook(sourceHook); - } - } - - private void RemoveSourceHook() + private IntPtr SourceHook(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam, ref bool handled) { - if (source != null && - sourceHook != null) + if(handled) { - source.RemoveHook(sourceHook); - source = null; + return IntPtr.Zero; } - } - - private IntPtr SourceHook(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam, ref bool handled) - { - handled = false; switch ((WM)message) { From 061c350a9ccd5249d66d249b3d210d67c0f80d67 Mon Sep 17 00:00:00 2001 From: amaitland Date: Thu, 18 Dec 2014 12:44:38 +1000 Subject: [PATCH 085/134] Improve formatting and include comment about source code origin --- CefSharp.Core/ManagedCefBrowserAdapter.h | 171 ++++++++++++----------- 1 file changed, 87 insertions(+), 84 deletions(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 8f8f3d52df..085d519217 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -25,7 +25,7 @@ namespace CefSharp BrowserProcessServiceHost^ _browserProcessServiceHost; IWebBrowserInternal^ _webBrowserInternal; JavascriptObjectRepository^ _javaScriptObjectRepository; - + protected: virtual void DoDispose(bool isDisposing) override { @@ -200,88 +200,91 @@ namespace CefSharp bool isKeyDown(WPARAM wparam) { - return (GetKeyState(wparam) & 0x8000) != 0; + return (GetKeyState(wparam) & 0x8000) != 0; } + //Code imported from + //https://bitbucket.org/chromiumembedded/branches-2062-cef3/src/a073e92426b3967f1fc2f1d3fd7711d809eeb03a/tests/cefclient/cefclient_osr_widget_win.cpp?at=master#cl-361 int GetCefKeyboardModifiers(WPARAM wparam, LPARAM lparam) { - int modifiers = 0; - if (isKeyDown(VK_SHIFT)) - modifiers |= EVENTFLAG_SHIFT_DOWN; - if (isKeyDown(VK_CONTROL)) - modifiers |= EVENTFLAG_CONTROL_DOWN; - if (isKeyDown(VK_MENU)) - modifiers |= EVENTFLAG_ALT_DOWN; - - // Low bit set from GetKeyState indicates "toggled". - if (::GetKeyState(VK_NUMLOCK) & 1) - modifiers |= EVENTFLAG_NUM_LOCK_ON; - if (::GetKeyState(VK_CAPITAL) & 1) - modifiers |= EVENTFLAG_CAPS_LOCK_ON; - - switch (wparam) { - case VK_RETURN: - if ((lparam >> 16) & KF_EXTENDED) - modifiers |= EVENTFLAG_IS_KEY_PAD; - break; - case VK_INSERT: - case VK_DELETE: - case VK_HOME: - case VK_END: - case VK_PRIOR: - case VK_NEXT: - case VK_UP: - case VK_DOWN: - case VK_LEFT: - case VK_RIGHT: - if (!((lparam >> 16) & KF_EXTENDED)) - modifiers |= EVENTFLAG_IS_KEY_PAD; - break; - case VK_NUMLOCK: - case VK_NUMPAD0: - case VK_NUMPAD1: - case VK_NUMPAD2: - case VK_NUMPAD3: - case VK_NUMPAD4: - case VK_NUMPAD5: - case VK_NUMPAD6: - case VK_NUMPAD7: - case VK_NUMPAD8: - case VK_NUMPAD9: - case VK_DIVIDE: - case VK_MULTIPLY: - case VK_SUBTRACT: - case VK_ADD: - case VK_DECIMAL: - case VK_CLEAR: - modifiers |= EVENTFLAG_IS_KEY_PAD; - break; - case VK_SHIFT: - if (isKeyDown(VK_LSHIFT)) - modifiers |= EVENTFLAG_IS_LEFT; - else if (isKeyDown(VK_RSHIFT)) - modifiers |= EVENTFLAG_IS_RIGHT; - break; - case VK_CONTROL: - if (isKeyDown(VK_LCONTROL)) - modifiers |= EVENTFLAG_IS_LEFT; - else if (isKeyDown(VK_RCONTROL)) - modifiers |= EVENTFLAG_IS_RIGHT; - break; - case VK_MENU: - if (isKeyDown(VK_LMENU)) - modifiers |= EVENTFLAG_IS_LEFT; - else if (isKeyDown(VK_RMENU)) - modifiers |= EVENTFLAG_IS_RIGHT; - break; - case VK_LWIN: - modifiers |= EVENTFLAG_IS_LEFT; - break; - case VK_RWIN: - modifiers |= EVENTFLAG_IS_RIGHT; - break; - } - return modifiers; + int modifiers = 0; + if (isKeyDown(VK_SHIFT)) + modifiers |= EVENTFLAG_SHIFT_DOWN; + if (isKeyDown(VK_CONTROL)) + modifiers |= EVENTFLAG_CONTROL_DOWN; + if (isKeyDown(VK_MENU)) + modifiers |= EVENTFLAG_ALT_DOWN; + + // Low bit set from GetKeyState indicates "toggled". + if (::GetKeyState(VK_NUMLOCK) & 1) + modifiers |= EVENTFLAG_NUM_LOCK_ON; + if (::GetKeyState(VK_CAPITAL) & 1) + modifiers |= EVENTFLAG_CAPS_LOCK_ON; + + switch (wparam) + { + case VK_RETURN: + if ((lparam >> 16) & KF_EXTENDED) + modifiers |= EVENTFLAG_IS_KEY_PAD; + break; + case VK_INSERT: + case VK_DELETE: + case VK_HOME: + case VK_END: + case VK_PRIOR: + case VK_NEXT: + case VK_UP: + case VK_DOWN: + case VK_LEFT: + case VK_RIGHT: + if (!((lparam >> 16) & KF_EXTENDED)) + modifiers |= EVENTFLAG_IS_KEY_PAD; + break; + case VK_NUMLOCK: + case VK_NUMPAD0: + case VK_NUMPAD1: + case VK_NUMPAD2: + case VK_NUMPAD3: + case VK_NUMPAD4: + case VK_NUMPAD5: + case VK_NUMPAD6: + case VK_NUMPAD7: + case VK_NUMPAD8: + case VK_NUMPAD9: + case VK_DIVIDE: + case VK_MULTIPLY: + case VK_SUBTRACT: + case VK_ADD: + case VK_DECIMAL: + case VK_CLEAR: + modifiers |= EVENTFLAG_IS_KEY_PAD; + break; + case VK_SHIFT: + if (isKeyDown(VK_LSHIFT)) + modifiers |= EVENTFLAG_IS_LEFT; + else if (isKeyDown(VK_RSHIFT)) + modifiers |= EVENTFLAG_IS_RIGHT; + break; + case VK_CONTROL: + if (isKeyDown(VK_LCONTROL)) + modifiers |= EVENTFLAG_IS_LEFT; + else if (isKeyDown(VK_RCONTROL)) + modifiers |= EVENTFLAG_IS_RIGHT; + break; + case VK_MENU: + if (isKeyDown(VK_LMENU)) + modifiers |= EVENTFLAG_IS_LEFT; + else if (isKeyDown(VK_RMENU)) + modifiers |= EVENTFLAG_IS_RIGHT; + break; + case VK_LWIN: + modifiers |= EVENTFLAG_IS_LEFT; + break; + case VK_RWIN: + modifiers |= EVENTFLAG_IS_RIGHT; + break; + } + return modifiers; } void OnMouseMove(int x, int y, bool mouseLeave, CefEventFlags modifiers) @@ -393,7 +396,7 @@ namespace CefSharp cefHost->StopFinding(clearSelection); } } - + void Reload() { Reload(false); @@ -451,7 +454,7 @@ namespace CefSharp void Cut() { auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); - + if (cefFrame != nullptr) { cefFrame->Cut(); @@ -517,7 +520,7 @@ namespace CefSharp cefFrame->Redo(); } } - + void ExecuteScriptAsync(String^ script) { auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); @@ -536,7 +539,7 @@ namespace CefSharp } auto browser = _renderClientAdapter->GetCefBrowser(); - + if (_browserProcessServiceHost == nullptr && browser == nullptr) { @@ -561,7 +564,7 @@ namespace CefSharp { return cefHost->GetZoomLevel(); } - + return 0; } From 3325daf692feb442b14366b17d60612f4c135d92 Mon Sep 17 00:00:00 2001 From: amaitland Date: Thu, 18 Dec 2014 13:28:41 +1000 Subject: [PATCH 086/134] As per MSDN article's recommendation always call base.OnPreviewKey method so that subscribers are notified. --- CefSharp.Wpf/ChromiumWebBrowser.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index ffc065c036..b839876f45 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -837,26 +837,22 @@ private void OnLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) protected override void OnPreviewKeyDown(KeyEventArgs e) { - if (e.Handled) - { - base.OnPreviewKeyDown(e); - } - else + if (!e.Handled) { OnPreviewKey(e); } + + base.OnPreviewKeyDown(e); } protected override void OnPreviewKeyUp(KeyEventArgs e) { - if (e.Handled) - { - base.OnPreviewKeyUp(e); - } - else + if (!e.Handled) { OnPreviewKey(e); } + + base.OnPreviewKeyUp(e); } private void OnPreviewKey(KeyEventArgs e) From af24c31592aec1aee3617f8af79b4e4e89a98f16 Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 22 Dec 2014 23:16:57 +1000 Subject: [PATCH 087/134] Add license disclaimer to GdiBitmapInfo --- CefSharp.OffScreen/GdiBitmapInfo.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CefSharp.OffScreen/GdiBitmapInfo.cs b/CefSharp.OffScreen/GdiBitmapInfo.cs index 968c72e6c5..a697abeaf1 100644 --- a/CefSharp.OffScreen/GdiBitmapInfo.cs +++ b/CefSharp.OffScreen/GdiBitmapInfo.cs @@ -1,4 +1,8 @@ -using System.Drawing; +// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +using System.Drawing; using CefSharp.Internals; namespace CefSharp.OffScreen From 8b8d97e350e1dd6a65a60fd16f687e656560c1f9 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 08:42:29 +1000 Subject: [PATCH 088/134] Pass in WPF Window handle when creating offscreeen browser --- CefSharp.Core/ManagedCefBrowserAdapter.h | 5 +++-- CefSharp.OffScreen/ChromiumWebBrowser.cs | 2 +- CefSharp.Wpf/ChromiumWebBrowser.cs | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 085d519217..ea36a6f693 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -53,9 +53,10 @@ namespace CefSharp _javaScriptObjectRepository = gcnew JavascriptObjectRepository(); } - void CreateOffscreenBrowser(BrowserSettings^ browserSettings, String^ address) + void CreateOffscreenBrowser(IntPtr^ windowHandle, BrowserSettings^ browserSettings, String^ address) { - HWND hwnd = HWND(); + auto hwnd = static_cast(windowHandle->ToPointer()); + CefWindowInfo window; window.SetAsWindowless(hwnd, TRUE); CefString addressNative = StringUtils::ToNative(address); diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index 29e258ac51..2fca5f7448 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -49,7 +49,7 @@ public ChromiumWebBrowser(string address, BrowserSettings browserSettings = null Cef.AddDisposable(this); managedCefBrowserAdapter = new ManagedCefBrowserAdapter(this); - managedCefBrowserAdapter.CreateOffscreenBrowser(browserSettings ?? new BrowserSettings(), address); + managedCefBrowserAdapter.CreateOffscreenBrowser(IntPtr.Zero, browserSettings ?? new BrowserSettings(), address); } public void Dispose() diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 18324c927e..124703f022 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -496,7 +496,7 @@ private void CreateOffscreenBrowserWhenActualSizeChanged() return; } - managedCefBrowserAdapter.CreateOffscreenBrowser(BrowserSettings, Address); + managedCefBrowserAdapter.CreateOffscreenBrowser(source.Handle, BrowserSettings, Address); browserCreated = true; } From b70a309d353c2055050b4f7ac971a67060330c47 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 08:48:07 +1000 Subject: [PATCH 089/134] Move methods from RenderClientAdapter to ClientAdapter RenderClientAdapter should really only contains methods that relate to `OSR` (not relevant to the WinForms implementation) --- CefSharp.Core/Internals/ClientAdapter.cpp | 51 +++++++++++++++++++ CefSharp.Core/Internals/ClientAdapter.h | 4 ++ CefSharp.Core/Internals/RenderClientAdapter.h | 50 ------------------ 3 files changed, 55 insertions(+), 50 deletions(-) diff --git a/CefSharp.Core/Internals/ClientAdapter.cpp b/CefSharp.Core/Internals/ClientAdapter.cpp index 1bc2d93cc6..8bdb689545 100644 --- a/CefSharp.Core/Internals/ClientAdapter.cpp +++ b/CefSharp.Core/Internals/ClientAdapter.cpp @@ -17,6 +17,57 @@ namespace CefSharp { namespace Internals { + + CefRefPtr ClientAdapter::TryGetCefHost() + { + if (!this->GetCefBrowser().get() || + !this->GetCefBrowser()->GetHost().get()) + { + return nullptr; + } + else + { + return this->GetCefBrowser()->GetHost(); + } + }; + + CefRefPtr ClientAdapter::TryGetCefMainFrame() + { + auto cefBrowser = this->GetCefBrowser().get(); + + if (!cefBrowser) + { + return nullptr; + } + + return cefBrowser->GetMainFrame(); + }; + + void ClientAdapter::ShowDevTools() + { + auto cefHost = TryGetCefHost(); + + if (cefHost != nullptr) + { + CefWindowInfo windowInfo; + CefBrowserSettings settings; + + windowInfo.SetAsPopup(cefHost->GetWindowHandle(), "DevTools"); + + cefHost->ShowDevTools(windowInfo, this, settings, CefPoint()); + } + } + + void ClientAdapter::CloseDevTools() + { + auto cefHost = TryGetCefHost(); + + if (cefHost != nullptr) + { + cefHost->CloseDevTools(); + } + } + void ClientAdapter::CloseAllPopups(bool forceClose) { if (!_popupBrowsers.empty()) diff --git a/CefSharp.Core/Internals/ClientAdapter.h b/CefSharp.Core/Internals/ClientAdapter.h index 272d03423a..330c072457 100644 --- a/CefSharp.Core/Internals/ClientAdapter.h +++ b/CefSharp.Core/Internals/ClientAdapter.h @@ -59,6 +59,10 @@ namespace CefSharp HWND GetBrowserHwnd() { return _browserHwnd; } CefRefPtr GetCefBrowser() { return _cefBrowser; } + CefRefPtr TryGetCefHost(); + CefRefPtr TryGetCefMainFrame(); + void ShowDevTools(); + void CloseDevTools(); void CloseAllPopups(bool forceClose); // CefClient diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index 427132c082..4f81dc181f 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -106,56 +106,6 @@ namespace CefSharp _renderWebBrowser->SetCursor((IntPtr)cursor); }; - CefRefPtr TryGetCefHost() - { - if (!this->GetCefBrowser().get() || - !this->GetCefBrowser()->GetHost().get()) - { - return nullptr; - } - else - { - return this->GetCefBrowser()->GetHost(); - } - }; - - CefRefPtr TryGetCefMainFrame() - { - auto cefBrowser = this->GetCefBrowser().get(); - - if (!cefBrowser) - { - return nullptr; - } - - return cefBrowser->GetMainFrame(); - }; - - void ShowDevTools() - { - auto cefHost = TryGetCefHost(); - - if (cefHost != nullptr) - { - CefWindowInfo windowInfo; - CefBrowserSettings settings; - - windowInfo.SetAsPopup(cefHost->GetWindowHandle(), "DevTools"); - - cefHost->ShowDevTools(windowInfo, this, settings, CefPoint()); - } - } - - void CloseDevTools() - { - auto cefHost = TryGetCefHost(); - - if (cefHost != nullptr) - { - cefHost->CloseDevTools(); - } - } - private: void SetBuffer(BitmapInfo^ bitmapInfo, int newWidth, int newHeight, const void* buffer) From f9821ae5494483f7eac08855e0ffe7eca5c451b0 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 08:53:16 +1000 Subject: [PATCH 090/134] Add offScreenRendering param to ManagedCefBrowserAdapter and create the relevant Client Adapter as required. --- CefSharp.Core/ManagedCefBrowserAdapter.h | 17 ++++++++++++++--- CefSharp.OffScreen/ChromiumWebBrowser.cs | 2 +- CefSharp.WinForms.Example/Program.cs | 4 ++-- CefSharp.WinForms/ChromiumWebBrowser.cs | 2 +- CefSharp.Wpf/ChromiumWebBrowser.cs | 2 +- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index ea36a6f693..5d2ea92dae 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -8,6 +8,7 @@ #include "BrowserSettings.h" #include "MouseButtonType.h" #include "PaintElementType.h" +#include "Internals/ClientAdapter.h" #include "Internals/RenderClientAdapter.h" #include "Internals/MCefRefPtr.h" #include "Internals/StringVisitor.h" @@ -21,7 +22,7 @@ namespace CefSharp { public ref class ManagedCefBrowserAdapter : public DisposableResource { - MCefRefPtr _renderClientAdapter; + MCefRefPtr _renderClientAdapter; BrowserProcessServiceHost^ _browserProcessServiceHost; IWebBrowserInternal^ _webBrowserInternal; JavascriptObjectRepository^ _javaScriptObjectRepository; @@ -46,9 +47,19 @@ namespace CefSharp }; public: - ManagedCefBrowserAdapter(IWebBrowserInternal^ webBrowserInternal) + ManagedCefBrowserAdapter(IWebBrowserInternal^ webBrowserInternal, bool offScreenRendering) { - _renderClientAdapter = new RenderClientAdapter(webBrowserInternal, gcnew Action(this, &ManagedCefBrowserAdapter::OnAfterBrowserCreated)); + if (offScreenRendering) + { + _renderClientAdapter = new RenderClientAdapter(webBrowserInternal, + gcnew Action(this, &ManagedCefBrowserAdapter::OnAfterBrowserCreated)); + } + else + { + _renderClientAdapter = new ClientAdapter(webBrowserInternal, + gcnew Action(this, &ManagedCefBrowserAdapter::OnAfterBrowserCreated)); + } + _webBrowserInternal = webBrowserInternal; _javaScriptObjectRepository = gcnew JavascriptObjectRepository(); } diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index 2fca5f7448..04fa481fe8 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -48,7 +48,7 @@ public ChromiumWebBrowser(string address, BrowserSettings browserSettings = null Cef.AddDisposable(this); - managedCefBrowserAdapter = new ManagedCefBrowserAdapter(this); + managedCefBrowserAdapter = new ManagedCefBrowserAdapter(this, true); managedCefBrowserAdapter.CreateOffscreenBrowser(IntPtr.Zero, browserSettings ?? new BrowserSettings(), address); } diff --git a/CefSharp.WinForms.Example/Program.cs b/CefSharp.WinForms.Example/Program.cs index 57002ad9ea..d124c41b4d 100644 --- a/CefSharp.WinForms.Example/Program.cs +++ b/CefSharp.WinForms.Example/Program.cs @@ -16,8 +16,8 @@ static void Main() { CefExample.Init(); - var browser = new BrowserForm(); - //var browser = new SimpleBrowserForm(); + //var browser = new BrowserForm(); + var browser = new SimpleBrowserForm(); Application.Run(browser); } } diff --git a/CefSharp.WinForms/ChromiumWebBrowser.cs b/CefSharp.WinForms/ChromiumWebBrowser.cs index c5c1a786f4..40ec8d6fe3 100644 --- a/CefSharp.WinForms/ChromiumWebBrowser.cs +++ b/CefSharp.WinForms/ChromiumWebBrowser.cs @@ -63,7 +63,7 @@ public ChromiumWebBrowser(string address) FocusHandler = new DefaultFocusHandler(this); ResourceHandler = new DefaultResourceHandler(); - managedCefBrowserAdapter = new ManagedCefBrowserAdapter(this); + managedCefBrowserAdapter = new ManagedCefBrowserAdapter(this, false); } protected override void Dispose(bool disposing) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 124703f022..ff6ead787f 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -447,7 +447,7 @@ public ChromiumWebBrowser() UndoCommand = new DelegateCommand(Undo); RedoCommand = new DelegateCommand(Redo); - managedCefBrowserAdapter = new ManagedCefBrowserAdapter(this); + managedCefBrowserAdapter = new ManagedCefBrowserAdapter(this, true); disposables.Add(managedCefBrowserAdapter); disposables.Add(new DisposableEventWrapper(this, ActualHeightProperty, OnActualSizeChanged)); From 995974d3df24e57e0f3903da291779da20241bd2 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 08:55:27 +1000 Subject: [PATCH 091/134] Rename _renderClientAdapter to _clientAdapter --- CefSharp.Core/ManagedCefBrowserAdapter.h | 92 ++++++++++++------------ 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index 5d2ea92dae..b38cf3369b 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -22,7 +22,7 @@ namespace CefSharp { public ref class ManagedCefBrowserAdapter : public DisposableResource { - MCefRefPtr _renderClientAdapter; + MCefRefPtr _clientAdapter; BrowserProcessServiceHost^ _browserProcessServiceHost; IWebBrowserInternal^ _webBrowserInternal; JavascriptObjectRepository^ _javaScriptObjectRepository; @@ -33,7 +33,7 @@ namespace CefSharp CloseAllPopups(true); Close(true); - _renderClientAdapter = nullptr; + _clientAdapter = nullptr; if (_browserProcessServiceHost != nullptr) { _browserProcessServiceHost->Close(); @@ -51,12 +51,12 @@ namespace CefSharp { if (offScreenRendering) { - _renderClientAdapter = new RenderClientAdapter(webBrowserInternal, + _clientAdapter = new RenderClientAdapter(webBrowserInternal, gcnew Action(this, &ManagedCefBrowserAdapter::OnAfterBrowserCreated)); } else { - _renderClientAdapter = new ClientAdapter(webBrowserInternal, + _clientAdapter = new ClientAdapter(webBrowserInternal, gcnew Action(this, &ManagedCefBrowserAdapter::OnAfterBrowserCreated)); } @@ -72,7 +72,7 @@ namespace CefSharp window.SetAsWindowless(hwnd, TRUE); CefString addressNative = StringUtils::ToNative(address); - if (!CefBrowserHost::CreateBrowser(window, _renderClientAdapter.get(), addressNative, + if (!CefBrowserHost::CreateBrowser(window, _clientAdapter.get(), addressNative, *(CefBrowserSettings*) browserSettings->_internalBrowserSettings, NULL)) { throw gcnew InvalidOperationException( "Failed to create offscreen browser. Call Cef.Initialize() first." ); @@ -81,7 +81,7 @@ namespace CefSharp void Close(bool forceClose) { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -91,12 +91,12 @@ namespace CefSharp void CloseAllPopups(bool forceClose) { - _renderClientAdapter->CloseAllPopups(forceClose); + _clientAdapter->CloseAllPopups(forceClose); } void LoadUrl(String^ address) { - auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); + auto cefFrame = _clientAdapter->TryGetCefMainFrame(); if (cefFrame != nullptr) { @@ -117,7 +117,7 @@ namespace CefSharp void LoadHtml(String^ html, String^ url) { - auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); + auto cefFrame = _clientAdapter->TryGetCefMainFrame(); if (cefFrame != nullptr) { @@ -127,7 +127,7 @@ namespace CefSharp void WasResized() { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -137,7 +137,7 @@ namespace CefSharp void WasHidden(bool hidden) { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -147,7 +147,7 @@ namespace CefSharp void Invalidate(PaintElementType type) { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -157,7 +157,7 @@ namespace CefSharp void SendFocusEvent(bool isFocused) { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -167,7 +167,7 @@ namespace CefSharp void SetFocus(bool isFocused) { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -177,7 +177,7 @@ namespace CefSharp bool SendKeyEvent(int message, int wParam, int lParam) { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost == nullptr) { @@ -301,7 +301,7 @@ namespace CefSharp void OnMouseMove(int x, int y, bool mouseLeave, CefEventFlags modifiers) { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -322,7 +322,7 @@ namespace CefSharp void OnMouseButton(int x, int y, MouseButtonType mouseButtonType, bool mouseUp, int clickCount, CefEventFlags modifiers) { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -337,7 +337,7 @@ namespace CefSharp void OnMouseWheel(int x, int y, int deltaX, int deltaY) { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -351,7 +351,7 @@ namespace CefSharp void Stop() { - auto cefBrowser = _renderClientAdapter->GetCefBrowser(); + auto cefBrowser = _clientAdapter->GetCefBrowser(); if (cefBrowser != nullptr) { @@ -361,7 +361,7 @@ namespace CefSharp void GoBack() { - auto cefBrowser = _renderClientAdapter->GetCefBrowser(); + auto cefBrowser = _clientAdapter->GetCefBrowser(); if (cefBrowser != nullptr) { @@ -371,7 +371,7 @@ namespace CefSharp void GoForward() { - auto cefBrowser = _renderClientAdapter->GetCefBrowser(); + auto cefBrowser = _clientAdapter->GetCefBrowser(); if (cefBrowser != nullptr) { @@ -381,7 +381,7 @@ namespace CefSharp void Print() { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -391,7 +391,7 @@ namespace CefSharp void Find(int identifier, String^ searchText, bool forward, bool matchCase, bool findNext) { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -401,7 +401,7 @@ namespace CefSharp void StopFinding(bool clearSelection) { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -416,7 +416,7 @@ namespace CefSharp void Reload(bool ignoreCache) { - auto cefBrowser = _renderClientAdapter->GetCefBrowser(); + auto cefBrowser = _clientAdapter->GetCefBrowser(); if (cefBrowser != nullptr) { @@ -433,7 +433,7 @@ namespace CefSharp void ViewSource() { - auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); + auto cefFrame = _clientAdapter->TryGetCefMainFrame(); if (cefFrame != nullptr) { @@ -443,7 +443,7 @@ namespace CefSharp void GetSource(IStringVisitor^ visitor) { - auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); + auto cefFrame = _clientAdapter->TryGetCefMainFrame(); if (cefFrame != nullptr) { @@ -454,7 +454,7 @@ namespace CefSharp void GetText(IStringVisitor^ visitor) { - auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); + auto cefFrame = _clientAdapter->TryGetCefMainFrame(); if (cefFrame != nullptr) { @@ -465,7 +465,7 @@ namespace CefSharp void Cut() { - auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); + auto cefFrame = _clientAdapter->TryGetCefMainFrame(); if (cefFrame != nullptr) { @@ -475,7 +475,7 @@ namespace CefSharp void Copy() { - auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); + auto cefFrame = _clientAdapter->TryGetCefMainFrame(); if (cefFrame != nullptr) { @@ -485,7 +485,7 @@ namespace CefSharp void Paste() { - auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); + auto cefFrame = _clientAdapter->TryGetCefMainFrame(); if (cefFrame != nullptr) { @@ -495,7 +495,7 @@ namespace CefSharp void Delete() { - auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); + auto cefFrame = _clientAdapter->TryGetCefMainFrame(); if (cefFrame != nullptr) { @@ -505,7 +505,7 @@ namespace CefSharp void SelectAll() { - auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); + auto cefFrame = _clientAdapter->TryGetCefMainFrame(); if (cefFrame != nullptr) { @@ -515,7 +515,7 @@ namespace CefSharp void Undo() { - auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); + auto cefFrame = _clientAdapter->TryGetCefMainFrame(); if (cefFrame != nullptr) { @@ -525,7 +525,7 @@ namespace CefSharp void Redo() { - auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); + auto cefFrame = _clientAdapter->TryGetCefMainFrame(); if (cefFrame != nullptr) { @@ -535,7 +535,7 @@ namespace CefSharp void ExecuteScriptAsync(String^ script) { - auto cefFrame = _renderClientAdapter->TryGetCefMainFrame(); + auto cefFrame = _clientAdapter->TryGetCefMainFrame(); if (cefFrame != nullptr) { @@ -550,7 +550,7 @@ namespace CefSharp throw gcnew ArgumentOutOfRangeException("timeout", "Timeout greater than Maximum allowable value of " + UInt32::MaxValue); } - auto browser = _renderClientAdapter->GetCefBrowser(); + auto browser = _clientAdapter->GetCefBrowser(); if (_browserProcessServiceHost == nullptr && browser == nullptr) @@ -570,7 +570,7 @@ namespace CefSharp double GetZoomLevel() { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -582,7 +582,7 @@ namespace CefSharp void SetZoomLevel(double zoomLevel) { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -592,12 +592,12 @@ namespace CefSharp void ShowDevTools() { - _renderClientAdapter->ShowDevTools(); + _clientAdapter->ShowDevTools(); } void CloseDevTools() { - _renderClientAdapter->CloseDevTools(); + _clientAdapter->CloseDevTools(); } void CreateBrowser(BrowserSettings^ browserSettings, IntPtr^ sourceHandle, String^ address) @@ -609,13 +609,13 @@ namespace CefSharp window.SetAsChild(hwnd, rect); CefString addressNative = StringUtils::ToNative(address); - CefBrowserHost::CreateBrowser(window, _renderClientAdapter.get(), addressNative, + CefBrowserHost::CreateBrowser(window, _clientAdapter.get(), addressNative, *(CefBrowserSettings*)browserSettings->_internalBrowserSettings, NULL); } void Resize(int width, int height) { - HWND browserHwnd = _renderClientAdapter->GetBrowserHwnd(); + HWND browserHwnd = _clientAdapter->GetBrowserHwnd(); if (browserHwnd) { if (width == 0 && height == 0) @@ -633,7 +633,7 @@ namespace CefSharp void NotifyMoveOrResizeStarted() { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -648,7 +648,7 @@ namespace CefSharp void ReplaceMisspelling(String^ word) { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { @@ -659,7 +659,7 @@ namespace CefSharp void AddWordToDictionary(String^ word) { - auto cefHost = _renderClientAdapter->TryGetCefHost(); + auto cefHost = _clientAdapter->TryGetCefHost(); if (cefHost != nullptr) { From 3cf7b0159ac85bae3bb81793ffdf298faf885959 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 09:10:56 +1000 Subject: [PATCH 092/134] Remove TryGetCefMainFrame method - now just using calls directly to GetMainFrame() (brings code more inline with cefclient example) --- CefSharp.Core/Internals/ClientAdapter.cpp | 12 ---- CefSharp.Core/Internals/ClientAdapter.h | 1 - CefSharp.Core/ManagedCefBrowserAdapter.h | 78 +++++++++++------------ 3 files changed, 39 insertions(+), 52 deletions(-) diff --git a/CefSharp.Core/Internals/ClientAdapter.cpp b/CefSharp.Core/Internals/ClientAdapter.cpp index 8bdb689545..accbfad587 100644 --- a/CefSharp.Core/Internals/ClientAdapter.cpp +++ b/CefSharp.Core/Internals/ClientAdapter.cpp @@ -31,18 +31,6 @@ namespace CefSharp } }; - CefRefPtr ClientAdapter::TryGetCefMainFrame() - { - auto cefBrowser = this->GetCefBrowser().get(); - - if (!cefBrowser) - { - return nullptr; - } - - return cefBrowser->GetMainFrame(); - }; - void ClientAdapter::ShowDevTools() { auto cefHost = TryGetCefHost(); diff --git a/CefSharp.Core/Internals/ClientAdapter.h b/CefSharp.Core/Internals/ClientAdapter.h index 330c072457..24d5583507 100644 --- a/CefSharp.Core/Internals/ClientAdapter.h +++ b/CefSharp.Core/Internals/ClientAdapter.h @@ -60,7 +60,6 @@ namespace CefSharp HWND GetBrowserHwnd() { return _browserHwnd; } CefRefPtr GetCefBrowser() { return _cefBrowser; } CefRefPtr TryGetCefHost(); - CefRefPtr TryGetCefMainFrame(); void ShowDevTools(); void CloseDevTools(); void CloseAllPopups(bool forceClose); diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index b38cf3369b..f0d8be157c 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -96,11 +96,11 @@ namespace CefSharp void LoadUrl(String^ address) { - auto cefFrame = _clientAdapter->TryGetCefMainFrame(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefFrame != nullptr) + if (browser != nullptr) { - cefFrame->LoadURL(StringUtils::ToNative(address)); + browser->GetMainFrame()->LoadURL(StringUtils::ToNative(address)); } } @@ -117,11 +117,11 @@ namespace CefSharp void LoadHtml(String^ html, String^ url) { - auto cefFrame = _clientAdapter->TryGetCefMainFrame(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefFrame != nullptr) + if (browser != nullptr) { - cefFrame->LoadString(StringUtils::ToNative(html), StringUtils::ToNative(url)); + browser->GetMainFrame()->LoadString(StringUtils::ToNative(html), StringUtils::ToNative(url)); } } @@ -433,113 +433,113 @@ namespace CefSharp void ViewSource() { - auto cefFrame = _clientAdapter->TryGetCefMainFrame(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefFrame != nullptr) + if (browser != nullptr) { - cefFrame->ViewSource(); + browser->GetMainFrame()->ViewSource(); } } void GetSource(IStringVisitor^ visitor) { - auto cefFrame = _clientAdapter->TryGetCefMainFrame(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefFrame != nullptr) + if (browser != nullptr) { auto stringVisitor = new StringVisitor(visitor); - cefFrame->GetSource(stringVisitor); + browser->GetMainFrame()->GetSource(stringVisitor); } } void GetText(IStringVisitor^ visitor) { - auto cefFrame = _clientAdapter->TryGetCefMainFrame(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefFrame != nullptr) + if (browser != nullptr) { auto stringVisitor = new StringVisitor(visitor); - cefFrame->GetText(stringVisitor); + browser->GetMainFrame()->GetText(stringVisitor); } } void Cut() { - auto cefFrame = _clientAdapter->TryGetCefMainFrame(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefFrame != nullptr) + if (browser != nullptr) { - cefFrame->Cut(); + browser->GetMainFrame()->Cut(); } } void Copy() { - auto cefFrame = _clientAdapter->TryGetCefMainFrame(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefFrame != nullptr) + if (browser != nullptr) { - cefFrame->Copy(); + browser->GetMainFrame()->Copy(); } } void Paste() { - auto cefFrame = _clientAdapter->TryGetCefMainFrame(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefFrame != nullptr) + if (browser != nullptr) { - cefFrame->Paste(); + browser->GetMainFrame()->Paste(); } } void Delete() { - auto cefFrame = _clientAdapter->TryGetCefMainFrame(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefFrame != nullptr) + if (browser != nullptr) { - cefFrame->Delete(); + browser->GetMainFrame()->Delete(); } } void SelectAll() { - auto cefFrame = _clientAdapter->TryGetCefMainFrame(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefFrame != nullptr) + if (browser != nullptr) { - cefFrame->SelectAll(); + browser->GetMainFrame()->SelectAll(); } } void Undo() { - auto cefFrame = _clientAdapter->TryGetCefMainFrame(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefFrame != nullptr) + if (browser != nullptr) { - cefFrame->Undo(); + browser->GetMainFrame()->Undo(); } } void Redo() { - auto cefFrame = _clientAdapter->TryGetCefMainFrame(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefFrame != nullptr) + if (browser != nullptr) { - cefFrame->Redo(); + browser->GetMainFrame()->Redo(); } } void ExecuteScriptAsync(String^ script) { - auto cefFrame = _clientAdapter->TryGetCefMainFrame(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefFrame != nullptr) + if (browser != nullptr) { - cefFrame->ExecuteJavaScript(StringUtils::ToNative(script), "about:blank", 0); + browser->GetMainFrame()->ExecuteJavaScript(StringUtils::ToNative(script), "about:blank", 0); } } From f1ddf6f61f401ea8de3fd4936039d56ccf725300 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 09:16:28 +1000 Subject: [PATCH 093/134] Remove TryGetCefHost method - similar cleanup to previous commit, brings code more inline with cefclient example (It would appear that having an instance of the browser then there will always to be a host) --- CefSharp.Core/Internals/ClientAdapter.cpp | 28 ++---- CefSharp.Core/Internals/ClientAdapter.h | 1 - CefSharp.Core/ManagedCefBrowserAdapter.h | 108 +++++++++++----------- 3 files changed, 61 insertions(+), 76 deletions(-) diff --git a/CefSharp.Core/Internals/ClientAdapter.cpp b/CefSharp.Core/Internals/ClientAdapter.cpp index accbfad587..b72e6a4c75 100644 --- a/CefSharp.Core/Internals/ClientAdapter.cpp +++ b/CefSharp.Core/Internals/ClientAdapter.cpp @@ -17,42 +17,28 @@ namespace CefSharp { namespace Internals { - - CefRefPtr ClientAdapter::TryGetCefHost() - { - if (!this->GetCefBrowser().get() || - !this->GetCefBrowser()->GetHost().get()) - { - return nullptr; - } - else - { - return this->GetCefBrowser()->GetHost(); - } - }; - void ClientAdapter::ShowDevTools() { - auto cefHost = TryGetCefHost(); + auto browser = GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { CefWindowInfo windowInfo; CefBrowserSettings settings; - windowInfo.SetAsPopup(cefHost->GetWindowHandle(), "DevTools"); + windowInfo.SetAsPopup(browser->GetHost()->GetWindowHandle(), "DevTools"); - cefHost->ShowDevTools(windowInfo, this, settings, CefPoint()); + browser->GetHost()->ShowDevTools(windowInfo, this, settings, CefPoint()); } } void ClientAdapter::CloseDevTools() { - auto cefHost = TryGetCefHost(); + auto browser = GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { - cefHost->CloseDevTools(); + browser->GetHost()->CloseDevTools(); } } diff --git a/CefSharp.Core/Internals/ClientAdapter.h b/CefSharp.Core/Internals/ClientAdapter.h index 24d5583507..b3cd2a151f 100644 --- a/CefSharp.Core/Internals/ClientAdapter.h +++ b/CefSharp.Core/Internals/ClientAdapter.h @@ -59,7 +59,6 @@ namespace CefSharp HWND GetBrowserHwnd() { return _browserHwnd; } CefRefPtr GetCefBrowser() { return _cefBrowser; } - CefRefPtr TryGetCefHost(); void ShowDevTools(); void CloseDevTools(); void CloseAllPopups(bool forceClose); diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index f0d8be157c..dbd8cbf4e9 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -81,11 +81,11 @@ namespace CefSharp void Close(bool forceClose) { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { - cefHost->CloseBrowser(forceClose); + browser->GetHost()->CloseBrowser(forceClose); } } @@ -127,59 +127,59 @@ namespace CefSharp void WasResized() { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { - cefHost->WasResized(); + browser->GetHost()->WasResized(); } } void WasHidden(bool hidden) { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { - cefHost->WasHidden(hidden); + browser->GetHost()->WasHidden(hidden); } } void Invalidate(PaintElementType type) { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { - cefHost->Invalidate((CefBrowserHost::PaintElementType)type); + browser->GetHost()->Invalidate((CefBrowserHost::PaintElementType)type); } } void SendFocusEvent(bool isFocused) { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { - cefHost->SendFocusEvent(isFocused); + browser->GetHost()->SendFocusEvent(isFocused); } } void SetFocus(bool isFocused) { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { - cefHost->SetFocus(isFocused); + browser->GetHost()->SetFocus(isFocused); } } bool SendKeyEvent(int message, int wParam, int lParam) { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost == nullptr) + if (browser->GetHost() == nullptr) { return false; } @@ -205,7 +205,7 @@ namespace CefSharp } keyEvent.modifiers = GetCefKeyboardModifiers(wParam, lParam); - cefHost->SendKeyEvent(keyEvent); + browser->GetHost()->SendKeyEvent(keyEvent); return true; } @@ -301,9 +301,9 @@ namespace CefSharp void OnMouseMove(int x, int y, bool mouseLeave, CefEventFlags modifiers) { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { CefMouseEvent mouseEvent; mouseEvent.x = x; @@ -311,7 +311,7 @@ namespace CefSharp mouseEvent.modifiers = (uint32)modifiers; - cefHost->SendMouseMoveEvent(mouseEvent, mouseLeave); + browser->GetHost()->SendMouseMoveEvent(mouseEvent, mouseLeave); if (mouseLeave == true) { @@ -322,30 +322,30 @@ namespace CefSharp void OnMouseButton(int x, int y, MouseButtonType mouseButtonType, bool mouseUp, int clickCount, CefEventFlags modifiers) { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { CefMouseEvent mouseEvent; mouseEvent.x = x; mouseEvent.y = y; mouseEvent.modifiers = (uint32)modifiers; - cefHost->SendMouseClickEvent(mouseEvent, (CefBrowserHost::MouseButtonType) mouseButtonType, mouseUp, clickCount); + browser->GetHost()->SendMouseClickEvent(mouseEvent, (CefBrowserHost::MouseButtonType) mouseButtonType, mouseUp, clickCount); } } void OnMouseWheel(int x, int y, int deltaX, int deltaY) { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { CefMouseEvent mouseEvent; mouseEvent.x = x; mouseEvent.y = y; - cefHost->SendMouseWheelEvent(mouseEvent, deltaX, deltaY); + browser->GetHost()->SendMouseWheelEvent(mouseEvent, deltaX, deltaY); } } @@ -381,31 +381,31 @@ namespace CefSharp void Print() { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { - cefHost->Print(); + browser->GetHost()->Print(); } } void Find(int identifier, String^ searchText, bool forward, bool matchCase, bool findNext) { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { - cefHost->Find(identifier, StringUtils::ToNative(searchText), forward, matchCase, findNext); + browser->GetHost()->Find(identifier, StringUtils::ToNative(searchText), forward, matchCase, findNext); } } void StopFinding(bool clearSelection) { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { - cefHost->StopFinding(clearSelection); + browser->GetHost()->StopFinding(clearSelection); } } @@ -570,11 +570,11 @@ namespace CefSharp double GetZoomLevel() { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { - return cefHost->GetZoomLevel(); + return browser->GetHost()->GetZoomLevel(); } return 0; @@ -582,11 +582,11 @@ namespace CefSharp void SetZoomLevel(double zoomLevel) { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { - cefHost->SetZoomLevel(zoomLevel); + browser->GetHost()->SetZoomLevel(zoomLevel); } } @@ -633,11 +633,11 @@ namespace CefSharp void NotifyMoveOrResizeStarted() { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { - cefHost->NotifyMoveOrResizeStarted(); + browser->GetHost()->NotifyMoveOrResizeStarted(); } } @@ -648,23 +648,23 @@ namespace CefSharp void ReplaceMisspelling(String^ word) { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { CefString wordNative = StringUtils::ToNative(word); - cefHost->ReplaceMisspelling(wordNative); + browser->GetHost()->ReplaceMisspelling(wordNative); } } void AddWordToDictionary(String^ word) { - auto cefHost = _clientAdapter->TryGetCefHost(); + auto browser = _clientAdapter->GetCefBrowser(); - if (cefHost != nullptr) + if (browser != nullptr) { CefString wordNative = StringUtils::ToNative(word); - cefHost->AddWordToDictionary(wordNative); + browser->GetHost()->AddWordToDictionary(wordNative); } } }; From 7daff28e6884cc6d5f1e7146d1b0c9f1c18734fe Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 09:17:57 +1000 Subject: [PATCH 094/134] Switch back to tabbed winforms example being the default (maybe one day create a method to switch between the two) --- CefSharp.WinForms.Example/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CefSharp.WinForms.Example/Program.cs b/CefSharp.WinForms.Example/Program.cs index d124c41b4d..57002ad9ea 100644 --- a/CefSharp.WinForms.Example/Program.cs +++ b/CefSharp.WinForms.Example/Program.cs @@ -16,8 +16,8 @@ static void Main() { CefExample.Init(); - //var browser = new BrowserForm(); - var browser = new SimpleBrowserForm(); + var browser = new BrowserForm(); + //var browser = new SimpleBrowserForm(); Application.Run(browser); } } From 794114c53ea59f5f4530d138959737043e06ff1a Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 09:29:14 +1000 Subject: [PATCH 095/134] Fix comment formatting Remove `this.` - no need --- CefSharp.OffScreen/ChromiumWebBrowser.cs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index 04fa481fe8..953c0f9a83 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -24,17 +24,22 @@ public class ChromiumWebBrowser : IRenderWebBrowser { private ManagedCefBrowserAdapter managedCefBrowserAdapter; - /// Contains the last rendering from Chromium. + /// + /// Contains the last rendering from Chromium. + /// private Bitmap bitmap; - /// Need a lock because the caller may be asking for the bitmap - /// while Chromium async rendering has returned on another thread. + /// + /// Need a lock because the caller may be asking for the bitmap + /// while Chromium async rendering has returned on another thread. + /// private readonly object bitmapLock = new object(); - /// Size of the Chromium viewport. - /// + /// + /// Size of the Chromium viewport. /// This must be set to something other than 0x0 otherwise Chromium will not render, - /// and the ScreenshotAsync task will deadlock. + /// and the ScreenshotAsync task will deadlock. + /// private System.Drawing.Size size = new System.Drawing.Size(1366, 768); /// @@ -486,7 +491,7 @@ void IWebBrowserInternal.OnStatusMessage(string value) void IWebBrowserInternal.SetAddress(string address) { - this.Address = address; + Address = address; } void IWebBrowserInternal.SetIsLoading(bool isloading) From 16905e02a730b6f50acee6c83f0dc00400b41770 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 10:27:07 +1000 Subject: [PATCH 096/134] Simplify ScreenshotAsync, now just uses a TaskCompletionSource --- CefSharp.OffScreen/ChromiumWebBrowser.cs | 43 +++++++----------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index 953c0f9a83..47e065b6c9 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -6,7 +6,6 @@ using System.Drawing; using System.Drawing.Imaging; using System.Text; -using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Interop; @@ -43,10 +42,10 @@ public class ChromiumWebBrowser : IRenderWebBrowser private System.Drawing.Size size = new System.Drawing.Size(1366, 768); /// - /// Create a new offscreen Chromium with the initial URL of "about:blank". + /// Create a new OffScreen Chromium Browser /// /// Initial address (url) to load - /// The browser settings to use. If null, the default settings are used. + /// The browser settings to use. If null, the default settings are used. public ChromiumWebBrowser(string address, BrowserSettings browserSettings = null) { ResourceHandler = new DefaultResourceHandler(); @@ -119,10 +118,7 @@ public Bitmap ScreenshotOrNull() { lock (bitmapLock) { - if (bitmap == null) - return null; - else - return new Bitmap(bitmap); + return bitmap == null ? null : new Bitmap(bitmap); } } @@ -142,43 +138,28 @@ public Task ScreenshotAsync() // Try our luck and see if there is already a screenshot, to save us creating a new thread for nothing. var screenshot = ScreenshotOrNull(); - Task task; + var completionSource = new TaskCompletionSource(); - if (screenshot != null) + if (screenshot == null) { - var completionSource = new TaskCompletionSource(); - completionSource.SetResult(screenshot); - task = completionSource.Task; - } - else - { - // No existing screenshot, so wait for Chromium to render itself. - - // A wait handle, so the task knows when NewScreenshot has fired. - var waitForBitmap = new EventWaitHandle(false, EventResetMode.AutoReset); - EventHandler newScreenshot = null; // otherwise we cannot reference ourselves in the anonymous method below newScreenshot = (sender, e) => { // Chromium has rendered. Tell the task about it. NewScreenshot -= newScreenshot; - waitForBitmap.Set(); + + completionSource.SetResult(ScreenshotOrNull()); }; NewScreenshot += newScreenshot; - - task = new Task(() => - { - // Wait in this thread for the NewScreenshot event to fire. - waitForBitmap.WaitOne(); - return ScreenshotOrNull(); - }); - - task.Start(); + } + else + { + completionSource.SetResult(screenshot); } - return task; + return completionSource.Task; } public IJsDialogHandler JsDialogHandler { get; set; } From 2684725c1109bfaeff3fa98278764a97119d4467 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 10:44:31 +1000 Subject: [PATCH 097/134] Expand OffScreen Example to include an example of capturing the first offscreen image (currently the first image is blank, though I'm thinking that's probably expected) This allows for testing of the updated ScreenshotAsync method --- CefSharp.OffScreen.Example/Program.cs | 51 ++++++++++++++++++--------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/CefSharp.OffScreen.Example/Program.cs b/CefSharp.OffScreen.Example/Program.cs index 592af442ac..287c180574 100644 --- a/CefSharp.OffScreen.Example/Program.cs +++ b/CefSharp.OffScreen.Example/Program.cs @@ -4,7 +4,10 @@ using System; using System.Diagnostics; +using System.Drawing; using System.IO; +using System.Text; +using System.Threading.Tasks; using CefSharp.Example; namespace CefSharp.OffScreen.Example @@ -12,6 +15,7 @@ namespace CefSharp.OffScreen.Example public class Program { private static ChromiumWebBrowser browser; + private static bool captureFirstRenderedImage = false; public static void Main(string[] args) { @@ -29,7 +33,15 @@ public static void Main(string[] args) // An event that is fired when the first page is finished loading. // This returns to us from another thread. - browser.FrameLoadEnd += BrowserFrameLoadEnd; + if (captureFirstRenderedImage) + { + browser.ResourceHandler.RegisterHandler(testUrl, ResourceHandler.FromString("

CefSharp OffScreen

")); + browser.ScreenshotAsync().ContinueWith(DisplayBitmap); + } + else + { + browser.FrameLoadEnd += BrowserFrameLoadEnd; + } // We have to wait for something, otherwise the process will exit too soon. Console.ReadKey(); @@ -52,27 +64,34 @@ private static void BrowserFrameLoadEnd(object sender, FrameLoadEndEventArgs e) var task = browser.ScreenshotAsync(); task.Wait(); - // Make a file to save it to (e.g. C:\Users\jan\Desktop\CefSharp screenshot.png) - var screenshotPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "CefSharp screenshot.png"); + DisplayBitmap(task); + } + } - Console.WriteLine(); - Console.WriteLine("Screenshot ready. Saving to {0}", screenshotPath); + private static void DisplayBitmap(Task task) + { + // Make a file to save it to (e.g. C:\Users\jan\Desktop\CefSharp screenshot.png) + var screenshotPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "CefSharp screenshot.png"); - // Save the Bitmap to the path. - // The image type is auto-detected via the ".png" extension. - task.Result.Save(screenshotPath); + Console.WriteLine(); + Console.WriteLine("Screenshot ready. Saving to {0}", screenshotPath); - // We no longer need the Bitmap. - // Dispose it to avoid keeping the memory alive. Especially important in 32-bit applications. - task.Result.Dispose(); + var bitmap = task.Result; - Console.WriteLine("Screenshot saved. Launching your default image viewer..."); + // Save the Bitmap to the path. + // The image type is auto-detected via the ".png" extension. + bitmap.Save(screenshotPath); - // Tell Windows to launch the saved image. - Process.Start(screenshotPath); + // We no longer need the Bitmap. + // Dispose it to avoid keeping the memory alive. Especially important in 32-bit applications. + bitmap.Dispose(); - Console.WriteLine("Image viewer launched. Press any key to exit."); - } + Console.WriteLine("Screenshot saved. Launching your default image viewer..."); + + // Tell Windows to launch the saved image. + Process.Start(screenshotPath); + + Console.WriteLine("Image viewer launched. Press any key to exit."); } } } From 8b92441fecad06ca20f8304a8296dc6e1f4204ed Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 10:56:51 +1000 Subject: [PATCH 098/134] Remove the second lock in InvokeRenderAsync - now using the same lock object for GdiBitmap --- CefSharp.OffScreen/ChromiumWebBrowser.cs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index 47e065b6c9..8836afca34 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -347,7 +347,7 @@ int IRenderWebBrowser.Height public BitmapInfo CreateBitmapInfo(bool isPopup) { //The bitmap buffer is 32 BPP - return new GdiBitmapInfo { IsPopup = isPopup, BytesPerPixel = 4 }; + return new GdiBitmapInfo { IsPopup = isPopup, BytesPerPixel = 4, BitmapLock = bitmapLock }; } void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) @@ -360,18 +360,15 @@ void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) bitmap = null; } - lock (bitmapInfo.BitmapLock) - { - var stride = bitmapInfo.Width * bitmapInfo.BytesPerPixel; + var stride = bitmapInfo.Width*bitmapInfo.BytesPerPixel; - bitmap = BitmapSourceToBitmap2(Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, - bitmapInfo.Width, bitmapInfo.Height, PixelFormats.Bgra32, stride, 0)); + bitmap = BitmapSourceToBitmap2(Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, + bitmapInfo.Width, bitmapInfo.Height, PixelFormats.Bgra32, stride, 0)); - var handler = NewScreenshot; - if (handler != null) - { - handler(this, EventArgs.Empty); - } + var handler = NewScreenshot; + if (handler != null) + { + handler(this, EventArgs.Empty); } } } From 99eceb77d38d88ad3c4be66515d78ed95efcc9a2 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 11:04:00 +1000 Subject: [PATCH 099/134] Slight code simplification in OffScreen.Example --- CefSharp.OffScreen.Example/Program.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CefSharp.OffScreen.Example/Program.cs b/CefSharp.OffScreen.Example/Program.cs index 287c180574..ae6fd95317 100644 --- a/CefSharp.OffScreen.Example/Program.cs +++ b/CefSharp.OffScreen.Example/Program.cs @@ -61,10 +61,7 @@ private static void BrowserFrameLoadEnd(object sender, FrameLoadEndEventArgs e) browser.FrameLoadEnd -= BrowserFrameLoadEnd; // Wait for the screenshot to be taken. - var task = browser.ScreenshotAsync(); - task.Wait(); - - DisplayBitmap(task); + browser.ScreenshotAsync().ContinueWith(DisplayBitmap); } } From 22f70bbb9ea48df169f94ef70c3c4f33d934567d Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 12:19:24 +1000 Subject: [PATCH 100/134] Copy the buffer directly into the bitmap rather than converting to InteropBitmap then back again Bitmap property was unused, so change to IsCleared property for now --- CefSharp.Core/CefSharp.Core.vcxproj | 2 ++ CefSharp.Core/CefSharp.Core.vcxproj.filters | 6 ++++ CefSharp.Core/NativeMethodWrapper.cpp | 18 ++++++++++ CefSharp.Core/NativeMethodWrapper.h | 18 ++++++++++ CefSharp.OffScreen/ChromiumWebBrowser.cs | 40 +++++---------------- CefSharp.OffScreen/GdiBitmapInfo.cs | 5 ++- 6 files changed, 55 insertions(+), 34 deletions(-) create mode 100644 CefSharp.Core/NativeMethodWrapper.cpp create mode 100644 CefSharp.Core/NativeMethodWrapper.h diff --git a/CefSharp.Core/CefSharp.Core.vcxproj b/CefSharp.Core/CefSharp.Core.vcxproj index 5a28c9ece4..776af7086f 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj +++ b/CefSharp.Core/CefSharp.Core.vcxproj @@ -225,6 +225,7 @@ + @@ -251,6 +252,7 @@ + diff --git a/CefSharp.Core/CefSharp.Core.vcxproj.filters b/CefSharp.Core/CefSharp.Core.vcxproj.filters index fb7be235ca..d949f61955 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj.filters +++ b/CefSharp.Core/CefSharp.Core.vcxproj.filters @@ -53,6 +53,9 @@ Source Files + + Source Files + @@ -130,6 +133,9 @@ Header Files + + Header Files + diff --git a/CefSharp.Core/NativeMethodWrapper.cpp b/CefSharp.Core/NativeMethodWrapper.cpp new file mode 100644 index 0000000000..bd82975d2a --- /dev/null +++ b/CefSharp.Core/NativeMethodWrapper.cpp @@ -0,0 +1,18 @@ +// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +#pragma once + +#include "Stdafx.h" +#include "NativeMethodWrapper.h" + +using namespace System; + +namespace CefSharp +{ + void NativeMethodWrapper::CopyMemoryUsingHandle(IntPtr^ dest, IntPtr^ src, int numberOfBytes) + { + CopyMemory(dest->ToPointer(), src->ToPointer(), numberOfBytes); + } +} diff --git a/CefSharp.Core/NativeMethodWrapper.h b/CefSharp.Core/NativeMethodWrapper.h new file mode 100644 index 0000000000..ea6abbd449 --- /dev/null +++ b/CefSharp.Core/NativeMethodWrapper.h @@ -0,0 +1,18 @@ +// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +#pragma once + +#include "Stdafx.h" + +using namespace System; + +namespace CefSharp +{ + public ref class NativeMethodWrapper sealed + { + public: + static void CopyMemoryUsingHandle(IntPtr^ dest, IntPtr^ src, int numberOfBytes); + }; +} \ No newline at end of file diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index 8836afca34..c22251ba31 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -7,11 +7,8 @@ using System.Drawing.Imaging; using System.Text; using System.Threading.Tasks; -using System.Windows; -using System.Windows.Interop; -using System.Windows.Media; -using System.Windows.Media.Imaging; using CefSharp.Internals; +using PixelFormat = System.Drawing.Imaging.PixelFormat; namespace CefSharp.OffScreen { @@ -360,11 +357,16 @@ void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) bitmap = null; } - var stride = bitmapInfo.Width*bitmapInfo.BytesPerPixel; + var pixels = bitmapInfo.Width * bitmapInfo.Height; + var numberOfBytes = pixels * bitmapInfo.BytesPerPixel; - bitmap = BitmapSourceToBitmap2(Imaging.CreateBitmapSourceFromMemorySection(bitmapInfo.FileMappingHandle, - bitmapInfo.Width, bitmapInfo.Height, PixelFormats.Bgra32, stride, 0)); + bitmap = new Bitmap(bitmapInfo.Width, bitmapInfo.Height, PixelFormat.Format32bppPArgb); + var data = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.WriteOnly, PixelFormat.Format32bppPArgb); + NativeMethodWrapper.CopyMemoryUsingHandle(data.Scan0, bitmapInfo.BackBufferHandle, numberOfBytes); + + bitmap.UnlockBits(data); + var handler = NewScreenshot; if (handler != null) { @@ -373,30 +375,6 @@ void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) } } - /// - /// http://stackoverflow.com/a/5709472/450141 - /// - /// BitmapSource - /// Bitmap - private static Bitmap BitmapSourceToBitmap2(BitmapSource srs) - { - var bmp = new Bitmap( - srs.PixelWidth, - srs.PixelHeight, - System.Drawing.Imaging.PixelFormat.Format32bppPArgb); - var data = bmp.LockBits( - new Rectangle(System.Drawing.Point.Empty, bmp.Size), - ImageLockMode.WriteOnly, - System.Drawing.Imaging.PixelFormat.Format32bppPArgb); - srs.CopyPixels( - Int32Rect.Empty, - data.Scan0, - data.Height * data.Stride, - data.Stride); - bmp.UnlockBits(data); - return bmp; - } - void IRenderWebBrowser.SetCursor(IntPtr cursor) { } diff --git a/CefSharp.OffScreen/GdiBitmapInfo.cs b/CefSharp.OffScreen/GdiBitmapInfo.cs index a697abeaf1..a6d49e7f73 100644 --- a/CefSharp.OffScreen/GdiBitmapInfo.cs +++ b/CefSharp.OffScreen/GdiBitmapInfo.cs @@ -2,18 +2,17 @@ // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. -using System.Drawing; using CefSharp.Internals; namespace CefSharp.OffScreen { public class GdiBitmapInfo : BitmapInfo { - public Bitmap Bitmap { get; set; } + public bool IsCleared { get; set; } public override void ClearBitmap() { - Bitmap = null; + IsCleared = true; } } } From 592149ea21ba880bfc45b1de7d38988ccf441a2b Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 12:46:15 +1000 Subject: [PATCH 101/134] Simplified OffScreen InvokeRenderAsync again - create bitmap using the BackBufferHandle directly rather than copying the memory --- CefSharp.OffScreen/ChromiumWebBrowser.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index c22251ba31..0000defa19 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -357,15 +357,9 @@ void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) bitmap = null; } - var pixels = bitmapInfo.Width * bitmapInfo.Height; - var numberOfBytes = pixels * bitmapInfo.BytesPerPixel; + var stride = bitmapInfo.Width * bitmapInfo.BytesPerPixel; - bitmap = new Bitmap(bitmapInfo.Width, bitmapInfo.Height, PixelFormat.Format32bppPArgb); - var data = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), ImageLockMode.WriteOnly, PixelFormat.Format32bppPArgb); - - NativeMethodWrapper.CopyMemoryUsingHandle(data.Scan0, bitmapInfo.BackBufferHandle, numberOfBytes); - - bitmap.UnlockBits(data); + bitmap = new Bitmap(bitmapInfo.Width, bitmapInfo.Height, stride, PixelFormat.Format32bppPArgb, bitmapInfo.BackBufferHandle); var handler = NewScreenshot; if (handler != null) From 584baa21708b96dca52452a4be37e15cf65e503f Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 16:23:36 +1000 Subject: [PATCH 102/134] Remove User32.cs and implement Focused methods in NativeMethodWrapper --- CefSharp.Core/NativeMethodWrapper.cpp | 15 +++++++++++---- CefSharp.Core/NativeMethodWrapper.h | 11 ++++++----- CefSharp.WinForms/CefSharp.WinForms.csproj | 1 - CefSharp.WinForms/ChromiumWebBrowser.cs | 4 +--- CefSharp.WinForms/Internals/User32.cs | 18 ------------------ 5 files changed, 18 insertions(+), 31 deletions(-) delete mode 100644 CefSharp.WinForms/Internals/User32.cs diff --git a/CefSharp.Core/NativeMethodWrapper.cpp b/CefSharp.Core/NativeMethodWrapper.cpp index bd82975d2a..04c00538e9 100644 --- a/CefSharp.Core/NativeMethodWrapper.cpp +++ b/CefSharp.Core/NativeMethodWrapper.cpp @@ -11,8 +11,15 @@ using namespace System; namespace CefSharp { - void NativeMethodWrapper::CopyMemoryUsingHandle(IntPtr^ dest, IntPtr^ src, int numberOfBytes) - { - CopyMemory(dest->ToPointer(), src->ToPointer(), numberOfBytes); - } + void NativeMethodWrapper::CopyMemoryUsingHandle(IntPtr^ dest, IntPtr^ src, int numberOfBytes) + { + CopyMemory(dest->ToPointer(), src->ToPointer(), numberOfBytes); + } + + bool NativeMethodWrapper::IsFocused(IntPtr handle) + { + // Ask Windows which control has the focus and then check if it's one of our children + auto focusControl = GetFocus(); + return focusControl != 0 && (IsChild((HWND)handle.ToPointer(), focusControl) == 1); + } } diff --git a/CefSharp.Core/NativeMethodWrapper.h b/CefSharp.Core/NativeMethodWrapper.h index ea6abbd449..660fc4c8d4 100644 --- a/CefSharp.Core/NativeMethodWrapper.h +++ b/CefSharp.Core/NativeMethodWrapper.h @@ -10,9 +10,10 @@ using namespace System; namespace CefSharp { - public ref class NativeMethodWrapper sealed - { - public: - static void CopyMemoryUsingHandle(IntPtr^ dest, IntPtr^ src, int numberOfBytes); - }; + public ref class NativeMethodWrapper sealed + { + public: + static void CopyMemoryUsingHandle(IntPtr^ dest, IntPtr^ src, int numberOfBytes); + static bool IsFocused(IntPtr handle); + }; } \ No newline at end of file diff --git a/CefSharp.WinForms/CefSharp.WinForms.csproj b/CefSharp.WinForms/CefSharp.WinForms.csproj index d945875db0..708d642ed9 100644 --- a/CefSharp.WinForms/CefSharp.WinForms.csproj +++ b/CefSharp.WinForms/CefSharp.WinForms.csproj @@ -52,7 +52,6 @@ - Component diff --git a/CefSharp.WinForms/ChromiumWebBrowser.cs b/CefSharp.WinForms/ChromiumWebBrowser.cs index 40ec8d6fe3..ea2fdc6189 100644 --- a/CefSharp.WinForms/ChromiumWebBrowser.cs +++ b/CefSharp.WinForms/ChromiumWebBrowser.cs @@ -384,9 +384,7 @@ public override bool Focused return false; } - // Ask Windows which control has the focus and then check if it's one of our children - var focus = User32.GetFocus(); - return focus != IntPtr.Zero && User32.IsChild(Handle, focus); + return NativeMethodWrapper.IsFocused(Handle); } } diff --git a/CefSharp.WinForms/Internals/User32.cs b/CefSharp.WinForms/Internals/User32.cs deleted file mode 100644 index 8aadba2853..0000000000 --- a/CefSharp.WinForms/Internals/User32.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. -// -// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. - -using System; -using System.Runtime.InteropServices; - -namespace CefSharp.WinForms.Internals -{ - public static class User32 - { - [DllImport("User32.dll")] - public extern static IntPtr GetFocus(); - - [DllImport("user32.dll")] - public extern static bool IsChild(IntPtr parent, IntPtr child); - } -} \ No newline at end of file From 251ae9a8ec75d6661ce475949e22b81a0ffb739f Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 30 Dec 2014 16:29:07 +1000 Subject: [PATCH 103/134] IntPtr is a struct so pass by value rather than reference --- CefSharp.Core/ManagedCefBrowserAdapter.h | 8 ++++---- CefSharp.Core/NativeMethodWrapper.cpp | 4 ++-- CefSharp.Core/NativeMethodWrapper.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CefSharp.Core/ManagedCefBrowserAdapter.h b/CefSharp.Core/ManagedCefBrowserAdapter.h index dbd8cbf4e9..d56fcef42f 100644 --- a/CefSharp.Core/ManagedCefBrowserAdapter.h +++ b/CefSharp.Core/ManagedCefBrowserAdapter.h @@ -64,9 +64,9 @@ namespace CefSharp _javaScriptObjectRepository = gcnew JavascriptObjectRepository(); } - void CreateOffscreenBrowser(IntPtr^ windowHandle, BrowserSettings^ browserSettings, String^ address) + void CreateOffscreenBrowser(IntPtr windowHandle, BrowserSettings^ browserSettings, String^ address) { - auto hwnd = static_cast(windowHandle->ToPointer()); + auto hwnd = static_cast(windowHandle.ToPointer()); CefWindowInfo window; window.SetAsWindowless(hwnd, TRUE); @@ -600,9 +600,9 @@ namespace CefSharp _clientAdapter->CloseDevTools(); } - void CreateBrowser(BrowserSettings^ browserSettings, IntPtr^ sourceHandle, String^ address) + void CreateBrowser(BrowserSettings^ browserSettings, IntPtr sourceHandle, String^ address) { - HWND hwnd = static_cast(sourceHandle->ToPointer()); + HWND hwnd = static_cast(sourceHandle.ToPointer()); RECT rect; GetClientRect(hwnd, &rect); CefWindowInfo window; diff --git a/CefSharp.Core/NativeMethodWrapper.cpp b/CefSharp.Core/NativeMethodWrapper.cpp index 04c00538e9..795ac8f05b 100644 --- a/CefSharp.Core/NativeMethodWrapper.cpp +++ b/CefSharp.Core/NativeMethodWrapper.cpp @@ -11,9 +11,9 @@ using namespace System; namespace CefSharp { - void NativeMethodWrapper::CopyMemoryUsingHandle(IntPtr^ dest, IntPtr^ src, int numberOfBytes) + void NativeMethodWrapper::CopyMemoryUsingHandle(IntPtr dest, IntPtr src, int numberOfBytes) { - CopyMemory(dest->ToPointer(), src->ToPointer(), numberOfBytes); + CopyMemory(dest.ToPointer(), src.ToPointer(), numberOfBytes); } bool NativeMethodWrapper::IsFocused(IntPtr handle) diff --git a/CefSharp.Core/NativeMethodWrapper.h b/CefSharp.Core/NativeMethodWrapper.h index 660fc4c8d4..b215127405 100644 --- a/CefSharp.Core/NativeMethodWrapper.h +++ b/CefSharp.Core/NativeMethodWrapper.h @@ -13,7 +13,7 @@ namespace CefSharp public ref class NativeMethodWrapper sealed { public: - static void CopyMemoryUsingHandle(IntPtr^ dest, IntPtr^ src, int numberOfBytes); + static void CopyMemoryUsingHandle(IntPtr dest, IntPtr src, int numberOfBytes); static bool IsFocused(IntPtr handle); }; } \ No newline at end of file From 1ba06eddad6c124765073446c40f897894495a85 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 6 Jan 2015 12:04:49 +1000 Subject: [PATCH 104/134] Remove redundant stdToString and replace with StringUtils call Minor code cleanup to TypeUtils --- CefSharp.BrowserSubprocess.Core/TypeUtils.cpp | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/CefSharp.BrowserSubprocess.Core/TypeUtils.cpp b/CefSharp.BrowserSubprocess.Core/TypeUtils.cpp index 16bf8d52f9..9b347e01d9 100644 --- a/CefSharp.BrowserSubprocess.Core/TypeUtils.cpp +++ b/CefSharp.BrowserSubprocess.Core/TypeUtils.cpp @@ -150,11 +150,6 @@ namespace CefSharp throw gcnew Exception(String::Format("Cannot convert '{0}' object from CLR to CEF.", type->FullName)); } - System::String^ stdToString(const std::string& s) - { - return gcnew System::String(s.c_str()); - } - Object^ TypeUtils::ConvertFromCef(CefRefPtr obj) { if (obj->IsNull() || obj->IsUndefined()) @@ -210,18 +205,15 @@ namespace CefSharp int objLength = keys.size(); if (objLength > 0) { - Dictionary^ result = gcnew Dictionary(); + auto result = gcnew Dictionary(); for (int i = 0; i < objLength; i++) { - std::string p_key = keys[i].ToString(); - String^ p_keyStr = stdToString(p_key); + String^ p_keyStr = StringUtils::ToClr(keys[i].ToString()); if ((obj->HasValue(keys[i])) && (!p_keyStr->StartsWith("__"))) { - CefRefPtr data; - - data = obj->GetValue(keys[i]); + CefRefPtr data = obj->GetValue(keys[i]); if (data != nullptr) { Object^ p_data = TypeUtils::ConvertFromCef(data); From 18837ae5e8f95dddf46b9b36ba60b09aa7fe75fd Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 6 Jan 2015 12:05:45 +1000 Subject: [PATCH 105/134] Move variable to inner scope Remove TODO comment --- CefSharp.Wpf/ChromiumWebBrowser.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index ff6ead787f..69fbcf81b4 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -649,11 +649,12 @@ void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) // Inform parents that the browser rendering is updating OnRendering(this, interopBitmapInfo); - var img = bitmapInfo.IsPopup ? popupImage : image; // Now update the WPF image var bitmap = interopBitmapInfo.InteropBitmap; if (bitmap == null) { + var img = bitmapInfo.IsPopup ? popupImage : image; + img.Source = null; GC.Collect(1); @@ -663,9 +664,6 @@ void IRenderWebBrowser.InvokeRenderAsync(BitmapInfo bitmapInfo) bitmapInfo.Width, bitmapInfo.Height, PixelFormat, stride, 0); img.Source = bitmap; - //TODO: Look into - //bitmap.CopyPixels - interopBitmapInfo.InteropBitmap = bitmap; } From 82d202e831d006265c6b55c0ea80b35ef23a2d3e Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 6 Jan 2015 16:07:16 +1000 Subject: [PATCH 106/134] Merge SetBuffer method into OnPaint --- CefSharp.Core/Internals/RenderClientAdapter.h | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index 4f81dc181f..4e6be413c0 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -97,25 +97,14 @@ namespace CefSharp virtual DECL void OnPaint(CefRefPtr browser, PaintElementType type, const RectList& dirtyRects, const void* buffer, int width, int height) OVERRIDE { - SetBuffer(type == PET_VIEW ? MainBitmapInfo : PopupBitmapInfo, width, height, buffer); - }; - - virtual DECL void OnCursorChange(CefRefPtr browser, CefCursorHandle cursor, CursorType type, - const CefCursorInfo& custom_cursor_info) OVERRIDE - { - _renderWebBrowser->SetCursor((IntPtr)cursor); - }; - - private: + auto bitmapInfo = type == PET_VIEW ? MainBitmapInfo : PopupBitmapInfo; - void SetBuffer(BitmapInfo^ bitmapInfo, int newWidth, int newHeight, const void* buffer) - { lock l(bitmapInfo->BitmapLock); auto fileMappingHandle = (HANDLE)bitmapInfo->FileMappingHandle; auto backBufferHandle = (HANDLE)bitmapInfo->BackBufferHandle; - SetBufferHelper(bitmapInfo, newWidth, newHeight, &fileMappingHandle, + SetBufferHelper(bitmapInfo, width, height, &fileMappingHandle, &backBufferHandle, buffer); bitmapInfo->FileMappingHandle = (IntPtr)fileMappingHandle; @@ -124,6 +113,13 @@ namespace CefSharp _renderWebBrowser->InvokeRenderAsync(bitmapInfo); }; + virtual DECL void OnCursorChange(CefRefPtr browser, CefCursorHandle cursor, CursorType type, + const CefCursorInfo& custom_cursor_info) OVERRIDE + { + _renderWebBrowser->SetCursor((IntPtr)cursor); + }; + + private: void SetBufferHelper(BitmapInfo^ bitmapInfo, int newWidth, int newHeight, HANDLE* fileMappingHandle, HANDLE* backBufferHandle, const void* buffer) { From 5ee13cc54f059c469cfceca77f4667f9aa307b8a Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 6 Jan 2015 16:10:38 +1000 Subject: [PATCH 107/134] Make MainBitmapInfo and PopupBitmapInfo private Make DisposeBitmapInfo private --- CefSharp.Core/Internals/RenderClientAdapter.h | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/CefSharp.Core/Internals/RenderClientAdapter.h b/CefSharp.Core/Internals/RenderClientAdapter.h index 4e6be413c0..7d6073b5f5 100644 --- a/CefSharp.Core/Internals/RenderClientAdapter.h +++ b/CefSharp.Core/Internals/RenderClientAdapter.h @@ -20,19 +20,18 @@ namespace CefSharp private: gcroot _webBrowserInternal; gcroot _renderWebBrowser; + gcroot _mainBitmapInfo; + gcroot _popupBitmapInfo; public: - gcroot MainBitmapInfo; - gcroot PopupBitmapInfo; - RenderClientAdapter(IWebBrowserInternal^ webBrowserInternal, Action^ onAfterBrowserCreated): ClientAdapter(webBrowserInternal, onAfterBrowserCreated), _webBrowserInternal(webBrowserInternal) { _renderWebBrowser = dynamic_cast(webBrowserInternal); - MainBitmapInfo = _renderWebBrowser->CreateBitmapInfo(false); - PopupBitmapInfo = _renderWebBrowser->CreateBitmapInfo(true); + _mainBitmapInfo = _renderWebBrowser->CreateBitmapInfo(false); + _popupBitmapInfo = _renderWebBrowser->CreateBitmapInfo(true); } ~RenderClientAdapter() @@ -40,23 +39,15 @@ namespace CefSharp _renderWebBrowser = nullptr; _webBrowserInternal = nullptr; - DisposeBitmapInfo(MainBitmapInfo); - - delete MainBitmapInfo; - MainBitmapInfo = nullptr; + DisposeBitmapInfo(_mainBitmapInfo); - DisposeBitmapInfo(PopupBitmapInfo); + delete _mainBitmapInfo; + _mainBitmapInfo = nullptr; - delete PopupBitmapInfo; - PopupBitmapInfo = nullptr; - } + DisposeBitmapInfo(_popupBitmapInfo); - void DisposeBitmapInfo(BitmapInfo^ bitmapInfo) - { - auto backBufferHandle = (HANDLE)bitmapInfo->BackBufferHandle; - auto fileMappingHandle = (HANDLE)bitmapInfo->FileMappingHandle; - - ReleaseBitmapHandlers(&backBufferHandle, &fileMappingHandle); + delete _popupBitmapInfo; + _popupBitmapInfo = nullptr; } // CefClient @@ -97,7 +88,7 @@ namespace CefSharp virtual DECL void OnPaint(CefRefPtr browser, PaintElementType type, const RectList& dirtyRects, const void* buffer, int width, int height) OVERRIDE { - auto bitmapInfo = type == PET_VIEW ? MainBitmapInfo : PopupBitmapInfo; + auto bitmapInfo = type == PET_VIEW ? _mainBitmapInfo : _popupBitmapInfo; lock l(bitmapInfo->BitmapLock); @@ -175,6 +166,14 @@ namespace CefSharp } } + void DisposeBitmapInfo(BitmapInfo^ bitmapInfo) + { + auto backBufferHandle = (HANDLE)bitmapInfo->BackBufferHandle; + auto fileMappingHandle = (HANDLE)bitmapInfo->FileMappingHandle; + + ReleaseBitmapHandlers(&backBufferHandle, &fileMappingHandle); + } + IMPLEMENT_REFCOUNTING(RenderClientAdapter) }; } From 742ef8ee3212abff0af3180806f6e04a40182a45 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 6 Jan 2015 16:21:26 +1000 Subject: [PATCH 108/134] Add Alt->F shortcut key to WinForms example --- CefSharp.WinForms.Example/BrowserForm.Designer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CefSharp.WinForms.Example/BrowserForm.Designer.cs b/CefSharp.WinForms.Example/BrowserForm.Designer.cs index 9d130463cc..a1f4094fd4 100644 --- a/CefSharp.WinForms.Example/BrowserForm.Designer.cs +++ b/CefSharp.WinForms.Example/BrowserForm.Designer.cs @@ -79,7 +79,7 @@ private void InitializeComponent() this.exitToolStripMenuItem}); this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); - this.fileToolStripMenuItem.Text = "File"; + this.fileToolStripMenuItem.Text = "&File"; // // newTabToolStripMenuItem // From fc65192e4252bd3ccbf4b82eb09b392fb016ff82 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 6 Jan 2015 16:46:09 +1000 Subject: [PATCH 109/134] Upgrade example projects to .Net 4.5 (as discussed in #381) --- .../CefSharp.OffScreen.Example.csproj | 9 +++++++-- CefSharp.OffScreen.Example/app.config | 2 +- .../CefSharp.WinForms.Example.csproj | 6 +++++- CefSharp.WinForms.Example/app.config | 2 +- CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj | 8 +++++++- CefSharp.Wpf.Example/app.config | 2 +- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj b/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj index 0e663d886c..9714102b68 100644 --- a/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj +++ b/CefSharp.OffScreen.Example/CefSharp.OffScreen.Example.csproj @@ -9,9 +9,10 @@ Properties CefSharp.OffScreen.Example CefSharp.OffScreen.Example - v4.0 + v4.5 512 - Client + + 320b0b24 @@ -22,6 +23,7 @@ x64 prompt MinimumRecommendedRules.ruleset + false bin\x64\Release\ @@ -31,6 +33,7 @@ x64 prompt MinimumRecommendedRules.ruleset + false true @@ -40,6 +43,7 @@ x86 prompt MinimumRecommendedRules.ruleset + false bin\x86\Release\ @@ -49,6 +53,7 @@ x86 prompt MinimumRecommendedRules.ruleset + false diff --git a/CefSharp.OffScreen.Example/app.config b/CefSharp.OffScreen.Example/app.config index 2f7cce784b..c5e1daefd3 100644 --- a/CefSharp.OffScreen.Example/app.config +++ b/CefSharp.OffScreen.Example/app.config @@ -1,3 +1,3 @@ - + diff --git a/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj b/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj index 196133da78..b283b4e74f 100644 --- a/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj +++ b/CefSharp.WinForms.Example/CefSharp.WinForms.Example.csproj @@ -10,7 +10,7 @@ Properties CefSharp.WinForms.Example CefSharp.WinForms.Example - v4.0 + v4.5 512 @@ -26,21 +26,25 @@ x64 bin\x64\Debug\ + false x64 bin\x64\Release\ + false true bin\x86\Debug\ x86 MinimumRecommendedRules.ruleset + false bin\x86\Release\ x86 MinimumRecommendedRules.ruleset + false app.manifest diff --git a/CefSharp.WinForms.Example/app.config b/CefSharp.WinForms.Example/app.config index 2f7cce784b..c5e1daefd3 100644 --- a/CefSharp.WinForms.Example/app.config +++ b/CefSharp.WinForms.Example/app.config @@ -1,3 +1,3 @@ - + diff --git a/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj b/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj index 37e8ff465a..65d6a80986 100644 --- a/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj +++ b/CefSharp.Wpf.Example/CefSharp.Wpf.Example.csproj @@ -10,7 +10,7 @@ Properties CefSharp.Wpf.Example CefSharp.Wpf.Example - v4.0 + v4.5 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 @@ -34,6 +34,7 @@ x64 AllRules.ruleset true + false pdbonly @@ -44,6 +45,7 @@ 4 x86 AllRules.ruleset + false true @@ -53,6 +55,7 @@ x64 prompt AllRules.ruleset + false bin\x64\Release\ @@ -62,6 +65,7 @@ x64 prompt AllRules.ruleset + false true @@ -71,6 +75,7 @@ x86 prompt AllRules.ruleset + false bin\x86\Release\ @@ -80,6 +85,7 @@ x86 prompt AllRules.ruleset + false diff --git a/CefSharp.Wpf.Example/app.config b/CefSharp.Wpf.Example/app.config index 2f7cce784b..c5e1daefd3 100644 --- a/CefSharp.Wpf.Example/app.config +++ b/CefSharp.Wpf.Example/app.config @@ -1,3 +1,3 @@ - + From 7aa1c262b1b2899e7c8c80a239fc81912bf0555a Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 6 Jan 2015 16:50:32 +1000 Subject: [PATCH 110/134] Update two methods in the WPF and WinForms examples to use async/await --- .../BrowserTabUserControl.cs | 15 ++++----------- .../ViewModels/BrowserTabViewModel.cs | 15 +++------------ 2 files changed, 7 insertions(+), 23 deletions(-) diff --git a/CefSharp.WinForms.Example/BrowserTabUserControl.cs b/CefSharp.WinForms.Example/BrowserTabUserControl.cs index 28095a5b4d..eca1fdb734 100644 --- a/CefSharp.WinForms.Example/BrowserTabUserControl.cs +++ b/CefSharp.WinForms.Example/BrowserTabUserControl.cs @@ -188,19 +188,12 @@ private void LoadUrl(string url) } } - public void CopySourceToClipBoardAsync() + public async void CopySourceToClipBoardAsync() { - var task = Browser.GetSourceAsync(); + var htmlSource = await Browser.GetSourceAsync(); - task.ContinueWith(t => - { - if (!t.IsFaulted) - { - Clipboard.SetText(t.Result); - DisplayOutput("HTML Source copied to clipboard"); - } - }, - TaskScheduler.FromCurrentSynchronizationContext()); + Clipboard.SetText(htmlSource); + DisplayOutput("HTML Source copied to clipboard"); } private void ToggleBottomToolStrip() diff --git a/CefSharp.Wpf.Example/ViewModels/BrowserTabViewModel.cs b/CefSharp.Wpf.Example/ViewModels/BrowserTabViewModel.cs index 91b4337375..d0a0d4fbb2 100644 --- a/CefSharp.Wpf.Example/ViewModels/BrowserTabViewModel.cs +++ b/CefSharp.Wpf.Example/ViewModels/BrowserTabViewModel.cs @@ -2,7 +2,6 @@ // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. -using System.Threading.Tasks; using CefSharp.Example; using CefSharp.Wpf.Example.Mvvm; using System; @@ -94,21 +93,13 @@ public BrowserTabViewModel(string address) OutputMessage = version; } - private void EvaluateJavaScript(string s) + private async void EvaluateJavaScript(string s) { try { - var task = webBrowser.EvaluateScriptAsync(s); + var response = await webBrowser.EvaluateScriptAsync(s); - task.ContinueWith(t => - { - if (!t.IsFaulted) - { - var response = t.Result; - EvaluateJavaScriptResult = response.Success ? (response.Result ?? "null") : response.Message; - } - }, - TaskScheduler.FromCurrentSynchronizationContext()); + EvaluateJavaScriptResult = response.Success ? (response.Result ?? "null") : response.Message; } catch (Exception e) { From 0a3ef1d0e2f27a63d0f9a1e893cf674ea4e37faa Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 6 Jan 2015 20:42:52 +1000 Subject: [PATCH 111/134] Add service ServiceKnownTypes for object[] and Dictionary so that basic arrays can be passed two and from functions --- CefSharp/Internals/IBrowserProcess.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CefSharp/Internals/IBrowserProcess.cs b/CefSharp/Internals/IBrowserProcess.cs index dc6e2c31d8..783a523d08 100644 --- a/CefSharp/Internals/IBrowserProcess.cs +++ b/CefSharp/Internals/IBrowserProcess.cs @@ -2,11 +2,14 @@ // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. +using System.Collections.Generic; using System.ServiceModel; namespace CefSharp.Internals { [ServiceContract(CallbackContract = typeof(IRenderProcess), SessionMode = SessionMode.Required)] + [ServiceKnownType(typeof(object[]))] + [ServiceKnownType(typeof(Dictionary))] public interface IBrowserProcess { [OperationContract] From fc4cde6e7847d55bc1e89a595070a1e25b502df9 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 6 Jan 2015 20:44:19 +1000 Subject: [PATCH 112/134] Improve JavascriptMethodHandler error handling - return clr exception to Cef --- .../JavascriptMethodHandler.h | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.h b/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.h index 3ffad755d8..70a55ab9c1 100644 --- a/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.h +++ b/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.h @@ -37,13 +37,21 @@ namespace CefSharp parameter[i] = TypeUtils::ConvertFromCef(arguments[i]); } - auto response = _method->Invoke(parameter); + try + { + auto response = _method->Invoke(parameter); - retval = TypeUtils::ConvertToCef(response->Result, nullptr); - if(!response->Success) + retval = TypeUtils::ConvertToCef(response->Result, nullptr); + if (!response->Success) + { + exception = StringUtils::ToNative(response->Message); + } + } + catch (Exception^ ex) { - exception = StringUtils::ToNative(response->Message); + exception = StringUtils::ToNative(ex->Message); } + //NOTE: Return true otherwise exception is ignored return true; } From be5d3db546a9c7587987cdccd80baa4f59641e9d Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 6 Jan 2015 20:47:30 +1000 Subject: [PATCH 113/134] Add ComplexParamObject method to BoundObject - test for passing a complex object from javascript (which is converted into a dictionary) Example usage bound.complexParamObject({ 'color': 'purple' }); --- CefSharp.Example/BoundObject.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CefSharp.Example/BoundObject.cs b/CefSharp.Example/BoundObject.cs index 50fc60a81b..61c948785a 100644 --- a/CefSharp.Example/BoundObject.cs +++ b/CefSharp.Example/BoundObject.cs @@ -207,5 +207,14 @@ public string IgnoredMethod() { return "I am an Ignored Method"; } + + public string ComplexParamObject(object param) + { + if (param == null) + { + return "param is null"; + } + return "The param type is:" + param.GetType(); + } } } From c3aff2f80344c71eecc82b6e47e20eb8a742960e Mon Sep 17 00:00:00 2001 From: amaitland Date: Thu, 8 Jan 2015 10:39:40 +1000 Subject: [PATCH 114/134] Resharper inspired cleanup - remove redundant using --- CefSharp.OffScreen/ChromiumWebBrowser.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CefSharp.OffScreen/ChromiumWebBrowser.cs b/CefSharp.OffScreen/ChromiumWebBrowser.cs index 0000defa19..b047d4125e 100644 --- a/CefSharp.OffScreen/ChromiumWebBrowser.cs +++ b/CefSharp.OffScreen/ChromiumWebBrowser.cs @@ -4,7 +4,6 @@ using System; using System.Drawing; -using System.Drawing.Imaging; using System.Text; using System.Threading.Tasks; using CefSharp.Internals; @@ -36,7 +35,7 @@ public class ChromiumWebBrowser : IRenderWebBrowser /// This must be set to something other than 0x0 otherwise Chromium will not render, /// and the ScreenshotAsync task will deadlock. ///
- private System.Drawing.Size size = new System.Drawing.Size(1366, 768); + private Size size = new Size(1366, 768); /// /// Create a new OffScreen Chromium Browser @@ -80,7 +79,7 @@ public void Dispose() /// /// This also changes the size of the next screenshot. /// - public System.Drawing.Size Size + public Size Size { get { return size; } set From 6ef03d4cc5381d09d3edcba0a781f87be5d26002 Mon Sep 17 00:00:00 2001 From: amaitland Date: Thu, 8 Jan 2015 10:44:11 +1000 Subject: [PATCH 115/134] Simplify CefWebPluginInfoWrapper - no need to keep reference, simply read values into properties (Reduces risk of memory leaks if user keeps reference to IWebPluginInfo for some reason) --- CefSharp.Core/CefSharp.Core.vcxproj | 1 - CefSharp.Core/CefSharp.Core.vcxproj.filters | 3 -- .../Internals/CefWebPluginInfoWrapper.cpp | 32 ------------------- .../Internals/CefWebPluginInfoWrapper.h | 19 ++++++----- 4 files changed, 11 insertions(+), 44 deletions(-) delete mode 100644 CefSharp.Core/Internals/CefWebPluginInfoWrapper.cpp diff --git a/CefSharp.Core/CefSharp.Core.vcxproj b/CefSharp.Core/CefSharp.Core.vcxproj index 776af7086f..2c6a3d50b6 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj +++ b/CefSharp.Core/CefSharp.Core.vcxproj @@ -218,7 +218,6 @@ - diff --git a/CefSharp.Core/CefSharp.Core.vcxproj.filters b/CefSharp.Core/CefSharp.Core.vcxproj.filters index d949f61955..07d82bd4c9 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj.filters +++ b/CefSharp.Core/CefSharp.Core.vcxproj.filters @@ -38,9 +38,6 @@ Source Files - - Source Files - Source Files diff --git a/CefSharp.Core/Internals/CefWebPluginInfoWrapper.cpp b/CefSharp.Core/Internals/CefWebPluginInfoWrapper.cpp deleted file mode 100644 index d634a57657..0000000000 --- a/CefSharp.Core/Internals/CefWebPluginInfoWrapper.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright © 2010-2014 The CefSharp Project. All rights reserved. -// -// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. - -#include "Stdafx.h" -#include "CefWebPluginInfoWrapper.h" - -namespace CefSharp -{ - namespace Internals - { - String^ CefWebPluginInfoWrapper::Description::get() - { - return StringUtils::ToClr(_wrappedInfo->GetDescription()); - } - - String^ CefWebPluginInfoWrapper::Name::get() - { - return StringUtils::ToClr(_wrappedInfo->GetName()); - } - - String^ CefWebPluginInfoWrapper::Path::get() - { - return StringUtils::ToClr(_wrappedInfo->GetPath()); - } - - String^ CefWebPluginInfoWrapper::Version::get() - { - return StringUtils::ToClr(_wrappedInfo->GetVersion()); - } - } -} diff --git a/CefSharp.Core/Internals/CefWebPluginInfoWrapper.h b/CefSharp.Core/Internals/CefWebPluginInfoWrapper.h index 6de3133ef0..b6a83dbc23 100644 --- a/CefSharp.Core/Internals/CefWebPluginInfoWrapper.h +++ b/CefSharp.Core/Internals/CefWebPluginInfoWrapper.h @@ -5,7 +5,6 @@ #pragma once #include "Stdafx.h" -#include "MCefRefPtr.h" using namespace System; using namespace System::Collections::Generic; @@ -16,16 +15,20 @@ namespace CefSharp { ref class CefWebPluginInfoWrapper : public IWebPluginInfo { - MCefRefPtr _wrappedInfo; - internal: - CefWebPluginInfoWrapper(CefRefPtr cefInfo) : _wrappedInfo(cefInfo) {} + CefWebPluginInfoWrapper(CefRefPtr webPluginInfo) + { + Description = StringUtils::ToClr(webPluginInfo->GetDescription()); + Name = StringUtils::ToClr(webPluginInfo->GetName()); + Path = StringUtils::ToClr(webPluginInfo->GetPath()); + Version = StringUtils::ToClr(webPluginInfo->GetVersion()); + } public: - virtual property String^ Description { String^ get(); } - virtual property String^ Name { String^ get(); } - virtual property String^ Path { String^ get(); } - virtual property String^ Version { String^ get(); } + virtual property String^ Description; + virtual property String^ Name; + virtual property String^ Path; + virtual property String^ Version; }; } } From 57dad250f736377d569c5c58267966a212968365 Mon Sep 17 00:00:00 2001 From: amaitland Date: Thu, 8 Jan 2015 11:22:54 +1000 Subject: [PATCH 116/134] Add TypeConversion class as a common place for simple static methods used to convert to/from cef objects --- CefSharp.Core/CefSharp.Core.vcxproj | 1 + CefSharp.Core/CefSharp.Core.vcxproj.filters | 3 + CefSharp.Core/Internals/DownloadAdapter.cpp | 42 +------------- CefSharp.Core/Internals/DownloadAdapter.h | 2 - CefSharp.Core/Internals/TypeConversion.h | 62 +++++++++++++++++++++ 5 files changed, 69 insertions(+), 41 deletions(-) create mode 100644 CefSharp.Core/Internals/TypeConversion.h diff --git a/CefSharp.Core/CefSharp.Core.vcxproj b/CefSharp.Core/CefSharp.Core.vcxproj index 2c6a3d50b6..7bc7e17c42 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj +++ b/CefSharp.Core/CefSharp.Core.vcxproj @@ -251,6 +251,7 @@ + diff --git a/CefSharp.Core/CefSharp.Core.vcxproj.filters b/CefSharp.Core/CefSharp.Core.vcxproj.filters index 07d82bd4c9..de540494a9 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj.filters +++ b/CefSharp.Core/CefSharp.Core.vcxproj.filters @@ -133,6 +133,9 @@ Header Files + + Header Files + diff --git a/CefSharp.Core/Internals/DownloadAdapter.cpp b/CefSharp.Core/Internals/DownloadAdapter.cpp index 274aa80109..46cdfa49d5 100644 --- a/CefSharp.Core/Internals/DownloadAdapter.cpp +++ b/CefSharp.Core/Internals/DownloadAdapter.cpp @@ -7,6 +7,7 @@ #include "Stdafx.h" #include "include/cef_download_handler.h" #include "DownloadAdapter.h" +#include "TypeConversion.h" using namespace System; using namespace CefSharp; @@ -25,7 +26,7 @@ namespace CefSharp { String^ download_path; bool show_dialog; - auto downloadItem = GetDownloadItem(download_item); + auto downloadItem = TypeConversion::FromNative(download_item); downloadItem->SuggestedFileName = StringUtils::ToClr(suggested_name); if (_handler->OnBeforeDownload(downloadItem, download_path, show_dialog)) @@ -37,47 +38,10 @@ namespace CefSharp void DownloadAdapter::OnDownloadUpdated(CefRefPtr browser, CefRefPtr download_item, CefRefPtr callback) { - if (_handler->OnDownloadUpdated(GetDownloadItem(download_item))) + if (_handler->OnDownloadUpdated(TypeConversion::FromNative(download_item))) { callback->Cancel(); } } - - CefSharp::DownloadItem^ DownloadAdapter::GetDownloadItem(CefRefPtr download_item) - { - auto item = gcnew CefSharp::DownloadItem(); - item->IsValid = download_item->IsValid(); - //NOTE: Description for IsValid says `Do not call any other methods if this function returns false.` so only load if IsValid = true - if(item->IsValid) - { - item->IsInProgress = download_item->IsInProgress(); - item->IsComplete = download_item->IsComplete(); - item->IsCancelled = download_item->IsCanceled(); - item->CurrentSpeed = download_item->GetCurrentSpeed(); - item->PercentComplete = download_item->GetPercentComplete(); - item->TotalBytes = download_item->GetTotalBytes(); - item->ReceivedBytes = download_item->GetReceivedBytes(); - item->StartTime = ConvertCefTimeToNullableDateTime(download_item->GetStartTime()); - item->EndTime = ConvertCefTimeToNullableDateTime(download_item->GetEndTime()); - item->FullPath = StringUtils::ToClr(download_item->GetFullPath()); - item->Id = download_item->GetId(); - item->Url = StringUtils::ToClr(download_item->GetURL()); - item->SuggestedFileName = StringUtils::ToClr(download_item->GetSuggestedFileName()); - item->ContentDisposition = StringUtils::ToClr(download_item->GetContentDisposition()); - item->MimeType = StringUtils::ToClr(download_item->GetMimeType()); - } - - return item; - } - - Nullable DownloadAdapter::ConvertCefTimeToNullableDateTime(CefTime time) - { - auto epoch = time.GetDoubleT(); - if(epoch == 0) - { - return Nullable(); - } - return Nullable(DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(epoch).ToLocalTime()); - } } } diff --git a/CefSharp.Core/Internals/DownloadAdapter.h b/CefSharp.Core/Internals/DownloadAdapter.h index 752929a9b8..c3c130e575 100644 --- a/CefSharp.Core/Internals/DownloadAdapter.h +++ b/CefSharp.Core/Internals/DownloadAdapter.h @@ -18,8 +18,6 @@ namespace CefSharp { private: gcroot _handler; - DownloadItem^ DownloadAdapter::GetDownloadItem(CefRefPtr download_item); - Nullable ConvertCefTimeToNullableDateTime(CefTime time); public: DownloadAdapter(IDownloadHandler^ handler) : _handler(handler) { } diff --git a/CefSharp.Core/Internals/TypeConversion.h b/CefSharp.Core/Internals/TypeConversion.h new file mode 100644 index 0000000000..1814a9fdc5 --- /dev/null +++ b/CefSharp.Core/Internals/TypeConversion.h @@ -0,0 +1,62 @@ +// Copyright © 2010-2014 The CefSharp Authors. All rights reserved. +// +// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. + +#pragma once + +#include "include/internal/cef_ptr.h" +#include "include/cef_download_item.h" +#include "Internals/StringUtils.h" + +using namespace System; +using namespace CefSharp; + +namespace CefSharp +{ + namespace Internals + { + //Static class for converting to/from Cef classes + private ref class TypeConversion abstract sealed + { + public: + //ConvertFrom CefDownload to DownloadItem + static DownloadItem^ FromNative(CefRefPtr downloadItem) + { + auto item = gcnew CefSharp::DownloadItem(); + item->IsValid = downloadItem->IsValid(); + //NOTE: Description for IsValid says `Do not call any other methods if this function returns false.` so only load if IsValid = true + if(item->IsValid) + { + item->IsInProgress = downloadItem->IsInProgress(); + item->IsComplete = downloadItem->IsComplete(); + item->IsCancelled = downloadItem->IsCanceled(); + item->CurrentSpeed = downloadItem->GetCurrentSpeed(); + item->PercentComplete = downloadItem->GetPercentComplete(); + item->TotalBytes = downloadItem->GetTotalBytes(); + item->ReceivedBytes = downloadItem->GetReceivedBytes(); + item->StartTime = FromNative(downloadItem->GetStartTime()); + item->EndTime = FromNative(downloadItem->GetEndTime()); + item->FullPath = StringUtils::ToClr(downloadItem->GetFullPath()); + item->Id = downloadItem->GetId(); + item->Url = StringUtils::ToClr(downloadItem->GetURL()); + item->SuggestedFileName = StringUtils::ToClr(downloadItem->GetSuggestedFileName()); + item->ContentDisposition = StringUtils::ToClr(downloadItem->GetContentDisposition()); + item->MimeType = StringUtils::ToClr(downloadItem->GetMimeType()); + } + + return item; + } + + //Convert from CefTime to Nullable + static Nullable FromNative(CefTime time) + { + auto epoch = time.GetDoubleT(); + if(epoch == 0) + { + return Nullable(); + } + return Nullable(DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(epoch).ToLocalTime()); + } + }; + } +} \ No newline at end of file From ff634e299bddd32fe29f57ed3fec40974ed2cde8 Mon Sep 17 00:00:00 2001 From: amaitland Date: Thu, 8 Jan 2015 11:40:53 +1000 Subject: [PATCH 117/134] Replace IWebPluginInfo with WebPluginInfo Instead of wrapping the Cef object, just read it's properties through a helper method --- CefSharp.Core/CefSharp.Core.vcxproj | 1 - CefSharp.Core/CefSharp.Core.vcxproj.filters | 3 -- .../Internals/CefWebPluginInfoWrapper.h | 34 ------------------- CefSharp.Core/Internals/ClientAdapter.cpp | 8 ++--- CefSharp.Core/Internals/TypeConversion.h | 11 ++++++ CefSharp.Example/RequestHandler.cs | 2 +- CefSharp/CefSharp.csproj | 2 +- CefSharp/IRequestHandler.cs | 2 +- .../{IWebPluginInfo.cs => WebPluginInfo.cs} | 12 +++---- 9 files changed, 24 insertions(+), 51 deletions(-) delete mode 100644 CefSharp.Core/Internals/CefWebPluginInfoWrapper.h rename CefSharp/{IWebPluginInfo.cs => WebPluginInfo.cs} (52%) diff --git a/CefSharp.Core/CefSharp.Core.vcxproj b/CefSharp.Core/CefSharp.Core.vcxproj index 7bc7e17c42..6d9cd3ffa0 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj +++ b/CefSharp.Core/CefSharp.Core.vcxproj @@ -263,7 +263,6 @@ - diff --git a/CefSharp.Core/CefSharp.Core.vcxproj.filters b/CefSharp.Core/CefSharp.Core.vcxproj.filters index de540494a9..89770fcb7a 100644 --- a/CefSharp.Core/CefSharp.Core.vcxproj.filters +++ b/CefSharp.Core/CefSharp.Core.vcxproj.filters @@ -112,9 +112,6 @@ Header Files - - Header Files - Header Files diff --git a/CefSharp.Core/Internals/CefWebPluginInfoWrapper.h b/CefSharp.Core/Internals/CefWebPluginInfoWrapper.h deleted file mode 100644 index b6a83dbc23..0000000000 --- a/CefSharp.Core/Internals/CefWebPluginInfoWrapper.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright © 2010-2014 The CefSharp Project. All rights reserved. -// -// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. - -#pragma once - -#include "Stdafx.h" - -using namespace System; -using namespace System::Collections::Generic; - -namespace CefSharp -{ - namespace Internals - { - ref class CefWebPluginInfoWrapper : public IWebPluginInfo - { - internal: - CefWebPluginInfoWrapper(CefRefPtr webPluginInfo) - { - Description = StringUtils::ToClr(webPluginInfo->GetDescription()); - Name = StringUtils::ToClr(webPluginInfo->GetName()); - Path = StringUtils::ToClr(webPluginInfo->GetPath()); - Version = StringUtils::ToClr(webPluginInfo->GetVersion()); - } - - public: - virtual property String^ Description; - virtual property String^ Name; - virtual property String^ Path; - virtual property String^ Version; - }; - } -} diff --git a/CefSharp.Core/Internals/ClientAdapter.cpp b/CefSharp.Core/Internals/ClientAdapter.cpp index b72e6a4c75..0512a7ea78 100644 --- a/CefSharp.Core/Internals/ClientAdapter.cpp +++ b/CefSharp.Core/Internals/ClientAdapter.cpp @@ -5,12 +5,12 @@ #include "Stdafx.h" #include "Internals/CefRequestWrapper.h" -#include "Internals/CefWebPluginInfoWrapper.h" #include "Internals/CefContextMenuParamsWrapper.h" #include "Internals/CefDragDataWrapper.h" #include "ClientAdapter.h" #include "DownloadAdapter.h" #include "StreamAdapter.h" +#include "Internals/TypeConversion.h" #include "include/wrapper/cef_stream_resource_handler.h" namespace CefSharp @@ -272,7 +272,7 @@ namespace CefSharp // return value: // false: Load Plugin (do not block it) // true: Ignore Plugin (Block it) - bool ClientAdapter::OnBeforePluginLoad( CefRefPtr< CefBrowser > browser, const CefString& url, const CefString& policy_url, CefRefPtr< CefWebPluginInfo > info ) + bool ClientAdapter::OnBeforePluginLoad(CefRefPtr browser, const CefString& url, const CefString& policy_url, CefRefPtr info) { IRequestHandler^ handler = _browserControl->RequestHandler; @@ -281,9 +281,9 @@ namespace CefSharp return false; } - CefWebPluginInfoWrapper^ wrapper = gcnew CefWebPluginInfoWrapper(info); + auto pluginInfo = TypeConversion::FromNative(info); - return handler->OnBeforePluginLoad(_browserControl, StringUtils::ToClr(url), StringUtils::ToClr(policy_url), wrapper); + return handler->OnBeforePluginLoad(_browserControl, StringUtils::ToClr(url), StringUtils::ToClr(policy_url), pluginInfo); } void ClientAdapter::OnPluginCrashed(CefRefPtr browser, const CefString& plugin_path) diff --git a/CefSharp.Core/Internals/TypeConversion.h b/CefSharp.Core/Internals/TypeConversion.h index 1814a9fdc5..ac0cb50f65 100644 --- a/CefSharp.Core/Internals/TypeConversion.h +++ b/CefSharp.Core/Internals/TypeConversion.h @@ -57,6 +57,17 @@ namespace CefSharp } return Nullable(DateTime(1970, 1, 1, 0, 0, 0).AddSeconds(epoch).ToLocalTime()); } + + static WebPluginInfo^ FromNative(CefRefPtr webPluginInfo) + { + auto managedWebPluginInfo = gcnew WebPluginInfo(); + managedWebPluginInfo->Description = StringUtils::ToClr(webPluginInfo->GetDescription()); + managedWebPluginInfo->Name = StringUtils::ToClr(webPluginInfo->GetName()); + managedWebPluginInfo->Path = StringUtils::ToClr(webPluginInfo->GetPath()); + managedWebPluginInfo->Version = StringUtils::ToClr(webPluginInfo->GetVersion()); + + return managedWebPluginInfo; + } }; } } \ No newline at end of file diff --git a/CefSharp.Example/RequestHandler.cs b/CefSharp.Example/RequestHandler.cs index 11bce0a8d9..55b9f1a630 100644 --- a/CefSharp.Example/RequestHandler.cs +++ b/CefSharp.Example/RequestHandler.cs @@ -32,7 +32,7 @@ bool IRequestHandler.GetAuthCredentials(IWebBrowser browser, bool isProxy, strin return false; } - bool IRequestHandler.OnBeforePluginLoad(IWebBrowser browser, string url, string policyUrl, IWebPluginInfo info) + bool IRequestHandler.OnBeforePluginLoad(IWebBrowser browser, string url, string policyUrl, WebPluginInfo info) { bool blockPluginLoad = false; diff --git a/CefSharp/CefSharp.csproj b/CefSharp/CefSharp.csproj index 054fca8074..4ec0ff42ab 100644 --- a/CefSharp/CefSharp.csproj +++ b/CefSharp/CefSharp.csproj @@ -138,7 +138,7 @@ - + diff --git a/CefSharp/IRequestHandler.cs b/CefSharp/IRequestHandler.cs index c82e4ba566..27ebdd6a57 100644 --- a/CefSharp/IRequestHandler.cs +++ b/CefSharp/IRequestHandler.cs @@ -65,7 +65,7 @@ public interface IRequestHandler /// policy URL /// plugin information /// Return true to block loading of the plugin. - bool OnBeforePluginLoad(IWebBrowser browser, string url, string policyUrl, IWebPluginInfo info); + bool OnBeforePluginLoad(IWebBrowser browser, string url, string policyUrl, WebPluginInfo info); /// /// Called when the render process terminates unexpectedly. diff --git a/CefSharp/IWebPluginInfo.cs b/CefSharp/WebPluginInfo.cs similarity index 52% rename from CefSharp/IWebPluginInfo.cs rename to CefSharp/WebPluginInfo.cs index 3f67c651a1..2338d5358e 100644 --- a/CefSharp/IWebPluginInfo.cs +++ b/CefSharp/WebPluginInfo.cs @@ -5,16 +5,16 @@ namespace CefSharp { /// - /// Wrapper for the CEF3 CefWebPluginInfo + /// CefWebPluginInfo /// - public interface IWebPluginInfo + public class WebPluginInfo { - string Name { get; } + public string Name { get; set; } - string Description { get; } + public string Description { get; set; } - string Path { get; } + public string Path { get; set; } - string Version { get; } + public string Version { get; set; } } } From 44d00d79a0fc5218fc75cf54a674b0f7c278a5b1 Mon Sep 17 00:00:00 2001 From: amaitland Date: Thu, 8 Jan 2015 13:34:32 +1000 Subject: [PATCH 118/134] Cleanup some of the Cookie code in Cef.h - remove redundant casts, simplify if statements --- CefSharp.Core/Cef.h | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/CefSharp.Core/Cef.h b/CefSharp.Core/Cef.h index 5e7928b355..6ba4448854 100644 --- a/CefSharp.Core/Cef.h +++ b/CefSharp.Core/Cef.h @@ -164,17 +164,16 @@ namespace CefSharp /// Returns false if the CookieManager is not available; otherwise, true. static bool VisitAllCookies(ICookieVisitor^ visitor) { - CefRefPtr cookieVisitor = new CookieVisitor(visitor); CefRefPtr manager = CefCookieManager::GetGlobalManager(); - if (manager != nullptr) - { - return manager->VisitAllCookies(static_cast>(cookieVisitor)); - } - else + if (manager == nullptr) { return false; } + + CefRefPtr cookieVisitor = new CookieVisitor(visitor); + + return manager->VisitAllCookies(cookieVisitor); } /// Visits a subset of the cookies. The results are filtered by the given url scheme, host, domain and path. @@ -186,18 +185,16 @@ namespace CefSharp /// Returns false if the CookieManager is not available; otherwise, true. static bool VisitUrlCookies(String^ url, bool includeHttpOnly, ICookieVisitor^ visitor) { - CefRefPtr cookieVisitor = new CookieVisitor(visitor); CefRefPtr manager = CefCookieManager::GetGlobalManager(); - if (manager != nullptr) - { - return manager->VisitUrlCookies(StringUtils::ToNative(url), includeHttpOnly, - static_cast>(cookieVisitor)); - } - else + if (manager == nullptr) { return false; } + + CefRefPtr cookieVisitor = new CookieVisitor(visitor); + + return manager->VisitUrlCookies(StringUtils::ToNative(url), includeHttpOnly, cookieVisitor); } /// Sets a CefSharp Cookie. This function expects each attribute to be well-formed. It will check for disallowed @@ -296,14 +293,12 @@ namespace CefSharp { CefRefPtr manager = CefCookieManager::GetGlobalManager(); - if (manager != nullptr) - { - return manager->SetStoragePath(StringUtils::ToNative(path), persistSessionCookies); - } - else + if (manager == nullptr) { return false; } + + return manager->SetStoragePath(StringUtils::ToNative(path), persistSessionCookies); } /// Flush the backing store (if any) to disk and execute the specified |handler| on the IO thread when done. Returns @@ -318,9 +313,9 @@ namespace CefSharp return false; } - auto wrapper = new CompletionHandler(handler); + CefRefPtr wrapper = new CompletionHandler(handler); - return manager->FlushStore(static_cast>(wrapper)); + return manager->FlushStore(wrapper); } /// Shuts down CefSharp and the underlying CEF infrastructure. This method is safe to call multiple times; it will only From 901a70ac00079802a424faa1f57b436284fe6d3d Mon Sep 17 00:00:00 2001 From: amaitland Date: Thu, 8 Jan 2015 15:03:24 +1000 Subject: [PATCH 119/134] Automatically register function return types with WCF (only solves have the equation as the subprocess has no idea during deserialization) --- CefSharp.Example/BoundObject.cs | 5 +++ CefSharp/CefSharp.csproj | 1 + CefSharp/Internals/IBrowserProcess.cs | 4 +-- .../Internals/JavascriptObjectRepository.cs | 31 +++++++++++++++++- CefSharp/JavascriptKnownTypesRegistra.cs | 32 +++++++++++++++++++ 5 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 CefSharp/JavascriptKnownTypesRegistra.cs diff --git a/CefSharp.Example/BoundObject.cs b/CefSharp.Example/BoundObject.cs index 61c948785a..f76a086016 100644 --- a/CefSharp.Example/BoundObject.cs +++ b/CefSharp.Example/BoundObject.cs @@ -216,5 +216,10 @@ public string ComplexParamObject(object param) } return "The param type is:" + param.GetType(); } + + public SubBoundObject GetSubObject() + { + return SubObject; + } } } diff --git a/CefSharp/CefSharp.csproj b/CefSharp/CefSharp.csproj index 4ec0ff42ab..16194482ff 100644 --- a/CefSharp/CefSharp.csproj +++ b/CefSharp/CefSharp.csproj @@ -108,6 +108,7 @@ + diff --git a/CefSharp/Internals/IBrowserProcess.cs b/CefSharp/Internals/IBrowserProcess.cs index 783a523d08..bbe884c491 100644 --- a/CefSharp/Internals/IBrowserProcess.cs +++ b/CefSharp/Internals/IBrowserProcess.cs @@ -2,14 +2,12 @@ // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. -using System.Collections.Generic; using System.ServiceModel; namespace CefSharp.Internals { [ServiceContract(CallbackContract = typeof(IRenderProcess), SessionMode = SessionMode.Required)] - [ServiceKnownType(typeof(object[]))] - [ServiceKnownType(typeof(Dictionary))] + [ServiceKnownType("GetKnownTypes", typeof(JavascriptKnownTypesRegistra))] public interface IBrowserProcess { [OperationContract] diff --git a/CefSharp/Internals/JavascriptObjectRepository.cs b/CefSharp/Internals/JavascriptObjectRepository.cs index 84567e14f7..6d640bc1c2 100644 --- a/CefSharp/Internals/JavascriptObjectRepository.cs +++ b/CefSharp/Internals/JavascriptObjectRepository.cs @@ -156,6 +156,11 @@ private void Analyse(JavascriptObject obj) continue; } + if (IsComplexType(methodInfo.ReturnType)) + { + JavascriptKnownTypesRegistra.Register(methodInfo.ReturnType); + } + var jsMethod = CreateJavaScriptMethod(methodInfo); obj.Methods.Add(jsMethod); } @@ -202,12 +207,36 @@ private static JavascriptProperty CreateJavaScriptProperty(PropertyInfo property jsProperty.SetValue = (o, v) => propertyInfo.SetValue(o, v, null); jsProperty.GetValue = (o) => propertyInfo.GetValue(o, null); - jsProperty.IsComplexType = !propertyInfo.PropertyType.IsPrimitive && propertyInfo.PropertyType != typeof(string); + jsProperty.IsComplexType = IsComplexType(propertyInfo.PropertyType); jsProperty.IsReadOnly = !propertyInfo.CanWrite; return jsProperty; } + private static bool IsComplexType(Type type) + { + if (type == typeof(void)) + { + return false; + } + + var baseType = type; + + var nullable = type.IsGenericType && type.GetGenericTypeDefinition() == typeof (Nullable<>); + + if (nullable) + { + baseType = Nullable.GetUnderlyingType(type); + } + + if (baseType == null || baseType.Namespace.StartsWith("System")) + { + return false; + } + + return !baseType.IsPrimitive && baseType != typeof(string); + } + private static string LowercaseFirst(string str) { if (string.IsNullOrEmpty(str)) diff --git a/CefSharp/JavascriptKnownTypesRegistra.cs b/CefSharp/JavascriptKnownTypesRegistra.cs new file mode 100644 index 0000000000..0588ad013d --- /dev/null +++ b/CefSharp/JavascriptKnownTypesRegistra.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace CefSharp +{ + public static class JavascriptKnownTypesRegistra + { + private static readonly HashSet KnownTypes = new HashSet(); + + static JavascriptKnownTypesRegistra() + { + Register(typeof(object[])); + Register(typeof(Dictionary)); + } + + public static void Register(Type type) + { + KnownTypes.Add(type); + } + + public static void UnRegister(Type type) + { + KnownTypes.Remove(type); + } + + public static IEnumerable GetKnownTypes(ICustomAttributeProvider provider) + { + return KnownTypes; + } + } +} From 224cbcda9f46b852fbe5fc9f54e71b8454c440f4 Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 9 Jan 2015 12:18:56 +1000 Subject: [PATCH 120/134] First step towards getting JSB functions to return complex types - uses JavascriptOjbect/JavascriptProperty classes to represent the metadata transferred over WCF (Sending the complex type it's self is difficult as the type is not known by both client and server) --- CefSharp.BrowserSubprocess.Core/TypeUtils.cpp | 25 +++++++++ .../Internals/JavascriptObjectRepository.cs | 55 +++++++++++++++++-- CefSharp/Internals/JavascriptProperty.cs | 7 +++ CefSharp/JavascriptKnownTypesRegistra.cs | 4 ++ 4 files changed, 87 insertions(+), 4 deletions(-) diff --git a/CefSharp.BrowserSubprocess.Core/TypeUtils.cpp b/CefSharp.BrowserSubprocess.Core/TypeUtils.cpp index 9b347e01d9..2c26ee04d6 100644 --- a/CefSharp.BrowserSubprocess.Core/TypeUtils.cpp +++ b/CefSharp.BrowserSubprocess.Core/TypeUtils.cpp @@ -94,6 +94,31 @@ namespace CefSharp { return CefV8Value::CreateDate(TypeUtils::ConvertDateTimeToCefTime(safe_cast(obj))); } + if (type == JavascriptObject::typeid) + { + JavascriptObject^ javascriptObject = (JavascriptObject^)obj; + CefRefPtr cefObject = CefV8Value::CreateObject(NULL); + + for (int i = 0; i < javascriptObject->Properties->Count; i++) + { + auto prop = javascriptObject->Properties[i]; + + if(prop->IsComplexType) + { + auto v8Value = TypeUtils::ConvertToCef(prop->JsObject, nullptr); + + cefObject->SetValue(StringUtils::ToNative(prop->JavascriptName), v8Value, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE); + } + else + { + auto v8Value = TypeUtils::ConvertToCef(prop->PropertyValue, nullptr); + + cefObject->SetValue(StringUtils::ToNative(prop->JavascriptName), v8Value, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE); + } + } + + return cefObject; + } if (type->IsArray) { Array^ managedArray = (Array^)obj; diff --git a/CefSharp/Internals/JavascriptObjectRepository.cs b/CefSharp/Internals/JavascriptObjectRepository.cs index 6d640bc1c2..73748df781 100644 --- a/CefSharp/Internals/JavascriptObjectRepository.cs +++ b/CefSharp/Internals/JavascriptObjectRepository.cs @@ -67,6 +67,18 @@ public bool TryCallMethod(long objectId, string name, object[] parameters, out o { result = method.Function(obj.Value, parameters); + if(IsComplexType(result.GetType())) + { + var jsObject = CreateJavascriptObject(); + jsObject.Value = result; + jsObject.Name = "FunctionResult(" + name + ")"; + jsObject.JavascriptName = jsObject.Name; + + BuildJavascriptObjectForComplexFunctionResult(jsObject); + + result = jsObject; + } + return true; } catch (Exception ex) @@ -156,10 +168,10 @@ private void Analyse(JavascriptObject obj) continue; } - if (IsComplexType(methodInfo.ReturnType)) - { - JavascriptKnownTypesRegistra.Register(methodInfo.ReturnType); - } + //if (IsComplexType(methodInfo.ReturnType)) + //{ + // JavascriptKnownTypesRegistra.Register(methodInfo.ReturnType); + //} var jsMethod = CreateJavaScriptMethod(methodInfo); obj.Methods.Add(jsMethod); @@ -187,6 +199,41 @@ private void Analyse(JavascriptObject obj) } } + private void BuildJavascriptObjectForComplexFunctionResult(JavascriptObject obj) + { + if (obj.Value == null) + { + return; + } + + var type = obj.Value.GetType(); + + foreach (var propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => !p.IsSpecialName)) + { + if (propertyInfo.PropertyType == typeof(Type) || Attribute.IsDefined(propertyInfo, typeof(JavascriptIgnoreAttribute))) + { + continue; + } + + var jsProperty = CreateJavaScriptProperty(propertyInfo); + if (jsProperty.IsComplexType) + { + var jsObject = CreateJavascriptObject(); + jsObject.Name = propertyInfo.Name; + jsObject.JavascriptName = LowercaseFirst(propertyInfo.Name); + jsObject.Value = jsProperty.GetValue(obj.Value); + jsProperty.JsObject = jsObject; + + BuildJavascriptObjectForComplexFunctionResult(jsProperty.JsObject); + } + else + { + jsProperty.PropertyValue = jsProperty.GetValue(obj.Value); + } + obj.Properties.Add(jsProperty); + } + } + private static JavascriptMethod CreateJavaScriptMethod(MethodInfo methodInfo) { var jsMethod = new JavascriptMethod(); diff --git a/CefSharp/Internals/JavascriptProperty.cs b/CefSharp/Internals/JavascriptProperty.cs index 483442897f..ef49dba5dc 100644 --- a/CefSharp/Internals/JavascriptProperty.cs +++ b/CefSharp/Internals/JavascriptProperty.cs @@ -53,6 +53,13 @@ public class JavascriptProperty [DataMember] public bool IsReadOnly { get; set; } + /// + /// Gets or sets the property value + /// Only primative types can be stored in this property + /// + [DataMember] + public object PropertyValue { get; set; } + public override string ToString() { return ManagedName ?? base.ToString(); diff --git a/CefSharp/JavascriptKnownTypesRegistra.cs b/CefSharp/JavascriptKnownTypesRegistra.cs index 0588ad013d..d0bcaabb03 100644 --- a/CefSharp/JavascriptKnownTypesRegistra.cs +++ b/CefSharp/JavascriptKnownTypesRegistra.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using CefSharp.Internals; namespace CefSharp { @@ -12,6 +13,9 @@ static JavascriptKnownTypesRegistra() { Register(typeof(object[])); Register(typeof(Dictionary)); + Register(typeof(JavascriptObject)); + Register(typeof(JavascriptProperty)); + Register(typeof(JavascriptMethod)); } public static void Register(Type type) From 94eff9041187095c8812ec351e3c158a54aab8a8 Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 9 Jan 2015 12:22:10 +1000 Subject: [PATCH 121/134] Revert JavascriptKnownTypesRegistra changes - go back to using just knowntype attribute as it's no longer required. --- CefSharp/CefSharp.csproj | 1 - CefSharp/Internals/IBrowserProcess.cs | 7 ++++- CefSharp/JavascriptKnownTypesRegistra.cs | 36 ------------------------ 3 files changed, 6 insertions(+), 38 deletions(-) delete mode 100644 CefSharp/JavascriptKnownTypesRegistra.cs diff --git a/CefSharp/CefSharp.csproj b/CefSharp/CefSharp.csproj index 16194482ff..4ec0ff42ab 100644 --- a/CefSharp/CefSharp.csproj +++ b/CefSharp/CefSharp.csproj @@ -108,7 +108,6 @@ - diff --git a/CefSharp/Internals/IBrowserProcess.cs b/CefSharp/Internals/IBrowserProcess.cs index bbe884c491..444c13fb16 100644 --- a/CefSharp/Internals/IBrowserProcess.cs +++ b/CefSharp/Internals/IBrowserProcess.cs @@ -2,12 +2,17 @@ // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. +using System.Collections.Generic; using System.ServiceModel; namespace CefSharp.Internals { [ServiceContract(CallbackContract = typeof(IRenderProcess), SessionMode = SessionMode.Required)] - [ServiceKnownType("GetKnownTypes", typeof(JavascriptKnownTypesRegistra))] + [ServiceKnownType(typeof(object[]))] + [ServiceKnownType(typeof(Dictionary))] + [ServiceKnownType(typeof(JavascriptObject))] + [ServiceKnownType(typeof(JavascriptMethod))] + [ServiceKnownType(typeof(JavascriptProperty))] public interface IBrowserProcess { [OperationContract] diff --git a/CefSharp/JavascriptKnownTypesRegistra.cs b/CefSharp/JavascriptKnownTypesRegistra.cs deleted file mode 100644 index d0bcaabb03..0000000000 --- a/CefSharp/JavascriptKnownTypesRegistra.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using CefSharp.Internals; - -namespace CefSharp -{ - public static class JavascriptKnownTypesRegistra - { - private static readonly HashSet KnownTypes = new HashSet(); - - static JavascriptKnownTypesRegistra() - { - Register(typeof(object[])); - Register(typeof(Dictionary)); - Register(typeof(JavascriptObject)); - Register(typeof(JavascriptProperty)); - Register(typeof(JavascriptMethod)); - } - - public static void Register(Type type) - { - KnownTypes.Add(type); - } - - public static void UnRegister(Type type) - { - KnownTypes.Remove(type); - } - - public static IEnumerable GetKnownTypes(ICustomAttributeProvider provider) - { - return KnownTypes; - } - } -} From 6f5730e5c8bce87eba58a49b0f7272ca3e1dd327 Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 9 Jan 2015 12:26:27 +1000 Subject: [PATCH 122/134] Rename Analyse method to AnalyseObjectForBinding Add additional comment about it's functionality --- CefSharp/Internals/JavascriptObjectRepository.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/CefSharp/Internals/JavascriptObjectRepository.cs b/CefSharp/Internals/JavascriptObjectRepository.cs index 73748df781..f0cf1b80d1 100644 --- a/CefSharp/Internals/JavascriptObjectRepository.cs +++ b/CefSharp/Internals/JavascriptObjectRepository.cs @@ -42,7 +42,7 @@ public void Register(string name, object value) jsObject.Name = name; jsObject.JavascriptName = name; - Analyse(jsObject); + AnalyseObjectForBinding(jsObject); RootObject.MemberObjects.Add(jsObject); } @@ -147,7 +147,14 @@ public bool TrySetProperty(long objectId, string name, object value, out string return false; } - private void Analyse(JavascriptObject obj) + /// + /// Analyse the object to be bound and generate metadata + /// which will be used by the browser subprocess to interact + /// with Cef. + /// Method is called recursively + /// + /// Javascript object + private void AnalyseObjectForBinding(JavascriptObject obj) { if (obj.Value == null) { @@ -193,7 +200,7 @@ private void Analyse(JavascriptObject obj) jsObject.Value = jsProperty.GetValue(obj.Value); jsProperty.JsObject = jsObject; - Analyse(jsProperty.JsObject); + AnalyseObjectForBinding(jsProperty.JsObject); } obj.Properties.Add(jsProperty); } From e68b11a5dbd4d9b6672de0ce5d6d0e72f87cef5d Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 9 Jan 2015 12:35:03 +1000 Subject: [PATCH 123/134] Add simple test case of bound.getSubObject().simpleProperty to BindingTest.html --- CefSharp.Example/Resources/BindingTest.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CefSharp.Example/Resources/BindingTest.html b/CefSharp.Example/Resources/BindingTest.html index a4052deba8..1770fdca67 100644 --- a/CefSharp.Example/Resources/BindingTest.html +++ b/CefSharp.Example/Resources/BindingTest.html @@ -32,6 +32,14 @@ document.write("echoMyProperty result: " + myFunction(bound.echoMyProperty));

+ +

+ Function returning complex type +
+ +

Stress Test From 8d3ae5e6639be005dd8a3ce373947553e1f438f0 Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 9 Jan 2015 13:28:55 +1000 Subject: [PATCH 124/134] Move JavascriptObject to V8Value mapping from TypeUtils into JavascriptMethodHandler - may be possible to add support for function calls --- .../JavascriptMethodHandler.h | 40 ++++++++++++++++++- CefSharp.BrowserSubprocess.Core/TypeUtils.cpp | 25 ------------ 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.h b/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.h index 70a55ab9c1..31ddb166eb 100644 --- a/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.h +++ b/CefSharp.BrowserSubprocess.Core/JavascriptMethodHandler.h @@ -41,7 +41,7 @@ namespace CefSharp { auto response = _method->Invoke(parameter); - retval = TypeUtils::ConvertToCef(response->Result, nullptr); + retval = ConvertToCefObject(response->Result); if (!response->Success) { exception = StringUtils::ToNative(response->Message); @@ -56,6 +56,44 @@ namespace CefSharp return true; } + CefRefPtr ConvertToCefObject(Object^ obj) + { + if (obj == nullptr) + { + return CefV8Value::CreateNull(); + } + + auto type = obj->GetType(); + + if (type == JavascriptObject::typeid) + { + JavascriptObject^ javascriptObject = (JavascriptObject^)obj; + CefRefPtr cefObject = CefV8Value::CreateObject(NULL); + + for (int i = 0; i < javascriptObject->Properties->Count; i++) + { + auto prop = javascriptObject->Properties[i]; + + if(prop->IsComplexType) + { + auto v8Value = ConvertToCefObject(prop->JsObject); + + cefObject->SetValue(StringUtils::ToNative(prop->JavascriptName), v8Value, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE); + } + else + { + auto v8Value = TypeUtils::ConvertToCef(prop->PropertyValue, nullptr); + + cefObject->SetValue(StringUtils::ToNative(prop->JavascriptName), v8Value, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE); + } + } + + return cefObject; + } + + return TypeUtils::ConvertToCef(obj, nullptr); + } + IMPLEMENT_REFCOUNTING(JavascriptMethodHandler) }; } \ No newline at end of file diff --git a/CefSharp.BrowserSubprocess.Core/TypeUtils.cpp b/CefSharp.BrowserSubprocess.Core/TypeUtils.cpp index 2c26ee04d6..9b347e01d9 100644 --- a/CefSharp.BrowserSubprocess.Core/TypeUtils.cpp +++ b/CefSharp.BrowserSubprocess.Core/TypeUtils.cpp @@ -94,31 +94,6 @@ namespace CefSharp { return CefV8Value::CreateDate(TypeUtils::ConvertDateTimeToCefTime(safe_cast(obj))); } - if (type == JavascriptObject::typeid) - { - JavascriptObject^ javascriptObject = (JavascriptObject^)obj; - CefRefPtr cefObject = CefV8Value::CreateObject(NULL); - - for (int i = 0; i < javascriptObject->Properties->Count; i++) - { - auto prop = javascriptObject->Properties[i]; - - if(prop->IsComplexType) - { - auto v8Value = TypeUtils::ConvertToCef(prop->JsObject, nullptr); - - cefObject->SetValue(StringUtils::ToNative(prop->JavascriptName), v8Value, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE); - } - else - { - auto v8Value = TypeUtils::ConvertToCef(prop->PropertyValue, nullptr); - - cefObject->SetValue(StringUtils::ToNative(prop->JavascriptName), v8Value, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE); - } - } - - return cefObject; - } if (type->IsArray) { Array^ managedArray = (Array^)obj; From ff678b5ae2e37f87265dabac7dbdb5536544fdc9 Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 9 Jan 2015 13:32:44 +1000 Subject: [PATCH 125/134] Remove duplicate JavascriptObject analysis code - add additional params --- .../Internals/JavascriptObjectRepository.cs | 70 +++++-------------- 1 file changed, 19 insertions(+), 51 deletions(-) diff --git a/CefSharp/Internals/JavascriptObjectRepository.cs b/CefSharp/Internals/JavascriptObjectRepository.cs index f0cf1b80d1..5b6f792901 100644 --- a/CefSharp/Internals/JavascriptObjectRepository.cs +++ b/CefSharp/Internals/JavascriptObjectRepository.cs @@ -42,7 +42,7 @@ public void Register(string name, object value) jsObject.Name = name; jsObject.JavascriptName = name; - AnalyseObjectForBinding(jsObject); + AnalyseObjectForBinding(jsObject, analyseMethods: true, readPropertyValue: false); RootObject.MemberObjects.Add(jsObject); } @@ -74,7 +74,7 @@ public bool TryCallMethod(long objectId, string name, object[] parameters, out o jsObject.Name = "FunctionResult(" + name + ")"; jsObject.JavascriptName = jsObject.Name; - BuildJavascriptObjectForComplexFunctionResult(jsObject); + AnalyseObjectForBinding(jsObject, analyseMethods: false, readPropertyValue: true); result = jsObject; } @@ -148,13 +148,14 @@ public bool TrySetProperty(long objectId, string name, object value, out string } ///

- /// Analyse the object to be bound and generate metadata - /// which will be used by the browser subprocess to interact - /// with Cef. + /// Analyse the object and generate metadata which will + /// be used by the browser subprocess to interact with Cef. /// Method is called recursively /// /// Javascript object - private void AnalyseObjectForBinding(JavascriptObject obj) + /// Analyse methods for inclusion in metadata model + /// When analysis is done on a property, if true then get it's value for transmission over WCF + private void AnalyseObjectForBinding(JavascriptObject obj, bool analyseMethods, bool readPropertyValue) { if (obj.Value == null) { @@ -167,54 +168,21 @@ private void AnalyseObjectForBinding(JavascriptObject obj) return; } - foreach (var methodInfo in type.GetMethods(BindingFlags.Instance | BindingFlags.Public).Where(p => !p.IsSpecialName)) + if (analyseMethods) { - // Type objects can not be serialized. - if (methodInfo.ReturnType == typeof(Type) || Attribute.IsDefined(methodInfo, typeof(JavascriptIgnoreAttribute))) + foreach (var methodInfo in type.GetMethods(BindingFlags.Instance | BindingFlags.Public).Where(p => !p.IsSpecialName)) { - continue; - } - - //if (IsComplexType(methodInfo.ReturnType)) - //{ - // JavascriptKnownTypesRegistra.Register(methodInfo.ReturnType); - //} - - var jsMethod = CreateJavaScriptMethod(methodInfo); - obj.Methods.Add(jsMethod); - } - - foreach (var propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => !p.IsSpecialName)) - { - if (propertyInfo.PropertyType == typeof(Type) || Attribute.IsDefined(propertyInfo, typeof(JavascriptIgnoreAttribute))) - { - continue; - } - - var jsProperty = CreateJavaScriptProperty(propertyInfo); - if (jsProperty.IsComplexType) - { - var jsObject = CreateJavascriptObject(); - jsObject.Name = propertyInfo.Name; - jsObject.JavascriptName = LowercaseFirst(propertyInfo.Name); - jsObject.Value = jsProperty.GetValue(obj.Value); - jsProperty.JsObject = jsObject; - - AnalyseObjectForBinding(jsProperty.JsObject); + // Type objects can not be serialized. + if (methodInfo.ReturnType == typeof (Type) || Attribute.IsDefined(methodInfo, typeof (JavascriptIgnoreAttribute))) + { + continue; + } + + var jsMethod = CreateJavaScriptMethod(methodInfo); + obj.Methods.Add(jsMethod); } - obj.Properties.Add(jsProperty); - } - } - - private void BuildJavascriptObjectForComplexFunctionResult(JavascriptObject obj) - { - if (obj.Value == null) - { - return; } - var type = obj.Value.GetType(); - foreach (var propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(p => !p.IsSpecialName)) { if (propertyInfo.PropertyType == typeof(Type) || Attribute.IsDefined(propertyInfo, typeof(JavascriptIgnoreAttribute))) @@ -231,9 +199,9 @@ private void BuildJavascriptObjectForComplexFunctionResult(JavascriptObject obj) jsObject.Value = jsProperty.GetValue(obj.Value); jsProperty.JsObject = jsObject; - BuildJavascriptObjectForComplexFunctionResult(jsProperty.JsObject); + AnalyseObjectForBinding(jsProperty.JsObject, analyseMethods, readPropertyValue); } - else + else if (readPropertyValue) { jsProperty.PropertyValue = jsProperty.GetValue(obj.Value); } From c0cdae9ee3086c394762bde9c2e05adeb17b9988 Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 9 Jan 2015 20:59:31 +1000 Subject: [PATCH 126/134] Improve LoadHtml comment, include a valid example of the url param --- CefSharp/IWebBrowser.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CefSharp/IWebBrowser.cs b/CefSharp/IWebBrowser.cs index 71945619ee..52ad78b16c 100644 --- a/CefSharp/IWebBrowser.cs +++ b/CefSharp/IWebBrowser.cs @@ -61,6 +61,8 @@ public interface IWebBrowser : IDisposable /// the provided HTML in a and loads the provided url using /// the method. /// Defaults to using for character encoding + /// The url must start with a valid schema, other uri's such as about:blank are invalid + /// A valid example looks like http://test/page /// /// The HTML content. /// The URL that will be treated as the address of the content. From eded1747111cf8120f110d3b24ded20b2ff13717 Mon Sep 17 00:00:00 2001 From: amaitland Date: Wed, 14 Jan 2015 08:02:35 +1000 Subject: [PATCH 127/134] Add example disable gpu command line args to example --- CefSharp.Example/CefExample.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CefSharp.Example/CefExample.cs b/CefSharp.Example/CefExample.cs index f2dca272c4..26dd992808 100644 --- a/CefSharp.Example/CefExample.cs +++ b/CefSharp.Example/CefExample.cs @@ -19,6 +19,8 @@ public static void Init() settings.RemoteDebuggingPort = 8088; //settings.CefCommandLineArgs.Add("renderer-process-limit", "1"); //settings.CefCommandLineArgs.Add("renderer-startup-dialog", "renderer-startup-dialog"); + //settings.CefCommandLineArgs.Add("disable-gpu", "1"); + //settings.CefCommandLineArgs.Add("disable-gpu-vsync", "1"); settings.LogSeverity = LogSeverity.Verbose; if (DebuggingSubProcess) From 973da2813af9ed8dffcf8015e0d818063a9d3b00 Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 16 Jan 2015 17:39:19 +1000 Subject: [PATCH 128/134] Upgrade CefSharp.Example.csproj to .net 4.5 --- CefSharp.Example/CefSharp.Example.csproj | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/CefSharp.Example/CefSharp.Example.csproj b/CefSharp.Example/CefSharp.Example.csproj index 2c8d312fab..95cefec938 100644 --- a/CefSharp.Example/CefSharp.Example.csproj +++ b/CefSharp.Example/CefSharp.Example.csproj @@ -10,14 +10,15 @@ Properties CefSharp.Example CefSharp.Example - v4.0 + v4.5 512 3.5 - Client + + true @@ -29,6 +30,7 @@ 4 x64 AllRules.ruleset + false pdbonly @@ -38,6 +40,7 @@ prompt 4 AllRules.ruleset + false true @@ -47,6 +50,7 @@ x64 prompt AllRules.ruleset + false bin\x64\Release\ @@ -56,6 +60,7 @@ x64 prompt AllRules.ruleset + false true @@ -65,6 +70,7 @@ x86 prompt AllRules.ruleset + false bin\x86\Release\ @@ -74,6 +80,7 @@ x86 prompt AllRules.ruleset + false From 928da8df5e6c92ba7d79a14a51cd2264491843eb Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 16 Jan 2015 17:40:09 +1000 Subject: [PATCH 129/134] Update ProcessRequestAsync example to execute in an async fashion --- CefSharp.Example/CefSharpSchemeHandler.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/CefSharp.Example/CefSharpSchemeHandler.cs b/CefSharp.Example/CefSharpSchemeHandler.cs index b1b5567ae4..1d7eb74148 100644 --- a/CefSharp.Example/CefSharpSchemeHandler.cs +++ b/CefSharp.Example/CefSharpSchemeHandler.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Text; +using System.Threading.Tasks; using CefSharp.Example.Properties; namespace CefSharp.Example @@ -42,13 +43,16 @@ public bool ProcessRequestAsync(IRequest request, ISchemeHandlerResponse respons var fileName = uri.AbsolutePath; string resource; - if (resources.TryGetValue(fileName, out resource) && - !String.IsNullOrEmpty(resource)) + if (resources.TryGetValue(fileName, out resource) && !String.IsNullOrEmpty(resource)) { - var bytes = Encoding.UTF8.GetBytes(resource); - response.ResponseStream = new MemoryStream(bytes); - response.MimeType = GetMimeType(fileName); - requestCompletedCallback(); + //Execute in async fashion + Task.Run(() => + { + var bytes = Encoding.UTF8.GetBytes(resource); + response.ResponseStream = new MemoryStream(bytes); + response.MimeType = GetMimeType(fileName); + requestCompletedCallback(); + }); return true; } From ae3bfb3d3aad637c8f2911768a1116b9636b65f8 Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 16 Jan 2015 18:25:29 +1000 Subject: [PATCH 130/134] Re-add Left and Right keys to PreviewKey - WPF was doing funny things with Right (was previously being captured before keyboard rewrite) --- CefSharp.Wpf/ChromiumWebBrowser.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CefSharp.Wpf/ChromiumWebBrowser.cs b/CefSharp.Wpf/ChromiumWebBrowser.cs index 69fbcf81b4..5aa8ca09f2 100644 --- a/CefSharp.Wpf/ChromiumWebBrowser.cs +++ b/CefSharp.Wpf/ChromiumWebBrowser.cs @@ -891,7 +891,8 @@ private void OnPreviewKey(KeyEventArgs e) // trigger the appropriate WM_ messages handled by our SourceHook, so we have to handle these extra keys here. // Hooking the Tab key like this makes the tab focusing in essence work like // KeyboardNavigation.TabNavigation="Cycle"; you will never be able to Tab out of the web browser control. - if (e.Key == Key.Tab || e.Key == Key.Home || e.Key == Key.End || e.Key == Key.Up || e.Key == Key.Down) + if (e.Key == Key.Tab || e.Key == Key.Home || e.Key == Key.End || e.Key == Key.Up + || e.Key == Key.Down || e.Key == Key.Left || e.Key == Key.Right) { var modifiers = GetModifiers(e); var message = (int)(e.IsDown ? WM.KEYDOWN : WM.KEYUP); From a0460e83d81bb7964d9027af2f69f277507443d1 Mon Sep 17 00:00:00 2001 From: amaitland Date: Fri, 16 Jan 2015 19:40:11 +1000 Subject: [PATCH 131/134] When running stress test of the latest branch (using http://ie.microsoft.com/testdrive/performance/fishbowl/) a ContextSwitchDeadlock exception occurred. Problem is reproducible, happens after a minute or two. Changing the recently updated schema handler code seems to resolve the problem. (ContextSwitchDeadlock debugging info http://stackoverflow.com/a/2797936) --- CefSharp.Example/CefSharpSchemeHandler.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/CefSharp.Example/CefSharpSchemeHandler.cs b/CefSharp.Example/CefSharpSchemeHandler.cs index 1d7eb74148..ebee9f77f1 100644 --- a/CefSharp.Example/CefSharpSchemeHandler.cs +++ b/CefSharp.Example/CefSharpSchemeHandler.cs @@ -36,7 +36,7 @@ public CefSharpSchemeHandler() }; } - public bool ProcessRequestAsync(IRequest request, ISchemeHandlerResponse response, OnRequestCompletedHandler requestCompletedCallback ) + public bool ProcessRequestAsync(IRequest request, ISchemeHandlerResponse response, OnRequestCompletedHandler requestCompletedCallback) { // The 'host' portion is entirely ignored by this scheme handler. var uri = new Uri(request.Url); @@ -45,14 +45,12 @@ public bool ProcessRequestAsync(IRequest request, ISchemeHandlerResponse respons string resource; if (resources.TryGetValue(fileName, out resource) && !String.IsNullOrEmpty(resource)) { + var bytes = Encoding.UTF8.GetBytes(resource); + response.ResponseStream = new MemoryStream(bytes); + response.MimeType = GetMimeType(fileName); + //Execute in async fashion - Task.Run(() => - { - var bytes = Encoding.UTF8.GetBytes(resource); - response.ResponseStream = new MemoryStream(bytes); - response.MimeType = GetMimeType(fileName); - requestCompletedCallback(); - }); + requestCompletedCallback.BeginInvoke(requestCompletedCallback.EndInvoke, null); return true; } From 9f7729c037e2af5fce75f6b4f5c6639560bebbdd Mon Sep 17 00:00:00 2001 From: amaitland Date: Sat, 17 Jan 2015 00:05:42 +1000 Subject: [PATCH 132/134] IRenderProcess - IncludeExceptionDetailInFaults=true --- CefSharp.BrowserSubprocess/CefRenderProcess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CefSharp.BrowserSubprocess/CefRenderProcess.cs b/CefSharp.BrowserSubprocess/CefRenderProcess.cs index b56d70e73b..926544fd7b 100644 --- a/CefSharp.BrowserSubprocess/CefRenderProcess.cs +++ b/CefSharp.BrowserSubprocess/CefRenderProcess.cs @@ -8,7 +8,7 @@ namespace CefSharp.BrowserSubprocess { - [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)] + [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, IncludeExceptionDetailInFaults=true)] public class CefRenderProcess : CefSubProcess, IRenderProcess { private int? parentBrowserId; From bf4983b52d37549c5ba0c5718203b520ac3605c7 Mon Sep 17 00:00:00 2001 From: amaitland Date: Mon, 19 Jan 2015 11:45:24 +1000 Subject: [PATCH 133/134] Resolve null pointer exception - Functions/Methods that return null or have no return value were through an exception --- CefSharp/Internals/JavascriptObjectRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CefSharp/Internals/JavascriptObjectRepository.cs b/CefSharp/Internals/JavascriptObjectRepository.cs index 5b6f792901..367a472b29 100644 --- a/CefSharp/Internals/JavascriptObjectRepository.cs +++ b/CefSharp/Internals/JavascriptObjectRepository.cs @@ -67,7 +67,7 @@ public bool TryCallMethod(long objectId, string name, object[] parameters, out o { result = method.Function(obj.Value, parameters); - if(IsComplexType(result.GetType())) + if(result != null && IsComplexType(result.GetType())) { var jsObject = CreateJavascriptObject(); jsObject.Value = result; From 72270b155b82515c86edb51faff0ae377ce92f95 Mon Sep 17 00:00:00 2001 From: amaitland Date: Tue, 20 Jan 2015 13:16:25 +1000 Subject: [PATCH 134/134] Explicitly specify msbuild from the .Net 4.0 framework directory --- build.ps1 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build.ps1 b/build.ps1 index ebf3dc3835..90afe23a14 100644 --- a/build.ps1 +++ b/build.ps1 @@ -14,6 +14,9 @@ $WorkingDir = split-path -parent $MyInvocation.MyCommand.Definition $CefSln = Join-Path $WorkingDir 'CefSharp3.sln' +$MSBuildExe = join-path -path (Get-ItemProperty "HKLM:\software\Microsoft\MSBuild\ToolsVersions\4.0").MSBuildToolsPath -childpath "msbuild.exe" +$MSBuildExe = $MSBuildExe -replace "Framework64", "Framework" + function Write-Diagnostic { param( @@ -162,7 +165,7 @@ function Msvs ) $StartInfo = New-Object System.Diagnostics.ProcessStartInfo - $StartInfo.FileName = "msbuild.exe" + $StartInfo.FileName = $MSBuildExe $StartInfo.Arguments = $Arguments $StartInfo.EnvironmentVariables.Clear()