CEF4Delphi/source/uCEFBrowserBitmap.pas

187 lines
4.7 KiB
ObjectPascal
Raw Normal View History

unit uCEFBrowserBitmap;
{$IFDEF FPC}
{$MODE OBJFPC}{$H+}
{$ENDIF}
{$I cef.inc}
interface
uses
{$IFDEF DELPHI16_UP}
{$IFDEF MSWINDOWS}Winapi.Windows,{$ELSE}System.SyncObjs,{$ENDIF} System.Classes, System.SysUtils, Vcl.Graphics;
{$ELSE}
2023-02-16 15:48:37 +01:00
{$IFDEF MSWINDOWS}Windows,{$ENDIF} Classes, SysUtils, Graphics
{$IFDEF FPC}, LCLProc, LCLType, LCLIntf, LResources, InterfaceBase{$ENDIF}
{$IFNDEF MSWINDOWS}, SyncObjs{$ENDIF};
{$ENDIF}
type
TCEFBrowserBitmap = class(TBitmap)
protected
FScanlineSize : integer;
FDeviceScaleFactor : single;
{$IFDEF MSWINDOWS}
FSyncObj : THandle;
{$ELSE}
FSyncObj : TCriticalSection;
{$ENDIF}
function GetBufferBits : pointer;
procedure CreateSyncObj;
procedure DestroySyncObj;
public
constructor Create; override;
destructor Destroy; override;
function BeginBufferDraw : boolean;
procedure EndBufferDraw;
function UpdateBufferDimensions(aWidth, aHeight : integer) : boolean;
function BufferIsResized(aUseMutex : boolean = True) : boolean;
procedure BufferDraw(const aBitmap : TBitmap; const aSrcRect, aDstRect : TRect);
property ScanlineSize : integer read FScanlineSize;
property BufferBits : pointer read GetBufferBits;
property DeviceScaleFactor : single read FDeviceScaleFactor write FDeviceScaleFactor;
end;
implementation
uses
uCEFMiscFunctions;
constructor TCEFBrowserBitmap.Create;
begin
inherited Create;
FScanlineSize := 0;
FDeviceScaleFactor := 1;
CreateSyncObj;
end;
destructor TCEFBrowserBitmap.Destroy;
begin
DestroySyncObj;
inherited Destroy;
end;
procedure TCEFBrowserBitmap.CreateSyncObj;
begin
{$IFDEF MSWINDOWS}
FSyncObj := CreateMutex(nil, False, nil);
{$ELSE}
FSyncObj := TCriticalSection.Create;
{$ENDIF}
end;
procedure TCEFBrowserBitmap.DestroySyncObj;
begin
{$IFDEF MSWINDOWS}
if (FSyncObj <> 0) then
begin
CloseHandle(FSyncObj);
FSyncObj := 0;
end;
{$ELSE}
if (FSyncObj <> nil) then FreeAndNil(FSyncObj);
{$ENDIF}
end;
function TCEFBrowserBitmap.GetBufferBits : pointer;
begin
if (Height <> 0) then
Result := Scanline[pred(Height)]
else
Result := nil;
end;
function TCEFBrowserBitmap.BeginBufferDraw : boolean;
begin
{$IFDEF MSWINDOWS}
Result := (FSyncObj <> 0) and (WaitForSingleObject(FSyncObj, 5000) = WAIT_OBJECT_0);
{$ELSE}
if (FSyncObj <> nil) then
begin
FSyncObj.Acquire;
Result := True;
end
else
Result := False;
{$ENDIF}
end;
procedure TCEFBrowserBitmap.EndBufferDraw;
begin
{$IFDEF MSWINDOWS}
if (FSyncObj <> 0) then ReleaseMutex(FSyncObj);
{$ELSE}
if (FSyncObj <> nil) then FSyncObj.Release;
{$ENDIF}
end;
function TCEFBrowserBitmap.UpdateBufferDimensions(aWidth, aHeight : integer) : boolean;
begin
Result := False;
FScanlineSize := aWidth * SizeOf(TRGBQuad);
if (Width <> aWidth) or
(Height <> aHeight) then
begin
{$IFDEF DELPHI16_UP}
SetSize(aWidth, aHeight);
{$ELSE}
Width := aWidth;
Height := aHeight;
{$ENDIF}
Result := True;
end;
end;
function TCEFBrowserBitmap.BufferIsResized(aUseMutex : boolean) : boolean;
var
TempDevWidth, TempLogWidth, TempDevHeight, TempLogHeight : integer;
begin
Result := False;
if not(aUseMutex) or BeginBufferDraw then
begin
if (FDeviceScaleFactor = 1) then
Result := (Width = Width) and
(Height = Height)
else
begin
// CEF and Chromium use 'floor' to round the float values in Device <-> Logical unit conversions
// and Delphi uses MulDiv, which uses the bankers rounding, to resize the components in high DPI mode.
// This is the cause of slight differences in size between the buffer and the panel in some occasions.
TempLogWidth := DeviceToLogical(Width, FDeviceScaleFactor);
TempLogHeight := DeviceToLogical(Height, FDeviceScaleFactor);
TempDevWidth := LogicalToDevice(TempLogWidth, FDeviceScaleFactor);
TempDevHeight := LogicalToDevice(TempLogHeight, FDeviceScaleFactor);
Result := (Width = TempDevWidth) and
(Height = TempDevHeight);
end;
if aUseMutex then EndBufferDraw;
end;
end;
procedure TCEFBrowserBitmap.BufferDraw(const aBitmap : TBitmap; const aSrcRect, aDstRect : TRect);
begin
if (aBitmap <> nil) then
begin
Canvas.Lock;
aBitmap.Canvas.Lock;
Canvas.CopyRect(aDstRect, aBitmap.Canvas, aSrcRect);
aBitmap.Canvas.UnLock;
Canvas.UnLock;
end;
end;
end.