Skip to content

Commit f717a8e

Browse files
authored
Sync Blitz/Native (Blitz v0.3.0-beta.1) (#5673)
Signed-off-by: Nico Burns <nico@nicoburns.com>
1 parent e1c6342 commit f717a8e

13 files changed

Lines changed: 441 additions & 136 deletions

File tree

Cargo.lock

Lines changed: 85 additions & 80 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -187,23 +187,23 @@ const-serialize-macro = { path = "packages/const-serialize-macro", version = "0.
187187
warnings = { version = "0.2.1" }
188188

189189
# blitz / native
190-
blitz-dom = { version = "=0.3.0-alpha.4", default-features = false }
191-
blitz-net = { version = "=0.3.0-alpha.4" }
192-
blitz-html = { version = "=0.3.0-alpha.4" }
193-
blitz-paint = { version = "=0.3.0-alpha.4" }
194-
blitz-traits = { version = "=0.3.0-alpha.4" }
195-
blitz-shell = { version = "=0.3.0-alpha.4", default-features = false }
190+
blitz-dom = { version = "=0.3.0-beta.1", default-features = false }
191+
blitz-net = { version = "=0.3.0-beta.1" }
192+
blitz-html = { version = "=0.3.0-beta.1" }
193+
blitz-paint = { version = "=0.3.0-beta.1" }
194+
blitz-traits = { version = "=0.3.0-beta.1" }
195+
blitz-shell = { version = "=0.3.0-beta.1", default-features = false }
196196
peniko = { version = "0.6.1", default-features = false }
197-
anyrender = { version = "0.10", default-features = false }
198-
anyrender_vello = { version = "0.10.1", default-features = false }
199-
anyrender_vello_cpu = { version = "0.13.0", default-features = false }
200-
anyrender_vello_hybrid = { version = "0.6.0", default-features = false }
201-
anyrender_skia = { version = "0.8", default-features = false }
202-
wgpu_context = { version = "0.6" }
197+
anyrender = { version = "0.11.0" }
198+
anyrender_vello = { version = "0.12.0" }
199+
anyrender_vello_cpu = { version = "0.14.0" }
200+
anyrender_vello_hybrid = { version = "0.8.0" }
201+
anyrender_skia = { version = "0.9.0" }
202+
wgpu_context = { version = "0.7.0" }
203203
wgpu = { version = "29.0.3" }
204204
vello = "0.9"
205205
winit = { version = "=0.31.0-beta.2" }
206-
206+
atomic_refcell = "0.1.13"
207207

208208
# a fork of pretty please for tests - let's get off of this if we can!
209209
prettier-please = { version = "0.3.0", features = ["verbatim"] }

examples/10-integrations/native-headless/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ bytemuck = "1.25"
2323
blitz-paint = { workspace = true, default-features = true }
2424
blitz-traits = { workspace = true, default-features = true }
2525
blitz-dom = { workspace = true, default-features = true }
26+
atomic_refcell = { workspace = true }

examples/10-integrations/native-headless/src/main.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
//! (this example is not really intended to be run as-is, and requires you to fill
55
//! in the missing pieces)
66
use anyrender_vello::VelloScenePainter;
7+
use atomic_refcell::AtomicRefCell;
78
use blitz_dom::{Document as _, DocumentConfig};
89
use blitz_paint::paint_scene;
910
use blitz_traits::{
1011
events::{
11-
BlitzPointerEvent, BlitzPointerId, MouseEventButton, MouseEventButtons, PointerCoords,
12-
PointerDetails, UiEvent,
12+
BlitzPointerEvent, BlitzPointerId, MouseEventButton, MouseEventButtons, Point,
13+
PointerCoords, PointerDetails, UiEvent,
1314
},
1415
shell::{ColorScheme, Viewport},
1516
};
@@ -160,6 +161,8 @@ fn main() {
160161
buttons: MouseEventButtons::Primary, // keep track of all pressed buttons
161162
mods: Modifiers::empty(), // ctrl, alt, shift, etc
162163
details: PointerDetails::default(),
164+
element: Point::default(),
165+
active_pointers: Arc::new(AtomicRefCell::new(Vec::new())),
163166
});
164167
dioxus_doc.handle_ui_event(event);
165168

packages/native-dom/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ floats = ["blitz-dom/floats"]
1818
incremental = ["blitz-dom/incremental"]
1919
accessibility = ["blitz-dom/accessibility"]
2020
tracing = ["dep:tracing", "blitz-dom/tracing"]
21-
system-fonts = ["blitz-dom/system_fonts"]
21+
system-fonts = ["blitz-dom/system-fonts"]
22+
# complex-scripts: enable dictionary-based line-breaking
23+
complex-scripts = ["blitz-dom/complex-scripts"]
2224
autofocus = ["blitz-dom/autofocus"]
2325

2426
[dependencies]

packages/native-dom/src/dioxus_document.rs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
use crate::NodeId;
33
use crate::events::{
44
BlitzKeyboardData, NativeConverter, NativeFocusData, NativeFormData, NativePointerData,
5-
NativeScrollData, NativeWheelData, NodeHandle,
5+
NativeScrollData, NativeTouchData, NativeWheelData, NodeHandle,
66
};
77
use crate::mutation_writer::{DioxusState, MutationWriter};
88
use crate::qual_name;
@@ -275,6 +275,7 @@ impl EventHandler for DioxusEventHandler<'_> {
275275
DomEventData::PointerMove(mevent)
276276
| DomEventData::PointerDown(mevent)
277277
| DomEventData::PointerUp(mevent)
278+
| DomEventData::PointerCancel(mevent)
278279
| DomEventData::PointerLeave(mevent)
279280
| DomEventData::PointerEnter(mevent)
280281
| DomEventData::PointerOver(mevent)
@@ -292,6 +293,13 @@ impl EventHandler for DioxusEventHandler<'_> {
292293
Some(wrap_event_data(NativePointerData(mevent.clone())))
293294
}
294295

