CEF4Delphi/source/uCEFClient.pas
Salvador Diaz Fau 830117e0ca Faster browser destruction
Faster browser destruction. All timers have been removed from the demos.
Removed unnecessary client handler class in TChromium. Now there's only
an interface.
Fixed an old memory leak in popup windows.
2017-06-11 17:48:20 +02:00

675 lines
20 KiB
ObjectPascal

// ************************************************************************
// ***************************** CEF4Delphi *******************************
// ************************************************************************
//
// CEF4Delphi is based on DCEF3 which uses CEF3 to embed a chromium-based
// browser in Delphi applications.
//
// The original license of DCEF3 still applies to CEF4Delphi.
//
// For more information about CEF4Delphi visit :
// https://www.briskbard.com/index.php?lang=en&pageid=cef
//
// Copyright © 2017 Salvador Díaz Fau. All rights reserved.
//
// ************************************************************************
// ************ vvvv Original license and comments below vvvv *************
// ************************************************************************
(*
* Delphi Chromium Embedded 3
*
* Usage allowed under the restrictions of the Lesser GNU General Public License
* or alternatively the restrictions of the Mozilla Public License 1.1
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
* the specific language governing rights and limitations under the License.
*
* Unit owner : Henri Gourvest <hgourvest@gmail.com>
* Web site : http://www.progdigy.com
* Repository : http://code.google.com/p/delphichromiumembedded/
* Group : http://groups.google.com/group/delphichromiumembedded
*
* Embarcadero Technologies, Inc is not permitted to use or redistribute
* this source code without explicit permission.
*
*)
unit uCEFClient;
{$IFNDEF CPUX64}
{$ALIGN ON}
{$MINENUMSIZE 4}
{$ENDIF}
{$I cef.inc}
interface
uses
{$IFDEF DELPHI16_UP}
WinApi.Windows,
{$ELSE}
Windows,
{$ENDIF}
uCEFBaseRefCounted, uCEFInterfaces, uCEFTypes;
type
TCefClientRef = class(TCefBaseRefCountedRef, ICefClient)
protected
function GetContextMenuHandler: ICefContextMenuHandler; virtual;
function GetDialogHandler: ICefDialogHandler; virtual;
function GetDisplayHandler: ICefDisplayHandler; virtual;
function GetDownloadHandler: ICefDownloadHandler; virtual;
function GetDragHandler: ICefDragHandler; virtual;
function GetFindHandler: ICefFindHandler; virtual;
function GetFocusHandler: ICefFocusHandler; virtual;
function GetGeolocationHandler: ICefGeolocationHandler; virtual;
function GetJsdialogHandler: ICefJsdialogHandler; virtual;
function GetKeyboardHandler: ICefKeyboardHandler; virtual;
function GetLifeSpanHandler: ICefLifeSpanHandler; virtual;
function GetRenderHandler: ICefRenderHandler; virtual;
function GetLoadHandler: ICefLoadHandler; virtual;
function GetRequestHandler: ICefRequestHandler; virtual;
function OnProcessMessageReceived(const browser: ICefBrowser; sourceProcess: TCefProcessId; const message: ICefProcessMessage): Boolean; virtual;
public
class function UnWrap(data: Pointer): ICefClient;
end;
TCefClientOwn = class(TCefBaseRefCountedOwn, ICefClient)
protected
function GetContextMenuHandler: ICefContextMenuHandler; virtual;
function GetDialogHandler: ICefDialogHandler; virtual;
function GetDisplayHandler: ICefDisplayHandler; virtual;
function GetDownloadHandler: ICefDownloadHandler; virtual;
function GetDragHandler: ICefDragHandler; virtual;
function GetFindHandler: ICefFindHandler; virtual;
function GetFocusHandler: ICefFocusHandler; virtual;
function GetGeolocationHandler: ICefGeolocationHandler; virtual;
function GetJsdialogHandler: ICefJsdialogHandler; virtual;
function GetKeyboardHandler: ICefKeyboardHandler; virtual;
function GetLifeSpanHandler: ICefLifeSpanHandler; virtual;
function GetRenderHandler: ICefRenderHandler; virtual;
function GetLoadHandler: ICefLoadHandler; virtual;
function GetRequestHandler: ICefRequestHandler; virtual;
function OnProcessMessageReceived(const browser: ICefBrowser; sourceProcess: TCefProcessId; const message: ICefProcessMessage): Boolean; virtual;
public
constructor Create; virtual;
end;
TCustomClientHandler = class(TCefClientOwn)
protected
FEvents : IChromiumEvents;
FLoadHandler : ICefLoadHandler;
FFocusHandler : ICefFocusHandler;
FContextMenuHandler : ICefContextMenuHandler;
FDialogHandler : ICefDialogHandler;
FKeyboardHandler : ICefKeyboardHandler;
FDisplayHandler : ICefDisplayHandler;
FDownloadHandler : ICefDownloadHandler;
FGeolocationHandler : ICefGeolocationHandler;
FJsDialogHandler : ICefJsDialogHandler;
FLifeSpanHandler : ICefLifeSpanHandler;
FRenderHandler : ICefRenderHandler;
FRequestHandler : ICefRequestHandler;
FDragHandler : ICefDragHandler;
FFindHandler : ICefFindHandler;
function GetContextMenuHandler: ICefContextMenuHandler; override;
function GetDialogHandler: ICefDialogHandler; override;
function GetDisplayHandler: ICefDisplayHandler; override;
function GetDownloadHandler: ICefDownloadHandler; override;
function GetDragHandler: ICefDragHandler; override;
function GetFindHandler: ICefFindHandler; override;
function GetFocusHandler: ICefFocusHandler; override;
function GetGeolocationHandler: ICefGeolocationHandler; override;
function GetJsdialogHandler: ICefJsdialogHandler; override;
function GetKeyboardHandler: ICefKeyboardHandler; override;
function GetLifeSpanHandler: ICefLifeSpanHandler; override;
function GetRenderHandler: ICefRenderHandler; override;
function GetLoadHandler: ICefLoadHandler; override;
function GetRequestHandler: ICefRequestHandler; override;
function OnProcessMessageReceived(const browser: ICefBrowser; sourceProcess: TCefProcessId; const message: ICefProcessMessage): Boolean; override;
public
constructor Create(const events: IChromiumEvents; renderer: Boolean); reintroduce; virtual;
destructor Destroy; override;
end;
TVCLClientHandler = class(TCustomClientHandler)
protected
function GetMultithreadApp : boolean;
function GetExternalMessagePump : boolean;
public
constructor Create(const crm: IChromiumEvents; renderer: Boolean); reintroduce;
destructor Destroy; override;
property MultithreadApp : boolean read GetMultithreadApp;
property ExternalMessagePump : boolean read GetExternalMessagePump;
end;
var
CefInstances : Integer = 0;
procedure CefDoMessageLoopWork;
implementation
uses
{$IFDEF DELPHI16_UP}
System.SysUtils,
{$ELSE}
SysUtils,
{$ENDIF}
uCEFMiscFunctions, uCEFLibFunctions, uCEFProcessMessage, uCEFBrowser, uCEFLoadHandler,
uCEFFocusHandler, uCEFContextMenuHandler, uCEFDialogHandler, uCEFKeyboardHandler,
uCEFDisplayHandler, uCEFDownloadHandler, uCEFGeolocationHandler, uCEFJsDialogHandler,
uCEFLifeSpanHandler, uCEFRequestHandler, uCEFRenderHandler, uCEFDragHandler,
uCEFFindHandler, uCEFConstants, uCEFApplication;
var
looping : Boolean = False;
CefTimer : UINT = 0;
// ******************************************************
// ****************** TCefClientRef *********************
// ******************************************************
class function TCefClientRef.UnWrap(data: Pointer): ICefClient;
begin
if (data <> nil) then
Result := Create(data) as ICefClient
else
Result := nil;
end;
function TCefClientRef.GetContextMenuHandler: ICefContextMenuHandler;
begin
Result := nil;
end;
function TCefClientRef.GetDialogHandler: ICefDialogHandler;
begin
Result := nil;
end;
function TCefClientRef.GetDisplayHandler: ICefDisplayHandler;
begin
Result := nil;
end;
function TCefClientRef.GetDownloadHandler: ICefDownloadHandler;
begin
Result := nil;
end;
function TCefClientRef.GetDragHandler: ICefDragHandler;
begin
Result := nil;
end;
function TCefClientRef.GetFindHandler: ICefFindHandler;
begin
Result := nil;
end;
function TCefClientRef.GetFocusHandler: ICefFocusHandler;
begin
Result := nil;
end;
function TCefClientRef.GetGeolocationHandler: ICefGeolocationHandler;
begin
Result := nil;
end;
function TCefClientRef.GetJsdialogHandler: ICefJsDialogHandler;
begin
Result := nil;
end;
function TCefClientRef.GetKeyboardHandler: ICefKeyboardHandler;
begin
Result := nil;
end;
function TCefClientRef.GetLifeSpanHandler: ICefLifeSpanHandler;
begin
Result := nil;
end;
function TCefClientRef.GetLoadHandler: ICefLoadHandler;
begin
Result := nil;
end;
function TCefClientRef.GetRenderHandler: ICefRenderHandler;
begin
Result := nil;
end;
function TCefClientRef.GetRequestHandler: ICefRequestHandler;
begin
Result := nil;
end;
function TCefClientRef.OnProcessMessageReceived(const browser: ICefBrowser; sourceProcess: TCefProcessId; const message: ICefProcessMessage): Boolean;
begin
Result := False;
end;
// ******************************************************
// ****************** TCefClientOwn *********************
// ******************************************************
procedure CefDoMessageLoopWork;
begin
if looping then Exit;
if (CefInstances > 0) then
begin
looping := True;
try
cef_do_message_loop_work;
finally
looping := False;
end;
end;
end;
procedure TimerProc(hwnd: HWND; uMsg: UINT; idEvent: Pointer; dwTime: DWORD); stdcall;
begin
CefDoMessageLoopWork;
end;
function cef_client_own_get_context_menu_handler(self: PCefClient): PCefContextMenuHandler; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := CefGetData(GetContextMenuHandler);
end;
function cef_client_own_get_dialog_handler(self: PCefClient): PCefDialogHandler; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := CefGetData(GetDialogHandler);
end;
function cef_client_own_get_display_handler(self: PCefClient): PCefDisplayHandler; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := CefGetData(GetDisplayHandler);
end;
function cef_client_own_get_download_handler(self: PCefClient): PCefDownloadHandler; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := CefGetData(GetDownloadHandler);
end;
function cef_client_own_get_drag_handler(self: PCefClient): PCefDragHandler; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := CefGetData(GetDragHandler);
end;
function cef_client_own_get_find_handler(self: PCefClient): PCefFindHandler; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := CefGetData(GetFindHandler);
end;
function cef_client_own_get_focus_handler(self: PCefClient): PCefFocusHandler; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := CefGetData(GetFocusHandler);
end;
function cef_client_own_get_geolocation_handler(self: PCefClient): PCefGeolocationHandler; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := CefGetData(GetGeolocationHandler);
end;
function cef_client_own_get_jsdialog_handler(self: PCefClient): PCefJsDialogHandler; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := CefGetData(GetJsdialogHandler);
end;
function cef_client_own_get_keyboard_handler(self: PCefClient): PCefKeyboardHandler; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := CefGetData(GetKeyboardHandler);
end;
function cef_client_own_get_life_span_handler(self: PCefClient): PCefLifeSpanHandler; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := CefGetData(GetLifeSpanHandler);
end;
function cef_client_own_get_load_handler(self: PCefClient): PCefLoadHandler; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := CefGetData(GetLoadHandler);
end;
function cef_client_own_get_get_render_handler(self: PCefClient): PCefRenderHandler; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := CefGetData(GetRenderHandler);
end;
function cef_client_own_get_request_handler(self: PCefClient): PCefRequestHandler; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := CefGetData(GetRequestHandler);
end;
function cef_client_own_on_process_message_received(self: PCefClient; browser: PCefBrowser;
source_process: TCefProcessId; message: PCefProcessMessage): Integer; stdcall;
begin
with TCefClientOwn(CefGetObject(self)) do
Result := Ord(OnProcessMessageReceived(TCefBrowserRef.UnWrap(browser), source_process, TCefProcessMessageRef.UnWrap(message)));
end;
constructor TCefClientOwn.Create;
begin
inherited CreateData(SizeOf(TCefClient));
with PCefClient(FData)^ do
begin
get_context_menu_handler := cef_client_own_get_context_menu_handler;
get_dialog_handler := cef_client_own_get_dialog_handler;
get_display_handler := cef_client_own_get_display_handler;
get_download_handler := cef_client_own_get_download_handler;
get_drag_handler := cef_client_own_get_drag_handler;
get_find_handler := cef_client_own_get_find_handler;
get_focus_handler := cef_client_own_get_focus_handler;
get_geolocation_handler := cef_client_own_get_geolocation_handler;
get_jsdialog_handler := cef_client_own_get_jsdialog_handler;
get_keyboard_handler := cef_client_own_get_keyboard_handler;
get_life_span_handler := cef_client_own_get_life_span_handler;
get_load_handler := cef_client_own_get_load_handler;
get_render_handler := cef_client_own_get_get_render_handler;
get_request_handler := cef_client_own_get_request_handler;
on_process_message_received := cef_client_own_on_process_message_received;
end;
end;
function TCefClientOwn.GetContextMenuHandler: ICefContextMenuHandler;
begin
Result := nil;
end;
function TCefClientOwn.GetDialogHandler: ICefDialogHandler;
begin
Result := nil;
end;
function TCefClientOwn.GetDisplayHandler: ICefDisplayHandler;
begin
Result := nil;
end;
function TCefClientOwn.GetDownloadHandler: ICefDownloadHandler;
begin
Result := nil;
end;
function TCefClientOwn.GetDragHandler: ICefDragHandler;
begin
Result := nil;
end;
function TCefClientOwn.GetFindHandler: ICefFindHandler;
begin
Result := nil;
end;
function TCefClientOwn.GetFocusHandler: ICefFocusHandler;
begin
Result := nil;
end;
function TCefClientOwn.GetGeolocationHandler: ICefGeolocationHandler;
begin
Result := nil;
end;
function TCefClientOwn.GetJsdialogHandler: ICefJsDialogHandler;
begin
Result := nil;
end;
function TCefClientOwn.GetKeyboardHandler: ICefKeyboardHandler;
begin
Result := nil;
end;
function TCefClientOwn.GetLifeSpanHandler: ICefLifeSpanHandler;
begin
Result := nil;
end;
function TCefClientOwn.GetLoadHandler: ICefLoadHandler;
begin
Result := nil;
end;
function TCefClientOwn.GetRenderHandler: ICefRenderHandler;
begin
Result := nil;
end;
function TCefClientOwn.GetRequestHandler: ICefRequestHandler;
begin
Result := nil;
end;
function TCefClientOwn.OnProcessMessageReceived(const browser: ICefBrowser; sourceProcess: TCefProcessId; const message: ICefProcessMessage): Boolean;
begin
Result := False;
end;
// ******************************************************
// *************** TCustomClientHandler *****************
// ******************************************************
constructor TCustomClientHandler.Create(const events: IChromiumEvents; renderer: Boolean);
begin
inherited Create;
FEvents := events;
FLoadHandler := TCustomLoadHandler.Create(events);
FFocusHandler := TCustomFocusHandler.Create(events);
FContextMenuHandler := TCustomContextMenuHandler.Create(events);
FDialogHandler := TCustomDialogHandler.Create(events);
FKeyboardHandler := TCustomKeyboardHandler.Create(events);
FDisplayHandler := TCustomDisplayHandler.Create(events);
FDownloadHandler := TCustomDownloadHandler.Create(events);
FGeolocationHandler := TCustomGeolocationHandler.Create(events);
FJsDialogHandler := TCustomJsDialogHandler.Create(events);
FLifeSpanHandler := TCustomLifeSpanHandler.Create(events);
FRequestHandler := TCustomRequestHandler.Create(events);
FDragHandler := TCustomDragHandler.Create(events);
FFindHandler := TCustomFindHandler.Create(events);
if renderer then
FRenderHandler := TCustomRenderHandler.Create(events)
else
FRenderHandler := nil;
end;
destructor TCustomClientHandler.Destroy;
begin
FEvents := nil;
FLoadHandler := nil;
FFocusHandler := nil;
FContextMenuHandler := nil;
FDialogHandler := nil;
FKeyboardHandler := nil;
FDisplayHandler := nil;
FDownloadHandler := nil;
FGeolocationHandler := nil;
FJsDialogHandler := nil;
FLifeSpanHandler := nil;
FRequestHandler := nil;
FRenderHandler := nil;
FDragHandler := nil;
FFindHandler := nil;
inherited Destroy;
end;
function TCustomClientHandler.GetContextMenuHandler: ICefContextMenuHandler;
begin
Result := FContextMenuHandler;
end;
function TCustomClientHandler.GetDialogHandler: ICefDialogHandler;
begin
Result := FDialogHandler;
end;
function TCustomClientHandler.GetDisplayHandler: ICefDisplayHandler;
begin
Result := FDisplayHandler;
end;
function TCustomClientHandler.GetDownloadHandler: ICefDownloadHandler;
begin
Result := FDownloadHandler;
end;
function TCustomClientHandler.GetDragHandler: ICefDragHandler;
begin
Result := FDragHandler;
end;
function TCustomClientHandler.GetFindHandler: ICefFindHandler;
begin
Result := FFindHandler;
end;
function TCustomClientHandler.GetFocusHandler: ICefFocusHandler;
begin
Result := FFocusHandler;
end;
function TCustomClientHandler.GetGeolocationHandler: ICefGeolocationHandler;
begin
Result := FGeolocationHandler;
end;
function TCustomClientHandler.GetJsdialogHandler: ICefJsDialogHandler;
begin
Result := FJsDialogHandler;
end;
function TCustomClientHandler.GetKeyboardHandler: ICefKeyboardHandler;
begin
Result := FKeyboardHandler;
end;
function TCustomClientHandler.GetLifeSpanHandler: ICefLifeSpanHandler;
begin
Result := FLifeSpanHandler;
end;
function TCustomClientHandler.GetLoadHandler: ICefLoadHandler;
begin
Result := FLoadHandler;
end;
function TCustomClientHandler.GetRenderHandler: ICefRenderHandler;
begin
Result := FRenderHandler;
end;
function TCustomClientHandler.GetRequestHandler: ICefRequestHandler;
begin
Result := FRequestHandler;
end;
function TCustomClientHandler.OnProcessMessageReceived(const browser: ICefBrowser; sourceProcess: TCefProcessId; const message: ICefProcessMessage): Boolean;
begin
if Assigned(FEvents) then
Result := FEvents.doOnProcessMessageReceived(browser, sourceProcess, message)
else
Result := False;
end;
// ******************************************************
// **************** TVCLClientHandler *******************
// ******************************************************
constructor TVCLClientHandler.Create(const crm: IChromiumEvents; renderer : Boolean);
begin
inherited Create(crm, renderer);
if not(MultithreadApp) and not(ExternalMessagePump) then
begin
if (CefInstances = 0) then CefTimer := SetTimer(0, 0, USER_TIMER_MINIMUM, @TimerProc);
InterlockedIncrement(CefInstances);
end;
end;
destructor TVCLClientHandler.Destroy;
begin
try
try
if not(MultithreadApp) and not(ExternalMessagePump) then
begin
InterlockedDecrement(CefInstances);
if (CefInstances = 0) and (CefTimer <> 0) then
begin
KillTimer(0, CefTimer);
CefTimer := 0;
end;
end;
except
on e : exception do
if CustomExceptionHandler('TVCLClientHandler.Destroy', e) then raise;
end;
finally
inherited Destroy;
end;
end;
function TVCLClientHandler.GetMultithreadApp : boolean;
begin
Result := True;
try
if (GlobalCEFApp <> nil) then Result := GlobalCEFApp.MultiThreadedMessageLoop;
except
on e : exception do
if CustomExceptionHandler('TVCLClientHandler.GetMultithreadApp', e) then raise;
end;
end;
function TVCLClientHandler.GetExternalMessagePump : boolean;
begin
Result := True;
try
if (GlobalCEFApp <> nil) then Result := GlobalCEFApp.ExternalMessagePump;
except
on e : exception do
if CustomExceptionHandler('TVCLClientHandler.GetExternalMessagePump', e) then raise;
end;
end;
end.