mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			309 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			309 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2016 The Chromium Embedded Framework Authors. All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style license that can be found
 | |
| // in the LICENSE file.
 | |
| 
 | |
| #include "libcef/browser/views/view_util.h"
 | |
| 
 | |
| #include <utility>
 | |
| 
 | |
| #include "libcef/browser/views/view_adapter.h"
 | |
| 
 | |
| #include "ui/display/display.h"
 | |
| #include "ui/display/screen.h"
 | |
| #include "ui/gfx/geometry/point.h"
 | |
| #include "ui/gfx/geometry/point_conversions.h"
 | |
| #include "ui/views/widget/widget.h"
 | |
| #include "ui/views/widget/widget_delegate.h"
 | |
| #include "ui/views/window/non_client_view.h"
 | |
| 
 | |
| #if BUILDFLAG(IS_WIN)
 | |
| #include "ui/display/win/screen_win.h"
 | |
| #endif
 | |
| 
 | |
| #if defined(USE_AURA)
 | |
| #include "ui/aura/window.h"
 | |
| #include "ui/views/view_constants_aura.h"
 | |
| #endif
 | |
| 
 | |
| namespace view_util {
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| // Manages the association between views::View and CefView instances.
 | |
| class UserData : public base::SupportsUserData::Data {
 | |
|  public:
 | |
|   // Create the initial association between the views::View and the CefView. The
 | |
|   // CefView owns the views::View at this stage.
 | |
|   static void Register(CefRefPtr<CefView> cef_view) {
 | |
|     DCHECK(cef_view->IsValid());
 | |
|     DCHECK(!cef_view->IsAttached());
 | |
| 
 | |
|     views::View* view = CefViewAdapter::GetFor(cef_view)->Get();
 | |
|     DCHECK(view);
 | |
| 
 | |
|     // The CefView should not already be registered.
 | |
|     DCHECK(!view->GetUserData(UserDataKey()));
 | |
| 
 | |
|     view->SetUserData(UserDataKey(), base::WrapUnique(new UserData(cef_view)));
 | |
|   }
 | |
| 
 | |
|   static CefRefPtr<CefView> GetFor(const views::View* view) {
 | |
|     DCHECK(view);
 | |
|     UserData* data = static_cast<UserData*>(view->GetUserData(UserDataKey()));
 | |
|     if (data)
 | |
|       return data->view_ref_;
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   // Transfer ownership of the views::View to the caller. The views::View will
 | |
|   // gain a ref-counted reference to the CefView and the CefView will keep an
 | |
|   // unowned reference to the views::View. Destruction of the views::View will
 | |
|   // release the ref-counted reference to the CefView.
 | |
|   [[nodiscard]] static std::unique_ptr<views::View> PassOwnership(
 | |
|       CefRefPtr<CefView> cef_view) {
 | |
|     DCHECK(cef_view->IsValid());
 | |
|     DCHECK(!cef_view->IsAttached());
 | |
| 
 | |
|     std::unique_ptr<views::View> view =
 | |
|         CefViewAdapter::GetFor(cef_view)->PassOwnership();
 | |
|     DCHECK(view);
 | |
| 
 | |
|     UserData* data = static_cast<UserData*>(view->GetUserData(UserDataKey()));
 | |
|     DCHECK(data);
 | |
|     data->TakeReference();
 | |
| 
 | |
|     return view;
 | |
|   }
 | |
| 
 | |
|   // The CefView resumes ownership of the views::View. The views::View no longer
 | |
|   // keeps a ref-counted reference to the CefView.
 | |
|   static void ResumeOwnership(CefRefPtr<CefView> cef_view) {
 | |
|     DCHECK(cef_view->IsValid());
 | |
|     DCHECK(cef_view->IsAttached());
 | |
| 
 | |
|     CefViewAdapter* adapter = CefViewAdapter::GetFor(cef_view);
 | |
|     adapter->ResumeOwnership();
 | |
| 
 | |
|     views::View* view = adapter->Get();
 | |
|     DCHECK(view);
 | |
| 
 | |
|     UserData* data = static_cast<UserData*>(view->GetUserData(UserDataKey()));
 | |
|     DCHECK(data);
 | |
|     data->ReleaseReference();
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   friend std::default_delete<UserData>;
 | |
| 
 | |
|   explicit UserData(CefRefPtr<CefView> cef_view) : view_ref_(cef_view.get()) {
 | |
|     DCHECK(view_ref_);
 | |
|   }
 | |
| 
 | |
|   ~UserData() override {
 | |
|     if (view_) {
 | |
|       // The CefView does not own the views::View. Remove the CefView's
 | |
|       // reference to the views::View.
 | |
|       CefViewAdapter::GetFor(view_)->Detach();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   void TakeReference() { view_ = view_ref_; }
 | |
| 
 | |
|   void ReleaseReference() { view_ = nullptr; }
 | |
| 
 | |
|   static void* UserDataKey() {
 | |
|     // We just need a unique constant. Use the address of a static that
 | |
|     // COMDAT folding won't touch in an optimizing linker.
 | |
|     static int data_key = 0;
 | |
|     return reinterpret_cast<void*>(&data_key);
 | |
|   }
 | |
| 
 | |
|   CefRefPtr<CefView> view_;
 | |
|   CefView* view_ref_;
 | |
| };
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| const SkColor kDefaultBackgroundColor = SkColorSetARGB(255, 255, 255, 255);
 | |
| const char kDefaultFontList[] = "Arial, Helvetica, 14px";
 | |
| 
 | |
| void Register(CefRefPtr<CefView> view) {
 | |
|   UserData::Register(view);
 | |
| }
 | |
| 
 | |
| CefRefPtr<CefView> GetFor(const views::View* view, bool find_known_parent) {
 | |
|   if (!view)
 | |
|     return nullptr;
 | |
| 
 | |
|   if (!find_known_parent)
 | |
|     return UserData::GetFor(view);
 | |
| 
 | |
|   CefRefPtr<CefView> cef_view;
 | |
|   const views::View* current_view = view;
 | |
|   do {
 | |
|     cef_view = UserData::GetFor(current_view);
 | |
|     if (cef_view)
 | |
|       break;
 | |
|     current_view = current_view->parent();
 | |
|   } while (current_view);
 | |
| 
 | |
|   return cef_view;
 | |
| }
 | |
| 
 | |
| views::View* GetFor(CefRefPtr<CefView> view) {
 | |
|   return CefViewAdapter::GetFor(view)->Get();
 | |
| }
 | |
| 
 | |
| std::unique_ptr<views::View> PassOwnership(CefRefPtr<CefView> view) {
 | |
|   return UserData::PassOwnership(view);
 | |
| }
 | |
| 
 | |
| void ResumeOwnership(CefRefPtr<CefView> view) {
 | |
|   UserData::ResumeOwnership(view);
 | |
| }
 | |
| 
 | |
| CefRefPtr<CefWindow> GetWindowFor(views::Widget* widget) {
 | |
|   CefRefPtr<CefWindow> window;
 | |
| 
 | |
| #if defined(USE_AURA)
 | |
|   // Retrieve the parent Widget for an overlay.
 | |
|   if (widget) {
 | |
|     // See matching logic in CefOverlayViewHost::Init.
 | |
|     auto widget_view =
 | |
|         widget->GetNativeView()->GetProperty(views::kHostViewKey);
 | |
|     if (widget_view) {
 | |
|       widget = widget_view->GetWidget();
 | |
|     }
 | |
|   }
 | |
| #endif  // defined(USE_AURA)
 | |
| 
 | |
|   if (widget) {
 | |
|     // The views::WidgetDelegate should be a CefWindowView and |content_view|
 | |
|     // should be the same CefWindowView. However, just in case the views::Widget
 | |
|     // was created by something else let's go about this the safer way.
 | |
|     views::View* content_view = widget->widget_delegate()->GetContentsView();
 | |
|     CefRefPtr<CefView> cef_view = GetFor(content_view, false);
 | |
|     if (cef_view && cef_view->AsPanel())
 | |
|       window = cef_view->AsPanel()->AsWindow();
 | |
| 
 | |
|     // The Window should always exist if we created the views::Widget.
 | |
|     DCHECK(window);
 | |
|   }
 | |
| 
 | |
|   return window;
 | |
| }
 | |
| 
 | |
| display::Display GetDisplayNearestPoint(const gfx::Point& point,
 | |
|                                         bool input_pixel_coords) {
 | |
|   gfx::Point find_point = point;
 | |
| #if BUILDFLAG(IS_WIN)
 | |
|   if (input_pixel_coords) {
 | |
|     find_point = gfx::ToFlooredPoint(
 | |
|         display::win::ScreenWin::ScreenToDIPPoint(gfx::PointF(point)));
 | |
|   }
 | |
| #endif
 | |
|   return display::Screen::GetScreen()->GetDisplayNearestPoint(find_point);
 | |
| }
 | |
| 
 | |
| display::Display GetDisplayMatchingBounds(const gfx::Rect& bounds,
 | |
|                                           bool input_pixel_coords) {
 | |
|   gfx::Rect find_bounds = bounds;
 | |
| #if BUILDFLAG(IS_WIN)
 | |
|   if (input_pixel_coords) {
 | |
|     find_bounds =
 | |
|         display::win::ScreenWin::ScreenToDIPRect(nullptr, find_bounds);
 | |
|   }
 | |
| #endif
 | |
|   return display::Screen::GetScreen()->GetDisplayMatching(find_bounds);
 | |
| }
 | |
| 
 | |
| void ConvertPointFromPixels(gfx::Point* point, float device_scale_factor) {
 | |
|   *point = gfx::ToFlooredPoint(
 | |
|       gfx::ScalePoint(gfx::PointF(*point), 1.0f / device_scale_factor));
 | |
| }
 | |
| 
 | |
| void ConvertPointToPixels(gfx::Point* point, float device_scale_factor) {
 | |
|   *point = gfx::ToFlooredPoint(
 | |
|       gfx::ScalePoint(gfx::PointF(*point), device_scale_factor));
 | |
| }
 | |
| 
 | |
| bool ConvertPointToScreen(views::View* view,
 | |
|                           gfx::Point* point,
 | |
|                           bool output_pixel_coords) {
 | |
|   if (!view->GetWidget())
 | |
|     return false;
 | |
| 
 | |
|   views::View::ConvertPointToScreen(view, point);
 | |
| 
 | |
|   if (output_pixel_coords) {
 | |
|     const display::Display& display = GetDisplayNearestPoint(*point, false);
 | |
|     ConvertPointToPixels(point, display.device_scale_factor());
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool ConvertPointFromScreen(views::View* view,
 | |
|                             gfx::Point* point,
 | |
|                             bool input_pixel_coords) {
 | |
|   if (!view->GetWidget())
 | |
|     return false;
 | |
| 
 | |
|   if (input_pixel_coords) {
 | |
|     const display::Display& display = GetDisplayNearestPoint(*point, true);
 | |
|     ConvertPointFromPixels(point, display.device_scale_factor());
 | |
|   }
 | |
| 
 | |
|   views::View::ConvertPointFromScreen(view, point);
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool ConvertPointToWindow(views::View* view, gfx::Point* point) {
 | |
|   views::Widget* widget = view->GetWidget();
 | |
|   if (!widget)
 | |
|     return false;
 | |
| 
 | |
|   views::View::ConvertPointToWidget(view, point);
 | |
| 
 | |
|   if (widget->non_client_view()) {
 | |
|     views::NonClientFrameView* non_client_frame_view =
 | |
|         widget->non_client_view()->frame_view();
 | |
|     if (non_client_frame_view) {
 | |
|       // When using a custom drawn NonClientFrameView the native Window will not
 | |
|       // know the actual client bounds. Adjust the native Window bounds for the
 | |
|       // reported client bounds.
 | |
|       const gfx::Rect& client_bounds =
 | |
|           non_client_frame_view->GetBoundsForClientView();
 | |
|       *point -= client_bounds.OffsetFromOrigin();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool ConvertPointFromWindow(views::View* view, gfx::Point* point) {
 | |
|   views::Widget* widget = view->GetWidget();
 | |
|   if (!widget)
 | |
|     return false;
 | |
| 
 | |
|   if (widget->non_client_view()) {
 | |
|     views::NonClientFrameView* non_client_frame_view =
 | |
|         widget->non_client_view()->frame_view();
 | |
|     if (non_client_frame_view) {
 | |
|       // When using a custom drawn NonClientFrameView the native Window will not
 | |
|       // know the actual client bounds. Adjust the native Window bounds for the
 | |
|       // reported client bounds.
 | |
|       const gfx::Rect& client_bounds =
 | |
|           non_client_frame_view->GetBoundsForClientView();
 | |
|       *point += client_bounds.OffsetFromOrigin();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   views::View::ConvertPointFromWidget(view, point);
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| }  // namespace view_util
 |