296+
DomEventData::TouchStart(tevent)
297+
| DomEventData::TouchMove(tevent)
298+
| DomEventData::TouchEnd(tevent)
299+
| DomEventData::TouchCancel(tevent) => {
300+
Some(wrap_event_data(NativeTouchData(tevent.clone())))
301+
}
302+
295303
DomEventData::Scroll(sevent) => Some(wrap_event_data(NativeScrollData(sevent.clone()))),
296304
DomEventData::Wheel(wevent) => Some(wrap_event_data(NativeWheelData(wevent.clone()))),
297305

@@ -322,27 +330,26 @@ impl EventHandler for DioxusEventHandler<'_> {
322330
return;
323331
};
324332

325-
for &node_id in chain {
326-
// Get dioxus vdom id for node
327-
let dioxus_id = doc.inner().get_node(node_id).and_then(get_dioxus_id);
328-
let Some(id) = dioxus_id else {
329-
continue;
330-
};
331-
332-
// Handle event in vdom
333-
let dx_event = Event::new(event_data.clone(), event.bubbles);
334-
self.vdom
335-
.runtime()
336-
.handle_event(event.name(), dx_event.clone(), id);
337-
338-
// Update event state
339-
if !dx_event.default_action_enabled() {
340-
event_state.prevent_default();
341-
}
342-
if !dx_event.propagates() {
343-
event_state.stop_propagation();
344-
break;
345-
}
333+
// Get dioxus vdom id for node
334+
let dioxus_id = chain
335+
.iter()
336+
.find_map(|node_id| doc.inner().get_node(*node_id).and_then(get_dioxus_id));
337+
let Some(id) = dioxus_id else {
338+
return;
339+
};
340+
341+
// Handle event in vdom
342+
let dx_event = Event::new(event_data.clone(), event.bubbles);
343+
self.vdom
344+
.runtime()
345+
.handle_event(event.name(), dx_event.clone(), id);
346+
347+
// Update event state
348+
if !dx_event.default_action_enabled() {
349+
event_state.prevent_default();
350+
}
351+
if !dx_event.propagates() {
352+
event_state.stop_propagation();
346353
}
347354
}
348355
}

packages/native-dom/src/events.rs

