mirror of
https://github.com/salvadordf/CEF4Delphi.git
synced 2024-11-15 15:55:56 +01:00
fec1b3be79
Added functions to copy the CEF binaries and the CEF helpers automatically to FMXExternalPumpBrowser for MacOS Added TFMXBufferPanel.OnResized Added more comments with missing functionality in Linux and MacOS
531 lines
14 KiB
ObjectPascal
531 lines
14 KiB
ObjectPascal
// ************************************************************************
|
|
// ***************************** CEF4Delphi *******************************
|
|
// ************************************************************************
|
|
//
|
|
// CEF4Delphi is based on DCEF3 which uses CEF 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 © 2021 Salvador Diaz 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 uCEFFMXBufferPanel;
|
|
|
|
{$I cef.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF MSWINDOWS}
|
|
Winapi.Windows, FMX.Platform.Win,
|
|
{$ELSE}
|
|
System.SyncObjs,
|
|
{$ENDIF}
|
|
System.Classes, System.UIConsts, System.Types, System.UITypes,
|
|
{$IFDEF DELPHI17_UP}
|
|
FMX.Graphics,
|
|
{$ENDIF}
|
|
FMX.Types, FMX.Controls, FMX.Forms,
|
|
uCEFTypes;
|
|
|
|
type
|
|
TDialogKeyEvent = procedure(Sender: TObject; var Key: Word; Shift: TShiftState) of object;
|
|
|
|
{$IFNDEF FPC}{$IFDEF DELPHI16_UP}[ComponentPlatformsAttribute(pidWin32 or pidWin64)]{$ENDIF}{$ENDIF}
|
|
TFMXBufferPanel = class(TControl)
|
|
protected
|
|
{$IFDEF MSWINDOWS}
|
|
FMutex : THandle;
|
|
{$ELSE}
|
|
FBufferCS : TCriticalSection;
|
|
{$ENDIF}
|
|
FBuffer : TBitmap;
|
|
FScanlineSize : integer;
|
|
FColor : TAlphaColor;
|
|
FHighSpeedDrawing : boolean;
|
|
FOnDialogKey : TDialogKeyEvent;
|
|
FForcedDeviceScaleFactor : single;
|
|
|
|
procedure CreateSyncObj;
|
|
|
|
procedure DestroySyncObj;
|
|
procedure DestroyBuffer;
|
|
|
|
function GetScreenScale : single; virtual;
|
|
function GetBufferWidth : integer;
|
|
function GetBufferHeight : integer;
|
|
function GetParentForm : TCustomForm;
|
|
function GetParentFormHandle : TCefWindowHandle;
|
|
function GetRealScreenScale(var aResultScale : single) : boolean; virtual;
|
|
|
|
function CopyBuffer : boolean;
|
|
function SaveBufferToFile(const aFilename : string) : boolean;
|
|
|
|
procedure Paint; override;
|
|
procedure DialogKey(var Key: Word; Shift: TShiftState); override;
|
|
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure AfterConstruction; override;
|
|
function SaveToFile(const aFilename : string) : boolean;
|
|
procedure InvalidatePanel;
|
|
function BeginBufferDraw : boolean;
|
|
procedure EndBufferDraw;
|
|
procedure BufferDraw(const aBitmap : TBitmap; const aSrcRect, aDstRect : TRectF);
|
|
function UpdateBufferDimensions(aWidth, aHeight : integer) : boolean;
|
|
function BufferIsResized(aUseMutex : boolean = True) : boolean;
|
|
function ScreenToClient(aPoint : TPoint) : TPoint; overload;
|
|
function ScreenToClient(aPoint : TPointF) : TPointF; overload;
|
|
function ClientToScreen(aPoint : TPoint) : TPoint; overload;
|
|
function ClientToScreen(aPoint : TPointF) : TPointF; overload;
|
|
|
|
property Buffer : TBitmap read FBuffer;
|
|
property ScanlineSize : integer read FScanlineSize;
|
|
property BufferWidth : integer read GetBufferWidth;
|
|
property BufferHeight : integer read GetBufferHeight;
|
|
property ScreenScale : single read GetScreenScale;
|
|
property ForcedDeviceScaleFactor : single read FForcedDeviceScaleFactor write FForcedDeviceScaleFactor;
|
|
|
|
published
|
|
property Align;
|
|
property Anchors;
|
|
property Visible;
|
|
property Enabled;
|
|
property TabOrder;
|
|
property Color : TAlphaColor read FColor write FColor default claWhite;
|
|
property HighSpeedDrawing : boolean read FHighSpeedDrawing write FHighSpeedDrawing default True;
|
|
|
|
{$IFDEF DELPHI17_UP}
|
|
property TabStop;
|
|
property CanFocus;
|
|
property CanParentFocus;
|
|
property Height;
|
|
property Width;
|
|
property Padding;
|
|
property Opacity;
|
|
property Margins;
|
|
property Position;
|
|
property RotationAngle;
|
|
property RotationCenter;
|
|
property Scale;
|
|
property Size;
|
|
property OnResized;
|
|
{$ENDIF}
|
|
{$IFNDEF DELPHI23_UP}
|
|
property Hint;
|
|
property ShowHint;
|
|
{$ENDIF}
|
|
|
|
property OnEnter;
|
|
property OnExit;
|
|
property OnResize;
|
|
property OnClick;
|
|
property OnMouseDown;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
property OnMouseEnter;
|
|
property OnMouseLeave;
|
|
property OnMouseWheel;
|
|
property OnKeyUp;
|
|
property OnKeyDown;
|
|
property OnDialogKey : TDialogKeyEvent read FOnDialogKey write FOnDialogKey;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
System.SysUtils, System.Math,
|
|
{$IFDEF MSWINDOWS}FMX.Helpers.Win,{$ENDIF}
|
|
FMX.Platform, uCEFMiscFunctions, uCEFApplicationCore;
|
|
|
|
constructor TFMXBufferPanel.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
|
|
{$IFDEF MSWINDOWS}
|
|
FMutex := 0;
|
|
{$ELSE}
|
|
FBufferCS := nil;
|
|
{$ENDIF}
|
|
FBuffer := nil;
|
|
FScanlineSize := 0;
|
|
FColor := claWhite;
|
|
FOnDialogKey := nil;
|
|
FHighSpeedDrawing := True;
|
|
|
|
if (GlobalCEFApp <> nil) and (GlobalCEFApp.ForcedDeviceScaleFactor <> 0) then
|
|
FForcedDeviceScaleFactor := GlobalCEFApp.ForcedDeviceScaleFactor
|
|
else
|
|
FForcedDeviceScaleFactor := 0;
|
|
end;
|
|
|
|
destructor TFMXBufferPanel.Destroy;
|
|
begin
|
|
DestroyBuffer;
|
|
DestroySyncObj;
|
|
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TFMXBufferPanel.AfterConstruction;
|
|
begin
|
|
inherited AfterConstruction;
|
|
|
|
CreateSyncObj;
|
|
end;
|
|
|
|
procedure TFMXBufferPanel.CreateSyncObj;
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
FMutex := CreateMutex(nil, False, nil);
|
|
{$ELSE}
|
|
FBufferCS := TCriticalSection.Create;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TFMXBufferPanel.DestroySyncObj;
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
if (FMutex <> 0) then
|
|
begin
|
|
CloseHandle(FMutex);
|
|
FMutex := 0;
|
|
end;
|
|
{$ELSE}
|
|
if (FBufferCS <> nil) then FreeAndNil(FBufferCS);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TFMXBufferPanel.DestroyBuffer;
|
|
begin
|
|
if BeginBufferDraw then
|
|
begin
|
|
if (FBuffer <> nil) then FreeAndNil(FBuffer);
|
|
EndBufferDraw;
|
|
end;
|
|
end;
|
|
|
|
function TFMXBufferPanel.SaveBufferToFile(const aFilename : string) : boolean;
|
|
begin
|
|
Result := False;
|
|
|
|
try
|
|
if (FBuffer <> nil) then
|
|
begin
|
|
FBuffer.SaveToFile(aFilename);
|
|
Result := True;
|
|
end;
|
|
except
|
|
on e : exception do
|
|
if CustomExceptionHandler('TFMXBufferPanel.SaveBufferToFile', e) then raise;
|
|
end;
|
|
end;
|
|
|
|
function TFMXBufferPanel.SaveToFile(const aFilename : string) : boolean;
|
|
begin
|
|
Result := False;
|
|
|
|
if BeginBufferDraw then
|
|
begin
|
|
Result := SaveBufferToFile(aFilename);
|
|
EndBufferDraw;
|
|
end;
|
|
end;
|
|
|
|
procedure TFMXBufferPanel.InvalidatePanel;
|
|
begin
|
|
InvalidateRect(TRectF.Create(0, 0, Width, Height));
|
|
end;
|
|
|
|
function TFMXBufferPanel.BeginBufferDraw : boolean;
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
Result := (FMutex <> 0) and (WaitForSingleObject(FMutex, 5000) = WAIT_OBJECT_0);
|
|
{$ELSE}
|
|
if (FBufferCS <> nil) then
|
|
begin
|
|
FBufferCS.Acquire;
|
|
Result := True;
|
|
end
|
|
else
|
|
Result := False;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
procedure TFMXBufferPanel.EndBufferDraw;
|
|
begin
|
|
{$IFDEF MSWINDOWS}
|
|
if (FMutex <> 0) then ReleaseMutex(FMutex);
|
|
{$ELSE}
|
|
if (FBufferCS <> nil) then FBufferCS.Release;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TFMXBufferPanel.CopyBuffer : boolean;
|
|
var
|
|
TempSrc, TempDst, TempClip : TRectF;
|
|
TempState : TCanvasSaveState;
|
|
TempScale : single;
|
|
begin
|
|
Result := False;
|
|
|
|
if Canvas.BeginScene then
|
|
try
|
|
if BeginBufferDraw then
|
|
try
|
|
if (FBuffer <> nil) then
|
|
begin
|
|
TempScale := ScreenScale;
|
|
TempSrc := TRectF.Create(0, 0, FBuffer.Width, FBuffer.Height);
|
|
TempDst := TRectF.Create(0, 0, FBuffer.Width / TempScale, FBuffer.Height / TempScale);
|
|
TempClip := TRectF.Create(0, 0, Width, Height);
|
|
|
|
TempState := Canvas.SaveState;
|
|
try
|
|
Canvas.IntersectClipRect(TempClip);
|
|
Canvas.DrawBitmap(FBuffer, TempSrc, TempDst, 1, FHighSpeedDrawing);
|
|
Result := True;
|
|
finally
|
|
Canvas.RestoreState(TempState);
|
|
end;
|
|
end;
|
|
finally
|
|
EndBufferDraw;
|
|
end;
|
|
finally
|
|
Canvas.EndScene;
|
|
end;
|
|
end;
|
|
|
|
procedure TFMXBufferPanel.DialogKey(var Key: Word; Shift: TShiftState);
|
|
begin
|
|
if assigned(FOnDialogKey) then FOnDialogKey(self, Key, Shift);
|
|
|
|
inherited DialogKey(Key, Shift);
|
|
end;
|
|
|
|
procedure TFMXBufferPanel.Paint;
|
|
var
|
|
TempRect : TRectF;
|
|
begin
|
|
if (csDesigning in ComponentState) or not(CopyBuffer) then
|
|
begin
|
|
TempRect := TRectF.Create(0, 0, Width, Height);
|
|
|
|
if Canvas.BeginScene then
|
|
try
|
|
Canvas.ClearRect(TempRect, FColor);
|
|
finally
|
|
Canvas.EndScene;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TFMXBufferPanel.GetParentForm : TCustomForm;
|
|
var
|
|
TempComp : TComponent;
|
|
begin
|
|
Result := nil;
|
|
TempComp := Owner;
|
|
|
|
while (TempComp <> nil) do
|
|
if (TempComp is TCustomForm) then
|
|
begin
|
|
Result := TCustomForm(TempComp);
|
|
exit;
|
|
end
|
|
else
|
|
TempComp := TempComp.owner;
|
|
end;
|
|
|
|
function TFMXBufferPanel.GetParentFormHandle : TCefWindowHandle;
|
|
{$IFDEF MSWINDOWS}
|
|
var
|
|
TempForm : TCustomForm;
|
|
{$ENDIF}
|
|
begin
|
|
InitializeWindowHandle(Result);
|
|
|
|
{$IFDEF MSWINDOWS}
|
|
TempForm := GetParentForm;
|
|
|
|
if (TempForm <> nil) then
|
|
Result := FmxHandleToHWND(TempForm.Handle)
|
|
else
|
|
if (Application <> nil) and
|
|
(Application.MainForm <> nil) then
|
|
Result := FmxHandleToHWND(Application.MainForm.Handle);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
function TFMXBufferPanel.GetRealScreenScale(var aResultScale : single) : boolean;
|
|
{$IFDEF DELPHI24_UP}{$IFDEF MSWINDOWS}
|
|
var
|
|
TempHandle : TCefWindowHandle;
|
|
{$ENDIF}{$ENDIF}
|
|
begin
|
|
Result := False;
|
|
aResultScale := 1;
|
|
|
|
{$IFDEF DELPHI24_UP}{$IFDEF MSWINDOWS}
|
|
TempHandle := GetParentFormHandle;
|
|
|
|
if (TempHandle <> 0) then
|
|
begin
|
|
Result := True;
|
|
aResultScale := GetWndScale(TempHandle);
|
|
end;
|
|
{$ENDIF}{$ENDIF}
|
|
end;
|
|
|
|
function TFMXBufferPanel.GetScreenScale : single;
|
|
var
|
|
TempScale : single;
|
|
begin
|
|
if (FForcedDeviceScaleFactor <> 0) then
|
|
Result := FForcedDeviceScaleFactor
|
|
else
|
|
if GetRealScreenScale(TempScale) then
|
|
Result := TempScale
|
|
else
|
|
if (GlobalCEFApp <> nil) then
|
|
Result := GlobalCEFApp.DeviceScaleFactor
|
|
else
|
|
Result := 1;
|
|
end;
|
|
|
|
function TFMXBufferPanel.GetBufferWidth : integer;
|
|
begin
|
|
if (FBuffer <> nil) then
|
|
Result := FBuffer.Width
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TFMXBufferPanel.GetBufferHeight : integer;
|
|
begin
|
|
if (FBuffer <> nil) then
|
|
Result := FBuffer.Height
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
procedure TFMXBufferPanel.BufferDraw(const aBitmap : TBitmap; const aSrcRect, aDstRect : TRectF);
|
|
begin
|
|
if (FBuffer <> nil) then
|
|
if FBuffer.Canvas.BeginScene then
|
|
try
|
|
FBuffer.Canvas.DrawBitmap(aBitmap, aSrcRect, aDstRect, 1, FHighSpeedDrawing);
|
|
finally
|
|
FBuffer.Canvas.EndScene;
|
|
end;
|
|
end;
|
|
|
|
function TFMXBufferPanel.UpdateBufferDimensions(aWidth, aHeight : integer) : boolean;
|
|
var
|
|
TempScale : single;
|
|
begin
|
|
Result := False;
|
|
TempScale := ScreenScale;
|
|
|
|
if ((FBuffer = nil) or
|
|
(FBuffer.BitmapScale <> TempScale) or
|
|
(FBuffer.Width <> aWidth) or
|
|
(FBuffer.Height <> aHeight)) then
|
|
begin
|
|
if (FBuffer <> nil) then FreeAndNil(FBuffer);
|
|
|
|
FBuffer := TBitmap.Create(aWidth, aHeight);
|
|
{$IFDEF DELPHI17_UP}
|
|
FBuffer.BitmapScale := TempScale;
|
|
FScanlineSize := FBuffer.BytesPerLine;
|
|
{$ELSE}
|
|
FScanlineSize := aWidth * SizeOf(TRGBQuad);
|
|
{$ENDIF}
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
function TFMXBufferPanel.BufferIsResized(aUseMutex : boolean) : boolean;
|
|
var
|
|
TempWidth, TempHeight : integer;
|
|
TempScale : single;
|
|
begin
|
|
Result := False;
|
|
|
|
if not(aUseMutex) or BeginBufferDraw then
|
|
begin
|
|
TempScale := ScreenScale;
|
|
TempWidth := round(Width * TempScale);
|
|
TempHeight := round(Height * TempScale);
|
|
|
|
Result := (FBuffer <> nil) and
|
|
(FBuffer.BitmapScale = TempScale) and
|
|
(FBuffer.Width = TempWidth) and
|
|
(FBuffer.Height = TempHeight);
|
|
|
|
if aUseMutex then EndBufferDraw;
|
|
end;
|
|
end;
|
|
|
|
function TFMXBufferPanel.ScreenToClient(aPoint : TPoint) : TPoint;
|
|
var
|
|
TempPoint : TPointF;
|
|
begin
|
|
TempPoint.x := aPoint.x;
|
|
TempPoint.y := aPoint.y;
|
|
TempPoint := ScreenToLocal(TempPoint);
|
|
Result.x := round(TempPoint.x);
|
|
Result.y := round(TempPoint.y);
|
|
end;
|
|
|
|
function TFMXBufferPanel.ScreenToClient(aPoint : TPointF) : TPointF;
|
|
begin
|
|
Result := ScreenToLocal(aPoint);
|
|
end;
|
|
|
|
function TFMXBufferPanel.ClientToScreen(aPoint : TPoint) : TPoint;
|
|
var
|
|
TempPoint : TPointF;
|
|
begin
|
|
TempPoint.x := aPoint.x;
|
|
TempPoint.y := aPoint.y;
|
|
TempPoint := LocalToScreen(TempPoint);
|
|
Result.x := round(TempPoint.x);
|
|
Result.y := round(TempPoint.y);
|
|
end;
|
|
|
|
function TFMXBufferPanel.ClientToScreen(aPoint : TPointF) : TPointF;
|
|
begin
|
|
Result := LocalToScreen(aPoint);
|
|
end;
|
|
|
|
end.
|