Commit 181d852d authored by Ella Ge's avatar Ella Ge Committed by Commit Bot

Add gesture_provider to mac

We were skipping Mac PointerEvent tests with pointerType = 'touch'
because mac doesn't have touch event support.
This CL adds InjectTouchEvent function in mac RWHV, which supports injecting
WebTouchEvent to mac platform.
This adds gesture_provider to mac RWHV for testing purpose and will be used
on touch emulator in the future.

Tests with multiple touch point is still failing because of an
issue with SyntheticTouchDriver. Still skip these tests(crbug.com/613672)

This Cl also correct that screen coordinate wasn't set when creating
synthetic WebMouseEvent.
Because of that PointerLock movementX_Y test is failing. On mac,
movement_delta was set from NS event. The injected event doesn't set
the movement. Skip these two tests until crbug.com/802067 is resolved.

Bug: 613672
Change-Id: I78d442032ff36da2bc1ad3b84cc8ba9181ae8f0a
Reviewed-on: https://chromium-review.googlesource.com/1039773
Commit-Queue: Ella Ge <eirage@chromium.org>
Reviewed-by: default avatarTimothy Dresser <tdresser@chromium.org>
Reviewed-by: default avatarenne <enne@chromium.org>
Reviewed-by: default avatarJames MacLean <wjmaclean@chromium.org>
Reviewed-by: default avatarNavid Zolghadr <nzolghadr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#556443}
parent 611d4005
......@@ -20,6 +20,9 @@ class SyntheticGestureTargetMac : public SyntheticGestureTargetBase {
// SyntheticGestureTarget:
void DispatchInputEventToPlatform(const blink::WebInputEvent& event) override;
void DispatchWebTouchEventToPlatform(
const blink::WebTouchEvent& event,
const ui::LatencyInfo& latency_info) override;
private:
RenderWidgetHostViewCocoa* cocoa_view_;
......
......@@ -131,4 +131,10 @@ void SyntheticGestureTargetMac::DispatchInputEventToPlatform(
SyntheticGestureTargetBase::DispatchInputEventToPlatform(event);
}
void SyntheticGestureTargetMac::DispatchWebTouchEventToPlatform(
const blink::WebTouchEvent& web_touch,
const ui::LatencyInfo& latency_info) {
render_widget_host()->GetView()->InjectTouchEvent(web_touch, latency_info);
}
} // namespace content
......@@ -327,6 +327,9 @@ class CONTENT_EXPORT RenderWidgetHostViewBase
gfx::PointF* transformed_point,
bool* out_query_renderer);
virtual void InjectTouchEvent(const blink::WebTouchEvent& event,
const ui::LatencyInfo& latency) {}
virtual void PreProcessMouseEvent(const blink::WebMouseEvent& event) {}
virtual void PreProcessTouchEvent(const blink::WebTouchEvent& event) {}
......
......@@ -25,6 +25,7 @@
#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
#include "ui/accelerated_widget_mac/display_link_mac.h"
#include "ui/base/cocoa/remote_layer_api.h"
#include "ui/events/gesture_detection/filtered_gesture_provider.h"
namespace content {
class CursorManager;
......@@ -67,6 +68,7 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
public RenderWidgetHostNSViewClient,
public BrowserCompositorMacClient,
public TextInputManager::Observer,
public ui::GestureProviderClient,
public ui::AcceleratedWidgetMacNSView,
public IPC::Sender {
public:
......@@ -120,6 +122,7 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
void UpdateCursor(const WebCursor& cursor) override;
void DisplayCursor(const WebCursor& cursor) override;
CursorManager* GetCursorManager() override;
void OnDidNavigateMainFrameToNewPage() override;
void SetIsLoading(bool is_loading) override;
void RenderProcessGone(base::TerminationStatus status,
int error_code) override;
......@@ -166,6 +169,8 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
bool IsKeyboardLocked() override;
void GestureEventAck(const blink::WebGestureEvent& event,
InputEventAckState ack_result) override;
void ProcessAckedTouchEvent(const TouchEventWithLatencyInfo& touch,
InputEventAckState ack_result) override;
void DidOverscroll(const ui::DidOverscrollParams& params) override;
......@@ -184,6 +189,11 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// consumer, such as PDF or maps, wants to intercept them and implement a
// custom behavior.
void SendGesturePinchEvent(blink::WebGestureEvent* event);
// Inject synthetic touch events.
void InjectTouchEvent(const blink::WebTouchEvent& event,
const ui::LatencyInfo& latency_info) override;
bool TransformPointToLocalCoordSpace(const gfx::PointF& point,
const viz::SurfaceId& original_surface,
gfx::PointF* transformed_point) override;
......@@ -209,15 +219,15 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
void OnTextSelectionChanged(TextInputManager* text_input_manager,
RenderWidgetHostViewBase* updated_view) override;
// ui::GestureProviderClient implementation.
void OnGestureEvent(const ui::GestureEventData& gesture) override;
// RenderFrameMetadataProvider::Observer
void OnRenderFrameMetadataChanged() override;
// IPC::Sender implementation.
bool Send(IPC::Message* message) override;
// Forwards the mouse event to the renderer.
void ForwardMouseEvent(const blink::WebMouseEvent& event);
void SetTextInputActive(bool active);
// Returns true and stores first rectangle for character range if the
......@@ -515,6 +525,10 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// Used to track active password input sessions.
std::unique_ptr<ui::ScopedPasswordInputEnabler> password_input_enabler_;
// Provides gesture synthesis given a stream of touch events and touch event
// acks. This is for generating gesture events from injected touch events.
ui::FilteredGestureProvider gesture_provider_;
// Used to ensure that a consistent RenderWidgetHost is targeted throughout
// the duration of a keyboard event.
bool in_keyboard_event_ = false;
......
......@@ -19,6 +19,7 @@
#include "base/strings/utf_string_conversions.h"
#include "content/browser/accessibility/browser_accessibility_manager_mac.h"
#include "content/browser/renderer_host/cursor_manager.h"
#include "content/browser/renderer_host/input/motion_event_web.h"
#import "content/browser/renderer_host/input/synthetic_gesture_target_mac.h"
#include "content/browser/renderer_host/input/web_input_event_builders_mac.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
......@@ -28,6 +29,7 @@
#import "content/browser/renderer_host/render_widget_host_ns_view_bridge.h"
#import "content/browser/renderer_host/render_widget_host_view_cocoa.h"
#import "content/browser/renderer_host/text_input_client_mac.h"
#import "content/browser/renderer_host/ui_events_helper.h"
#include "content/common/text_input_state.h"
#include "content/common/view_messages.h"
#include "content/public/browser/browser_context.h"
......@@ -45,6 +47,7 @@
#include "ui/base/cocoa/text_services_context_menu.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/events/gesture_detection/gesture_provider_config_helper.h"
#include "ui/events/keycodes/dom/dom_code.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/mac/coordinate_conversion.h"
......@@ -53,6 +56,7 @@
using blink::WebInputEvent;
using blink::WebMouseEvent;
using blink::WebGestureEvent;
using blink::WebTouchEvent;
namespace content {
......@@ -132,6 +136,9 @@ RenderWidgetHostViewMac::RenderWidgetHostViewMac(RenderWidgetHost* widget,
is_loading_(false),
allow_pause_for_resize_or_repaint_(true),
is_guest_view_hack_(is_guest_view_hack),
gesture_provider_(ui::GetGestureProviderConfig(
ui::GestureProviderConfigType::CURRENT_PLATFORM),
this),
weak_factory_(this) {
// The NSView is on the other side of |ns_view_bridge_|.
ns_view_bridge_ = RenderWidgetHostNSViewBridge::Create(this);
......@@ -415,6 +422,10 @@ CursorManager* RenderWidgetHostViewMac::GetCursorManager() {
return cursor_manager_.get();
}
void RenderWidgetHostViewMac::OnDidNavigateMainFrameToNewPage() {
gesture_provider_.ResetDetection();
}
void RenderWidgetHostViewMac::SetIsLoading(bool is_loading) {
is_loading_ = is_loading;
// If we ever decide to show the waiting cursor while the page is loading
......@@ -521,6 +532,22 @@ void RenderWidgetHostViewMac::OnTextSelectionChanged(
selection->range());
}
void RenderWidgetHostViewMac::OnGestureEvent(
const ui::GestureEventData& gesture) {
blink::WebGestureEvent web_gesture =
ui::CreateWebGestureEventFromGestureEventData(gesture);
ui::LatencyInfo latency_info(ui::SourceEventType::TOUCH);
if (ShouldRouteEvent(web_gesture)) {
blink::WebGestureEvent gesture_event(web_gesture);
host()->delegate()->GetInputEventRouter()->RouteGestureEvent(
this, &gesture_event, latency_info);
} else {
host()->ForwardGestureEventWithLatencyInfo(web_gesture, latency_info);
}
}
void RenderWidgetHostViewMac::OnRenderFrameMetadataChanged() {
last_frame_root_background_color_ = host()
->render_frame_metadata_provider()
......@@ -1015,6 +1042,23 @@ void RenderWidgetHostViewMac::GestureEventAck(const WebGestureEvent& event,
mouse_wheel_phase_handler_.GestureEventAck(event, ack_result);
}
void RenderWidgetHostViewMac::ProcessAckedTouchEvent(
const TouchEventWithLatencyInfo& touch,
InputEventAckState ack_result) {
const bool event_consumed = ack_result == INPUT_EVENT_ACK_STATE_CONSUMED;
gesture_provider_.OnTouchEventAck(
touch.event.unique_touch_event_id, event_consumed,
InputEventAckStateIsSetNonBlocking(ack_result));
if (touch.event.touch_start_or_first_touch_move && event_consumed &&
host()->delegate() && host()->delegate()->GetInputEventRouter()) {
host()
->delegate()
->GetInputEventRouter()
->OnHandledTouchStartOrFirstTouchMove(
touch.event.unique_touch_event_id);
}
}
void RenderWidgetHostViewMac::DidOverscroll(
const ui::DidOverscrollParams& params) {
[cocoa_view() processedOverscroll:params];
......@@ -1041,9 +1085,8 @@ bool RenderWidgetHostViewMac::ShouldRouteEvent(
// See also RenderWidgetHostViewAura::ShouldRouteEvent.
// TODO(wjmaclean): Update this function if RenderWidgetHostViewMac implements
// OnTouchEvent(), to match what we are doing in RenderWidgetHostViewAura.
DCHECK(WebInputEvent::IsMouseEventType(event.GetType()) ||
event.GetType() == WebInputEvent::kMouseWheel ||
WebInputEvent::IsPinchGestureEventType(event.GetType()));
// The only touch events and touch gesture events expected here are
// injected synthetic events.
return host()->delegate() && host()->delegate()->GetInputEventRouter();
}
......@@ -1059,6 +1102,23 @@ void RenderWidgetHostViewMac::SendGesturePinchEvent(WebGestureEvent* event) {
host()->ForwardGestureEvent(*event);
}
void RenderWidgetHostViewMac::InjectTouchEvent(
const WebTouchEvent& event,
const ui::LatencyInfo& latency_info) {
ui::FilteredGestureProvider::TouchHandlingResult result =
gesture_provider_.OnTouchEvent(MotionEventWeb(event));
if (!result.succeeded)
return;
if (ShouldRouteEvent(event)) {
WebTouchEvent touch_event(event);
host()->delegate()->GetInputEventRouter()->RouteTouchEvent(
this, &touch_event, latency_info);
} else {
host()->ForwardTouchEventWithLatencyInfo(event, latency_info);
}
}
bool RenderWidgetHostViewMac::TransformPointToLocalCoordSpace(
const gfx::PointF& point,
const viz::SurfaceId& original_surface,
......
......@@ -35,6 +35,7 @@ WebMouseEvent SyntheticWebMouseEventBuilder::Build(
DCHECK(WebInputEvent::IsMouseEventType(type));
WebMouseEvent result(type, modifiers, ui::EventTimeForNow());
result.SetPositionInWidget(window_x, window_y);
result.SetPositionInScreen(window_x, window_y);
result.SetModifiers(modifiers);
result.pointer_type = pointer_type;
result.id = ui::MouseEvent::kMousePointerId;
......@@ -198,6 +199,7 @@ int SyntheticWebTouchEvent::PressPoint(float x, float y) {
point.rotation_angle = 1.f;
point.force = 1.f;
point.tilt_x = point.tilt_y = 0;
point.pointer_type = blink::WebPointerProperties::PointerType::kTouch;
++touches_length;
WebTouchEventTraits::ResetType(WebInputEvent::kTouchStart, TimeStamp(), this);
return point.id;
......
......@@ -117,14 +117,6 @@ bool ActionsParser::ParsePointerActions(const base::DictionaryValue& pointer) {
if (source_type_.empty()) {
source_type_ = source_type;
#if defined(OS_MACOSX)
if (source_type == "touch") {
error_message_ =
base::StringPrintf("Mac OS does not support touch events");
return false;
}
#endif // defined(OS_MACOSX)
}
if (source_type_ != source_type) {
......
......@@ -2359,66 +2359,23 @@ crbug.com/662010 [ Win7 ] http/tests/csspaint/invalidation-background-image.html
crbug.com/807152 vr/VRDisplay_rAF_fires_with_window_rAF.html [ Pass Failure ]
crbug.com/813697 vr/getFrameData_oneframeupdate.html [ Pass Failure ]
crbug.com/806357 [ Win Debug ] fast/events/pointerevents/pointerevent_touch-action-pinch_zoom_touch.html [ Pass Failure ]
crbug.com/839038 [ Mac ] external/wpt/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html [ Skip ]
# These tests are skipped as there is no touch support on Mac.
crbug.com/613672 [ Mac ] fast/events/touch/multi-touch-user-gesture.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/mouseevent_fractional/fast/events/touch/multi-touch-user-gesture.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/scroll_customization/fast/events/touch/multi-touch-user-gesture.html [ Skip ]
crbug.com/613672 [ Mac ] fast/events/pointerevents/multi-pointer-event-in-slop-region.html [ Skip ]
crbug.com/613672 [ Mac ] fast/events/pointerevents/pointerevent_touch-action-pinch_zoom_touch.html [ Skip ]
crbug.com/806357 [ Win Debug ] fast/events/pointerevents/pointerevent_touch-action-pinch_zoom_touch.html [ Pass Failure ]
crbug.com/613672 [ Mac ] fast/events/pointerevents/pointerevent_touch-adjustment_click_target.html [ Skip ]
crbug.com/613672 [ Mac ] fast/events/pointerevents/pointer-event-consumed-touchstart-in-slop-region.html [ Skip ]
crbug.com/613672 [ Mac ] fast/events/pointerevents/pointer-event-in-slop-region.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerlock/pointerevent_movementxy-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/compat/pointerevent_touch-action_two-finger_interaction-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/extension/pointerevent_coalesced_events_attributes-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_sequence_at_implicit_release_on_drag-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_sequence_at_implicit_release_on_click-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_boundary_events_in_capturing-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_attributes_nohover_pointers-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_change-touch-action-onpointerdown_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_pointerleave_after_pointercancel_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_pointercancel_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_releasepointercapture_events_to_original_target-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_releasepointercapture_onpointercancel_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_pointerout_after_pointercancel_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-auto-css_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/extension/pointerevent_touch-action-pan-left-css_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/extension/pointerevent_touch-action-pan-right-css_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/extension/pointerevent_touch-action-pan-up-css_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/extension/pointerevent_touch-action-pan-down-css_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-button-test_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-table-test_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-inherit_highest-parent-none_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-span-test_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-svg-test_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-x_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-none-css_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-inherit_parent-none_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-none_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-pan-x-child-pan-y_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_touch-action-inherit_child-auto-child-none_touch-manual.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/pointerevent_fractional_coordinates-manual.html [ Skip ]
crbug.com/613672 [ Mac ] fast/events/synthetic-events/tap-on-scaled-screen.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/scalefactor150/fast/events/synthetic-events/tap-on-scaled-screen.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/mouseevent_fractional/fast/events/pointerevents/multi-pointer-event-in-slop-region.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/mouseevent_fractional/fast/events/pointerevents/pointerevent_touch-action-pinch_zoom_touch.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/mouseevent_fractional/fast/events/pointerevents/pointerevent_touch-adjustment_click_target.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/mouseevent_fractional/fast/events/pointerevents/pointer-event-consumed-touchstart-in-slop-region.html [ Skip ]
crbug.com/613672 [ Mac ] fast/events/pointerevents/pointer-event-in-slop-region.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/mouseevent_fractional/fast/events/pointerevents/pointer-event-in-slop-region.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/mouseevent_fractional/fast/events/synthetic-events/tap-on-scaled-screen.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/scroll_customization/fast/scroll-behavior/scroll-customization/scroll-customization-property.html [ Skip ]
crbug.com/613672 [ Mac ] media/controls/modern/tap-to-hide-controls.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/video-surface-layer/media/controls/modern/tap-to-hide-controls.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/new-remote-playback-pipeline/media/controls/modern/tap-to-hide-controls.html [ Skip ]
crbug.com/613672 [ Mac ] media/controls/modern/singletouch-on-play-button.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/video-surface-layer/media/controls/modern/singletouch-on-play-button.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/new-remote-playback-pipeline/media/controls/modern/singletouch-on-play-button.html [ Skip ]
crbug.com/613672 [ Mac ] fast/events/pointerevents/pointerevent_touch-action-pinch_zoom_touch.html [ Skip ]
crbug.com/613672 [ Mac ] virtual/mouseevent_fractional/fast/events/pointerevents/pointerevent_touch-action-pinch_zoom_touch.html [ Skip ]
crbug.com/613672 [ Mac ] external/wpt/pointerevents/compat/pointerevent_touch-action_two-finger_interaction-manual.html [ Skip ]
crbug.com/802067 [ Mac ] external/wpt/pointerlock/movementX_Y_basic-manual.html [ Failure ]
crbug.com/802067 [ Mac ] external/wpt/pointerevents/pointerlock/pointerevent_movementxy-manual.html [ Failure ]
# We should send PointerLeave events for stylus devices.
crbug.com/583413 external/wpt/pointerevents/pointerevent_pointerleave_pen-manual.html [ Failure ]
......
This is a testharness.js-based test.
PASS touch coalesced events attributes in pointerevents
PASS PointerEvent Automation
PASS touch pointercancel should not have any coalesced events
PASS touch pointerover should not have any coalesced events
PASS touch pointerenter should not have any coalesced events
PASS touch pointerdown should not have any coalesced events
FAIL touch pointermove should have >2 coalesced events as main thread is busy. assert_greater_than: pointermove should have at least 2 coalesced events. expected a number greater than 1 but got 1
PASS touch pointermove coalesced events should all be marked as trusted.
PASS touch time stamps of coalesced events must be ascending.
PASS touch pointermove coalesced events should all bubbles and cancelable as false.
PASS touch pointerup should not have any coalesced events
PASS touch pointerout should not have any coalesced events
PASS touch pointerleave should not have any coalesced events
Harness: the test ran to completion.
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