From 47765631e37037ff2eb53aa4e0307905c2170fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Salvador=20D=C3=ADaz=20Fau?= Date: Sun, 19 Nov 2017 11:30:26 +0100 Subject: [PATCH] Buffer panel resize fixes for SimpleOSRBrowser --- demos/SimpleOSRBrowser/uSimpleOSRBrowser.dfm | 5 +- demos/SimpleOSRBrowser/uSimpleOSRBrowser.pas | 208 ++++++++++++------- source/uBufferPanel.pas | 94 +++++---- source/uCEFConstants.pas | 2 + 4 files changed, 199 insertions(+), 110 deletions(-) diff --git a/demos/SimpleOSRBrowser/uSimpleOSRBrowser.dfm b/demos/SimpleOSRBrowser/uSimpleOSRBrowser.dfm index 63ac08e2..bb673a28 100644 --- a/demos/SimpleOSRBrowser/uSimpleOSRBrowser.dfm +++ b/demos/SimpleOSRBrowser/uSimpleOSRBrowser.dfm @@ -48,7 +48,8 @@ object Form1: TForm1 'https://html5demos.com/drag' 'https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_selec' + - 't_form') + 't_form' + 'https://www.briskbard.com') end object Panel2: TPanel Left = 726 @@ -111,10 +112,10 @@ object Form1: TForm1 OnEnter = Panel1Enter OnExit = Panel1Exit OnMouseDown = Panel1MouseDown - OnMouseLeave = Panel1MouseLeave OnMouseMove = Panel1MouseMove OnMouseUp = Panel1MouseUp OnResize = Panel1Resize + OnMouseLeave = Panel1MouseLeave end object chrmosr: TChromium OnAfterCreated = chrmosrAfterCreated diff --git a/demos/SimpleOSRBrowser/uSimpleOSRBrowser.pas b/demos/SimpleOSRBrowser/uSimpleOSRBrowser.pas index 1e80ca97..173f40a8 100644 --- a/demos/SimpleOSRBrowser/uSimpleOSRBrowser.pas +++ b/demos/SimpleOSRBrowser/uSimpleOSRBrowser.pas @@ -103,15 +103,20 @@ type FPopUpBitmap : TBitmap; FPopUpRect : TRect; FShowPopUp : boolean; + FResizing : boolean; + FPendingResize : boolean; + FResizeCS : TCriticalSection; function getModifiers(Shift: TShiftState): TCefEventFlags; function GetButton(Button: TMouseButton): TCefMouseButtonType; + procedure DoResize; procedure WMMove(var aMessage : TWMMove); message WM_MOVE; procedure WMMoving(var aMessage : TMessage); message WM_MOVING; procedure WMCaptureChanged(var aMessage : TMessage); message WM_CAPTURECHANGED; procedure WMCancelMode(var aMessage : TMessage); message WM_CANCELMODE; procedure BrowserCreatedMsg(var aMessage : TMessage); message CEF_AFTERCREATED; + procedure PendingResizeMsg(var aMessage : TMessage); message CEF_PENDINGRESIZE; public { Public declarations } @@ -132,6 +137,15 @@ uses {$ENDIF} 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); var TempKeyEvent : TCefKeyEvent; @@ -248,6 +262,11 @@ end; procedure TForm1.GoBtnClick(Sender: TObject); begin + FResizeCS.Acquire; + FResizing := False; + FPendingResize := False; + FResizeCS.Release; + chrmosr.LoadURL(ComboBox1.Text); end; @@ -327,11 +346,11 @@ procedure TForm1.chrmosrGetViewRect(Sender : TObject; begin if (GlobalCEFApp <> nil) then begin - rect.x := 0; - rect.y := 0; - rect.width := DeviceToLogical(Panel1.Width, GlobalCEFApp.DeviceScaleFactor); - rect.height := DeviceToLogical(Panel1.Height, GlobalCEFApp.DeviceScaleFactor); - Result := True; + rect.x := 0; + rect.y := 0; + rect.width := DeviceToLogical(Panel1.Width, GlobalCEFApp.DeviceScaleFactor); + rect.height := DeviceToLogical(Panel1.Height, GlobalCEFApp.DeviceScaleFactor); + Result := True; end else Result := False; @@ -351,83 +370,100 @@ var n : NativeUInt; TempWidth, TempHeight, TempScanlineSize : integer; TempBufferBits : Pointer; + TempForcedResize : boolean; begin - if Panel1.BeginBufferDraw then - begin - if (kind = PET_POPUP) then - begin - if (FPopUpBitmap = nil) or - (width <> FPopUpBitmap.Width) or - (height <> FPopUpBitmap.Height) then - begin - if (FPopUpBitmap <> nil) then FPopUpBitmap.Free; + try + FResizeCS.Acquire; + TempForcedResize := False; - FPopUpBitmap := TBitmap.Create; - FPopUpBitmap.PixelFormat := pf32bit; - FPopUpBitmap.HandleType := bmDIB; - FPopUpBitmap.Width := width; - FPopUpBitmap.Height := height; - end; + if Panel1.BeginBufferDraw then + begin + if (kind = PET_POPUP) then + begin + if (FPopUpBitmap = nil) or + (width <> FPopUpBitmap.Width) or + (height <> FPopUpBitmap.Height) then + begin + if (FPopUpBitmap <> nil) then FPopUpBitmap.Free; - TempWidth := FPopUpBitmap.Width; - TempHeight := FPopUpBitmap.Height; - TempScanlineSize := FPopUpBitmap.Width * SizeOf(TRGBQuad); - TempBufferBits := FPopUpBitmap.Scanline[pred(FPopUpBitmap.Height)]; - end - else - begin - TempWidth := Panel1.BufferWidth; - TempHeight := Panel1.BufferHeight; - TempScanlineSize := Panel1.ScanlineSize; - TempBufferBits := Panel1.BufferBits; - end; + FPopUpBitmap := TBitmap.Create; + FPopUpBitmap.PixelFormat := pf32bit; + FPopUpBitmap.HandleType := bmDIB; + FPopUpBitmap.Width := width; + FPopUpBitmap.Height := height; + end; - if (TempBufferBits <> nil) then - begin - SrcStride := Width * SizeOf(TRGBQuad); - DstStride := - TempScanlineSize; + TempWidth := FPopUpBitmap.Width; + TempHeight := FPopUpBitmap.Height; + TempScanlineSize := FPopUpBitmap.Width * SizeOf(TRGBQuad); + 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 - begin - if (dirtyRects[n].x >= 0) and (dirtyRects[n].y >= 0) then - begin - TempLineSize := min(dirtyRects[n].width, TempWidth - dirtyRects[n].x) * SizeOf(TRGBQuad); + n := 0; - if (TempLineSize > 0) then - begin - TempSrcOffset := ((dirtyRects[n].y * Width) + dirtyRects[n].x) * SizeOf(TRGBQuad); - TempDstOffset := ((TempScanlineSize * pred(TempHeight)) - (dirtyRects[n].y * TempScanlineSize)) + - (dirtyRects[n].x * SizeOf(TRGBQuad)); + while (n < dirtyRectsCount) do + begin + if (dirtyRects[n].x >= 0) and (dirtyRects[n].y >= 0) then + begin + TempLineSize := min(dirtyRects[n].width, TempWidth - dirtyRects[n].x) * SizeOf(TRGBQuad); - src := @PByte(buffer)[TempSrcOffset]; - dst := @PByte(TempBufferBits)[TempDstOffset]; + if (TempLineSize > 0) then + 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; - j := min(dirtyRects[n].height, TempHeight - dirtyRects[n].y); + src := @PByte(buffer)[TempSrcOffset]; + dst := @PByte(TempBufferBits)[TempDstOffset]; - while (i < j) do - begin - Move(src^, dst^, TempLineSize); + i := 0; + j := min(dirtyRects[n].height, TempHeight - dirtyRects[n].y); - Inc(dst, DstStride); - Inc(src, SrcStride); - inc(i); - end; - end; - end; + while (i < j) do + begin + Move(src^, dst^, TempLineSize); - inc(n); - end; + Inc(dst, DstStride); + Inc(src, SrcStride); + inc(i); + end; + end; + end; - if FShowPopup and (FPopUpBitmap <> nil) then - Panel1.BufferDraw(FPopUpRect.Left, FPopUpRect.Top, FPopUpBitmap); - end; + inc(n); + end; - Panel1.EndBufferDraw; - Panel1.InvalidatePanel; - end; + if FShowPopup and (FPopUpBitmap <> nil) then + Panel1.BufferDraw(FPopUpRect.Left, FPopUpRect.Top, FPopUpBitmap); + 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; procedure TForm1.chrmosrPopupShow(Sender : TObject; @@ -532,9 +568,12 @@ end; procedure TForm1.FormCreate(Sender: TObject); begin - FPopUpBitmap := nil; - FPopUpRect := rect(0, 0, 0, 0); - FShowPopUp := False; + FPopUpBitmap := nil; + FPopUpRect := rect(0, 0, 0, 0); + FShowPopUp := False; + FResizing := False; + FPendingResize := False; + FResizeCS := TCriticalSection.Create; end; procedure TForm1.FormDestroy(Sender: TObject); @@ -635,7 +674,32 @@ end; procedure TForm1.Panel1Resize(Sender: TObject); 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; procedure TForm1.Panel1Enter(Sender: TObject); diff --git a/source/uBufferPanel.pas b/source/uBufferPanel.pas index 1afd2f17..fe8c5644 100644 --- a/source/uBufferPanel.pas +++ b/source/uBufferPanel.pas @@ -61,10 +61,9 @@ type function GetBufferWidth : 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; procedure DestroyBuffer; - procedure Resize; override; procedure WMPaint(var aMessage: TWMPaint); message WM_PAINT; procedure WMEraseBkgnd(var aMessage : TWMEraseBkgnd); message WM_ERASEBKGND; @@ -78,6 +77,8 @@ type function BeginBufferDraw : boolean; procedure EndBufferDraw; 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 ScanlineSize : integer read FScanlineSize; @@ -173,7 +174,7 @@ type implementation uses - uCEFMiscFunctions; + uCEFMiscFunctions, uCEFApplication; constructor TBufferPanel.Create(AOwner: TComponent); begin @@ -254,14 +255,17 @@ begin if (FMutex <> 0) then ReleaseMutex(FMutex); end; -procedure TBufferPanel.CopyBuffer(aDC : HDC; const aRect : TRect); +function TBufferPanel.CopyBuffer(aDC : HDC; const aRect : TRect) : boolean; begin + Result := False; + if BeginBufferDraw then begin - if (FBuffer <> nil) and (aDC <> 0) then - BitBlt(aDC, aRect.Left, aRect.Top, aRect.Right - aRect.Left, aRect.Bottom - aRect.Top, - FBuffer.Canvas.Handle, aRect.Left, aRect.Top, - SrcCopy); + Result := (FBuffer <> nil) and + (aDC <> 0) and + BitBlt(aDC, aRect.Left, aRect.Top, aRect.Right - aRect.Left, aRect.Bottom - aRect.Top, + FBuffer.Canvas.Handle, aRect.Left, aRect.Top, + SrcCopy); EndBufferDraw; end; @@ -269,8 +273,8 @@ end; procedure TBufferPanel.WMPaint(var aMessage: TWMPaint); var - TempPaintStruct: TPaintStruct; - TempDC : HDC; + TempPaintStruct : TPaintStruct; + TempDC : HDC; begin try TempDC := BeginPaint(Handle, TempPaintStruct); @@ -285,38 +289,18 @@ begin Canvas.Rectangle(0, 0, Width, Height); end 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 EndPaint(Handle, TempPaintStruct); aMessage.Result := 1; 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); begin aMessage.Result := 1; @@ -351,4 +335,42 @@ begin if (FBuffer <> nil) then FBuffer.Canvas.Draw(x, y, aBitmap); 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. diff --git a/source/uCEFConstants.pas b/source/uCEFConstants.pas index 76fbea0a..d792b733 100644 --- a/source/uCEFConstants.pas +++ b/source/uCEFConstants.pas @@ -360,6 +360,7 @@ const CEF_DOONCLOSE = WM_APP + $A01; CEF_STARTDRAGGING = WM_APP + $A02; CEF_AFTERCREATED = WM_APP + $A03; + CEF_PENDINGRESIZE = WM_APP + $A04; CEF_USER_TIMER_MINIMUM = $0000000A; CEF_USER_TIMER_MAXIMUM = $7FFFFFFF; @@ -370,3 +371,4 @@ const implementation end. +