Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support w3c DeviceOrientationEvent #602

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions bridge/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ if ($ENV{WEBF_JS_ENGINE} MATCHES "quickjs")
core/events/message_event.cc
core/events/animation_event.cc
core/events/close_event.cc
core/events/deviceorientation_event.cc
core/events/ui_event.cc
core/events/focus_event.cc
core/events/gesture_event.cc
Expand Down Expand Up @@ -431,6 +432,8 @@ if ($ENV{WEBF_JS_ENGINE} MATCHES "quickjs")
out/qjs_hashchange_event.cc
out/qjs_hashchange_event_init.cc
out/qjs_gesture_event_init.cc
out/qjs_deviceorientation_event.cc
out/qjs_deviceorientation_event_init.cc
out/qjs_intersection_change_event.cc
out/qjs_intersection_change_event_init.cc
out/qjs_touch.cc
Expand Down
2 changes: 2 additions & 0 deletions bridge/bindings/qjs/binding_initializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "qjs_event_target.h"
#include "qjs_focus_event.h"
#include "qjs_gesture_event.h"
#include "qjs_deviceorientation_event.h"
#include "qjs_hashchange_event.h"
#include "qjs_html_all_collection.h"
#include "qjs_html_anchor_element.h"
Expand Down Expand Up @@ -120,6 +121,7 @@ void InstallBindings(ExecutingContext* context) {
QJSFocusEvent::Install(context);
QJSGestureEvent::Install(context);
QJSHashchangeEvent::Install(context);
QJSDeviceorientationEvent::Install(context);
QJSInputEvent::Install(context);
QJSCustomEvent::Install(context);
QJSMouseEvent::Install(context);
Expand Down
1 change: 1 addition & 0 deletions bridge/bindings/qjs/wrapper_type_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ enum {
JS_CLASS_FOCUS_EVENT,
JS_CLASS_GESTURE_EVENT,
JS_CLASS_HASHCHANGE_EVENT,
JS_CLASS_DEVICEORIENTATION_EVENT,
JS_CLASS_POP_STATE_EVENT,
JS_CLASS_INTERSECTION_CHANGE_EVENT,
JS_CLASS_KEYBOARD_EVENT,
Expand Down
4 changes: 4 additions & 0 deletions bridge/core/dom/events/event.cc
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,10 @@ bool Event::IsHashChangeEvent() const {
return false;
}

bool Event::IsDeviceorientationEvent() const {
return false;
}

bool Event::IsIntersectionchangeEvent() const {
return false;
}
Expand Down
1 change: 1 addition & 0 deletions bridge/core/dom/events/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ class Event : public ScriptWrappable {
virtual bool IsPopstateEvent() const;
virtual bool IsIntersectionchangeEvent() const;
virtual bool IsHashChangeEvent() const;
virtual bool IsDeviceorientationEvent() const;

// Drag events are a subset of mouse events.
virtual bool IsDragEvent() const;
Expand Down
1 change: 1 addition & 0 deletions bridge/core/events/dart_created_events.json5
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
]
},
"hashchange",
"deviceorientation",
"input",
{
"class": "FocusEvent",
Expand Down
67 changes: 67 additions & 0 deletions bridge/core/events/deviceorientation_event.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (C) 2024-present The WebF authors. All rights reserved.
*/

#include "deviceorientation_event.h"
#include "qjs_deviceorientation_event.h"
#include "qjs_deviceorientation_event_init.h"

namespace webf {

DeviceorientationEvent* DeviceorientationEvent::Create(ExecutingContext* context,
const AtomicString& type,
ExceptionState& exception_state) {
return MakeGarbageCollected<DeviceorientationEvent>(context, type, exception_state);
}

DeviceorientationEvent* DeviceorientationEvent::Create(ExecutingContext* context,
const AtomicString& type,
const std::shared_ptr<DeviceorientationEventInit>& initializer,
ExceptionState& exception_state) {
return MakeGarbageCollected<DeviceorientationEvent>(context, type, initializer, exception_state);
}

DeviceorientationEvent::DeviceorientationEvent(ExecutingContext* context, const AtomicString& type, ExceptionState& exception_state)
: Event(context, type) {}

DeviceorientationEvent::DeviceorientationEvent(ExecutingContext* context,
const AtomicString& type,
const std::shared_ptr<DeviceorientationEventInit>& initializer,
ExceptionState& exception_state)
: Event(context, type),
absolute_(initializer->hasAbsolute() ? initializer->absolute() : 0.0),
alpha_(initializer->hasAlpha() ? initializer->alpha() : 0.0),
beta_(initializer->hasBeta() ? initializer->beta() : 0.0),
gamma_(initializer->hasGamma() ? initializer->gamma() : 0.0) {}

DeviceorientationEvent::DeviceorientationEvent(ExecutingContext* context,
const AtomicString& type,
NativeDeviceorientationEvent* native_orientation_event)
: Event(context, type, &native_orientation_event->native_event),
absolute_(native_orientation_event->absolute),
alpha_(native_orientation_event->alpha),
beta_(native_orientation_event->beta),
gamma_(native_orientation_event->gamma) {
}

bool DeviceorientationEvent::IsDeviceorientationEvent() const {
return true;
}

bool DeviceorientationEvent::absolute() const {
return absolute_;
}

double DeviceorientationEvent::alpha() const {
return alpha_;
}

double DeviceorientationEvent::beta() const {
return beta_;
}

double DeviceorientationEvent::gamma() const {
return gamma_;
}

} // namespace webf
11 changes: 11 additions & 0 deletions bridge/core/events/deviceorientation_event.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {Event} from "../dom/events/event";
import {DeviceorientationEventInit} from "./deviceorientation_event_init";

interface DeviceorientationEvent extends Event {
readonly absolute: boolean;
readonly alpha: number;
readonly beta: number;
readonly gamma: number;
[key: string]: any;
new(type: string, init?: DeviceorientationEventInit): DeviceorientationEvent;
}
56 changes: 56 additions & 0 deletions bridge/core/events/deviceorientation_event.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (C) 2024-present The WebF authors. All rights reserved.
*/

#ifndef BRIDGE_CORE_EVENTS_DEVICE_ORIENTATION_EVENT_H_
#define BRIDGE_CORE_EVENTS_DEVICE_ORIENTATION_EVENT_H_

#include "bindings/qjs/dictionary_base.h"
#include "bindings/qjs/source_location.h"
#include "core/dom/events/event.h"
#include "qjs_deviceorientation_event_init.h"

namespace webf {

struct NativeDeviceorientationEvent;
class DeviceorientationEventInit;

class DeviceorientationEvent : public Event {
DEFINE_WRAPPERTYPEINFO();

public:
using ImplType = DeviceorientationEvent*;

static DeviceorientationEvent* Create(ExecutingContext* context, const AtomicString& type, ExceptionState& exception_state);

static DeviceorientationEvent* Create(ExecutingContext* context,
const AtomicString& type,
const std::shared_ptr<DeviceorientationEventInit>& initializer,
ExceptionState& exception_state);

explicit DeviceorientationEvent(ExecutingContext* context, const AtomicString& type, ExceptionState& exception_state);

explicit DeviceorientationEvent(ExecutingContext* context,
const AtomicString& type,
const std::shared_ptr<DeviceorientationEventInit>& initializer,
ExceptionState& exception_state);

explicit DeviceorientationEvent(ExecutingContext* context, const AtomicString& type, NativeDeviceorientationEvent* native_orientation_event);

bool absolute() const;
double alpha() const;
double beta() const;
double gamma() const;

bool IsDeviceorientationEvent() const override;

private:
bool absolute_;
double alpha_;
double beta_;
double gamma_;
};

} // namespace webf

#endif // BRIDGE_CORE_EVENTS_DEVICE_ORIENTATION_EVENT_H_
10 changes: 10 additions & 0 deletions bridge/core/events/deviceorientation_event_init.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { EventInit } from "../dom/events/event_init";

// @ts-ignore
@Dictionary()
export interface DeviceorientationEventInit extends EventInit {
absolute?: boolean;
alpha?: number;
beta?: number;
gamma?: number;
}
1 change: 1 addition & 0 deletions bridge/core/events/event_type_names.json5
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@
"wheel",
"zoom",
"intersectionchange",
"deviceorientation",
"gcopen"
]
}
27 changes: 27 additions & 0 deletions webf/lib/src/dom/event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ const String EVENT_STATE_START = 'start';
const String EVENT_STATE_UPDATE = 'update';
const String EVENT_STATE_END = 'end';
const String EVENT_STATE_CANCEL = 'cancel';
const String EVENT_DEVICE_ORIENTATION = 'deviceorientation';

