// Copyright 2022 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef ASH_CAPTURE_MODE_CAPTURE_MODE_CAMERA_PREVIEW_VIEW_H_ #define ASH_CAPTURE_MODE_CAPTURE_MODE_CAMERA_PREVIEW_VIEW_H_ #include "ash/accessibility/accessibility_controller_impl.h" #include "ash/accessibility/accessibility_observer.h" #include "ash/capture_mode/camera_video_frame_renderer.h" #include "ash/capture_mode/capture_mode_button.h" #include "ash/capture_mode/capture_mode_camera_controller.h" #include "ash/capture_mode/capture_mode_session_focus_cycler.h" #include "base/memory/weak_ptr.h" #include "base/scoped_observation.h" #include "mojo/public/cpp/bindings/remote.h" #include "ui/base/metadata/metadata_header_macros.h" #include "ui/gfx/geometry/size.h" #include "ui/views/view.h" namespace media { struct VideoCaptureFormat; } // namespace media namespace video_capture::mojom { class VideoSource; } // namespace video_capture::mojom namespace views { class NativeViewHost; } // namespace views namespace ash { class CaptureModeCameraController; class ScopedA11yOverrideWindowSetter; // Resize button inside the camera preview view. class CameraPreviewResizeButton : public CaptureModeButton { public: METADATA_HEADER(CameraPreviewResizeButton); CameraPreviewResizeButton(CameraPreviewView* camera_preview_view, views::Button::PressedCallback callback, const gfx::VectorIcon& icon); CameraPreviewResizeButton(const CameraPreviewResizeButton&) = delete; CameraPreviewResizeButton& operator=(const CameraPreviewResizeButton&) = delete; ~CameraPreviewResizeButton() override; // CaptureModeSessionFocusCycler::HighlightableView: void PseudoFocus() override; void PseudoBlur() override; private: CameraPreviewView* const camera_preview_view_; // not owned. }; // A view that acts as the contents view of the camera preview widget. It will // be responsible for painting the latest camera video frame inside its bounds. class CameraPreviewView : public views::View, public CaptureModeSessionFocusCycler::HighlightableView, public AccessibilityObserver { public: METADATA_HEADER(CameraPreviewView); CameraPreviewView( CaptureModeCameraController* camera_controller, const CameraId& camera_id, mojo::Remote camera_video_source, const media::VideoCaptureFormat& capture_format, bool should_flip_frames_horizontally); CameraPreviewView(const CameraPreviewView&) = delete; CameraPreviewView& operator=(const CameraPreviewView&) = delete; ~CameraPreviewView() override; const CameraId& camera_id() const { return camera_id_; } CameraPreviewResizeButton* resize_button() const { return resize_button_; } bool is_collapsible() const { return is_collapsible_; } bool should_flip_frames_horizontally() const { return camera_video_renderer_.should_flip_frames_horizontally(); } // Sets this camera preview collapsability to the given `value`, which will // update the resize button visibility. void SetIsCollapsible(bool value); // Returns true if the `event` has been handled by CameraPrevieView. It // happens if it is control+arrow keys, which will be used to move the camera // preview to different snap positions. bool MaybeHandleKeyEvent(const ui::KeyEvent* event); // Called to update visibility of the `resize_button_` when necessary. void RefreshResizeButtonVisibility(); // Updates the a11y override window when focus state changes on the camera // preview. The a11y override window will be set to nullptr if neither the // camera preview nor the resize button has focus. This is done to make sure // a11y focus can be moved to others appropriately. void UpdateA11yOverrideWindow(); // Removes the focus from camera preview when necessary. Happens if mouse // pressing outside of the camera preview when it has focus. A11y override // window will be updated as well. void MaybeBlurFocus(const ui::MouseEvent& event); // views::View: void AddedToWidget() override; bool OnMousePressed(const ui::MouseEvent& event) override; bool OnMouseDragged(const ui::MouseEvent& event) override; void OnMouseReleased(const ui::MouseEvent& event) override; void OnGestureEvent(ui::GestureEvent* event) override; void OnMouseEntered(const ui::MouseEvent& event) override; void OnMouseExited(const ui::MouseEvent& event) override; void Layout() override; void GetAccessibleNodeData(ui::AXNodeData* node_data) override; // CaptureModeSessionFocusCycler::HighlightableView: views::View* GetView() override; std::unique_ptr CreatePathGenerator() override; // AccessibilityObserver: void OnAccessibilityStatusChanged() override; void OnAccessibilityControllerShutdown() override; base::OneShotTimer* resize_button_hide_timer_for_test() { return &resize_button_hide_timer_; } private: friend class CameraPreviewResizeButton; friend class CaptureModeTestApi; // Called when the resize button is clicked or touched. void OnResizeButtonPressed(); // Updates the icon of the `resize_button_` based on value of // `is_camera_preview_collapsed()` inferred from the `camera_controller`. void UpdateResizeButton(); // Updates the tooltip of the `resize_button_`. The `resize_button_` can be an // expand button or collapse button. void UpdateResizeButtonTooltip(); // Located events within the bounds of this view should be sent to, and // handled by this view only (e.g. for drag and drop). They should not be sent // to any native window hosting the camera video frames, otherwise we will // lose those events. This function disable event targeting for the // `camera_video_host_view_` and all the native windows it is hosting. void DisableEventHandlingInCameraVideoHostHierarchy(); // Fades in or out the `resize_button_` and updates its visibility // accordingly. void FadeInResizeButton(); void FadeOutResizeButton(); // Called when the mouse exits the camera preview, after the latest tap inside // the camera preview or when focus being removed from the resize button to // start the `resize_button_hide_timer_`. void ScheduleRefreshResizeButtonVisibility(); // Returns the target opacity for resize button. float CalculateResizeButtonTargetOpacity(); // Removes the focus from the camera preview and updates the a11y override // window. void BlurA11yFocus(); CaptureModeCameraController* const camera_controller_; // The ID of the camera for which this preview was created. const CameraId camera_id_; // Renders the camera video frames into its `host_window()`. CameraVideoFrameRenderer camera_video_renderer_; // The view that hosts the native window `host_window()` of the // `camera_video_renderer_` into this view's hierarchy. views::NativeViewHost* const camera_video_host_view_; CameraPreviewResizeButton* const resize_button_; // Started when the mouse exits the camera preview or after the latest tap // inside the camera preview. Runs RefreshResizeButtonVisibility() to fade out // the resize button if possible. base::OneShotTimer resize_button_hide_timer_; // True if the size of the preview in the expanded state is big enough to // allow it to be collapsible. bool is_collapsible_ = true; // True only while handling a gesture tap event on this view. bool has_been_tapped_ = false; base::ScopedObservation accessibility_observation_{this}; // Helps to update the current a11y override window. It will be the native // window of the camera preview or nullptr, depends on whether the camera // preview has focus or not. Accessibility features will focus on the window // after it is set. Once `this` goes out of scope, the a11y override window is // set to nullptr. std::unique_ptr scoped_a11y_overrider_; base::WeakPtrFactory weak_ptr_factory_{this}; }; } // namespace ash #endif // ASH_CAPTURE_MODE_CAPTURE_MODE_CAMERA_PREVIEW_VIEW_H_