Lines changed: 170 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ use blitz_traits::events::{
66
use dioxus_html::{
77
AnimationData, BeforeInputData, CancelData, ClipboardData, CompositionData, DragData,
88
FocusData, FormData, FormValue, HasFileData, HasFocusData, HasFormData, HasKeyboardData,
9-
HasMouseData, HasPointerData, HasScrollData, HasWheelData, HtmlEventConverter, ImageData,
10-
KeyboardData, MediaData, MountedData, MountedError, MountedResult, MouseData,
11-
PlatformEventData, PointerData, RenderedElementBacking, ResizeData, ScrollBehavior, ScrollData,
12-
ScrollToOptions, SelectionData, ToggleData, TouchData, TransitionData, VisibleData, WheelData,
9+
HasMouseData, HasPointerData, HasScrollData, HasTouchData, HasTouchPointData, HasWheelData,
10+
HtmlEventConverter, ImageData, KeyboardData, MediaData, MountedData, MountedError,
11+
MountedResult, MouseData, PlatformEventData, PointerData, RenderedElementBacking, ResizeData,
12+
ScrollBehavior, ScrollData, ScrollToOptions, SelectionData, ToggleData, TouchData, TouchPoint,
13+
TransitionData, VisibleData, WheelData,
1314
geometry::{
1415
ClientPoint, ElementPoint, PagePoint, PixelsRect, PixelsSize, PixelsVector2D, ScreenPoint,
1516
WheelDelta,
@@ -117,8 +118,8 @@ impl HtmlEventConverter for NativeConverter {
117118
unimplemented!("todo: convert_toggle_data in dioxus-native. requires support in blitz")
118119
}
119120

120-
fn convert_touch_data(&self, _event: &PlatformEventData) -> TouchData {
121-
unimplemented!("todo: convert_touch_data in dioxus-native. requires support in blitz")
121+
fn convert_touch_data(&self, event: &PlatformEventData) -> TouchData {
122+
event.downcast::<NativeTouchData>().unwrap().clone().into()
122123
}
123124

124125
fn convert_transition_data(&self, _event: &PlatformEventData) -> TransitionData {
@@ -335,8 +336,7 @@ impl InteractionLocation for NativePointerData {
335336

336337
impl InteractionElementOffset for NativePointerData {
337338
fn element_coordinates(&self) -> ElementPoint {
338-
// TODO: implement element point
339-
ElementPoint::new(0.0, 0.0)
339+
ElementPoint::new(self.0.element_x() as f64, self.0.element_y() as f64)
340340
}
341341
}
342342

@@ -417,6 +417,92 @@ impl HasPointerData for NativePointerData {
417417
}
418418
}
419419

420+
/// Touch event data exposed to Dioxus Native application code.
421+
///
422+
/// Blitz tracks input via pointer events, so a touch event is generated from the
423+
/// pointer event of the finger that triggered it (`touches_changed`). The full
424+
/// list of concurrent touches is carried on the triggering event's
425+
/// [`BlitzPointerEvent::active_pointers`] list and reported via `touches`.
426+
#[derive(Clone)]
427+
pub struct NativeTouchData(pub(crate) BlitzPointerEvent);
428+
429+
impl ModifiersInteraction for NativeTouchData {
430+
fn modifiers(&self) -> Modifiers {
431+
self.0.mods
432+
}
433+
}
434+
435+
impl HasTouchData for NativeTouchData {
436+
fn touches(&self) -> Vec<TouchPoint> {
437+
// All pointers currently active on the surface (multi-touch).
438+
self.0
439+
.active_pointers
440+
.borrow()
441+
.iter()
442+
.map(|event| TouchPoint::new(NativeTouchPointData(event.clone())))
443+
.collect()
444+
}
445+
446+
fn touches_changed(&self) -> Vec<TouchPoint> {
447+
// Just the touch that triggered this event.
448+
vec![TouchPoint::new(NativeTouchPointData(self.0.clone()))]
449+
}
450+
451+
fn target_touches(&self) -> Vec<TouchPoint> {
452+
// We don't track a per-touch target, so approximate `targetTouches`
453+
// (touches that started on the event target) with all active touches.
454+
self.touches()
455+
}
456+
457+
fn as_any(&self) -> &dyn Any {
458+
self as &dyn Any
459+
}
460+
}
461+
462+
#[derive(Clone)]
463+
pub struct NativeTouchPointData(BlitzPointerEvent);
464+
465+
impl InteractionLocation for NativeTouchPointData {
466+
fn client_coordinates(&self) -> ClientPoint {
467+
ClientPoint::new(self.0.client_x() as f64, self.0.client_y() as f64)
468+
}
469+
470+
fn screen_coordinates(&self) -> ScreenPoint {
471+
ScreenPoint::new(self.0.screen_x() as f64, self.0.screen_y() as f64)
472+
}
473+
474+
fn page_coordinates(&self) -> PagePoint {
475+
PagePoint::new(self.0.page_x() as f64, self.0.page_y() as f64)
476+
}
477+
}
478+
479+
impl HasTouchPointData for NativeTouchPointData {
480+
fn identifier(&self) -> i32 {
481+
match self.0.id {
482+
BlitzPointerId::Finger(id) => id as i32,
483+
BlitzPointerId::Mouse | BlitzPointerId::Pen => 0,
484+
}
485+
}
486+
487+
fn force(&self) -> f64 {
488+
self.0.details.pressure
489+
}
490+
491+
fn radius(&self) -> ScreenPoint {
492+
// TODO: expose real touch radius once blitz tracks it
493+
ScreenPoint::new(1.0, 1.0)
494+
}
495+
496+
fn rotation(&self) -> f64 {
497+
// TODO: expose real touch rotation once blitz tracks it
498+
0.0
499+
}
500+
501+
fn as_any(&self) -> &dyn Any {
502+
self as &dyn Any
503+
}
504+
}
505+
420506
#[derive(Clone)]
421507
pub struct NativeFocusData;
422508
impl HasFocusData for NativeFocusData {
@@ -500,8 +586,7 @@ impl ModifiersInteraction for NativeWheelData {
500586

501587
impl InteractionElementOffset for NativeWheelData {
502588
fn element_coordinates(&self) -> ElementPoint {
503-
// TODO: implement element point
504-
ElementPoint::new(0.0, 0.0)
589+
ElementPoint::new(self.0.element_x() as f64, self.0.element_y() as f64)
505590
}
506591
}
507592

@@ -524,3 +609,78 @@ pub fn synthetic_click_event(node: &Node, modifiers: Modifiers) -> Box<dyn Any>
524609
node.synthetic_click_event_data(modifiers),
525610
))
526611
}
612+
613+
#[cfg(test)]
614+
mod tests {
615+
use super::*;
616+
use blitz_traits::events::{
617+
BlitzPointerId, MouseEventButton, MouseEventButtons, Point, PointerCoords, PointerDetails,
618+
};
619+
620+
fn finger_event(id: u64, x: f32, y: f32) -> BlitzPointerEvent {
621+
BlitzPointerEvent {
622+
id: BlitzPointerId::Finger(id),
623+
is_primary: id == 0,
624+
coords: PointerCoords {
625+
page_x: x,
626+
page_y: y,
627+
screen_x: x,
628+
screen_y: y,
629+
client_x: x,
630+
client_y: y,
631+
},
632+
button: MouseEventButton::Main,
633+
buttons: MouseEventButtons::from(MouseEventButton::Main),
634+
mods: Default::default(),
635+
details: PointerDetails::default(),
636+
element: Point::default(),
637+
active_pointers: Default::default(),
638+
}
639+
}
640+
641+
#[test]
642+
fn touches_reports_all_active_pointers() {
643+
let f0 = finger_event(0, 10.0, 20.0);
644+
let f1 = finger_event(1, 30.0, 40.0);
645+
646+
// The triggering event (second finger down) carries the list of all
647+
// currently-active pointers.
648+
let trigger = f1.clone();
649+
{
650+
let mut list = trigger.active_pointers.borrow_mut();
651+
list.push(f0.clone());
652+
list.push(f1.clone());
653+
}
654+
655+
let data = NativeTouchData(trigger);
656+
657+
// `touches` reports every active pointer ...
658+
let touches = data.touches();
659+
assert_eq!(touches.len(), 2);
660+
let coords: Vec<(f64, f64)> = touches
661+
.iter()
662+
.map(|t| {
663+
let c = t.client_coordinates();
664+
(c.x, c.y)
665+
})
666+
.collect();
667+
assert!(coords.contains(&(10.0, 20.0)));
668+
assert!(coords.contains(&(30.0, 40.0)));
669+
670+
// ... while `changed_touches` reports only the triggering touch.
671+
assert_eq!(data.touches_changed().len(), 1);
672+
let changed = data.touches_changed();
673+
let changed_coords = changed[0].client_coordinates();
674+
assert_eq!((changed_coords.x, changed_coords.y), (30.0, 40.0));
675+
}
676+
677+
#[test]
678+
fn touches_is_empty_when_no_pointers_are_active() {
679+
// e.g. a `touchend` for the last finger: it has been removed from the
680+
// active list before dispatch, so `touches` is empty but
681+
// `changed_touches` still reports the finger that ended.
682+
let data = NativeTouchData(finger_event(0, 1.0, 2.0));
683+
assert!(data.touches().is_empty());
684+
assert_eq!(data.touches_changed().len(), 1);
685+
}
686+
}

packages/native-dom/src/mutation_writer.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ pub struct DioxusState {
1717
pub(crate) stack: Vec<NodeId>,
1818
/// Mapping from vdom ElementId -> rdom NodeId
1919
pub(crate) node_id_mapping: Vec<Option<NodeId>>,
20-
/// Count of each handler type
21-
pub(crate) event_handler_counts: [u32; 32],
20+
/// Count of each handler type (indexed by `DomEventKind` discriminant)
21+
pub(crate) event_handler_counts: [u32; 64],
2222
/// Mounted events queued as elements are mounted
2323
pub(crate) queued_mounted_events: Vec<ElementId>,
2424
}
@@ -30,7 +30,7 @@ impl DioxusState {
3030
templates: FxHashMap::default(),
3131
stack: vec![root_id],
3232
node_id_mapping: vec![Some(root_id)],
33-
event_handler_counts: [0; 32],
33+
event_handler_counts: [0; 64],
3434
queued_mounted_events: Vec::new(),
3535
}
3636
}

0 commit comments

Comments
 (0)