123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444 |
- using System;
- using System.Threading.Tasks;
- using Xilium.CefGlue.Common.Helpers;
- using Xilium.CefGlue.Common.Helpers.Logger;
- using Xilium.CefGlue.Common.InternalHandlers;
- using Xilium.CefGlue.Common.Platform;
- using Xilium.CefGlue.Common.Shared.Helpers;
- namespace Xilium.CefGlue.Common
- {
- internal class CommonOffscreenBrowserAdapter : CommonBrowserAdapter, IOffscreenCefBrowserHost
- {
- private static readonly TimeSpan ResizeDelay = TimeSpan.FromMilliseconds(50);
- private bool _isVisible = true;
- private Func<CefRectangle> _getViewRectOverride;
- public CommonOffscreenBrowserAdapter(object eventsEmitter, string name, IOffScreenControlHost control, IOffScreenPopupHost popup, ILogger logger)
- : base(eventsEmitter, name, control, logger) {
- Popup = popup;
- }
- protected new IOffScreenControlHost Control => (IOffScreenControlHost) base.Control;
- private IOffScreenPopupHost Popup { get; }
- protected override void InnerDispose()
- {
- Control.RenderSurface.Dispose();
- Popup.RenderSurface.Dispose();
- }
- private int Width => Control.RenderSurface.Width;
- private int Height => Control.RenderSurface.Height;
- private void SendMouseClickEvent(CefMouseEvent mouseEvent, CefMouseButtonType mouseButton, bool isMouseUp, int clickCount)
- {
- BrowserHost?.SendMouseClickEvent(mouseEvent, mouseButton, isMouseUp, clickCount);
- }
- protected override void HandleGotFocus()
- {
- WithErrorHandling(nameof(HandleGotFocus), () =>
- {
- BrowserHost?.SendFocusEvent(true);
- });
- }
- private void HandleLostFocus()
- {
- WithErrorHandling(nameof(HandleLostFocus), () =>
- {
- BrowserHost?.SendFocusEvent(false);
- });
- }
- private void HandleMouseMove(CefMouseEvent mouseEvent)
- {
- WithErrorHandling(nameof(HandleMouseMove), () =>
- {
- BrowserHost?.SendMouseMoveEvent(mouseEvent, false);
- });
- }
- private void HandleMouseLeave(CefMouseEvent mouseEvent)
- {
- WithErrorHandling(nameof(HandleMouseLeave), () =>
- {
- BrowserHost?.SendMouseMoveEvent(mouseEvent, true);
- });
- }
- private void HandleMouseButtonDown(IOffScreenControlHost control, CefMouseEvent mouseEvent, CefMouseButtonType mouseButton, int clickCount)
- {
- WithErrorHandling(nameof(HandleMouseButtonDown), () =>
- {
- control.Focus();
- if (BrowserHost != null)
- {
- SendMouseClickEvent(mouseEvent, mouseButton, false, clickCount);
- }
- });
- }
- private void HandleMouseButtonUp(CefMouseEvent mouseEvent, CefMouseButtonType mouseButton)
- {
- WithErrorHandling(nameof(HandleMouseButtonUp), () =>
- {
- if (BrowserHost != null)
- {
- SendMouseClickEvent(mouseEvent, mouseButton, true, 1);
- }
- });
- }
- private void HandleMouseWheel(CefMouseEvent mouseEvent, int deltaX, int deltaY)
- {
- WithErrorHandling(nameof(HandleMouseWheel), () =>
- {
- BrowserHost?.SendMouseWheelEvent(mouseEvent, deltaX, deltaY);
- });
- }
- private void HandleTextInput(string text, out bool handled)
- {
- var _handled = false;
- WithErrorHandling(nameof(HandleMouseWheel), () =>
- {
- if (BrowserHost != null)
- {
- foreach (var c in text)
- {
- var keyEvent = new CefKeyEvent()
- {
- EventType = CefKeyEventType.Char,
- WindowsKeyCode = c,
- Character = c
- };
- BrowserHost?.SendKeyEvent(keyEvent);
- }
- _handled = true;
- }
- });
- handled = _handled;
- }
- private void HandleKeyPress(CefKeyEvent keyEvent, out bool handled)
- {
- WithErrorHandling(nameof(HandleKeyPress), () =>
- {
- if (BrowserHost != null)
- {
- //_logger.Debug(string.Format("KeyDown: system key {0}, key {1}", arg.SystemKey, arg.Key));
- BrowserHost?.SendKeyEvent(keyEvent);
- }
- });
- handled = false;
- }
- private void HandleDragEnter(CefMouseEvent mouseEvent, CefDragData dragData, CefDragOperationsMask effects)
- {
- WithErrorHandling(nameof(HandleDragEnter), () =>
- {
- BrowserHost?.DragTargetDragEnter(dragData, mouseEvent, effects);
- BrowserHost?.DragTargetDragOver(mouseEvent, effects);
- });
- }
- private void HandleDragOver(CefMouseEvent mouseEvent, CefDragOperationsMask effects)
- {
- WithErrorHandling(nameof(HandleDragOver), () =>
- {
- BrowserHost?.DragTargetDragOver(mouseEvent, effects);
- });
- // TODO
- //e.Effects = currentDragDropEffects;
- //e.Handled = true;
- }
- private void HandleDragLeave()
- {
- WithErrorHandling(nameof(HandleDragLeave), () =>
- {
- BrowserHost?.DragTargetDragLeave();
- });
- }
- private void HandleDrop(CefMouseEvent mouseEvent, CefDragOperationsMask effects)
- {
- WithErrorHandling(nameof(HandleDrop), () =>
- {
- BrowserHost?.DragTargetDragOver(mouseEvent, effects);
- BrowserHost?.DragTargetDrop(mouseEvent);
- });
- }
- private void HandleVisibilityChanged(bool isVisible)
- {
- if (isVisible == _isVisible)
- {
- // visiblity didn't change at all
- return;
- }
- WithErrorHandling(nameof(HandleVisibilityChanged), () =>
- {
- if (BrowserHost != null)
- {
- _isVisible = isVisible;
- if (isVisible)
- {
- BrowserHost.WasHidden(false);
- // workaround cef OSR bug (https://bitbucket.org/chromiumembedded/cef/issues/2483/osr-invalidate-does-not-generate-frame)
- // we notify browser of a resize and return height+1px on next GetViewRect call
- // then restore the original size back again
- ActionTask.Run(async () =>
- {
- _getViewRectOverride = () =>
- {
- return new CefRectangle(0, 0, Width, Height + 1);
- };
- BrowserHost.WasResized();
- await Task.Delay(ResizeDelay);
- if (BrowserHost != null)
- {
- _getViewRectOverride = null;
- BrowserHost.WasResized();
- }
- });
- }
- else
- {
- BrowserHost.WasHidden(true);
- }
- }
- });
- }
- private void HandleScreenInfoChanged(float deviceScaleFactor)
- {
- WithErrorHandling(nameof(HandleScreenInfoChanged), () =>
- {
- Control.RenderSurface.DeviceScaleFactor = deviceScaleFactor;
- Popup.RenderSurface.DeviceScaleFactor = deviceScaleFactor;
- BrowserHost?.WasResized();
- // Might cause a crash due to a SurfaceSync check in chromium code.
- //
- // Fixed in chromium versions >= 79.0.3909.0 (https://chromium-review.googlesource.com/c/chromium/src/+/1792459)
- //
- //_browserHost?.NotifyScreenInfoChanged();
- });
- }
- protected override void HandleControlSizeChanged(CefSize size)
- {
- if (IsBrowserCreated)
- {
- ResizeBrowser(size.Width, size.Height);
- }
- else
- {
- CreateBrowser(size.Width, size.Height);
- }
- }
- private void AttachEventHandlers(IOffScreenControlHost control)
- {
- control.LostFocus += HandleLostFocus;
- control.MouseMoved += HandleMouseMove;
- control.MouseLeave += HandleMouseLeave;
- control.MouseButtonPressed += HandleMouseButtonDown;
- control.MouseButtonReleased += HandleMouseButtonUp;
- control.MouseWheelChanged += HandleMouseWheel;
- control.KeyDown += HandleKeyPress;
- control.KeyUp += HandleKeyPress;
- control.TextInput += HandleTextInput;
- control.DragEnter += HandleDragEnter;
- control.DragOver += HandleDragOver;
- control.DragLeave += HandleDragLeave;
- control.Drop += HandleDrop;
- }
- protected override CommonCefClient CreateCefClient()
- {
- return new CommonCefClient(this, new CommonCefRenderHandler(this, _logger), _logger);
- }
- protected override void SetupBrowserView(CefWindowInfo windowInfo, int width, int height, IntPtr hostViewHandle)
- {
- AttachEventHandlers(Control);
- AttachEventHandlers(Popup);
- Control.ScreenInfoChanged += HandleScreenInfoChanged;
- Control.VisibilityChanged += HandleVisibilityChanged;
- Control.RenderSurface.Resize(width, height);
- // Find the window that's hosting us
- windowInfo.SetAsWindowless(hostViewHandle, Control.RenderSurface.AllowsTransparency);
- }
- protected override void OnBrowserHostCreated(CefBrowserHost browserHost)
- {
- if (Width > 0 && Height > 0)
- {
- browserHost.WasResized();
- }
- }
- protected void ResizeBrowser(int newWidth, int newHeight)
- {
- if (Width == newWidth && Height == newHeight)
- {
- return;
- }
- Control.RenderSurface.Resize(newWidth, newHeight);
- BrowserHost?.WasResized();
-
- _logger.Debug($"Browser resized {newWidth}x{newHeight}");
- }
- protected override bool OnBrowserClose(CefBrowser browser)
- {
- Cleanup(browser);
- // According to cef documentation:
- // If no OS window exists (window rendering disabled) returning false will cause the browser object to be destroyed immediately
- return false;
- }
- #region IOffscreenCefBrowserHost
- void IOffscreenCefBrowserHost.GetViewRect(out CefRectangle rect)
- {
- rect = GetViewRect();
- }
- private CefRectangle GetViewRect()
- {
- var result = _getViewRectOverride?.Invoke() ?? new CefRectangle(0, 0, Width, Height);
- // The simulated screen and view rectangle are the same. This is necessary
- // for popup menus to be located and sized inside the view.
- if (result.Width <= 0 || result.Height <= 0)
- {
- // NOTE: width and height must be > 0, otherwise cef will blow up
- return new CefRectangle(0, 0, Math.Max(1, result.Width), Math.Max(1, result.Height));
- }
- return result;
- }
- void IOffscreenCefBrowserHost.GetScreenPoint(int viewX, int viewY, ref int screenX, ref int screenY)
- {
- GetScreenPoint(viewX, viewY, ref screenX, ref screenY);
- }
- private void GetScreenPoint(int viewX, int viewY, ref int screenX, ref int screenY)
- {
- // TODO
- //var point = new Point(0, 0);
- //WithErrorHandling(nameof(GetScreenPoint), () =>
- //{
- // point = _control.PointToScreen(new Point(viewX, viewY), _controlRenderHandler.DeviceScaleFactor);
- //});
- //screenX = point.X;
- //screenY = point.Y;
- }
- void IOffscreenCefBrowserHost.GetScreenInfo(CefScreenInfo screenInfo)
- {
- screenInfo.DeviceScaleFactor = Control.RenderSurface.DeviceScaleFactor;
- }
- void IOffscreenCefBrowserHost.HandlePopupShow(bool show)
- {
- WithErrorHandling(nameof(IOffscreenCefBrowserHost.HandlePopupShow), () =>
- {
- if (show)
- {
- Popup.Open();
- }
- else
- {
- Popup.Close();
- }
- });
- }
- void IOffscreenCefBrowserHost.HandlePopupSizeChange(CefRectangle rect)
- {
- WithErrorHandling(nameof(IOffscreenCefBrowserHost.HandlePopupSizeChange), () =>
- {
- Popup.RenderSurface.Resize(rect.Width, rect.Height);
- Popup.MoveAndResize(rect.X, rect.Y, rect.Width, rect.Height);
- });
- }
- void IOffscreenCefBrowserHost.HandleCursorChange(IntPtr cursorHandle)
- {
- WithErrorHandling((nameof(IOffscreenCefBrowserHost.HandleCursorChange)), () =>
- {
- Control.SetCursor(cursorHandle);
- });
- }
- void IOffscreenCefBrowserHost.HandleViewPaint(IntPtr buffer, int width, int height, CefRectangle[] dirtyRects, bool isPopup)
- {
- if (_getViewRectOverride != null)
- {
- return;
- }
- OffScreenRenderSurface renderHandler;
- if (isPopup)
- {
- renderHandler = Popup.RenderSurface;
- }
- else
- {
- renderHandler = Control.RenderSurface;
- }
- const string ScopeName = nameof(IOffscreenCefBrowserHost.HandleViewPaint);
- WithErrorHandling(ScopeName, () =>
- {
- renderHandler?.Render(buffer, width, height, dirtyRects)
- .ContinueWith(t => HandleException(ScopeName, t.Exception), TaskContinuationOptions.OnlyOnFaulted);
- });
- }
- void IOffscreenCefBrowserHost.HandleStartDragging(CefBrowser browser, CefDragData dragData, CefDragOperationsMask allowedOps, int x, int y)
- {
- WithErrorHandling(nameof(IOffscreenCefBrowserHost.HandleStartDragging), async () =>
- {
- var result = await Control.StartDrag(dragData, allowedOps, x, y);
- BrowserHost.DragSourceEndedAt(x, y, result);
- BrowserHost.DragSourceSystemDragEnded();
- });
- }
- void IOffscreenCefBrowserHost.HandleUpdateDragCursor(CefBrowser browser, CefDragOperationsMask operation)
- {
- Control.UpdateDragCursor(operation);
- }
- #endregion
- }
- }
|