1
0
mirror of https://github.com/salvadordf/CEF4Delphi.git synced 2025-07-12 22:30:17 +02:00

Buffer panel resize fixes for SimpleOSRBrowser

This commit is contained in:
Salvador Díaz Fau
2017-11-19 11:30:26 +01:00
parent 042c3ac088
commit 47765631e3
4 changed files with 199 additions and 110 deletions

View File

@ -48,7 +48,8 @@ object Form1: TForm1
'https://html5demos.com/drag' 'https://html5demos.com/drag'
'https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_selec' + 'https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_selec' +
't_form') 't_form'
'https://www.briskbard.com')
end end
object Panel2: TPanel object Panel2: TPanel
Left = 726 Left = 726
@ -111,10 +112,10 @@ object Form1: TForm1
OnEnter = Panel1Enter OnEnter = Panel1Enter
OnExit = Panel1Exit OnExit = Panel1Exit
OnMouseDown = Panel1MouseDown OnMouseDown = Panel1MouseDown
OnMouseLeave = Panel1MouseLeave
OnMouseMove = Panel1MouseMove OnMouseMove = Panel1MouseMove
OnMouseUp = Panel1MouseUp OnMouseUp = Panel1MouseUp
OnResize = Panel1Resize OnResize = Panel1Resize
OnMouseLeave = Panel1MouseLeave
end end
object chrmosr: TChromium object chrmosr: TChromium
OnAfterCreated = chrmosrAfterCreated OnAfterCreated = chrmosrAfterCreated

View File

