#ifndef EXTENSIONS_BROWSER_APP_WINDOW_APP_WINDOW_H_
#define EXTENSIONS_BROWSER_APP_WINDOW_APP_WINDOW_H_
#include <stdint.h>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "components/sessions/core/session_id.h"
#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "extensions/browser/app_window/native_app_window.h"
#include "extensions/browser/extension_function_dispatcher.h"
#include "extensions/browser/extension_registry_observer.h"
#include "extensions/common/extension_id.h"
#include "extensions/common/mojom/frame.mojom-forward.h"
#include "third_party/blink/public/mojom/page/draggable_region.mojom-forward.h"
#include "ui/base/mojom/window_show_state.mojom-forward.h"
#include "ui/gfx/image/image.h"
class GURL;
class SkRegion;
namespace base {
class Value;
}
namespace gfx {
class Rect;
class RoundedCornersF;
}
namespace content {
class BrowserContext;
class RenderFrameHost;
class WebContents;
}
namespace extensions {
class AppDelegate;
class AppWebContentsHelper;
class Extension;
class PlatformAppBrowserTest;
class AppWindowContents {
public:
AppWindowContents() {}
AppWindowContents(const AppWindowContents&) = delete;
AppWindowContents& operator=(const AppWindowContents&) = delete;
virtual ~AppWindowContents() {}
virtual void Initialize(content::BrowserContext* context,
content::RenderFrameHost* creator_frame,
const GURL& url) = 0;
virtual void LoadContents(int32_t creator_process_id) = 0;
virtual void NativeWindowChanged(NativeAppWindow* native_app_window) = 0;
virtual void NativeWindowClosed(bool send_onclosed) = 0;
virtual content::WebContents* GetWebContents() const = 0;
virtual extensions::WindowController* GetWindowController() const = 0;
};
class AppWindow : public content::WebContentsDelegate,
public content::WebContentsObserver,
public web_modal::WebContentsModalDialogManagerDelegate,
public ExtensionFunctionDispatcher::Delegate,
public ExtensionRegistryObserver {
public:
enum WindowType {
WINDOW_TYPE_DEFAULT = 0,
DEPRECATED_WINDOW_TYPE_PANEL = 1,
WINDOW_TYPE_COUNT = 2,
};
enum Frame {
FRAME_CHROME,
FRAME_NONE,
};
enum FullscreenType {
FULLSCREEN_TYPE_NONE = 0,
FULLSCREEN_TYPE_WINDOW_API = 1 << 0,
FULLSCREEN_TYPE_HTML_API = 1 << 1,
FULLSCREEN_TYPE_OS = 1 << 2,
FULLSCREEN_TYPE_FORCED = 1 << 3,
};
using ShapeRects = std::vector<gfx::Rect>;
struct BoundsSpecification {
static const int kUnspecifiedPosition;
BoundsSpecification();
~BoundsSpecification();
gfx::Rect bounds;
gfx::Size minimum_size;
gfx::Size maximum_size;
void ResetBounds();
};
struct CreateParams {
CreateParams();
CreateParams(const CreateParams& other);
~CreateParams();
WindowType window_type;
Frame frame;
bool has_frame_color;
SkColor active_frame_color;
SkColor inactive_frame_color;
bool alpha_enabled;
bool is_ime_window;
BoundsSpecification content_spec;
BoundsSpecification window_spec;
std::string window_key;
int32_t creator_process_id;
ui::mojom::WindowShowState state;
bool hidden;
bool resizable;
bool focused;
bool always_on_top;
bool visible_on_all_workspaces;
bool show_in_shelf;
GURL window_icon_url;
gfx::Rect GetInitialWindowBounds(
const gfx::Insets& frame_insets,
const gfx::RoundedCornersF& window_radii) const;
gfx::Size GetContentMinimumSize(const gfx::Insets& frame_insets) const;
gfx::Size GetContentMaximumSize(const gfx::Insets& frame_insets) const;
gfx::Size GetWindowMinimumSize(
const gfx::Insets& frame_insets,
const gfx::RoundedCornersF& window_radii) const;
gfx::Size GetWindowMaximumSize(
const gfx::Insets& frame_insets,
const gfx::RoundedCornersF& window_radii) const;
};
static SkRegion* RawDraggableRegionsToSkRegion(
const std::vector<blink::mojom::DraggableRegionPtr>& regions);
AppWindow(content::BrowserContext* context,
std::unique_ptr<AppDelegate> app_delegate,
const Extension* extension);
AppWindow(const AppWindow&) = delete;
AppWindow& operator=(const AppWindow&) = delete;
void Init(const GURL& url,
std::unique_ptr<AppWindowContents> app_window_contents,
content::RenderFrameHost* creator_frame,
const CreateParams& params);
const std::string& window_key() const { return window_key_; }
SessionID session_id() const { return session_id_; }
const ExtensionId& extension_id() const { return extension_id_; }
content::WebContents* web_contents() const;
WindowType window_type() const { return window_type_; }
content::BrowserContext* browser_context() const { return browser_context_; }
const gfx::Image& custom_app_icon() const { return custom_app_icon_; }
const GURL& app_icon_url() const { return app_icon_url_; }
const GURL& initial_url() const { return initial_url_; }
bool is_hidden() const { return is_hidden_; }
const Extension* GetExtension() const;
NativeAppWindow* GetBaseWindow();
gfx::NativeWindow GetNativeWindow();
gfx::Rect GetClientBounds() const;
std::u16string GetTitle() const;
using DidFinishFirstNavigationCallback =
base::OnceCallback<void(bool did_finish)>;
void AddOnDidFinishFirstNavigationCallback(
DidFinishFirstNavigationCallback callback);
void OnDidFinishFirstNavigation();
void OnNativeClose();
void OnNativeWindowChanged();
void OnNativeWindowActivated();
void SetAppIconUrl(const GURL& icon_url);
void UpdateShape(std::unique_ptr<ShapeRects> rects);
void AppWindowReady();
void UpdateAppIcon(const gfx::Image& image);
void SetFullscreen(FullscreenType type, bool enable);
bool IsFullscreen() const;
bool IsForcedFullscreen() const;
bool IsHtmlApiFullscreen() const;
bool IsOsFullscreen() const;
void Fullscreen();
void Maximize();
void Minimize();
void Restore();
void OSFullscreen();
void ForcedFullscreen();
void SetContentSizeConstraints(const gfx::Size& min_size,
const gfx::Size& max_size);
enum ShowType { SHOW_ACTIVE, SHOW_INACTIVE };
void Show(ShowType show_type);
void Hide();
AppWindowContents* app_window_contents_for_test() {
return app_window_contents_.get();
}
int fullscreen_types_for_test() { return fullscreen_types_; }
void SetAlwaysOnTop(bool always_on_top);
bool IsAlwaysOnTop() const;
void RestoreAlwaysOnTop();
void GetSerializedState(base::Value::Dict* properties) const;
bool requested_alpha_enabled() const { return requested_alpha_enabled_; }
bool is_ime_window() const { return is_ime_window_; }
bool show_in_shelf() const { return show_in_shelf_; }
AppDelegate* app_delegate() { return app_delegate_.get(); }
void SetAppWindowContentsForTesting(
std::unique_ptr<AppWindowContents> contents) {
app_window_contents_ = std::move(contents);
}
void SetNativeAppWindowForTesting(
std::unique_ptr<NativeAppWindow> native_app_window) {
native_app_window_ = std::move(native_app_window);
}
void SetOnDraggableRegionsChangedForTesting(base::OnceClosure callback) {
on_update_draggable_regions_callback_for_testing_ = std::move(callback);
}
bool DidFinishFirstNavigation() { return did_finish_first_navigation_; }
protected:
~AppWindow() override;
private:
friend class PlatformAppBrowserTest;
void ActivateContents(content::WebContents* contents) override;
void CloseContents(content::WebContents* contents) override;
bool ShouldSuppressDialogs(content::WebContents* source) override;
void RunFileChooser(content::RenderFrameHost* render_frame_host,
scoped_refptr<content::FileSelectListener> listener,
const blink::mojom::FileChooserParams& params) override;
void SetContentsBounds(content::WebContents* source,
const gfx::Rect& bounds) override;
void NavigationStateChanged(content::WebContents* source,
content::InvalidateTypes changed_flags) override;
void EnterFullscreenModeForTab(
content::RenderFrameHost* requesting_frame,
const blink::mojom::FullscreenOptions& options) override;
void ExitFullscreenModeForTab(content::WebContents* source) override;
bool IsFullscreenForTabOrPending(const content::WebContents* source) override;
blink::mojom::DisplayMode GetDisplayMode(
const content::WebContents* source) override;
void RequestMediaAccessPermission(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
content::MediaResponseCallback callback) override;
bool CheckMediaAccessPermission(content::RenderFrameHost* render_frame_host,
const url::Origin& security_origin,
blink::mojom::MediaStreamType type) override;
content::WebContents* OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params,
base::OnceCallback<void(content::NavigationHandle&)>
navigation_handle_callback) override;
content::WebContents* AddNewContents(
content::WebContents* source,
std::unique_ptr<content::WebContents> new_contents,
const GURL& target_url,
WindowOpenDisposition disposition,
const blink::mojom::WindowFeatures& window_features,
bool user_gesture,
bool* was_blocked) override;
content::KeyboardEventProcessingResult PreHandleKeyboardEvent(
content::WebContents* source,
const input::NativeWebKeyboardEvent& event) override;
bool HandleKeyboardEvent(content::WebContents* source,
const input::NativeWebKeyboardEvent& event) override;
void RequestPointerLock(content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target) override;
bool PreHandleGestureEvent(content::WebContents* source,
const blink::WebGestureEvent& event) override;
content::PictureInPictureResult EnterPictureInPicture(
content::WebContents* web_contents) override;
void ExitPictureInPicture() override;
bool ShouldShowStaleContentOnEviction(content::WebContents* source) override;
void DraggableRegionsChanged(
const std::vector<blink::mojom::DraggableRegionPtr>& draggable_regions,
content::WebContents* contents) override;
void RenderFrameCreated(content::RenderFrameHost* frame_host) override;
WindowController* GetExtensionWindowController() const override;
content::WebContents* GetAssociatedWebContents() const override;
void OnExtensionUnloaded(content::BrowserContext* browser_context,
const Extension* extension,
UnloadedExtensionReason reason) override;
void SetWebContentsBlocked(content::WebContents* web_contents,
bool blocked) override;
bool IsWebContentsVisible(content::WebContents* web_contents) override;
void ToggleFullscreenModeForTab(content::WebContents* source,
bool enter_fullscreen);
void SaveWindowPosition();
void AdjustBoundsToBeVisibleOnScreen(const gfx::Rect& cached_bounds,
const gfx::Rect& cached_screen_bounds,
const gfx::Rect& current_screen_bounds,
const gfx::Size& minimum_size,
gfx::Rect* bounds) const;
CreateParams LoadDefaults(CreateParams params) const;
void SetNativeWindowFullscreen();
bool IntersectsWithTaskbar() const;
void UpdateNativeAlwaysOnTop();
void SendOnWindowShownIfShown();
web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost(
content::WebContents* web_contents) override;
void StartAppIconDownload();
void DidDownloadFavicon(int id,
int http_status_code,
const GURL& image_url,
const std::vector<SkBitmap>& bitmaps,
const std::vector<gfx::Size>& original_bitmap_sizes);
raw_ptr<content::BrowserContext> browser_context_;
const ExtensionId extension_id_;
std::string window_key_;
const SessionID session_id_;
WindowType window_type_ = WINDOW_TYPE_DEFAULT;
gfx::Image custom_app_icon_;
GURL app_icon_url_;
std::vector<DidFinishFirstNavigationCallback>
on_did_finish_first_navigation_callbacks_;
bool did_finish_first_navigation_ = false;
std::unique_ptr<NativeAppWindow> native_app_window_;
std::unique_ptr<AppWindowContents> app_window_contents_;
std::unique_ptr<AppDelegate> app_delegate_;
std::unique_ptr<AppWebContentsHelper> helper_;
GURL initial_url_;
int fullscreen_types_ = FULLSCREEN_TYPE_NONE;
bool has_been_shown_ = false;
bool is_hidden_ = false;
bool cached_always_on_top_ = false;
bool requested_alpha_enabled_ = false;
bool is_ime_window_ = false;
bool show_in_shelf_ = false;
bool window_ready_ = false;
base::OnceClosure on_update_draggable_regions_callback_for_testing_;
base::WeakPtrFactory<AppWindow> image_loader_ptr_factory_{this};
};
}
#endif