diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2019-07-25 04:39:50 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-07-25 04:39:50 -0400 |
commit | 3e90b93b83de03afed0712b7090be99e0193883d (patch) | |
tree | cbd5f39e1e006256f323dbbb2d389860f0d5f1ab | |
parent | 9f6d134957ffeb27aa33b4e5fcc8b92b96dfbc0f (diff) | |
parent | d0436f16b6abd19306e65de15967b49331d64f13 (diff) | |
download | servo-3e90b93b83de03afed0712b7090be99e0193883d.tar.gz servo-3e90b93b83de03afed0712b7090be99e0193883d.zip |
Auto merge of #23845 - paulrouget:cleanup, r=jdm
[hololens] More events, remove most of the statics, better shutdown
Depends on #23831
- Buttons are greyed out when necessary
- Reload, Stop, Back and Fwd are properly bound
- Servo.cpp rewritten in a much cleaner way
- Removed most of the statics
- Improved (but not full) shutdown
<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23845)
<!-- Reviewable:end -->
-rw-r--r-- | support/hololens/ServoApp/App.cpp | 7 | ||||
-rw-r--r-- | support/hololens/ServoApp/BrowserPage.cpp | 332 | ||||
-rw-r--r-- | support/hololens/ServoApp/BrowserPage.h | 34 | ||||
-rw-r--r-- | support/hololens/ServoApp/BrowserPage.xaml | 6 | ||||
-rw-r--r-- | support/hololens/ServoApp/Common/DeviceResources.h | 3 | ||||
-rw-r--r-- | support/hololens/ServoApp/Servo.cpp | 100 | ||||
-rw-r--r-- | support/hololens/ServoApp/Servo.h | 78 | ||||
-rw-r--r-- | support/hololens/ServoApp/pch.h | 1 |
8 files changed, 343 insertions, 218 deletions
diff --git a/support/hololens/ServoApp/App.cpp b/support/hololens/ServoApp/App.cpp index e373f05210d..9f6495c49e1 100644 --- a/support/hololens/ServoApp/App.cpp +++ b/support/hololens/ServoApp/App.cpp @@ -63,7 +63,12 @@ void App::OnLaunched(LaunchActivatedEventArgs const &e) { } void App::OnSuspending([[maybe_unused]] IInspectable const &sender, - [[maybe_unused]] SuspendingEventArgs const &e) {} + [[maybe_unused]] SuspendingEventArgs const &e) { + auto content = Window::Current().Content(); + Frame rootFrame = content.try_as<Frame>(); + auto page = rootFrame.Content().try_as<BrowserPage>(); + page->Shutdown(); +} void App::OnNavigationFailed(IInspectable const &, NavigationFailedEventArgs const &e) { diff --git a/support/hololens/ServoApp/BrowserPage.cpp b/support/hololens/ServoApp/BrowserPage.cpp index 2c2c6c6420b..c6fe3d9b969 100644 --- a/support/hololens/ServoApp/BrowserPage.cpp +++ b/support/hololens/ServoApp/BrowserPage.cpp @@ -16,96 +16,59 @@ using namespace winrt::Windows::UI::ViewManagement; using namespace winrt::Windows::Foundation; using namespace winrt::Windows::Graphics::Holographic; using namespace concurrency; - -static char sWakeupEvent[] = "SIGNAL_WAKEUP"; +using namespace servo; namespace winrt::ServoApp::implementation { BrowserPage::BrowserPage() { - InitializeComponent(); log("BrowserPage::BrowserPage()"); + InitializeComponent(); Loaded(std::bind(&BrowserPage::OnPageLoaded, this, _1, _2)); Window::Current().CoreWindow().VisibilityChanged( std::bind(&BrowserPage::OnVisibilityChanged, this, _1, _2)); } +void BrowserPage::Shutdown() { + log("BrowserPage::Shutdown()"); + + if (mServo != nullptr) { + if (!IsLoopRunning()) { + // FIXME: this should not happen. In that case, we can't send the + // shutdown event to Servo. + } else { + HANDLE hEvent = ::CreateEventA(nullptr, FALSE, FALSE, sShutdownEvent); + SendEventToServo({{Event::SHUTDOWN}}); + log("Waiting for Servo to shutdown"); + ::WaitForSingleObject(hEvent, INFINITE); + StopRenderLoop(); + mServo.reset(); // will call servo::deinit + } + } +} + void BrowserPage::OnPageLoaded(IInspectable const &, RoutedEventArgs const &) { log("BrowserPage::OnPageLoaded()"); CreateRenderSurface(); StartRenderLoop(); - swapChainPanel().PointerReleased( std::bind(&BrowserPage::OnSurfaceClicked, this, _1, _2)); - swapChainPanel().ManipulationDelta( std::bind(&BrowserPage::OnSurfaceManipulationDelta, this, _1, _2)); } -void BrowserPage::OnSurfaceManipulationDelta( - IInspectable const &, Input::ManipulationDeltaRoutedEventArgs const &e) { - auto x = e.Position().X; - auto y = e.Position().Y; - auto dx = e.Delta().Translation.X; - auto dy = e.Delta().Translation.Y; - Event event = {{Event::SCROLL}}; - event.scrollCoords = {dx, dy, x, y}; - SendEventToServo(event); - e.Handled(true); -} - -void BrowserPage::OnSurfaceClicked(IInspectable const &, - Input::PointerRoutedEventArgs const &e) { - auto coords = e.GetCurrentPoint(swapChainPanel()); - auto x = coords.Position().X; - auto y = coords.Position().Y; - - SendEventToServo({{Event::CLICK}, {x, y}}); - - e.Handled(true); -} - -void BrowserPage::SendEventToServo(Event event) { - mEventsMutex.lock(); - mEvents.push_back(event); - mEventsMutex.unlock(); - Servo::sWakeUp(); -} - -void BrowserPage::OnBackButtonClicked(IInspectable const &, - RoutedEventArgs const &) { - SendEventToServo({{Event::BACK}}); -} - -void BrowserPage::OnForwardButtonClicked(IInspectable const &, - RoutedEventArgs const &) { - SendEventToServo({{Event::FORWARD}}); -} -void BrowserPage::OnImmersiveButtonClicked(IInspectable const &, - RoutedEventArgs const &) { - if (HolographicSpace::IsAvailable()) { - log("Holographic space available"); - auto v = - winrt::Windows::ApplicationModel::Core::CoreApplication::CreateNewView( - mImmersiveViewSource); - auto parentId = ApplicationView::GetForCurrentView().Id(); - v.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [=]() { - auto winId = ApplicationView::GetForCurrentView().Id(); - ApplicationViewSwitcher::SwitchAsync(winId, parentId); - log("Immersive view started"); - }); - } else { - log("Holographic space not available"); - } -} - void BrowserPage::OnVisibilityChanged(CoreWindow const &, VisibilityChangedEventArgs const &args) { auto visible = args.Visible(); - if (visible && !IsLoopRunning()) { - StartRenderLoop(); - } - if (!visible && IsLoopRunning()) { - StopRenderLoop(); - } + + // FIXME: for now, this is disabled as we get this message before shutdown, + // stopping the event loop, which we can't recover from yet (see comment in + // Loop()) + + // if (visible && !IsLoopRunning()) { + // StartRenderLoop(); + //} + // if (!visible && IsLoopRunning()) { + // StopRenderLoop(); + //} } void BrowserPage::CreateRenderSurface() { @@ -127,6 +90,8 @@ void BrowserPage::RecoverFromLostDevice() { StartRenderLoop(); } +/**** GL THREAD LOOP ****/ + bool BrowserPage::IsLoopRunning() { return mLoopTask != nullptr && !mLoopTask->is_done(); } @@ -136,65 +101,35 @@ void BrowserPage::Loop(cancellation_token cancel) { HANDLE hEvent = ::CreateEventA(nullptr, FALSE, FALSE, sWakeupEvent); - Servo::sOnAlert = [=](std::wstring message) { - // FIXME: make this sync - swapChainPanel().Dispatcher().RunAsync( - Windows::UI::Core::CoreDispatcherPriority::High, [=]() { - Windows::UI::Popups::MessageDialog msg{message}; - msg.ShowAsync(); - }); - }; - - Servo::sOnTitleChanged = [=](std::wstring title) { - swapChainPanel().Dispatcher().RunAsync(CoreDispatcherPriority::High, [=]() { - ApplicationView::GetForCurrentView().Title(title); - }); - }; - - Servo::sOnURLChanged = [=](std::wstring url) { - swapChainPanel().Dispatcher().RunAsync(CoreDispatcherPriority::High, - [=]() { urlTextbox().Text(url); }); - }; - - Servo::sMakeCurrent = [=]() { - /* EGLint panelWidth = 0; */ - /* EGLint panelHeight = 0; */ - /* mOpenGLES->GetSurfaceDimensions(mRenderSurface, &panelWidth, - * &panelHeight); */ - /* glViewport(0, 0, panelWidth, panelHeight); */ - /* mServo->SetSize(panelWidth, panelHeight); */ - mOpenGLES.MakeCurrent(mRenderSurface); - }; - - Servo::sFlush = [=]() { - if (mOpenGLES.SwapBuffers(mRenderSurface) != GL_TRUE) { - // The call to eglSwapBuffers might not be successful (i.e. due to Device - // Lost) If the call fails, then we must reinitialize EGL and the GL - // resources. - swapChainPanel().Dispatcher().RunAsync( - CoreDispatcherPriority::High, [this]() { RecoverFromLostDevice(); }); - } - }; - mOpenGLES.MakeCurrent(mRenderSurface); EGLint panelWidth = 0; EGLint panelHeight = 0; mOpenGLES.GetSurfaceDimensions(mRenderSurface, &panelWidth, &panelHeight); glViewport(0, 0, panelWidth, panelHeight); - mServo = std::make_unique<Servo>(panelWidth, panelHeight); + + if (mServo == nullptr) { + log("Entering loop"); + ServoDelegate *sd = static_cast<ServoDelegate *>(this); + mServo = std::make_unique<Servo>(panelWidth, panelHeight, *sd); + } else { + // FIXME: this will fail since create_task didn't pick the thread + // where Servo was running initially. + throw winrt::hresult_error(E_FAIL, L"Recovering loop unimplemented"); + } // mServo->SetBatchMode(true); - // FIXME: ^ this should be necessary as call perform_update + // FIXME: ^ this should be necessary as we call perform_update // ourself. But enabling batch mode will make clicking a link // not working because during the click, this thread is not // waiting on the hEvent object. See the "wakeup" comment. + log("Entering loop"); while (!cancel.is_canceled()) { - // Block until Servo::sWakeUp is called. - // Or run full speed if animating (see on_animating_changed), - // it will endup blocking on SwapBuffers to limit rendering to 60FPS - if (!Servo::sAnimating) { + // Block until wakeup is called. + // Or run full speed if animating (see OnAnimatingChanged), + // it will endup blocking on Flush to limit rendering to 60FPS + if (!mAnimating) { ::WaitForSingleObject(hEvent, INFINITE); } mEventsMutex.lock(); @@ -216,31 +151,36 @@ void BrowserPage::Loop(cancellation_token cancel) { case Event::BACK: mServo->GoBack(); break; + case Event::RELOAD: + mServo->Reload(); + break; + case Event::STOP: + mServo->Stop(); + break; + case Event::SHUTDOWN: + log("Requesting Servo to shutdown"); + mServo->RequestShutdown(); + break; } } mEvents.clear(); mEventsMutex.unlock(); mServo->PerformUpdates(); } + log("Leaving loop"); cancel_current_task(); -} +} // namespace winrt::ServoApp::implementation void BrowserPage::StartRenderLoop() { if (IsLoopRunning()) { +#if defined _DEBUG + throw winrt::hresult_error(E_FAIL, L"GL thread is already looping"); +#else return; +#endif } - - auto token = mLoopCancel.get_token(); - - Servo::sWakeUp = []() { - // FIXME: this won't work if it's triggered while the thread is not - // waiting. We need a better looping logic. - HANDLE hEvent = ::OpenEventA(EVENT_ALL_ACCESS, FALSE, sWakeupEvent); - ::SetEvent(hEvent); - }; - log("BrowserPage::StartRenderLoop(). UI thread: %i", GetCurrentThreadId()); - + auto token = mLoopCancel.get_token(); mLoopTask = std::make_unique<Concurrency::task<void>>( Concurrency::create_task([=] { Loop(token); }, token)); } @@ -253,4 +193,144 @@ void BrowserPage::StopRenderLoop() { } } +/**** SERVO CALLBACKS ****/ + +void BrowserPage::OnLoadStarted() { + RunOnUIThread([=] { + reloadButton().IsEnabled(false); + stopButton().IsEnabled(true); + }); +} + +void BrowserPage::OnLoadEnded() { + RunOnUIThread([=] { + reloadButton().IsEnabled(true); + stopButton().IsEnabled(false); + }); +} + +void BrowserPage::OnHistoryChanged(bool back, bool forward) { + RunOnUIThread([=] { + backButton().IsEnabled(back); + forwardButton().IsEnabled(forward); + }); +} + +void BrowserPage::OnShutdownComplete() { + log("Servo notified ShutdownComplete"); + HANDLE hEvent = ::OpenEventA(EVENT_ALL_ACCESS, FALSE, sShutdownEvent); + ::SetEvent(hEvent); +} + +void BrowserPage::OnAlert(std::wstring message) { + // FIXME: make this sync + RunOnUIThread([=] { + Windows::UI::Popups::MessageDialog msg{message}; + msg.ShowAsync(); + }); +} + +void BrowserPage::OnTitleChanged(std::wstring title) { + RunOnUIThread([=] { ApplicationView::GetForCurrentView().Title(title); }); +} + +void BrowserPage::OnURLChanged(std::wstring url) { + RunOnUIThread([=] { urlTextbox().Text(url); }); +} + +void BrowserPage::Flush() { + if (mOpenGLES.SwapBuffers(mRenderSurface) != GL_TRUE) { + // The call to eglSwapBuffers might not be successful (i.e. due to Device + // Lost) If the call fails, then we must reinitialize EGL and the GL + // resources. + RunOnUIThread([=] { RecoverFromLostDevice(); }); + } +} + +void BrowserPage::MakeCurrent() { mOpenGLES.MakeCurrent(mRenderSurface); } + +void BrowserPage::WakeUp() { + // FIXME: this won't work if it's triggered while the thread is not + // waiting. We need a better looping logic. + HANDLE hEvent = ::OpenEventA(EVENT_ALL_ACCESS, FALSE, sWakeupEvent); + ::SetEvent(hEvent); +} + +bool BrowserPage::OnAllowNavigation(std::wstring) { return true; } + +void BrowserPage::OnAnimatingChanged(bool animating) { mAnimating = animating; } + +template <typename Callable> void BrowserPage::RunOnUIThread(Callable cb) { + swapChainPanel().Dispatcher().RunAsync( + Windows::UI::Core::CoreDispatcherPriority::High, cb); +} + +/**** USER INTERACTIONS WITH UI ****/ + +void BrowserPage::OnBackButtonClicked(IInspectable const &, + RoutedEventArgs const &) { + SendEventToServo({{Event::BACK}}); +} + +void BrowserPage::OnForwardButtonClicked(IInspectable const &, + RoutedEventArgs const &) { + SendEventToServo({{Event::FORWARD}}); +} + +void BrowserPage::OnReloadButtonClicked(IInspectable const &, + RoutedEventArgs const &) { + SendEventToServo({{Event::RELOAD}}); +} + +void BrowserPage::OnStopButtonClicked(IInspectable const &, + RoutedEventArgs const &) { + SendEventToServo({{Event::STOP}}); +} + +void BrowserPage::OnImmersiveButtonClicked(IInspectable const &, + RoutedEventArgs const &) { + if (HolographicSpace::IsAvailable()) { + log("Holographic space available"); + auto v = + winrt::Windows::ApplicationModel::Core::CoreApplication::CreateNewView( + mImmersiveViewSource); + auto parentId = ApplicationView::GetForCurrentView().Id(); + v.Dispatcher().RunAsync(CoreDispatcherPriority::Normal, [=] { + auto winId = ApplicationView::GetForCurrentView().Id(); + ApplicationViewSwitcher::SwitchAsync(winId, parentId); + log("Immersive view started"); + }); + } else { + log("Holographic space not available"); + } +} + +void BrowserPage::OnSurfaceManipulationDelta( + IInspectable const &, Input::ManipulationDeltaRoutedEventArgs const &e) { + auto x = e.Position().X; + auto y = e.Position().Y; + auto dx = e.Delta().Translation.X; + auto dy = e.Delta().Translation.Y; + Event event = {{Event::SCROLL}}; + event.scrollCoords = {dx, dy, x, y}; + SendEventToServo(event); + e.Handled(true); +} + +void BrowserPage::OnSurfaceClicked(IInspectable const &, + Input::PointerRoutedEventArgs const &e) { + auto coords = e.GetCurrentPoint(swapChainPanel()); + auto x = coords.Position().X; + auto y = coords.Position().Y; + SendEventToServo({{Event::CLICK}, {x, y}}); + e.Handled(true); +} + +void BrowserPage::SendEventToServo(Event event) { + mEventsMutex.lock(); + mEvents.push_back(event); + mEventsMutex.unlock(); + WakeUp(); +} + } // namespace winrt::ServoApp::implementation diff --git a/support/hololens/ServoApp/BrowserPage.h b/support/hololens/ServoApp/BrowserPage.h index 4eca25d363a..efa27ea4215 100644 --- a/support/hololens/ServoApp/BrowserPage.h +++ b/support/hololens/ServoApp/BrowserPage.h @@ -11,13 +11,17 @@ namespace winrt::ServoApp::implementation { +static char sWakeupEvent[] = "SIGNAL_WAKEUP"; +static char sShutdownEvent[] = "SIGNAL_SHUTDOWN"; + struct Event { - enum { CLICK, SCROLL, BACK, FORWARD } type; + enum { CLICK, SCROLL, BACK, FORWARD, RELOAD, STOP, SHUTDOWN } type; std::tuple<float, float> clickCoords; std::tuple<float, float, float, float> scrollCoords; }; -struct BrowserPage : BrowserPageT<BrowserPage> { +struct BrowserPage : BrowserPageT<BrowserPage>, + public servo::ServoDelegate { public: BrowserPage(); @@ -27,7 +31,10 @@ public: Windows::UI::Xaml::RoutedEventArgs const &); void OnBackButtonClicked(Windows::Foundation::IInspectable const &, Windows::UI::Xaml::RoutedEventArgs const &); - + void OnReloadButtonClicked(Windows::Foundation::IInspectable const &, + Windows::UI::Xaml::RoutedEventArgs const &); + void OnStopButtonClicked(Windows::Foundation::IInspectable const &, + Windows::UI::Xaml::RoutedEventArgs const &); void OnSurfaceClicked(Windows::Foundation::IInspectable const &, Windows::UI::Xaml::Input::PointerRoutedEventArgs const &); @@ -36,13 +43,28 @@ public: IInspectable const &, Windows::UI::Xaml::Input::ManipulationDeltaRoutedEventArgs const &e); + template <typename Callable> void RunOnUIThread(Callable); + void Shutdown(); + + virtual void WakeUp(); + virtual void OnLoadStarted(); + virtual void OnLoadEnded(); + virtual void OnHistoryChanged(bool, bool); + virtual void OnShutdownComplete(); + virtual void OnTitleChanged(std::wstring); + virtual void OnAlert(std::wstring); + virtual void OnURLChanged(std::wstring); + virtual void Flush(); + virtual void MakeCurrent(); + virtual bool OnAllowNavigation(std::wstring); + virtual void OnAnimatingChanged(bool); + private: void OnVisibilityChanged( Windows::UI::Core::CoreWindow const &, Windows::UI::Core::VisibilityChangedEventArgs const &args); void OnPageLoaded(Windows::Foundation::IInspectable const &, Windows::UI::Xaml::RoutedEventArgs const &); - void CreateRenderSurface(); void DestroyRenderSurface(); void RecoverFromLostDevice(); @@ -56,13 +78,15 @@ private: std::unique_ptr<Concurrency::task<void>> mLoopTask; winrt::ServoApp::ImmersiveViewSource mImmersiveViewSource; EGLSurface mRenderSurface{EGL_NO_SURFACE}; - std::unique_ptr<Servo> mServo; + std::unique_ptr<servo::Servo> mServo; void BrowserPage::SendEventToServo(Event event); std::vector<Event> mEvents; std::mutex mEventsMutex; OpenGLES mOpenGLES; // FIXME: shared pointer + + bool mAnimating; }; } // namespace winrt::ServoApp::implementation diff --git a/support/hololens/ServoApp/BrowserPage.xaml b/support/hololens/ServoApp/BrowserPage.xaml index 4247c9a1f68..f6e6e227318 100644 --- a/support/hololens/ServoApp/BrowserPage.xaml +++ b/support/hololens/ServoApp/BrowserPage.xaml @@ -20,8 +20,10 @@ <ColumnDefinition Width="auto"/> </Grid.ColumnDefinitions> <StackPanel Orientation="Horizontal" Grid.Column="0"> - <Button Content="Back" Click="OnBackButtonClicked"/> - <Button Content="Forward" Click="OnForwardButtonClicked"/> + <Button x:Name="backButton" IsEnabled="false" Content="Back" Click="OnBackButtonClicked"/> + <Button x:Name="forwardButton" IsEnabled="false" Content="Forward" Click="OnForwardButtonClicked"/> + <Button x:Name="reloadButton" IsEnabled="false" Content="reload" Click="OnReloadButtonClicked"/> + <Button x:Name="stopButton" IsEnabled="false" Content="stop" Click="OnStopButtonClicked"/> </StackPanel> <TextBox Text="" AcceptsReturn="True" PlaceholderText="Type a URL" x:Name="urlTextbox" Grid.Column="1" IsReadOnly="True"/> <StackPanel Orientation="Horizontal" Grid.Column="2"> diff --git a/support/hololens/ServoApp/Common/DeviceResources.h b/support/hololens/ServoApp/Common/DeviceResources.h index ff0248b221d..f4bb4a0030f 100644 --- a/support/hololens/ServoApp/Common/DeviceResources.h +++ b/support/hololens/ServoApp/Common/DeviceResources.h @@ -1,5 +1,4 @@ - -#pragma once +#pragma once #include "CameraResources.h" diff --git a/support/hololens/ServoApp/Servo.cpp b/support/hololens/ServoApp/Servo.cpp index b262d420819..4283b66bc11 100644 --- a/support/hololens/ServoApp/Servo.cpp +++ b/support/hololens/ServoApp/Servo.cpp @@ -1,55 +1,38 @@ #include "pch.h" #include "Servo.h" -void on_load_started() {} -void on_load_ended() {} -void on_history_changed(bool, bool) {} -void on_shutdown_complete() {} +// FIXME: rename mozilla to something else +namespace servo { -std::function<void()> Servo::sFlush = []() {}; -std::function<void()> Servo::sMakeCurrent = []() {}; -std::function<void()> Servo::sWakeUp = []() {}; -std::function<void(std::wstring const &)> Servo::sOnAlert = - [](std::wstring const &) {}; -std::function<void(std::wstring const &)> Servo::sOnTitleChanged = - [](std::wstring const &) {}; -std::function<void(std::wstring const &)> Servo::sOnURLChanged = - [](std::wstring const &) {}; - -bool Servo::sAnimating = false; - -std::wstring char2w(const char *c_str) { - auto str = std::string(c_str); - int size_needed = - MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0); - std::wstring str2(size_needed, 0); - MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &str2[0], - size_needed); - return str2; +void on_load_started() { sServo->Delegate().OnLoadStarted(); } +void on_load_ended() { sServo->Delegate().OnLoadEnded(); } +void on_history_changed(bool back, bool forward) { + sServo->Delegate().OnHistoryChanged(back, forward); +} +void on_shutdown_complete() { sServo->Delegate().OnShutdownComplete(); } +void on_alert(const char *message) { + sServo->Delegate().OnAlert(char2w(message)); } - -void on_alert(const char *message) { Servo::sOnAlert(char2w(message)); } - void on_title_changed(const char *title) { - Servo::sOnTitleChanged(char2w(title)); + sServo->Delegate().OnTitleChanged(char2w(title)); +} +void on_url_changed(const char *url) { + sServo->Delegate().OnURLChanged(char2w(url)); +} +void flush() { sServo->Delegate().Flush(); } +void make_current() { sServo->Delegate().MakeCurrent(); } +void wakeup() { sServo->Delegate().WakeUp(); } +bool on_allow_navigation(const char *url) { + return sServo->Delegate().OnAllowNavigation(char2w(url)); +}; +void on_animating_changed(bool aAnimating) { + sServo->Delegate().OnAnimatingChanged(aAnimating); } -void on_url_changed(const char *url) { Servo::sOnURLChanged(char2w(url)); } - -void flush() { Servo::sFlush(); } - -void make_current() { Servo::sMakeCurrent(); } - -void wakeup() { Servo::sWakeUp(); } - -bool on_allow_navigation(const char *url) { return true; }; - -void on_animating_changed(bool aAnimating) { Servo::sAnimating = aAnimating; } - -Servo::Servo(GLsizei width, GLsizei height) - : mAnimating(false), mWindowHeight(height), mWindowWidth(width) { +Servo::Servo(GLsizei width, GLsizei height, ServoDelegate &aDelegate) + : mWindowHeight(height), mWindowWidth(width), mDelegate(aDelegate) { - CInitOptions o; + capi::CInitOptions o; o.args = NULL; o.url = "https://servo.org"; o.width = mWindowWidth; @@ -58,7 +41,9 @@ Servo::Servo(GLsizei width, GLsizei height) o.enable_subpixel_text_antialiasing = false; o.vr_pointer = NULL; - CHostCallbacks c; + sServo = this; // FIXME; + + capi::CHostCallbacks c; c.flush = &flush; c.make_current = &make_current; c.on_alert = &on_alert; @@ -74,23 +59,16 @@ Servo::Servo(GLsizei width, GLsizei height) init_with_egl(o, &wakeup, c); } -Servo::~Servo() { deinit(); } - -void Servo::PerformUpdates() { perform_updates(); } - -void Servo::SetBatchMode(bool mode) { set_batch_mode(mode); } - -void Servo::GoForward() { go_forward(); } - -void Servo::GoBack() { go_back(); } +Servo::~Servo() { capi::deinit(); } -void Servo::SetSize(GLsizei width, GLsizei height) { - if (width != mWindowWidth || height != mWindowHeight) { - mWindowWidth = width; - mWindowHeight = height; - resize(mWindowWidth, mWindowHeight); - } +std::wstring char2w(const char *c_str) { + auto str = std::string(c_str); + int size_needed = + MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0); + std::wstring str2(size_needed, 0); + MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &str2[0], + size_needed); + return str2; } -void Servo::Click(float x, float y) { click(x, y); } -void Servo::Scroll(float dx, float dy, float x, float y) { scroll(dx, dy, x, y); } +} // namespace mozilla diff --git a/support/hololens/ServoApp/Servo.h b/support/hololens/ServoApp/Servo.h index 2772d5ea20b..17f283cdf56 100644 --- a/support/hololens/ServoApp/Servo.h +++ b/support/hololens/ServoApp/Servo.h @@ -5,37 +5,73 @@ #pragma once #include "pch.h" +#include "logs.h" +namespace servo { + +namespace capi { extern "C" { #include <simpleservo.h> } +} // namespace capi + +class ServoDelegate { +public: + // Called from any thread + virtual void WakeUp() = 0; + // Called from GL thread + virtual void OnLoadStarted() = 0; + virtual void OnLoadEnded() = 0; + virtual void OnHistoryChanged(bool, bool) = 0; + virtual void OnShutdownComplete() = 0; + virtual void OnTitleChanged(std::wstring) = 0; + virtual void OnAlert(std::wstring) = 0; + virtual void OnURLChanged(std::wstring) = 0; + virtual void Flush() = 0; + virtual void MakeCurrent() = 0; + virtual bool OnAllowNavigation(std::wstring) = 0; + virtual void OnAnimatingChanged(bool) = 0; + +protected: + virtual ~ServoDelegate(){log("A1");}; +}; class Servo { public: - Servo(GLsizei width, GLsizei height); + Servo(GLsizei, GLsizei, ServoDelegate &); ~Servo(); - void PerformUpdates(); - void Click(float, float); - void Scroll(float dx, float dy, float x, float y); - void SetSize(GLsizei width, GLsizei height); - void SetBatchMode(bool); - void GoBack(); - void GoForward(); - - // Static lambas called by Servo callbacks. - - // Will be called from any thead - static std::function<void()> sWakeUp; - // Will be called from GL thread - static std::function<void()> sFlush; - static std::function<void()> sMakeCurrent; - static std::function<void(std::wstring const &)> sOnAlert; - static std::function<void(std::wstring const &)> sOnTitleChanged; - static std::function<void(std::wstring const &)> sOnURLChanged; - static bool sAnimating; + ServoDelegate &Delegate() { return mDelegate; } + + void PerformUpdates() { capi::perform_updates(); } + void RequestShutdown() { capi::request_shutdown(); } + void SetBatchMode(bool mode) { capi::set_batch_mode(mode); } + void GoForward() { capi::go_forward(); } + void GoBack() { capi::go_back(); } + void Click(float x, float y) { capi::click(x, y); } + void Reload() { capi::reload(); } + void Stop() { capi::stop(); } + void Scroll(float dx, float dy, float x, float y) { + capi::scroll(dx, dy, x, y); + } + void SetSize(GLsizei width, GLsizei height) { + if (width != mWindowWidth || height != mWindowHeight) { + mWindowWidth = width; + mWindowHeight = height; + capi::resize(mWindowWidth, mWindowHeight); + } + } private: + ServoDelegate &mDelegate; GLsizei mWindowWidth; GLsizei mWindowHeight; - bool mAnimating; }; + +// This is sad. We need a static pointer to Servo because we use function +// pointer as callback in Servo, and these functions need a way to get +// the Servo instance. See https://github.com/servo/servo/issues/22967 +static Servo *sServo = nullptr; + +std::wstring char2w(const char *c_str); + +} // namespace servo diff --git a/support/hololens/ServoApp/pch.h b/support/hololens/ServoApp/pch.h index c8689fab90e..0b8e6047454 100644 --- a/support/hololens/ServoApp/pch.h +++ b/support/hololens/ServoApp/pch.h @@ -1,5 +1,6 @@ #pragma once +#include <functional> #include <future> #include <hstring.h> #include <map> |