@ -103,15 +103,20 @@ type
FPopUpBitmap : TBitmap; FPopUpBitmap : TBitmap;
FPopUpRect : TRect; FPopUpRect : TRect;
FShowPopUp : boolean; FShowPopUp : boolean;
FResizing : boolean;
FPendingResize : boolean;
FResizeCS : TCriticalSection;
function getModifiers(Shift: TShiftState): TCefEventFlags; function getModifiers(Shift: TShiftState): TCefEventFlags;
function GetButton(Button: TMouseButton): TCefMouseButtonType; function GetButton(Button: TMouseButton): TCefMouseButtonType;
procedure DoResize;
procedure WMMove(var aMessage : TWMMove); message WM_MOVE; procedure WMMove(var aMessage : TWMMove); message WM_MOVE;
procedure WMMoving(var aMessage : TMessage); message WM_MOVING; procedure WMMoving(var aMessage : TMessage); message WM_MOVING;
procedure WMCaptureChanged(var aMessage : TMessage); message WM_CAPTURECHANGED; procedure WMCaptureChanged(var aMessage : TMessage); message WM_CAPTURECHANGED;
procedure WMCancelMode(var aMessage : TMessage); message WM_CANCELMODE; procedure WMCancelMode(var aMessage : TMessage); message WM_CANCELMODE;
procedure BrowserCreatedMsg(var aMessage : TMessage); message CEF_AFTERCREATED; procedure BrowserCreatedMsg(var aMessage : TMessage); message CEF_AFTERCREATED;
procedure PendingResizeMsg(var aMessage : TMessage); message CEF_PENDINGRESIZE;
public public
{ Public declarations } { Public declarations }
@ -132,6 +137,15 @@ uses
{$ENDIF} {$ENDIF}
uCEFMiscFunctions, uCEFApplication; uCEFMiscFunctions, uCEFApplication;
// *********************************
// ********* ATTENTION !!! *********
// *********************************
//
// There is a known bug in the destruction of TChromium in OSR mode.
// If you destroy the TChromium in OSR mode before the application is closed,
// add a timer and wait 1-2 seconds after the TChromium's destruction.
// After that you can close the app. Hide the application in the task bar if necessary.
procedure TForm1.AppEventsMessage(var Msg: tagMSG; var Handled: Boolean); procedure TForm1.AppEventsMessage(var Msg: tagMSG; var Handled: Boolean);
var var
TempKeyEvent : TCefKeyEvent; TempKeyEvent : TCefKeyEvent;
@ -248,6 +262,11 @@ end;
procedure TForm1.GoBtnClick(Sender: TObject); procedure TForm1.GoBtnClick(Sender: TObject);
begin begin
FResizeCS.Acquire;
FResizing := False;
FPendingResize := False;
FResizeCS.Release;
chrmosr.LoadURL(ComboBox1.Text); chrmosr.LoadURL(ComboBox1.Text);
end; end;
@ -327,11 +346,11 @@ procedure TForm1.chrmosrGetViewRect(Sender : TObject;
begin begin
if (GlobalCEFApp <> nil) then if (GlobalCEFApp <> nil) then
begin begin
rect.x := 0; rect.x := 0;
rect.y := 0; rect.y := 0;
rect.width := DeviceToLogical(Panel1.Width, GlobalCEFApp.DeviceScaleFactor); rect.width := DeviceToLogical(Panel1.Width, GlobalCEFApp.DeviceScaleFactor);
rect.height := DeviceToLogical(Panel1.Height, GlobalCEFApp.DeviceScaleFactor); rect.height := DeviceToLogical(Panel1.Height, GlobalCEFApp.DeviceScaleFactor);
Result := True; Result := True;
end end
else else
Result := False; Result := False;
@ -351,83 +370,100 @@ var
n : NativeUInt; n : NativeUInt;
TempWidth, TempHeight, TempScanlineSize : integer; TempWidth, TempHeight, TempScanlineSize : integer;
TempBufferBits : Pointer; TempBufferBits : Pointer;
TempForcedResize : boolean;
begin begin
if Panel1.BeginBufferDraw then try
begin FResizeCS.Acquire;
if (kind = PET_POPUP) then TempForcedResize := False;
begin
if (FPopUpBitmap = nil) or
(width <> FPopUpBitmap.Width) or
(height <> FPopUpBitmap.Height) then
begin
if (FPopUpBitmap <> nil) then FPopUpBitmap.Free;
FPopUpBitmap := TBitmap.Create; if Panel1.BeginBufferDraw then
FPopUpBitmap.PixelFormat := pf32bit; begin
FPopUpBitmap.HandleType := bmDIB; if (kind = PET_POPUP) then
FPopUpBitmap.Width := width; begin
FPopUpBitmap.Height := height; if (FPopUpBitmap = nil) or
end; (width <> FPopUpBitmap.Width) or
(height <> FPopUpBitmap.Height) then
begin
if (FPopUpBitmap <> nil) then FPopUpBitmap.Free;
TempWidth := FPopUpBitmap.Width; FPopUpBitmap := TBitmap.Create;
TempHeight := FPopUpBitmap.Height; FPopUpBitmap.PixelFormat := pf32bit;
TempScanlineSize := FPopUpBitmap.Width * SizeOf(TRGBQuad); FPopUpBitmap.HandleType := bmDIB;
TempBufferBits := FPopUpBitmap.Scanline[pred(FPopUpBitmap.Height)]; FPopUpBitmap.Width := width;
end FPopUpBitmap.Height := height;
else end;
begin
TempWidth := Panel1.BufferWidth;
TempHeight := Panel1.BufferHeight;
TempScanlineSize := Panel1.ScanlineSize;
TempBufferBits := Panel1.BufferBits;
end;
if (TempBufferBits <> nil) then TempWidth := FPopUpBitmap.Width;
begin TempHeight := FPopUpBitmap.Height;
SrcStride := Width * SizeOf(TRGBQuad); TempScanlineSize := FPopUpBitmap.Width * SizeOf(TRGBQuad);
DstStride := - TempScanlineSize; TempBufferBits := FPopUpBitmap.Scanline[pred(FPopUpBitmap.Height)];
end
else
begin
TempForcedResize := Panel1.UpdateBufferDimensions(Width, Height) or not(Panel1.BufferIsResized(False));
TempWidth := Panel1.BufferWidth;
TempHeight := Panel1.BufferHeight;
TempScanlineSize := Panel1.ScanlineSize;
TempBufferBits := Panel1.BufferBits;
end;
n := 0; if (TempBufferBits <> nil) then
begin
SrcStride := Width * SizeOf(TRGBQuad);
DstStride := - TempScanlineSize;
while (n < dirtyRectsCount) do n := 0;
begin
if (dirtyRects[n].x >= 0) and (dirtyRects[n].y >= 0) then
begin
TempLineSize := min(dirtyRects[n].width, TempWidth - dirtyRects[n].x) * SizeOf(TRGBQuad);
if (TempLineSize > 0) then while (n < dirtyRectsCount) do
begin begin
TempSrcOffset := ((dirtyRects[n].y * Width) + dirtyRects[n].x) * SizeOf(TRGBQuad); if (dirtyRects[n].x >= 0) and (dirtyRects[n].y >= 0) then
TempDstOffset := ((TempScanlineSize * pred(TempHeight)) - (dirtyRects[n].y * TempScanlineSize)) + begin
(dirtyRects[n].x * SizeOf(TRGBQuad)); TempLineSize := min(dirtyRects[n].width, TempWidth - dirtyRects[n].x) * SizeOf(TRGBQuad);
src := @PByte(buffer)[TempSrcOffset]; if (TempLineSize > 0) then
dst := @PByte(TempBufferBits)[TempDstOffset]; begin
TempSrcOffset := ((dirtyRects[n].y * Width) + dirtyRects[n].x) * SizeOf(TRGBQuad);
TempDstOffset := ((TempScanlineSize * pred(TempHeight)) - (dirtyRects[n].y * TempScanlineSize)) +
(dirtyRects[n].x * SizeOf(TRGBQuad));
i := 0; src := @PByte(buffer)[TempSrcOffset];
j := min(dirtyRects[n].height, TempHeight - dirtyRects[n].y); dst := @PByte(TempBufferBits)[TempDstOffset];
while (i < j) do i := 0;
begin j := min(dirtyRects[n].height, TempHeight - dirtyRects[n].y);
Move(src^, dst^, TempLineSize);
Inc(dst, DstStride); while (i < j) do
Inc(src, SrcStride); begin
inc(i); Move(src^, dst^, TempLineSize);
end;
end;
end;
inc(n); Inc(dst, DstStride);
end; Inc(src, SrcStride);
inc(i);
end;
end;
end;
if FShowPopup and (FPopUpBitmap <> nil) then inc(n);
Panel1.BufferDraw(FPopUpRect.Left, FPopUpRect.Top, FPopUpBitmap); end;
end;
Panel1.EndBufferDraw; if FShowPopup and (FPopUpBitmap <> nil) then
Panel1.InvalidatePanel; Panel1.BufferDraw(FPopUpRect.Left, FPopUpRect.Top, FPopUpBitmap);
end; end;
Panel1.EndBufferDraw;
Panel1.InvalidatePanel;
if (kind = PET_VIEW) then
begin
if TempForcedResize or FPendingResize then PostMessage(Handle, CEF_PENDINGRESIZE, 0, 0);
FResizing := False;
FPendingResize := False;
end;
end;
finally
FResizeCS.Release;
end;
end; end;
procedure TForm1.chrmosrPopupShow(Sender : TObject; procedure TForm1.chrmosrPopupShow(Sender : TObject;
@ -532,9 +568,12 @@ end;
procedure TForm1.FormCreate(Sender: TObject); procedure TForm1.FormCreate(Sender: TObject);
begin begin
FPopUpBitmap := nil; FPopUpBitmap := nil;
FPopUpRect := rect(0, 0, 0, 0); FPopUpRect := rect(0, 0, 0, 0);
FShowPopUp := False; FShowPopUp := False;
FResizing := False;
FPendingResize := False;
FResizeCS := TCriticalSection.Create;
end; end;
procedure TForm1.FormDestroy(Sender: TObject); procedure TForm1.FormDestroy(Sender: TObject);
@ -635,7 +674,32 @@ end;
procedure TForm1.Panel1Resize(Sender: TObject); procedure TForm1.Panel1Resize(Sender: TObject);
begin begin
chrmosr.WasResized; DoResize;
end;
procedure TForm1.PendingResizeMsg(var aMessage : TMessage);
begin
DoResize;
end;
procedure TForm1.DoResize;
begin
try
FResizeCS.Acquire;
if FResizing then
FPendingResize := True
else
if Panel1.BufferIsResized then
chrmosr.Invalidate(PET_VIEW)
else
begin
FResizing := True;
chrmosr.WasResized;
end;
finally
FResizeCS.Release;
end;
end; end;
procedure TForm1.Panel1Enter(Sender: TObject); procedure TForm1.Panel1Enter(Sender: TObject);

View File

@ -61,10 +61,9 @@ type
function GetBufferWidth : integer; function GetBufferWidth : integer;
function GetBufferHeight : integer; function GetBufferHeight : integer;
procedure CopyBuffer(aDC : HDC; const aRect : TRect); function CopyBuffer(aDC : HDC; const aRect : TRect) : boolean;
function SaveBufferToFile(const aFilename : string) : boolean; function SaveBufferToFile(const aFilename : string) : boolean;
procedure DestroyBuffer; procedure DestroyBuffer;
procedure Resize; override;
procedure WMPaint(var aMessage: TWMPaint); message WM_PAINT; procedure WMPaint(var aMessage: TWMPaint); message WM_PAINT;
procedure WMEraseBkgnd(var aMessage : TWMEraseBkgnd); message WM_ERASEBKGND; procedure WMEraseBkgnd(var aMessage : TWMEraseBkgnd); message WM_ERASEBKGND;
@ -78,6 +77,8 @@ type
function BeginBufferDraw : boolean; function BeginBufferDraw : boolean;
procedure EndBufferDraw; procedure EndBufferDraw;
procedure BufferDraw(x, y : integer; const aBitmap : TBitmap); procedure BufferDraw(x, y : integer; const aBitmap : TBitmap);
function UpdateBufferDimensions(aWidth, aHeight : integer) : boolean;
function BufferIsResized(aUseMutex : boolean = True) : boolean;
property Buffer : TBitmap read FBuffer; property Buffer : TBitmap read FBuffer;
property ScanlineSize : integer read FScanlineSize; property ScanlineSize : integer read FScanlineSize;
@ -173,7 +174,7 @@ type
implementation implementation
uses uses
uCEFMiscFunctions; uCEFMiscFunctions, uCEFApplication;
constructor TBufferPanel.Create(AOwner: TComponent); constructor TBufferPanel.Create(AOwner: TComponent);
begin begin
@ -254,14 +255,17 @@ begin
if (FMutex <> 0) then ReleaseMutex(FMutex); if (FMutex <> 0) then ReleaseMutex(FMutex);
end; end;
procedure TBufferPanel.CopyBuffer(aDC : HDC; const aRect : TRect); function TBufferPanel.CopyBuffer(aDC : HDC; const aRect : TRect) : boolean;
begin begin
Result := False;
if BeginBufferDraw then if BeginBufferDraw then
begin begin
if (FBuffer <> nil) and (aDC <> 0) then Result := (FBuffer <> nil) and
BitBlt(aDC, aRect.Left, aRect.Top, aRect.Right - aRect.Left, aRect.Bottom - aRect.Top, (aDC <> 0) and
FBuffer.Canvas.Handle, aRect.Left, aRect.Top, BitBlt(aDC, aRect.Left, aRect.Top, aRect.Right - aRect.Left, aRect.Bottom - aRect.Top,
SrcCopy); FBuffer.Canvas.Handle, aRect.Left, aRect.Top,
SrcCopy);
EndBufferDraw; EndBufferDraw;
end; end;
@ -269,8 +273,8 @@ end;
procedure TBufferPanel.WMPaint(var aMessage: TWMPaint); procedure TBufferPanel.WMPaint(var aMessage: TWMPaint);
var var
TempPaintStruct: TPaintStruct; TempPaintStruct : TPaintStruct;
TempDC : HDC; TempDC : HDC;
begin begin
try try
TempDC := BeginPaint(Handle, TempPaintStruct); TempDC := BeginPaint(Handle, TempPaintStruct);
@ -285,38 +289,18 @@ begin
Canvas.Rectangle(0, 0, Width, Height); Canvas.Rectangle(0, 0, Width, Height);
end end
else else
CopyBuffer(TempDC, TempPaintStruct.rcPaint); if not(CopyBuffer(TempDC, TempPaintStruct.rcPaint)) then
begin
Canvas.Brush.Color := Color;
Canvas.Brush.Style := bsSolid;
Canvas.FillRect(rect(0, 0, Width, Height));
end;
finally finally
EndPaint(Handle, TempPaintStruct); EndPaint(Handle, TempPaintStruct);
aMessage.Result := 1; aMessage.Result := 1;
end; end;
end; end;
procedure TBufferPanel.Resize;
begin
if BeginBufferDraw then
begin
if ((FBuffer = nil) or
(FBuffer.Width <> Width) or
(FBuffer.Height <> Height)) then
begin
if (FBuffer <> nil) then FreeAndNil(FBuffer);
FBuffer := TBitmap.Create;
FBuffer.PixelFormat := pf32bit;
FBuffer.HandleType := bmDIB;
FBuffer.Width := Width;
FBuffer.Height := Height;
FScanlineSize := FBuffer.Width * SizeOf(TRGBQuad);
end;
EndBufferDraw;
end;
inherited Resize;
end;
procedure TBufferPanel.WMEraseBkgnd(var aMessage : TWMEraseBkgnd); procedure TBufferPanel.WMEraseBkgnd(var aMessage : TWMEraseBkgnd);
begin begin
aMessage.Result := 1; aMessage.Result := 1;
@ -351,4 +335,42 @@ begin
if (FBuffer <> nil) then FBuffer.Canvas.Draw(x, y, aBitmap); if (FBuffer <> nil) then FBuffer.Canvas.Draw(x, y, aBitmap);
end; end;
function TBufferPanel.UpdateBufferDimensions(aWidth, aHeight : integer) : boolean;
begin
if ((FBuffer = nil) or
(FBuffer.Width <> aWidth) or
(FBuffer.Height <> aHeight)) then
begin
if (FBuffer <> nil) then FreeAndNil(FBuffer);
FBuffer := TBitmap.Create;
FBuffer.PixelFormat := pf32bit;
FBuffer.HandleType := bmDIB;
FBuffer.Width := aWidth;
FBuffer.Height := aHeight;
FScanlineSize := FBuffer.Width * SizeOf(TRGBQuad);
Result := True;
end
else
Result := False;
end;
function TBufferPanel.BufferIsResized(aUseMutex : boolean) : boolean;
begin
Result := False;
if not(aUseMutex) or BeginBufferDraw then
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.
Result := (FBuffer <> nil) and
(FBuffer.Width = LogicalToDevice(DeviceToLogical(Width, GlobalCEFApp.DeviceScaleFactor), GlobalCEFApp.DeviceScaleFactor)) and
(FBuffer.Height = LogicalToDevice(DeviceToLogical(Height, GlobalCEFApp.DeviceScaleFactor), GlobalCEFApp.DeviceScaleFactor));
if aUseMutex then EndBufferDraw;
end;
end;
end. end.

View File

@ -360,6 +360,7 @@ const
CEF_CONTENT_SETTING_NUM_SETTINGS = 5; CEF_CONTENT_SETTING_NUM_SETTINGS = 5;
// Used in the severity parameter of cef_log // Used in the severity parameter of cef_log
CEF_LOG_SEVERITY_INFO = 0;
CEF_LOG_SEVERITY_WARNING = 1; CEF_LOG_SEVERITY_WARNING = 1;
CEF_LOG_SEVERITY_ERROR = 2; CEF_LOG_SEVERITY_ERROR = 2;
@ -370,3 +371,4 @@ const
ZOOM_STEP_75 = 4; ZOOM_STEP_75 = 4;
ZOOM_STEP_90 = 5; ZOOM_STEP_90 = 5;
ZOOM_STEP_100 = 6; ZOOM_STEP_100 = 6;
ZOOM_STEP_110 = 7;