| // Copyright 2026 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_GLIC_SELECTION_SELECTION_OVERLAY_CONTROLLER_H_ |
| #define CHROME_BROWSER_GLIC_SELECTION_SELECTION_OVERLAY_CONTROLLER_H_ |
| |
| #include <string> |
| |
| #include "base/containers/flat_map.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/unguessable_token.h" |
| #include "chrome/browser/glic/host/context/glic_page_context_fetcher.h" |
| #include "chrome/browser/glic/host/glic.mojom-forward.h" |
| #include "chrome/browser/glic/selection/selection_overlay.mojom.h" |
| #include "chrome/browser/ui/lens/overlay_base_controller.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model_observer.h" |
| #include "components/page_content_annotations/content/page_context_fetcher.h" |
| #include "mojo/public/cpp/bindings/pending_receiver.h" |
| #include "mojo/public/cpp/bindings/pending_remote.h" |
| #include "mojo/public/cpp/bindings/receiver.h" |
| #include "mojo/public/cpp/bindings/remote.h" |
| #include "ui/base/unowned_user_data/scoped_unowned_user_data.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h" |
| |
| namespace content { |
| class WebContents; |
| } |
| |
| namespace input { |
| struct NativeWebKeyboardEvent; |
| } |
| |
| namespace views { |
| class WebView; |
| } |
| |
| namespace glic { |
| |
| class FocusedTabData; |
| class GlicSharingManagerInternal; |
| |
| class SelectionOverlayController |
| : public OverlayBaseController, |
| public selection::SelectionOverlayPageHandler, |
| public TabStripModelObserver { |
| public: |
| SelectionOverlayController(tabs::TabInterface* tab, |
| PrefService* pref_service); |
| ~SelectionOverlayController() override; |
| |
| DECLARE_USER_DATA(SelectionOverlayController); |
| |
| // A simple utility that gets the SelectionOverlayController TabFeature |
| // set by the embedding tab of a overlay WebUI hosted in |
| // `overlay_web_contents`. May return nullptr if no SelectionOverlayController |
| // TabFeature is associated with `overlay_web_contents`. |
| static SelectionOverlayController* FromOverlayWebContents( |
| content::WebContents* overlay_web_contents); |
| |
| // A simple utility that gets the SelectionOverlayController TabFeature |
| // set by the instances of WebContents associated with a tab. May return |
| // nullptr if no SelectionOverlayController TabFeature is associated with |
| // `tab_web_contents`. |
| static SelectionOverlayController* FromTabWebContents( |
| content::WebContents* tab_web_contents); |
| |
| size_t GetSelectedRegionCount() const { return selected_regions_.size(); } |
| std::vector<int> GetPolylineCounts() const; |
| |
| // This method is used to set up communication between this instance and the |
| // overlay WebUI. This is called by the WebUIController when the WebUI is |
| // executing javascript and ready to bind. |
| void BindOverlay( |
| mojo::PendingReceiver<selection::SelectionOverlayPageHandler> receiver, |
| mojo::PendingRemote<selection::SelectionOverlayPage> page); |
| |
| // Bind the legacy IPC endpoint. See the comment on |
| // `capture_region_observer_`. |
| void BindCaptureRegionObserver( |
| mojo::PendingRemote<mojom::CaptureRegionObserver> observer); |
| static void CaptureRegion( |
| tabs::TabInterface* tab, |
| GlicSharingManagerInternal& sharing_manager, |
| mojo::PendingRemote<mojom::CaptureRegionObserver> observer, |
| mojom::TabContextOptionsPtr options); |
| |
| void Show(mojom::TabContextOptionsPtr options); |
| // Shows the overlay with a region pre-selected around `selection_bounds`, |
| // which is in screen coordinates. |
| void ShowWithSelection(const gfx::Rect& selection_bounds); |
| void Close(); |
| |
| // `selection::SelectionOverlayPageHandler`: |
| void DeleteRegion(const base::UnguessableToken& id, |
| bool is_using_keyboard) override; |
| |
| private: |
| void WillDiscardContents(tabs::TabInterface* tab, |
| content::WebContents* old_contents, |
| content::WebContents* new_contents); |
| void WillDetach(tabs::TabInterface* tab, |
| tabs::TabInterface::DetachReason reason); |
| void TabDeactivated(tabs::TabInterface* tab); |
| void OnFocusedTabChanged(const FocusedTabData& tab_data); |
| // Called when the overlay's WebView takes focus, e.g. when the user clicks |
| // on it. In a split view the overlay can be rendered over the inactive tab, |
| // in which case `tab_` needs to be activated. |
| void OnOverlayWebViewFocused(views::WebView* web_view); |
| |
| void InitializeOverlay(); |
| |
| // `content::WebContentsDelegate`: |
| bool HandleKeyboardEvent(content::WebContents* source, |
| const input::NativeWebKeyboardEvent& event) override; |
| |
| // `TabStripModelObserver`: |
| void OnSplitTabChanged(const SplitTabChange& change) override; |
| |
| // OverlayBaseController overrides: |
| void CloseUI() override; |
| void RequestSyncClose(DismissalSource dismissal_source) override; |
| void StartScreenshotFlow() override; |
| void NotifyOverlayClosing() override; |
| bool IsResultsSidePanelShowing() override; |
| GURL GetInitialURL() override; |
| void NotifyIsOverlayShowing(bool is_showing) override {} |
| int GetToolResourceId() override; |
| ui::ElementIdentifier GetViewContainerId() const override; |
| SidePanelType GetSidePanelType() override; |
| bool ShouldCloseSidePanel() override; |
| bool ShouldShowPreselectionBubble() override; |
| bool UseOverlayBlur() override; |
| void NotifyPageNavigated() override; |
| void NotifyTabForegrounded() override; |
| void NotifyTabWillEnterBackground() override; |
| PreselectionUIConfig GetPreselectionBubbleConfig() override; |
| bool IsOverlayViewShared() const override; |
| void ShowPreselectionBubble() override; |
| void TabForegrounded(tabs::TabInterface* tab) override; |
| |
| // `selection::SelectionOverlayPageHandler`: |
| void DismissOverlay(selection::DismissOverlayReason reason) override; |
| void AdjustRegion(selection::SelectedRegionPtr target, |
| bool is_using_keyboard) override; |
| void ClosePreselectionBubble() override; |
| void AddBackgroundBlur() override; |
| void SetLiveBlur(bool enabled) override; |
| void SubmitPrompt(const std::string& prompt) override; |
| void GetSuggestedActions( |
| mojo::PendingRemote<selection::SuggestedActionsListener> listener) |
| override; |
| void ExecuteSuggestedAction(const base::UnguessableToken& action_id) override; |
| |
| private: |
| void OnScreenshotTaken(const SkBitmap& bitmap); |
| void OnScreenshotRedacted(const SkBitmap& bitmap); |
| void PageContextReady( |
| base::expected<glic::mojom::GetContextResultPtr, |
| page_content_annotations::FetchPageContextErrorDetails> |
| fetch_result); |
| |
| void SetScreenshot(const SkBitmap& screenshot, SkBitmap rgb_screenshot); |
| |
| // Render all the `selected_regions_` on top of `redacted_screenshot_`. |
| void RenderRegions(bool should_focus_panel); |
| |
| void Reset(); |
| std::vector<selection::SuggestedActionPtr> GetDefaultSuggestedActions(); |
| glic::mojom::AdditionalContextPtr CreateAdditionalContext( |
| std::vector<std::pair<base::UnguessableToken, |
| glic::mojom::CapturedRegionPtr>> regions); |
| |
| // Connections to and from the overlay WebUI. Only valid while |
| // `OverlayBaseController::overlay_view_` is showing and the underlying |
| // renderer is alive. |
| mojo::Receiver<selection::SelectionOverlayPageHandler> receiver_{this}; |
| mojo::Remote<selection::SelectionOverlayPage> page_; |
| |
| // Legacy IPC that's used to signal the WebUI any browser side errors, and |
| // used to dismiss the overlay from the WebUI. |
| // TODO(b/452032491): Remove this once the old codepath is no longer used. |
| mojo::Remote<mojom::CaptureRegionObserver> capture_region_observer_; |
| |
| // Stateful members. They should be added to Reset(). |
| bool screenshot_available_ = false; |
| SkBitmap initial_rgb_screenshot_; |
| SkBitmap redacted_screenshot_; |
| mojom::TabContextResultPtr tab_context_; |
| mojom::TabContextOptionsPtr options_; |
| // Caches the user-selected region. To be renderer on top of |
| // `initial_screenshot_`. |
| base::flat_map<base::UnguessableToken, selection::SelectedRegionPtr> |
| selected_regions_; |
| // Maps suggested action IDs to prompt strings. |
| base::flat_map<base::UnguessableToken, std::string> suggested_actions_; |
| mojo::Remote<selection::SuggestedActionsListener> suggested_actions_listener_; |
| // Subscription for `OverlayBaseController::overlay_web_view_` taking focus. |
| // Scoped to the lifetime of that WebView. |
| base::CallbackListSubscription overlay_web_view_focus_subscription_; |
| |
| ui::ScopedUnownedUserData<SelectionOverlayController> |
| scoped_unowned_user_data_; |
| |
| // Holds subscriptions for TabInterface callbacks. |
| std::vector<base::CallbackListSubscription> tab_subscriptions_; |
| |
| views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_; |
| |
| // Must be the last member. |
| base::WeakPtrFactory<SelectionOverlayController> weak_factory_{this}; |
| }; |
| |
| } // namespace glic |
| |
| #endif // CHROME_BROWSER_GLIC_SELECTION_SELECTION_OVERLAY_CONTROLLER_H_ |