mixin ElementEventMixin on ElementBase {
AppearEventType _prevAppearState = AppearEventType.none;
Expand Down Expand Up @@ -393,6 +394,32 @@ class MouseEvent extends UIEvent {
}
}

class DeviceOrientationEvent extends Event {
DeviceOrientationEvent(this.alpha, this.beta, this.gamma) : super(EVENT_DEVICE_ORIENTATION);

final bool absolute = true;
final double alpha;
final double beta;
final double gamma;

@override
Pointer<NativeType> toRaw([int extraLength = 0, bool isCustomEvent = false]) {
List<int> methods = [
absolute ? 1 : 0,
doubleToUint64(alpha),
doubleToUint64(beta),
doubleToUint64(gamma)
];
Pointer<RawEvent> rawEvent = super.toRaw(methods.length).cast<RawEvent>();
int currentStructSize = rawEvent.ref.length + methods.length;
Uint64List bytes = rawEvent.ref.bytes.asTypedList(currentStructSize);
bytes.setAll(rawEvent.ref.length, methods);
rawEvent.ref.length = currentStructSize;

return rawEvent;
}
}

/// reference: https://developer.mozilla.org/en-US/docs/Web/API/GestureEvent
class GestureEvent extends Event {
final String state;
Expand Down
48 changes: 48 additions & 0 deletions webf/lib/src/dom/window.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
* Copyright (C) 2019-2022 The Kraken authors. All rights reserved.
* Copyright (C) 2022-present The WebF authors. All rights reserved.
*/
import 'dart:math' as math;
import 'dart:async';
import 'dart:ui';

import 'package:sensors_plus/sensors_plus.dart';
import 'package:webf/bridge.dart';
import 'package:webf/dom.dart';
import 'package:webf/foundation.dart';
Expand Down Expand Up @@ -117,6 +120,9 @@ class Window extends EventTarget {
// Fired at the Document or element when the viewport or element is scrolled, respectively.
document.documentElement?.addEventListener(eventType, handler, addEventListenerOptions: addEventListenerOptions);
break;
case EVENT_DEVICE_ORIENTATION:
_registerGyroscope();
break;
}
}

