Commit 2d67fa3c authored by Ken Rockot's avatar Ken Rockot Committed by Commit Bot

[content-service] Enable in-process Mac usage

Changes in-process NavigableContentsView to work on any platform
supporting Views UI rather than restricting it to Aura platforms.

Adapts simple_browser to run in a non-Aura environment as well.

Bug: 855092
Test: Run DCHECK build of chrome --launch-in-process-simple-browser on Mac
Change-Id: Ibdf7ccd83a4c2f3d2c4d667898d3723166c257a3
Reviewed-on: https://chromium-review.googlesource.com/1178802
Commit-Queue: Ken Rockot <rockot@chromium.org>
Reviewed-by: default avatarAlex Moshchuk <alexmos@chromium.org>
Cr-Commit-Position: refs/heads/master@{#584349}
parent 9647a6ed
...@@ -54,7 +54,7 @@ declare_args() { ...@@ -54,7 +54,7 @@ declare_args() {
# application which consumes the Content Service. Useful primarily for # application which consumes the Content Service. Useful primarily for
# developer testing. # developer testing.
enable_simple_browser_service_in_process = enable_simple_browser_service_in_process =
use_aura && (is_debug || dcheck_always_on) (use_aura || is_mac) && (is_debug || dcheck_always_on) && !is_chromecast
enable_simple_browser_service_out_of_process = enable_simple_browser_service_out_of_process =
is_chromeos && (is_debug || dcheck_always_on) is_chromeos && (is_debug || dcheck_always_on)
......
...@@ -375,6 +375,10 @@ static_library("content_shell_lib") { ...@@ -375,6 +375,10 @@ static_library("content_shell_lib") {
] ]
} }
if (toolkit_views) {
deps += [ "//ui/views" ]
}
if (use_aura) { if (use_aura) {
deps += [ deps += [
"//ui/aura", "//ui/aura",
...@@ -391,7 +395,6 @@ static_library("content_shell_lib") { ...@@ -391,7 +395,6 @@ static_library("content_shell_lib") {
] ]
deps += [ deps += [
"//ui/resources", "//ui/resources",
"//ui/views",
"//ui/views:test_support", "//ui/views:test_support",
"//ui/views/controls/webview", "//ui/views/controls/webview",
"//ui/wm:test_support", "//ui/wm:test_support",
......
...@@ -13,13 +13,10 @@ ...@@ -13,13 +13,10 @@
#include "content/public/browser/web_contents_view_delegate.h" #include "content/public/browser/web_contents_view_delegate.h"
#include "content/public/common/context_menu_params.h" #include "content/public/common/context_menu_params.h"
namespace ui { #if defined(TOOLKIT_VIEWS)
class SimpleMenuModel; #include "ui/base/models/simple_menu_model.h" // nogncheck
} #include "ui/views/controls/menu/menu_runner.h" // nogncheck
#endif
namespace views {
class MenuRunner;
}
namespace content { namespace content {
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
import("//build/config/ui.gni")
import("//services/content/public/features.gni") import("//services/content/public/features.gni")
import("//services/service_manager/public/service_manifest.gni") import("//services/service_manager/public/service_manifest.gni")
...@@ -38,13 +39,16 @@ source_set("impl") { ...@@ -38,13 +39,16 @@ source_set("impl") {
"//services/content/public/mojom", "//services/content/public/mojom",
] ]
if (enable_navigable_contents_view_aura) { if (toolkit_views) {
deps += [ deps += [
"//ui/aura",
"//ui/base", "//ui/base",
"//ui/views", "//ui/views",
] ]
if (use_aura) {
deps += [ "//ui/aura" ]
}
if (enable_remote_navigable_contents_view) { if (enable_remote_navigable_contents_view) {
deps += [ "//ui/views/mus/remote_view:remote_view_provider" ] deps += [ "//ui/views/mus/remote_view:remote_view_provider" ]
} }
......
...@@ -11,15 +11,18 @@ ...@@ -11,15 +11,18 @@
#include "services/content/service.h" #include "services/content/service.h"
#include "services/content/service_delegate.h" #include "services/content/service_delegate.h"
#if BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #if defined(TOOLKIT_VIEWS)
#include "ui/aura/window.h" // nogncheck
#include "ui/views/controls/native/native_view_host.h" // nogncheck #include "ui/views/controls/native/native_view_host.h" // nogncheck
#if defined(USE_AURA)
#include "ui/aura/window.h" // nogncheck
#endif
#if BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW) #if BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW)
#include "ui/base/ui_base_features.h" // nogncheck #include "ui/base/ui_base_features.h" // nogncheck
#include "ui/views/mus/remote_view/remote_view_provider.h" // nogncheck #include "ui/views/mus/remote_view/remote_view_provider.h" // nogncheck
#endif #endif
#endif // BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #endif // defined(TOOLKIT_VIEWS)
namespace content { namespace content {
...@@ -82,10 +85,10 @@ void NavigableContentsImpl::CreateView(bool in_service_process, ...@@ -82,10 +85,10 @@ void NavigableContentsImpl::CreateView(bool in_service_process,
void NavigableContentsImpl::OnEmbedTokenReceived( void NavigableContentsImpl::OnEmbedTokenReceived(
CreateViewCallback callback, CreateViewCallback callback,
const base::UnguessableToken& token) { const base::UnguessableToken& token) {
#if BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #if defined(TOOLKIT_VIEWS)
if (native_content_view_) if (native_content_view_)
native_content_view_->Show(); native_content_view_->Show();
#endif // BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #endif // defined(TOOLKIT_VIEWS)
std::move(callback).Run(token); std::move(callback).Run(token);
} }
#endif // BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW) #endif // BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW)
...@@ -93,7 +96,7 @@ void NavigableContentsImpl::OnEmbedTokenReceived( ...@@ -93,7 +96,7 @@ void NavigableContentsImpl::OnEmbedTokenReceived(
void NavigableContentsImpl::EmbedInProcessClientView( void NavigableContentsImpl::EmbedInProcessClientView(
NavigableContentsView* view) { NavigableContentsView* view) {
DCHECK(native_content_view_); DCHECK(native_content_view_);
#if BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #if defined(TOOLKIT_VIEWS)
DCHECK(!local_view_host_); DCHECK(!local_view_host_);
local_view_host_ = std::make_unique<views::NativeViewHost>(); local_view_host_ = std::make_unique<views::NativeViewHost>();
local_view_host_->set_owned_by_client(); local_view_host_->set_owned_by_client();
...@@ -104,7 +107,7 @@ void NavigableContentsImpl::EmbedInProcessClientView( ...@@ -104,7 +107,7 @@ void NavigableContentsImpl::EmbedInProcessClientView(
// TODO(https://crbug.com/855092): Support embedding of other native client // TODO(https://crbug.com/855092): Support embedding of other native client
// views without Views + Aura. // views without Views + Aura.
NOTREACHED() NOTREACHED()
<< "NavigableContents views are currently only supported on Aura."; << "NavigableContents views are currently only supported on Views UI.";
#endif #endif
} }
......
...@@ -62,7 +62,7 @@ class NavigableContentsImpl : public mojom::NavigableContents { ...@@ -62,7 +62,7 @@ class NavigableContentsImpl : public mojom::NavigableContents {
std::unique_ptr<views::RemoteViewProvider> remote_view_provider_; std::unique_ptr<views::RemoteViewProvider> remote_view_provider_;
#endif #endif
#if BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #if defined(TOOLKIT_VIEWS)
// Used to support local view embedding in cases where remote embedding is // Used to support local view embedding in cases where remote embedding is
// not supported and the client controlling this NavigableContents is running // not supported and the client controlling this NavigableContents is running
// within the same process as the Content Service. // within the same process as the Content Service.
......
...@@ -6,10 +6,7 @@ import("//services/content/public/features.gni") ...@@ -6,10 +6,7 @@ import("//services/content/public/features.gni")
buildflag_header("buildflags") { buildflag_header("buildflags") {
header = "buildflags.h" header = "buildflags.h"
flags = [ flags = [ "ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW=$enable_remote_navigable_contents_view" ]
"ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA=$enable_navigable_contents_view_aura",
"ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW=$enable_remote_navigable_contents_view",
]
} }
component("cpp") { component("cpp") {
...@@ -35,7 +32,7 @@ component("cpp") { ...@@ -35,7 +32,7 @@ component("cpp") {
] ]
deps = [] deps = []
if (enable_navigable_contents_view_aura) { if (toolkit_views) {
deps += [ deps += [
"//ui/base", "//ui/base",
"//ui/views", "//ui/views",
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include "base/unguessable_token.h" #include "base/unguessable_token.h"
#include "services/content/public/cpp/buildflags.h" #include "services/content/public/cpp/buildflags.h"
#if BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #if defined(TOOLKIT_VIEWS)
#include "ui/views/layout/fill_layout.h" // nogncheck #include "ui/views/layout/fill_layout.h" // nogncheck
#include "ui/views/view.h" // nogncheck #include "ui/views/view.h" // nogncheck
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "ui/base/ui_base_features.h" // nogncheck #include "ui/base/ui_base_features.h" // nogncheck
#include "ui/views/mus/remote_view/remote_view_host.h" // nogncheck #include "ui/views/mus/remote_view/remote_view_host.h" // nogncheck
#endif // BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW) #endif // BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW)
#endif // BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #endif // defined(TOOLKIT_VIEWS)
namespace content { namespace content {
...@@ -56,7 +56,7 @@ bool NavigableContentsView::IsClientRunningInServiceProcess() { ...@@ -56,7 +56,7 @@ bool NavigableContentsView::IsClientRunningInServiceProcess() {
} }
NavigableContentsView::NavigableContentsView() { NavigableContentsView::NavigableContentsView() {
#if BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #if defined(TOOLKIT_VIEWS)
view_ = std::make_unique<views::View>(); view_ = std::make_unique<views::View>();
view_->set_owned_by_client(); view_->set_owned_by_client();
view_->SetLayoutManager(std::make_unique<views::FillLayout>()); view_->SetLayoutManager(std::make_unique<views::FillLayout>());
...@@ -67,12 +67,12 @@ NavigableContentsView::NavigableContentsView() { ...@@ -67,12 +67,12 @@ NavigableContentsView::NavigableContentsView() {
view_->AddChildView(remote_view_host_); view_->AddChildView(remote_view_host_);
} }
#endif // BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW) #endif // BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW)
#endif // BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #endif // defined(TOOLKIT_VIEWS)
} }
void NavigableContentsView::EmbedUsingToken( void NavigableContentsView::EmbedUsingToken(
const base::UnguessableToken& token) { const base::UnguessableToken& token) {
#if BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #if defined(TOOLKIT_VIEWS)
#if BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW) #if BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW)
if (remote_view_host_) { if (remote_view_host_) {
const uint32_t kEmbedFlags = const uint32_t kEmbedFlags =
...@@ -97,7 +97,7 @@ void NavigableContentsView::EmbedUsingToken( ...@@ -97,7 +97,7 @@ void NavigableContentsView::EmbedUsingToken(
auto callback = std::move(it->second); auto callback = std::move(it->second);
embeddings.erase(it); embeddings.erase(it);
std::move(callback).Run(this); std::move(callback).Run(this);
#endif // BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #endif // defined(TOOLKIT_VIEWS)
} }
// static // static
......
...@@ -23,10 +23,10 @@ class NavigableContentsImpl; ...@@ -23,10 +23,10 @@ class NavigableContentsImpl;
// NavigableContentsView encapsulates cross-platform manipulation and // NavigableContentsView encapsulates cross-platform manipulation and
// presentation of a NavigableContents within a native application UI based on // presentation of a NavigableContents within a native application UI based on
// either Aura, UIKit, AppKit, or the Android Framework. // either Views, UIKit, AppKit, or the Android Framework.
// //
// TODO(https://crbug.com/855092): Actually support UI frameworks other than // TODO(https://crbug.com/855092): Actually support UI frameworks other than
// Aura. // Views UI.
class COMPONENT_EXPORT(CONTENT_SERVICE_CPP) NavigableContentsView { class COMPONENT_EXPORT(CONTENT_SERVICE_CPP) NavigableContentsView {
public: public:
~NavigableContentsView(); ~NavigableContentsView();
...@@ -39,7 +39,7 @@ class COMPONENT_EXPORT(CONTENT_SERVICE_CPP) NavigableContentsView { ...@@ -39,7 +39,7 @@ class COMPONENT_EXPORT(CONTENT_SERVICE_CPP) NavigableContentsView {
static void SetClientRunningInServiceProcess(); static void SetClientRunningInServiceProcess();
static bool IsClientRunningInServiceProcess(); static bool IsClientRunningInServiceProcess();
#if BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #if defined(TOOLKIT_VIEWS)
views::View* view() const { return view_.get(); } views::View* view() const { return view_.get(); }
#endif #endif
...@@ -59,15 +59,15 @@ class COMPONENT_EXPORT(CONTENT_SERVICE_CPP) NavigableContentsView { ...@@ -59,15 +59,15 @@ class COMPONENT_EXPORT(CONTENT_SERVICE_CPP) NavigableContentsView {
const base::UnguessableToken& token, const base::UnguessableToken& token,
base::OnceCallback<void(NavigableContentsView*)> callback); base::OnceCallback<void(NavigableContentsView*)> callback);
#if BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #if defined(TOOLKIT_VIEWS)
// This NavigableContents's View. Only initialized if |GetView()| is called, // This NavigableContents's View. Only initialized if |GetView()| is called,
// and only on platforms which support View embedding via Aura. // and only on platforms which support Views UI.
std::unique_ptr<views::View> view_; std::unique_ptr<views::View> view_;
#if BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW) #if BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW)
views::RemoteViewHost* remote_view_host_ = nullptr; views::RemoteViewHost* remote_view_host_ = nullptr;
#endif #endif
#endif // BUILDFLAG(ENABLE_NAVIGABLE_CONTENTS_VIEW_AURA) #endif // BUILDFLAG(TOOLKIT_VIEWS)
DISALLOW_COPY_AND_ASSIGN(NavigableContentsView); DISALLOW_COPY_AND_ASSIGN(NavigableContentsView);
}; };
......
...@@ -7,23 +7,14 @@ import("//build/config/chromecast_build.gni") ...@@ -7,23 +7,14 @@ import("//build/config/chromecast_build.gni")
import("//build/config/ui.gni") import("//build/config/ui.gni")
declare_args() { declare_args() {
# Determines whether or not the Content Service should support a
# NavigableContentsView based on the Aura framework. For platforms which
# only support Aura-based UI, setting this to |false| means that
# NavigableContentsView will have no actual UI presence.
enable_navigable_contents_view_aura =
use_aura && !is_fuchsia && !is_chromecast
# Determines whether or not the Content Service should support remote # Determines whether or not the Content Service should support remote
# (i.e., out-of-process) clients embedding NavigableContentsViews within their # (i.e., out-of-process) clients embedding NavigableContentsViews within their
# UI. If this is false, only clients in the same process as the Content # UI. If this is false, only clients in the same process as the Content
# Service may use NavigableContentsView. # Service may use NavigableContentsView.
# #
# Currently only supported on Chrome OS, where # Currently only supported on Chrome OS, where |toolkit_views| is implied and
# |enable_navigable_contents_view_aura| is implied and the UI service # the UI service (i.e. Mus) is available.
# (i.e. Mus) is available.
enable_remote_navigable_contents_view = is_chromeos enable_remote_navigable_contents_view = is_chromeos
} }
assert(!enable_remote_navigable_contents_view || assert(!enable_remote_navigable_contents_view || toolkit_views)
enable_navigable_contents_view_aura)
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
import("//build/config/ui.gni")
import("//services/content/public/features.gni")
import("//services/service_manager/public/service_manifest.gni") import("//services/service_manager/public/service_manifest.gni")
component("simple_browser") { component("simple_browser") {
...@@ -28,11 +30,20 @@ component("simple_browser") { ...@@ -28,11 +30,20 @@ component("simple_browser") {
deps = [ deps = [
"//services/content/public/cpp", "//services/content/public/cpp",
"//services/content/public/mojom", "//services/content/public/mojom",
"//ui/aura",
"//ui/views",
"//ui/views/mus",
] ]
if (toolkit_views) {
deps += [ "//ui/views" ]
}
if (use_aura) {
deps += [ "//ui/aura" ]
}
if (enable_remote_navigable_contents_view) {
deps += [ "//ui/views/mus" ]
}
if (is_linux) { if (is_linux) {
public_deps += [ public_deps += [
"//components/services/font/public/cpp", "//components/services/font/public/cpp",
......
...@@ -7,7 +7,7 @@ integration tests. ...@@ -7,7 +7,7 @@ integration tests.
The simple_browser application can run in an isolated sandboxed process on The simple_browser application can run in an isolated sandboxed process on
platforms which support the UI Service (currently only Chrome OS), or within the platforms which support the UI Service (currently only Chrome OS), or within the
browser process on platforms which otherwise support NavigableContentsView browser process on platforms which otherwise support NavigableContentsView
embedding (currently Chrome OS, Linux, and Windows). embedding (currently Chrome OS, Linux, Mac, and Windows).
To play around with simple_browser today, run a DCHECK-enabled build of Chrome To play around with simple_browser today, run a DCHECK-enabled build of Chrome
with `--launch-in-process-simple-browser` on any supported platform listed with `--launch-in-process-simple-browser` on any supported platform listed
......
...@@ -7,12 +7,15 @@ ...@@ -7,12 +7,15 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "services/content/simple_browser/window.h" #include "services/content/simple_browser/window.h"
#include "services/service_manager/public/cpp/service_context.h" #include "services/service_manager/public/cpp/service_context.h"
#include "ui/views/mus/aura_init.h"
#if defined(OS_LINUX) #if defined(OS_LINUX)
#include "third_party/skia/include/ports/SkFontConfigInterface.h" // nogncheck #include "third_party/skia/include/ports/SkFontConfigInterface.h" // nogncheck
#endif #endif
#if defined(USE_AURA) && BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW)
#include "ui/views/mus/aura_init.h" // nogncheck
#endif
namespace simple_browser { namespace simple_browser {
SimpleBrowserService::SimpleBrowserService( SimpleBrowserService::SimpleBrowserService(
...@@ -28,12 +31,17 @@ void SimpleBrowserService::OnStart() { ...@@ -28,12 +31,17 @@ void SimpleBrowserService::OnStart() {
SkFontConfigInterface::SetGlobal(font_loader_); SkFontConfigInterface::SetGlobal(font_loader_);
#endif #endif
#if defined(USE_AURA) && BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW)
views::AuraInit::InitParams params; views::AuraInit::InitParams params;
params.connector = context()->connector(); params.connector = context()->connector();
params.identity = context()->identity(); params.identity = context()->identity();
params.register_path_provider = false; params.register_path_provider = false;
aura_init_ = views::AuraInit::Create(params); aura_init_ = views::AuraInit::Create(params);
CHECK(aura_init_); CHECK(aura_init_);
#else
NOTREACHED() << "Remote UI embedding not supported on this platform.";
#endif
} }
window_ = std::make_unique<Window>(context()->connector()); window_ = std::make_unique<Window>(context()->connector());
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/component_export.h" #include "base/component_export.h"
#include "base/macros.h" #include "base/macros.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "services/content/public/cpp/buildflags.h"
#include "services/service_manager/public/cpp/service.h" #include "services/service_manager/public/cpp/service.h"
#if defined(OS_LINUX) #if defined(OS_LINUX)
...@@ -51,7 +52,11 @@ class COMPONENT_EXPORT(SIMPLE_BROWSER) SimpleBrowserService ...@@ -51,7 +52,11 @@ class COMPONENT_EXPORT(SIMPLE_BROWSER) SimpleBrowserService
#endif #endif
const UIInitializationMode ui_initialization_mode_; const UIInitializationMode ui_initialization_mode_;
#if defined(USE_AURA) && BUILDFLAG(ENABLE_REMOTE_NAVIGABLE_CONTENTS_VIEW)
std::unique_ptr<views::AuraInit> aura_init_; std::unique_ptr<views::AuraInit> aura_init_;
#endif
std::unique_ptr<Window> window_; std::unique_ptr<Window> window_;
DISALLOW_COPY_AND_ASSIGN(SimpleBrowserService); DISALLOW_COPY_AND_ASSIGN(SimpleBrowserService);
......
...@@ -96,9 +96,13 @@ class SimpleBrowserUI : public views::WidgetDelegateView, ...@@ -96,9 +96,13 @@ class SimpleBrowserUI : public views::WidgetDelegateView,
Window::Window(service_manager::Connector* connector) { Window::Window(service_manager::Connector* connector) {
window_widget_ = views::Widget::CreateWindowWithContextAndBounds( window_widget_ = views::Widget::CreateWindowWithContextAndBounds(
new SimpleBrowserUI(connector), nullptr, gfx::Rect(10, 640, 0, 0)); new SimpleBrowserUI(connector), nullptr, gfx::Rect(10, 10, 640, 480));
#if defined(USE_AURA)
window_widget_->GetNativeWindow()->GetHost()->window()->SetName( window_widget_->GetNativeWindow()->GetHost()->window()->SetName(
"SimpleBrowser"); "SimpleBrowser");
#endif
window_widget_->Show(); window_widget_->Show();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment