diff --git a/cobalt/cobalt.cc b/cobalt/cobalt.cc index 32f64c9ea689..f73041a282af 100644 --- a/cobalt/cobalt.cc +++ b/cobalt/cobalt.cc @@ -27,7 +27,6 @@ int main(int argc, const char** argv) { content::ContentMainParams params(&delegate); // TODO: (cobalt b/375241103) Reimplement this in a clean way. - constexpr auto cobalt_args = std::to_array( {// Disable first run experience, kiosk, etc. "--disable-fre", "--no-first-run", "--kiosk", @@ -39,6 +38,8 @@ int main(int argc, const char** argv) { "--disable-features=Vulkan", // Force some ozone settings. "--ozone-platform=starboard", "--use-gl=egl", + // Set the default size for the content shell/starboard window. + "--content-shell-host-window-size=1920x1080", // Enable remote Devtools access. "--remote-debugging-port=9222", "--remote-allow-origins=http://localhost:9222", diff --git a/ui/ozone/platform/starboard/BUILD.gn b/ui/ozone/platform/starboard/BUILD.gn index 27cb68f84ea1..f143df826336 100644 --- a/ui/ozone/platform/starboard/BUILD.gn +++ b/ui/ozone/platform/starboard/BUILD.gn @@ -56,12 +56,24 @@ source_set("starboard_unittests") { testonly = true - sources = [ "test/surface_factory_starboard_unittest.cc" ] + sources = [ + "test/platform_window_starboard_unittest.cc", + "test/starboard_test_helper.cc", + "test/starboard_test_helper.h", + "test/surface_factory_starboard_unittest.cc", + ] deps = [ ":starboard", + "//starboard:starboard_headers_only", + "//starboard/common:common", + "//testing/gmock", "//testing/gtest", + "//ui/events:events", + "//ui/events:events_base", + "//ui/events/types:headers", "//ui/gl", + "//ui/platform_window:platform_window", ] } diff --git a/ui/ozone/platform/starboard/gl_ozone_egl_starboard.cc b/ui/ozone/platform/starboard/gl_ozone_egl_starboard.cc index 66e8b37069e0..93c6b7bc3637 100644 --- a/ui/ozone/platform/starboard/gl_ozone_egl_starboard.cc +++ b/ui/ozone/platform/starboard/gl_ozone_egl_starboard.cc @@ -32,22 +32,20 @@ namespace ui { GLOzoneEGLStarboard::GLOzoneEGLStarboard() = default; -GLOzoneEGLStarboard::~GLOzoneEGLStarboard() { - if (sb_window_) { - SbWindowDestroy(sb_window_); - } -} +GLOzoneEGLStarboard::~GLOzoneEGLStarboard() = default; scoped_refptr GLOzoneEGLStarboard::CreateViewGLSurface( gl::GLDisplay* display, gfx::AcceleratedWidget window) { + CHECK(window != gfx::kNullAcceleratedWidget); // TODO(b/371272304): Verify widget dimensions match our expected display size // (likely full screen for Cobalt). return gl::InitializeGLSurface(new gl::NativeViewGLSurfaceEGL( - display->GetAs(), GetNativeWindow(), + display->GetAs(), window, std::make_unique(base::TimeTicks(), GetVSyncInterval()))); } + scoped_refptr GLOzoneEGLStarboard::CreateOffscreenGLSurface( gl::GLDisplay* display, const gfx::Size& size) { @@ -55,13 +53,8 @@ scoped_refptr GLOzoneEGLStarboard::CreateOffscreenGLSurface( new gl::PbufferGLSurfaceEGL(display->GetAs(), size)); } -intptr_t GLOzoneEGLStarboard::GetNativeWindow() { - CreateDisplayTypeAndWindowIfNeeded(); - return reinterpret_cast(window_); -} - gl::EGLDisplayPlatform GLOzoneEGLStarboard::GetNativeDisplay() { - CreateDisplayTypeAndWindowIfNeeded(); + CreateDisplayTypeIfNeeded(); return gl::EGLDisplayPlatform( reinterpret_cast(display_type_)); } @@ -83,21 +76,12 @@ bool GLOzoneEGLStarboard::LoadGLES2Bindings( return true; } -void GLOzoneEGLStarboard::CreateDisplayTypeAndWindowIfNeeded() { +void GLOzoneEGLStarboard::CreateDisplayTypeIfNeeded() { // TODO(b/371272304): Initialize hardware here if needed. if (!have_display_type_) { display_type_ = reinterpret_cast(SB_EGL_DEFAULT_DISPLAY); have_display_type_ = true; } - if (!window_) { - SbWindowOptions options{}; - SbWindowSetDefaultOptions(&options); - - sb_window_ = SbWindowCreate(&options); - window_ = SbWindowGetPlatformHandle(sb_window_); - } - - CHECK(window_); } } // namespace ui diff --git a/ui/ozone/platform/starboard/gl_ozone_egl_starboard.h b/ui/ozone/platform/starboard/gl_ozone_egl_starboard.h index f39126359e62..cd0769a320a9 100644 --- a/ui/ozone/platform/starboard/gl_ozone_egl_starboard.h +++ b/ui/ozone/platform/starboard/gl_ozone_egl_starboard.h @@ -15,7 +15,6 @@ #ifndef UI_OZONE_PLATFORM_STARBOARD_GL_OZONE_EGL_STARBOARD_H_ #define UI_OZONE_PLATFORM_STARBOARD_GL_OZONE_EGL_STARBOARD_H_ -#include "starboard/window.h" #include "ui/gfx/native_widget_types.h" #include "ui/ozone/common/gl_ozone_egl.h" @@ -36,19 +35,16 @@ class GLOzoneEGLStarboard : public GLOzoneEGL { gl::GLDisplay* display, const gfx::Size& size) override; - intptr_t GetNativeWindow(); - protected: gl::EGLDisplayPlatform GetNativeDisplay() override; bool LoadGLES2Bindings( const gl::GLImplementationParts& implementation) override; private: - void CreateDisplayTypeAndWindowIfNeeded(); + void CreateDisplayTypeIfNeeded(); void* display_type_ = nullptr; bool have_display_type_ = false; - SbWindow sb_window_; void* window_ = nullptr; }; diff --git a/ui/ozone/platform/starboard/platform_window_starboard.cc b/ui/ozone/platform/starboard/platform_window_starboard.cc index 3d766d68266d..3f24401f4fc0 100644 --- a/ui/ozone/platform/starboard/platform_window_starboard.cc +++ b/ui/ozone/platform/starboard/platform_window_starboard.cc @@ -26,8 +26,15 @@ PlatformWindowStarboard::PlatformWindowStarboard( PlatformWindowDelegate* delegate, const gfx::Rect& bounds) : StubWindow(delegate, /*use_default_accelerated_widget=*/false, bounds) { - gfx::AcceleratedWidget widget = (bounds.width() << 16) + bounds.height(); - delegate->OnAcceleratedWidgetAvailable(widget); + SbWindowOptions options{}; + SbWindowSetDefaultOptions(&options); + options.size.width = bounds.width(); + options.size.height = bounds.height(); + sb_window_ = SbWindowCreate(&options); + CHECK(SbWindowIsValid(sb_window_)); + + delegate->OnAcceleratedWidgetAvailable( + reinterpret_cast(SbWindowGetPlatformHandle(sb_window_))); if (PlatformEventSource::GetInstance()) { PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this); @@ -35,6 +42,10 @@ PlatformWindowStarboard::PlatformWindowStarboard( } PlatformWindowStarboard::~PlatformWindowStarboard() { + if (sb_window_) { + SbWindowDestroy(sb_window_); + } + if (PlatformEventSource::GetInstance()) { PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this); } diff --git a/ui/ozone/platform/starboard/platform_window_starboard.h b/ui/ozone/platform/starboard/platform_window_starboard.h index 1cc81700b65f..eed07831a4d0 100644 --- a/ui/ozone/platform/starboard/platform_window_starboard.h +++ b/ui/ozone/platform/starboard/platform_window_starboard.h @@ -15,6 +15,7 @@ #ifndef UI_OZONE_PLATFORM_STARBOARD_PLATFORM_WINDOW_STARBOARD_H_ #define UI_OZONE_PLATFORM_STARBOARD_PLATFORM_WINDOW_STARBOARD_H_ +#include "starboard/window.h" #include "ui/events/platform/platform_event_dispatcher.h" #include "ui/platform_window/platform_window_delegate.h" #include "ui/platform_window/stub/stub_window.h" @@ -37,6 +38,9 @@ class PlatformWindowStarboard : public StubWindow, bool CanDispatchEvent(const PlatformEvent& event) override; uint32_t DispatchEvent(const PlatformEvent& event) override; + + private: + SbWindow sb_window_; }; } // namespace ui diff --git a/ui/ozone/platform/starboard/test/platform_window_starboard_unittest.cc b/ui/ozone/platform/starboard/test/platform_window_starboard_unittest.cc new file mode 100644 index 000000000000..ee9fdab5254c --- /dev/null +++ b/ui/ozone/platform/starboard/test/platform_window_starboard_unittest.cc @@ -0,0 +1,76 @@ +// Copyright 2025 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "ui/ozone/platform/starboard/platform_window_starboard.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/events/base_event_utils.h" +#include "ui/events/event.h" +#include "ui/events/event_utils.h" +#include "ui/events/types/event_type.h" +#include "ui/ozone/platform/starboard/test/starboard_test_helper.h" + +namespace ui { +namespace { +// Using OzoneStarboardTest to allow SbWindowCreate and SbWindowDestroy. +class PlatformWindowStarboardTest : public OzoneStarboardTest { + public: + PlatformWindowStarboardTest() { + sb_window_ = + std::make_unique(&delegate_, gfx::Rect(0, 0)); + } + + ~PlatformWindowStarboardTest() { + // Reset |sb_window_| before parent destructor is called so SbWindowDestroy + // can run. + sb_window_.reset(); + } + + PlatformWindowStarboard* window() { return sb_window_.get(); } + + protected: + MockPlatformWindowDelegate delegate_; + + private: + // Using a pointer to delay initialization of the window until after starting + // the main Starboard thread in partent constructor. + std::unique_ptr sb_window_; +}; + +TEST_F(PlatformWindowStarboardTest, CanDispatchEvent) { + ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), + ui::EventTimeForNow(), 0, 0); + const PlatformEvent& platform_event = &event; + + EXPECT_TRUE(window()->CanDispatchEvent(platform_event)); +} + +TEST_F(PlatformWindowStarboardTest, DispatchEvent) { + ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(), + ui::EventTimeForNow(), 0, 0); + const PlatformEvent& platform_event = &event; + + ui::EventType type; + EXPECT_CALL(delegate_, DispatchEvent(testing::_)) + .Times(1) + .WillOnce([&type](const PlatformEvent& event) { + type = ui::EventTypeFromNative(event); + }); + + auto result = window()->DispatchEvent(platform_event); + EXPECT_EQ(result, ui::POST_DISPATCH_STOP_PROPAGATION); + EXPECT_EQ(type, ui::ET_MOUSE_PRESSED); +} +} // namespace +} // namespace ui diff --git a/ui/ozone/platform/starboard/test/starboard_test_helper.cc b/ui/ozone/platform/starboard/test/starboard_test_helper.cc new file mode 100644 index 000000000000..8809376d3213 --- /dev/null +++ b/ui/ozone/platform/starboard/test/starboard_test_helper.cc @@ -0,0 +1,75 @@ +// Copyright 2025 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "ui/ozone/platform/starboard/test/starboard_test_helper.h" + +#include "starboard/system.h" + +namespace ui { +namespace { +// SbEventHandle needs to call into the test class' event handler to signal the +// |started_condition_|, so the test object is tracked here. +OzoneStarboardTest* ozone_starboard_test_instance = nullptr; + +// Static callback for SbEvents. This will pass events to the test class' +// implementation of |EventHandleInternal| to signal the main thread has +// started. +void SbEventHandle(const SbEvent* event) { + if (ozone_starboard_test_instance) { + ozone_starboard_test_instance->EventHandleInternal(event); + } +} +} // namespace + +OzoneStarboardTest::OzoneStarboardTest() { + ozone_starboard_test_instance = this; + + started_condition_ = std::make_unique(started_mutex_); + + // Start the main starboard thread to allow Starboard function calls. + sb_main_ = std::make_unique(); + started_mutex_.Acquire(); + sb_main_->Start(); + // Wait for the |kSbEventTypeStart| to signal the initialization completion + // before continuing. + started_condition_->Wait(); + started_mutex_.Release(); +} + +OzoneStarboardTest::~OzoneStarboardTest() { + // Kill and clean up the Starboard main thread. + SbSystemRequestStop(0); + sb_main_->Join(); + sb_main_.reset(); + + started_condition_.reset(); + ozone_starboard_test_instance = nullptr; +} + +// Note: If overriding this function, be sure to signal the started_condition_ +// or the test will hang. +void OzoneStarboardTest::EventHandleInternal(const SbEvent* event) { + switch (event->type) { + case kSbEventTypeStart: + started_condition_->Signal(); + break; + default: + break; + } +} + +void OzoneStarboardTest::OzoneStarboardThread::Run() { + SbRunStarboardMain(0, nullptr, &SbEventHandle); +} +} // namespace ui diff --git a/ui/ozone/platform/starboard/test/starboard_test_helper.h b/ui/ozone/platform/starboard/test/starboard_test_helper.h new file mode 100644 index 000000000000..87c3a79e4bb3 --- /dev/null +++ b/ui/ozone/platform/starboard/test/starboard_test_helper.h @@ -0,0 +1,90 @@ +// Copyright 2025 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef UI_OZONE_PLATFORM_STARBOARD_TEST_STARBOARD_TEST_HELPER_H_ +#define UI_OZONE_PLATFORM_STARBOARD_TEST_STARBOARD_TEST_HELPER_H_ + +#include "starboard/common/condition_variable.h" +#include "starboard/common/mutex.h" +#include "starboard/common/thread.h" +#include "starboard/event.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/platform_window/platform_window_delegate.h" + +using ::starboard::ConditionVariable; +using ::starboard::Mutex; +using ::starboard::Thread; + +namespace ui { + +class MockPlatformWindowDelegate : public ui::PlatformWindowDelegate { + public: + // Mock ui::PlatformWindowDelegate implementation. + MockPlatformWindowDelegate(); + + MockPlatformWindowDelegate(const MockPlatformWindowDelegate&) = delete; + MockPlatformWindowDelegate& operator=(const MockPlatformWindowDelegate&) = + delete; + + ~MockPlatformWindowDelegate() override; + + MOCK_METHOD(void, OnBoundsChanged, (const BoundsChange& change), (override)); + MOCK_METHOD(void, + OnDamageRect, + (const gfx::Rect& damaged_region), + (override)); + MOCK_METHOD(void, DispatchEvent, (ui::Event * event), (override)); + MOCK_METHOD(void, OnCloseRequest, (), (override)); + MOCK_METHOD(void, OnClosed, (), (override)); + MOCK_METHOD(void, + OnWindowStateChanged, + (ui::PlatformWindowState old_state, + ui::PlatformWindowState new_state), + (override)); + MOCK_METHOD(void, OnLostCapture, (), (override)); + MOCK_METHOD(void, + OnAcceleratedWidgetAvailable, + (gfx::AcceleratedWidget widget), + (override)); + MOCK_METHOD(void, OnWillDestroyAcceleratedWidget, (), (override)); + MOCK_METHOD(void, OnAcceleratedWidgetDestroyed, (), (override)); + MOCK_METHOD(void, OnActivationChanged, (bool active), (override)); + MOCK_METHOD(void, OnMouseEnter, (), (override)); +}; + +class OzoneStarboardTest : public testing::Test { + public: + OzoneStarboardTest(); + + virtual ~OzoneStarboardTest(); + + virtual void EventHandleInternal(const SbEvent* event); + + private: + class OzoneStarboardThread : public Thread { + public: + OzoneStarboardThread() : Thread("sb_thread") {} + + void Run() override; + }; + + // These are used to initialize the main Starboard thread, which must be + // running before some Starboard functions can be called. + std::unique_ptr sb_main_; + std::unique_ptr started_condition_; + Mutex started_mutex_; +}; +} // namespace ui +#endif // UI_OZONE_PLATFORM_STARBOARD_TEST_STARBOARD_TEST_HELPER_H_ diff --git a/ui/ozone/platform/starboard/test/surface_factory_starboard_unittest.cc b/ui/ozone/platform/starboard/test/surface_factory_starboard_unittest.cc index 575b8ec0c396..989707c68439 100644 --- a/ui/ozone/platform/starboard/test/surface_factory_starboard_unittest.cc +++ b/ui/ozone/platform/starboard/test/surface_factory_starboard_unittest.cc @@ -18,6 +18,17 @@ namespace ui { +namespace { +static const std::map + kGLImplementationToString = { + {gl::kGLImplementationNone, "none"}, + {gl::kGLImplementationEGLGLES2, "eglgles2"}, + {gl::kGLImplementationMockGL, "mockgl"}, + {gl::kGLImplementationStubGL, "stubgl"}, + {gl::kGLImplementationDisabled, "disabled"}, + {gl::kGLImplementationEGLANGLE, "eglangle"}, +}; + class SurfaceFactoryStarboardSupportTest : public testing::TestWithParam< testing::tuple> { @@ -49,5 +60,10 @@ INSTANTIATE_TEST_SUITE_P( std::make_tuple(gl::kGLImplementationMockGL, false), std::make_tuple(gl::kGLImplementationStubGL, false), std::make_tuple(gl::kGLImplementationDisabled, false), - std::make_tuple(gl::kGLImplementationEGLANGLE, false))); + std::make_tuple(gl::kGLImplementationEGLANGLE, false)), + [](const testing::TestParamInfo< + SurfaceFactoryStarboardSupportTest::ParamType>& info) { + return kGLImplementationToString.at(testing::get<0>(info.param)); + }); +} // namespace } // namespace ui