Expand All @@ -127,6 +133,9 @@ class Window extends EventTarget {
case EVENT_SCROLL:
document.documentElement?.removeEventListener(eventType, handler);
break;
case EVENT_DEVICE_ORIENTATION:
_unRegisterGyroscope(false);
break;
}
}

Expand All @@ -135,4 +144,43 @@ class Window extends EventTarget {
void focus() {
// TODO
}

StreamSubscription<GyroscopeEvent>? _gyroscopeStream;
void _registerGyroscope() {
_gyroscopeStream ??= gyroscopeEventStream().listen((GyroscopeEvent event) {
dispatchDeviceOrientationEvent(event.x, event.y, event.z);
},
cancelOnError: true,
);
}

void _unRegisterGyroscope(bool dispose) {
if (dispose || !hasEventListener(EVENT_DEVICE_ORIENTATION)) {
_gyroscopeStream?.cancel();
_gyroscopeStream = null;
}
}

/// Convert gyroscope data obtained in Flutter into rotation angle in the Web
/// In the w3c standard:
/// alpha: A number representing the motion of the device around the z axis, express in degrees with values ranging from 0 (inclusive) to 360 (exclusive).
/// beta: A number representing the motion of the device around the x axis, expressed in degrees with values ranging from -180 (inclusive) to 180 (exclusive).
/// gamma: A number representing the motion of the device around the y axis, expressed in degrees with values ranging from -90 (inclusive) to 90 (exclusive).
void dispatchDeviceOrientationEvent(x, y, z) {
var xAxisAngle= math.atan2(y, z) * (180 / math.pi); // Angle of rotation around the X-axis
var yAxisAngle = math.atan2(-x, math.sqrt(y * y + z * z)) * (180 / math.pi); // Rotation angle around Y axis
var zAxisAngle = math.atan2(y, z) * (180 / math.pi); // Rotation angle around Z axis
var alpha = zAxisAngle + 180;
var beta = xAxisAngle;
var gamma = yAxisAngle;
if (hasEventListener(EVENT_DEVICE_ORIENTATION)) {
dispatchEvent(DeviceOrientationEvent(alpha, beta, gamma));
}
}

@override
void dispose() async {
_unRegisterGyroscope(true);
super.dispose();
}
}
1 change: 1 addition & 0 deletions webf/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ dependencies:
shared_preferences: 2.2.0 # No AndroidX used.
archive: ^3.3.7 # Pure dart module.
web_socket_channel: ^2.2.0
sensors_plus: ^4.0.2

dev_dependencies:
flutter_test:
Expand Down
Loading