Commit 502b5a8a authored by Sergey Ulanov's avatar Sergey Ulanov Committed by Commit Bot

[Fuchsia, ozone] Implement ScenicWindow

ScenicWindow now creates View and listens to input events (mouse and keyboard).

Bug: 829980
Change-Id: If5d05bf1107fec553aecf2537fd197d177d2fbb1
Reviewed-on: https://chromium-review.googlesource.com/1081609
Commit-Queue: Sergey Ulanov <sergeyu@chromium.org>
Reviewed-by: default avatarRobert Kroeger <rjkroege@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarWez <wez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568293}
parent fdf2d30a
......@@ -29,6 +29,8 @@ source_set("scenic") {
"//third_party/fuchsia-sdk:images",
"//third_party/fuchsia-sdk:mem",
"//third_party/fuchsia-sdk:scenic",
"//third_party/fuchsia-sdk:views_v1",
"//third_party/fuchsia-sdk:views_v1_token",
"//ui/base",
"//ui/display/manager",
"//ui/events/ozone:events_ozone_layout",
......
......@@ -75,8 +75,12 @@ class OzonePlatformScenic : public OzonePlatform {
std::unique_ptr<PlatformWindow> CreatePlatformWindow(
PlatformWindowDelegate* delegate,
PlatformWindowInitProperties properties) override {
NOTREACHED();
return nullptr;
if (!properties.view_owner_request) {
NOTREACHED();
return nullptr;
}
return std::make_unique<ScenicWindow>(
&window_manager_, delegate, std::move(properties.view_owner_request));
}
std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate()
......
......@@ -6,6 +6,9 @@
#include <string>
#include <fuchsia/sys/cpp/fidl.h>
#include "base/fuchsia/fuchsia_logging.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
......@@ -16,25 +19,94 @@
namespace ui {
ScenicWindow::ScenicWindow(ScenicWindowManager* window_manager,
PlatformWindowDelegate* delegate)
namespace {
const uint32_t kUsbHidKeyboardPage = 0x07;
int KeyModifiersToFlags(int modifiers) {
int flags = 0;
if (modifiers & fuchsia::ui::input::kModifierShift)
flags |= EF_SHIFT_DOWN;
if (modifiers & fuchsia::ui::input::kModifierControl)
flags |= EF_CONTROL_DOWN;
if (modifiers & fuchsia::ui::input::kModifierAlt)
flags |= EF_ALT_DOWN;
// TODO(crbug.com/850697): Add AltGraph support.
return flags;
}
} // namespace
ScenicWindow::ScenicWindow(
ScenicWindowManager* window_manager,
PlatformWindowDelegate* delegate,
fidl::InterfaceRequest<fuchsia::ui::views_v1_token::ViewOwner>
view_owner_request)
: manager_(window_manager),
delegate_(delegate),
window_id_(manager_->AddWindow(this)) {
delegate_->OnAcceleratedWidgetAvailable(window_id_,
/*device_pixel_ratio=*/1.0);
window_id_(manager_->AddWindow(this)),
view_listener_binding_(this),
scenic_session_(manager_->GetScenic(), this),
input_listener_binding_(this) {
// Create event pair to import parent view node to Scenic. One end is passed
// directly to Scenic in ImportResource command and the second one is passed
// to ViewManager::CreateView(). ViewManager will passes it to Scenic when the
// view is added to a container.
zx::eventpair parent_export_token;
zx::eventpair parent_import_token;
zx_status_t status =
zx::eventpair::create(0u, &parent_import_token, &parent_export_token);
ZX_CHECK(status == ZX_OK, status) << "zx_eventpair_create()";
// Create a new node and add it as a child to the parent.
parent_node_id_ = scenic_session_.ImportResource(
fuchsia::ui::gfx::ImportSpec::NODE, std::move(parent_import_token));
node_id_ = scenic_session_.CreateEntityNode();
scenic_session_.AddNodeChild(parent_node_id_, node_id_);
// Subscribe to metrics events from the parent node. These events are used to
// get |device_pixel_ratio_| for the screen.
scenic_session_.SetEventMask(parent_node_id_,
fuchsia::ui::gfx::kMetricsEventMask);
// Create the view.
manager_->GetViewManager()->CreateView(
view_.NewRequest(), std::move(view_owner_request),
view_listener_binding_.NewBinding(), std::move(parent_export_token),
"Chromium");
view_.set_error_handler(fit::bind_member(this, &ScenicWindow::OnViewError));
view_listener_binding_.set_error_handler(
fit::bind_member(this, &ScenicWindow::OnViewError));
// Setup input event listener.
fuchsia::sys::ServiceProviderPtr view_service_provider;
view_->GetServiceProvider(view_service_provider.NewRequest());
view_service_provider->ConnectToService(
fuchsia::ui::input::InputConnection::Name_,
input_connection_.NewRequest().TakeChannel());
input_connection_->SetEventListener(input_listener_binding_.NewBinding());
// Call Present() to ensure that the scenic session commands are processed,
// which is necessary to receive metrics event from Scenic.
// OnAcceleratedWidgetAvailable() will be called after View metrics are
// received.
scenic_session_.Present();
}
ScenicWindow::~ScenicWindow() {
delegate_->OnAcceleratedWidgetDestroying();
scenic_session_.ReleaseResource(node_id_);
scenic_session_.ReleaseResource(parent_node_id_);
manager_->RemoveWindow(window_id_, this);
view_.Unbind();
delegate_->OnAcceleratedWidgetDestroyed();
}
gfx::Rect ScenicWindow::GetBounds() {
return gfx::Rect(size_);
return gfx::Rect(size_pixels_);
}
void ScenicWindow::SetBounds(const gfx::Rect& bounds) {
......@@ -112,4 +184,167 @@ PlatformImeController* ScenicWindow::GetPlatformImeController() {
return nullptr;
}
void ScenicWindow::UpdateSize() {
gfx::SizeF scaled = ScaleSize(size_dips_, device_pixel_ratio_);
size_pixels_ = gfx::Size(ceilf(scaled.width()), ceilf(scaled.height()));
delegate_->OnBoundsChanged(gfx::Rect(size_pixels_));
}
void ScenicWindow::OnPropertiesChanged(
fuchsia::ui::views_v1::ViewProperties properties,
OnPropertiesChangedCallback callback) {
if (properties.view_layout) {
size_dips_.SetSize(properties.view_layout->size.width,
properties.view_layout->size.height);
if (device_pixel_ratio_ > 0.0)
UpdateSize();
}
callback();
}
void ScenicWindow::OnScenicError(const std::string& error) {
LOG(ERROR) << "ScenicSession failed: " << error;
delegate_->OnClosed();
}
void ScenicWindow::OnScenicEvents(
const std::vector<fuchsia::ui::scenic::Event>& events) {
for (const auto& event : events) {
if (!event.is_gfx() || !event.gfx().is_metrics())
continue;
auto& metrics = event.gfx().metrics();
if (metrics.node_id == parent_node_id_) {
float new_device_pixel_ratio =
std::max(metrics.metrics.scale_x, metrics.metrics.scale_y);
if (device_pixel_ratio_ == 0.0) {
device_pixel_ratio_ = new_device_pixel_ratio;
delegate_->OnAcceleratedWidgetAvailable(window_id_,
device_pixel_ratio_);
if (!size_dips_.IsEmpty())
UpdateSize();
} else if (device_pixel_ratio_ != new_device_pixel_ratio) {
// Ozone currently doesn't support dynamic changes in
// device_pixel_ratio.
// TODO(crbug.com/850650): Update Ozone/Aura to allow DPI changes
// after OnAcceleratedWidgetAvailable().
NOTIMPLEMENTED() << "Ignoring display metrics event.";
}
}
}
}
void ScenicWindow::OnEvent(fuchsia::ui::input::InputEvent event,
OnEventCallback callback) {
bool result = false;
switch (event.Which()) {
case fuchsia::ui::input::InputEvent::Tag::kPointer:
// TODO(crbug.com/829980): Add touch support.
if (event.pointer().type == fuchsia::ui::input::PointerEventType::MOUSE)
result = OnMouseEvent(event.pointer());
break;
case fuchsia::ui::input::InputEvent::Tag::kKeyboard:
result = OnKeyboardEvent(event.keyboard());
break;
case fuchsia::ui::input::InputEvent::Tag::kFocus:
case fuchsia::ui::input::InputEvent::Tag::Invalid:
break;
}
callback(result);
}
void ScenicWindow::OnViewError() {
VLOG(1) << "views_v1::View connection was closed.";
delegate_->OnClosed();
}
bool ScenicWindow::OnMouseEvent(const fuchsia::ui::input::PointerEvent& event) {
int flags = 0;
if (event.buttons & 1)
flags |= EF_LEFT_MOUSE_BUTTON;
if (event.buttons & 2)
flags |= EF_RIGHT_MOUSE_BUTTON;
if (event.buttons & 4)
flags |= EF_MIDDLE_MOUSE_BUTTON;
EventType event_type;
switch (event.phase) {
case fuchsia::ui::input::PointerEventPhase::DOWN:
event_type = ET_MOUSE_PRESSED;
break;
case fuchsia::ui::input::PointerEventPhase::MOVE:
event_type = flags ? ET_MOUSE_DRAGGED : ET_MOUSE_MOVED;
break;
case fuchsia::ui::input::PointerEventPhase::UP:
event_type = ET_MOUSE_RELEASED;
break;
// Following phases are not expected for mouse events.
case fuchsia::ui::input::PointerEventPhase::HOVER:
case fuchsia::ui::input::PointerEventPhase::CANCEL:
case fuchsia::ui::input::PointerEventPhase::ADD:
case fuchsia::ui::input::PointerEventPhase::REMOVE:
NOTREACHED() << "Unexpected mouse phase " << event.phase;
return false;
}
gfx::Point location =
gfx::Point(event.x * device_pixel_ratio_, event.y * device_pixel_ratio_);
ui::MouseEvent mouse_event(event_type, location, location,
base::TimeTicks::FromZxTime(event.event_time),
flags, 0);
delegate_->DispatchEvent(&mouse_event);
return true;
}
bool ScenicWindow::OnKeyboardEvent(
const fuchsia::ui::input::KeyboardEvent& event) {
EventType event_type;
switch (event.phase) {
case fuchsia::ui::input::KeyboardEventPhase::PRESSED:
case fuchsia::ui::input::KeyboardEventPhase::REPEAT:
event_type = ET_KEY_PRESSED;
break;
case fuchsia::ui::input::KeyboardEventPhase::RELEASED:
event_type = ET_KEY_RELEASED;
break;
case fuchsia::ui::input::KeyboardEventPhase::CANCELLED:
NOTIMPLEMENTED() << "Key event cancellation is not supported.";
event_type = ET_KEY_RELEASED;
break;
}
// Currently KeyboardEvent doesn't specify HID Usage page. |hid_usage|
// field always contains values from the Keyboard page. See
// https://fuchsia.atlassian.net/browse/SCN-762 .
DomCode dom_code = KeycodeConverter::UsbKeycodeToDomCode(
(kUsbHidKeyboardPage << 16) | event.hid_usage);
DomKey dom_key;
KeyboardCode key_code;
if (!DomCodeToUsLayoutDomKey(dom_code, KeyModifiersToFlags(event.modifiers),
&dom_key, &key_code)) {
LOG(ERROR) << "DomCodeToUsLayoutDomKey() failed for usb_key: "
<< event.hid_usage;
key_code = VKEY_UNKNOWN;
}
if (event.code_point)
dom_key = DomKey::FromCharacter(event.code_point);
KeyEvent key_event(ET_KEY_PRESSED, key_code, dom_code,
KeyModifiersToFlags(event.modifiers), dom_key,
base::TimeTicks::FromZxTime(event.event_time));
delegate_->DispatchEvent(&key_event);
return true;
}
} // namespace ui
......@@ -5,10 +5,16 @@
#ifndef UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_H_
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_H_
#include <fuchsia/ui/input/cpp/fidl.h>
#include <fuchsia/ui/views_v1/cpp/fidl.h>
#include "base/macros.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/ozone_export.h"
#include "ui/ozone/platform/scenic/scenic_session.h"
#include "ui/platform_window/platform_window.h"
namespace ui {
......@@ -16,13 +22,25 @@ namespace ui {
class ScenicWindowManager;
class PlatformWindowDelegate;
class OZONE_EXPORT ScenicWindow : public PlatformWindow {
class OZONE_EXPORT ScenicWindow : public PlatformWindow,
public ScenicSessionListener,
public fuchsia::ui::views_v1::ViewListener,
public fuchsia::ui::input::InputListener {
public:
// Both |window_manager| and |delegate| must outlive the ScenicWindow.
// |view_owner_request| is passed to the view managed when creating the
// underlying view. In order for the View to be displayed the ViewOwner must
// be used to add the view to a ViewContainer.
ScenicWindow(ScenicWindowManager* window_manager,
PlatformWindowDelegate* delegate);
PlatformWindowDelegate* delegate,
fidl::InterfaceRequest<fuchsia::ui::views_v1_token::ViewOwner>
view_owner_request);
~ScenicWindow() override;
ScenicSession* scenic_session() { return &scenic_session_; }
ScenicSession::ResourceId node_id() const { return node_id_; }
float device_pixel_ratio() const { return device_pixel_ratio_; }
// PlatformWindow implementation.
gfx::Rect GetBounds() override;
void SetBounds(const gfx::Rect& bounds) override;
......@@ -45,11 +63,59 @@ class OZONE_EXPORT ScenicWindow : public PlatformWindow {
PlatformImeController* GetPlatformImeController() override;
private:
// views::ViewListener interface.
void OnPropertiesChanged(fuchsia::ui::views_v1::ViewProperties properties,
OnPropertiesChangedCallback callback) override;
// fuchsia::ui::input::InputListener interface.
void OnEvent(fuchsia::ui::input::InputEvent event,
OnEventCallback callback) override;
// ScenicSessionListener interface.
void OnScenicError(const std::string& error) override;
void OnScenicEvents(
const std::vector<fuchsia::ui::scenic::Event>& events) override;
// Error handler for |view_|. This error normally indicates the View was
// destroyed (e.g. dropping ViewOwner).
void OnViewError();
void UpdateSize();
bool OnMouseEvent(const fuchsia::ui::input::PointerEvent& event);
bool OnKeyboardEvent(const fuchsia::ui::input::KeyboardEvent& event);
ScenicWindowManager* const manager_;
PlatformWindowDelegate* const delegate_;
gfx::AcceleratedWidget const window_id_;
gfx::Size size_;
// Underlying View in the view_manager.
fuchsia::ui::views_v1::ViewPtr view_;
fidl::Binding<fuchsia::ui::views_v1::ViewListener> view_listener_binding_;
// Scenic session used for all drawing operations in this View.
ScenicSession scenic_session_;
// Node ID in |scenic_session_| for the parent view.
ScenicSession::ResourceId parent_node_id_;
// Node ID in |scenic_session_| for the view.
ScenicSession::ResourceId node_id_;
// Current view size in DIPs.
gfx::SizeF size_dips_;
// Current view size in device pixels.
gfx::Size size_pixels_;
// Device pixel ratio for the current device. Initialized in
// OnPropertiesChanged().
float device_pixel_ratio_ = 0.0;
// InputConnection and InputListener binding used to receive input events from
// the view.
fuchsia::ui::input::InputConnectionPtr input_connection_;
fidl::Binding<fuchsia::ui::input::InputListener> input_listener_binding_;
DISALLOW_COPY_AND_ASSIGN(ScenicWindow);
};
......
......@@ -11,6 +11,27 @@ namespace ui {
ScenicWindowManager::ScenicWindowManager() = default;
ScenicWindowManager::~ScenicWindowManager() = default;
fuchsia::ui::views_v1::ViewManager* ScenicWindowManager::GetViewManager() {
if (!view_manager_) {
view_manager_ =
base::fuchsia::ComponentContext::GetDefault()
->ConnectToService<fuchsia::ui::views_v1::ViewManager>();
view_manager_.set_error_handler(
[this]() { LOG(FATAL) << "ViewManager connection failed."; });
}
return view_manager_.get();
}
fuchsia::ui::scenic::Scenic* ScenicWindowManager::GetScenic() {
if (!scenic_) {
GetViewManager()->GetScenic(scenic_.NewRequest());
scenic_.set_error_handler(
[this]() { LOG(FATAL) << "Scenic connection failed."; });
}
return scenic_.get();
}
int32_t ScenicWindowManager::AddWindow(ScenicWindow* window) {
return windows_.Add(window);
}
......
......@@ -6,9 +6,10 @@
#define UI_OZONE_PLATFORM_SCENIC_SCENIC_WINDOW_MANAGER_H_
#include <stdint.h>
#include <memory>
#include <fuchsia/ui/views_v1/cpp/fidl.h>
#include "base/containers/id_map.h"
#include "base/macros.h"
#include "base/threading/thread_checker.h"
......@@ -32,6 +33,12 @@ class OZONE_EXPORT ScenicWindowManager {
ScenicWindowManager();
~ScenicWindowManager();
// ViewManager and Scenic services that are used by ScenicWindow. Both
// interfaces are initialized lazily on the first call and they don't change
// afterwards. ScenicWindowManager keeps the ownership.
fuchsia::ui::views_v1::ViewManager* GetViewManager();
fuchsia::ui::scenic::Scenic* GetScenic();
// Called by ScenicWindow when a new window instance is created. Returns
// window ID for the |window|.
int32_t AddWindow(ScenicWindow* window);
......@@ -44,6 +51,9 @@ class OZONE_EXPORT ScenicWindowManager {
private:
base::IDMap<ScenicWindow*> windows_;
fuchsia::ui::views_v1::ViewManagerPtr view_manager_;
fuchsia::ui::scenic::ScenicPtr scenic_;
DISALLOW_COPY_AND_ASSIGN(ScenicWindowManager);
};
......
......@@ -9,6 +9,7 @@ source_set("platform_window") {
"platform_ime_controller.h",
"platform_window.h",
"platform_window_delegate.h",
"platform_window_init_properties.cc",
"platform_window_init_properties.h",
"text_input_state.cc",
"text_input_state.h",
......@@ -20,6 +21,12 @@ source_set("platform_window") {
"//ui/base/ime:text_input_types",
"//ui/gfx",
]
if (is_fuchsia) {
public_deps = [
"//third_party/fuchsia-sdk:views_v1_token",
]
}
}
group("platform_impls") {
......
// Copyright 2018 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.
#include "ui/platform_window/platform_window_init_properties.h"
namespace ui {
PlatformWindowInitProperties::PlatformWindowInitProperties() = default;
PlatformWindowInitProperties::PlatformWindowInitProperties(
PlatformWindowInitProperties&& props) = default;
PlatformWindowInitProperties::~PlatformWindowInitProperties() = default;
} // namespace ui
......@@ -7,9 +7,14 @@
#include <string>
#include "build/build_config.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/native_widget_types.h"
#if defined(OS_FUCHSIA)
#include <fuchsia/ui/views_v1_token/cpp/fidl.h>
#endif
namespace ui {
enum PlatformWindowType {
......@@ -21,6 +26,11 @@ enum PlatformWindowType {
// Initial properties which are passed to PlatformWindow to be initialized
// with a desired set of properties.
struct PlatformWindowInitProperties {
PlatformWindowInitProperties();
PlatformWindowInitProperties(PlatformWindowInitProperties&& props);
~PlatformWindowInitProperties();
// Tells desired PlatformWindow type. It can be popup, menu or anything else.
PlatformWindowType type = PlatformWindowType::PLATFORM_WINDOW_TYPE_WINDOW;
// Sets the desired initial bounds. Can be empty.
......@@ -28,6 +38,11 @@ struct PlatformWindowInitProperties {
// Tells PlatformWindow which native widget its parent holds. It is usually
// used to find a parent from internal list of PlatformWindows.
gfx::AcceleratedWidget parent_widget = gfx::kNullAcceleratedWidget;
#if defined(OS_FUCHSIA)
fidl::InterfaceRequest<fuchsia::ui::views_v1_token::ViewOwner>
view_owner_request;
#endif
};
} // namespace ui
......
......@@ -75,7 +75,7 @@ void DesktopWindowTreeHostPlatform::Init(const Widget::InitParams& params) {
ui::PlatformWindowInitProperties properties =
ConvertWidgetInitParamsToInitProperties(params);
CreateAndSetPlatformWindow(properties);
CreateAndSetPlatformWindow(std::move(properties));
CreateCompositor(viz::FrameSinkId(), params.force_software_compositing);
aura::WindowTreeHost::OnAcceleratedWidgetAvailable();
InitHost();
......
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