Use ComponentRc during item tree traversal

This is in preparation for allowing the run-time / items to clone VRc's
of the component.

ComponentVTable functions like visit_children_item contine to take a
ComponentRefPin as "self" parameter type, as a VRc would not be
supported by rust right now. That means the implementation then uses
self_weak to obtain a strong self-reference.
This commit is contained in:
Simon Hausmann 2020-11-12 15:49:02 +01:00
parent 54cc66c400
commit 78fae068dd
9 changed files with 72 additions and 49 deletions

View file

@ -62,6 +62,7 @@ using ComponentRef = vtable::VRef<private_api::ComponentVTable>;
using ItemRef = vtable::VRef<private_api::ItemVTable>;
using ItemVisitorRefMut = vtable::VRefMut<cbindgen_private::ItemVisitorVTable>;
}
using cbindgen_private::ComponentRc;
using cbindgen_private::EasingCurve;
using cbindgen_private::PropertyAnimation;
using cbindgen_private::Slice;
@ -174,7 +175,7 @@ using cbindgen_private::MouseEvent;
using cbindgen_private::sixtyfps_visit_item_tree;
namespace private_api {
template<typename GetDynamic>
inline InputEventResult process_input_event(ComponentRef component, int64_t &mouse_grabber,
inline InputEventResult process_input_event(const ComponentRc &component_rc, int64_t &mouse_grabber,
MouseEvent mouse_event, Slice<ItemTreeNode> tree,
GetDynamic get_dynamic, const ComponentWindow *window,
const ComponentRef *app_component)
@ -182,7 +183,8 @@ inline InputEventResult process_input_event(ComponentRef component, int64_t &mou
if (mouse_grabber != -1) {
auto item_index = mouse_grabber & 0xffffffff;
auto rep_index = mouse_grabber >> 32;
auto offset = cbindgen_private::sixtyfps_item_offset(component, tree, item_index);
auto offset =
cbindgen_private::sixtyfps_item_offset(component_rc.borrow(), tree, item_index);
mouse_event.pos = { mouse_event.pos.x - offset.x, mouse_event.pos.y - offset.y };
const auto &item_node = tree.ptr[item_index];
InputEventResult result = InputEventResult::EventIgnored;
@ -191,7 +193,7 @@ inline InputEventResult process_input_event(ComponentRef component, int64_t &mou
result = item_node.item.item.vtable->input_event(
{
item_node.item.item.vtable,
reinterpret_cast<char *>(component.instance)
reinterpret_cast<char *>(component_rc.borrow().instance)
+ item_node.item.item.offset,
},
mouse_event, window, *app_component);
@ -207,7 +209,7 @@ inline InputEventResult process_input_event(ComponentRef component, int64_t &mou
return result;
} else {
return cbindgen_private::sixtyfps_process_ungrabbed_mouse_event(
component, mouse_event, window, *app_component, &mouse_grabber);
&component_rc, mouse_event, window, *app_component, &mouse_grabber);
}
}
template<typename GetDynamic>
@ -238,14 +240,14 @@ inline KeyEventResult process_key_event(ComponentRef component, int64_t focus_it
}
template<typename GetDynamic>
inline FocusEventResult process_focus_event(ComponentRef component, int64_t &focus_item,
inline FocusEventResult process_focus_event(const ComponentRc &component_rc, int64_t &focus_item,
const FocusEvent *event, Slice<ItemTreeNode> tree,
GetDynamic get_dynamic, const ComponentWindow *window)
{
switch (event->tag) {
case FocusEvent::Tag::FocusIn:
return cbindgen_private::sixtyfps_locate_and_activate_focus_item(component, event, window,
&focus_item);
return cbindgen_private::sixtyfps_locate_and_activate_focus_item(&component_rc, event,
window, &focus_item);
case FocusEvent::Tag::FocusOut:
[[fallthrough]];
case FocusEvent::Tag::WindowReceivedFocus:
@ -260,7 +262,7 @@ inline FocusEventResult process_focus_event(ComponentRef component, int64_t &foc
item_node.item.item.vtable->focus_event(
{
item_node.item.item.vtable,
reinterpret_cast<char *>(component.instance)
reinterpret_cast<char *>(component_rc.borrow().instance)
+ item_node.item.item.offset,
},
event, window);

View file

@ -74,6 +74,8 @@ private:
X data;
Layout layout;
};
void *data_ptr() { return reinterpret_cast<char *>(this) + data_offset; }
};
struct Dyn {};
@ -120,6 +122,8 @@ public:
}
VRc<VTable, Dyn> into_dyn() const { return *reinterpret_cast<const VRc<VTable, Dyn> *>(this); }
VRef<VTable> borrow() const { return { inner->vtable, inner->data_ptr() }; }
};
template<typename VTable, typename X = Dyn>

View file

@ -1020,7 +1020,8 @@ fn generate_component(
format!(" [[maybe_unused]] auto self = reinterpret_cast<const {}*>(base);", component_id),
format!(" switch(dyn_index) {{ {} }};", children_visitor_cases.join("")),
" std::abort();\n};".to_owned(),
"return sixtyfps::sixtyfps_visit_item_tree(component, item_tree() , index, order, visitor, dyn_visit);".to_owned(),
format!("auto self_rc = reinterpret_cast<const {}*>(component.instance)->self_weak.lock()->into_dyn();", component_id),
"return sixtyfps::sixtyfps_visit_item_tree(&self_rc, item_tree() , index, order, visitor, dyn_visit);".to_owned(),
]),
..Default::default()
}),
@ -1072,8 +1073,9 @@ fn generate_component(
.into(),
is_static: true,
statements: Some(vec![
format!(" auto self = reinterpret_cast<{}*>(component.instance);", component_id),
"return sixtyfps::private_api::process_input_event(component, self->mouse_grabber, mouse_event, item_tree(), [self](int dyn_index, [[maybe_unused]] int rep_index) {".into(),
format!("auto self = reinterpret_cast<{}*>(component.instance);", component_id),
"auto self_rc = self->self_weak.lock()->into_dyn();".into(),
"return sixtyfps::private_api::process_input_event(self_rc, self->mouse_grabber, mouse_event, item_tree(), [self](int dyn_index, [[maybe_unused]] int rep_index) {".into(),
" (void)self;".into(),
format!(" switch(dyn_index) {{ {} }};", repeated_input_branch.join("")),
" return sixtyfps::private_api::ComponentRef{nullptr, nullptr};\n}, window, app_component);".into(),
@ -1118,8 +1120,9 @@ fn generate_component(
.into(),
is_static: true,
statements: Some(vec![
format!(" auto self = reinterpret_cast<{}*>(component.instance);", component_id),
"return sixtyfps::private_api::process_focus_event(component, self->focus_item, focus_event, item_tree(), [self](int dyn_index, [[maybe_unused]] int rep_index) {".into(),
format!("auto self = reinterpret_cast<{}*>(component.instance);", component_id),
"auto self_rc = self->self_weak.lock()->into_dyn();".into(),
"return sixtyfps::private_api::process_focus_event(self_rc, self->focus_item, focus_event, item_tree(), [self](int dyn_index, [[maybe_unused]] int rep_index) {".into(),
" (void)self;".into(),
format!(" switch(dyn_index) {{ {} }};", repeated_input_branch.join("")),
" return sixtyfps::private_api::ComponentRef{nullptr, nullptr};\n}, window);".into(),

View file

@ -651,7 +651,7 @@ fn generate_component(
-> sixtyfps::re_exports::VisitChildrenResult
{
use sixtyfps::re_exports::*;
return sixtyfps::re_exports::visit_item_tree(self, VRef::new_pin(self), Self::item_tree(), index, order, visitor, visit_dynamic);
return sixtyfps::re_exports::visit_item_tree(self, &VRc::into_dyn(self.as_ref().self_weak.get().unwrap().upgrade().unwrap()), Self::item_tree(), index, order, visitor, visit_dynamic);
#[allow(unused)]
fn visit_dynamic(self_pinned: ::core::pin::Pin<&#component_id>, order: sixtyfps::re_exports::TraversalOrder, visitor: ItemVisitorRefMut, dyn_index: usize) -> VisitChildrenResult {
let _self = self_pinned;
@ -688,7 +688,7 @@ fn generate_component(
_ => (res, VisitChildrenResult::CONTINUE),
}
} else {
process_ungrabbed_mouse_event(VRef::new_pin(self), mouse_event, window, app_component.clone())
process_ungrabbed_mouse_event(&VRc::into_dyn(self.as_ref().self_weak.get().unwrap().upgrade().unwrap()), mouse_event, window, app_component.clone())
};
self.mouse_grabber.set(new_grab);
status
@ -722,7 +722,7 @@ fn generate_component(
#[allow(unused)]
match event {
FocusEvent::FocusIn(_) => {
let (event_result, visit_result) = locate_and_activate_focus_item(VRef::new_pin(self), event, window);
let (event_result, visit_result) = locate_and_activate_focus_item(&VRc::into_dyn(self.as_ref().self_weak.get().unwrap().upgrade().unwrap()), event, window);
if event_result == FocusEventResult::FocusItemFound {
self.focus_item.set(visit_result)
}

View file

@ -609,8 +609,8 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow for GraphicsWindo
}
fn draw(self: Rc<Self>) {
let component = self.component.borrow().upgrade().unwrap();
let component = ComponentRc::borrow_pin(&component);
let component_rc = self.component.borrow().upgrade().unwrap();
let component = ComponentRc::borrow_pin(&component_rc);
{
if self.layout_listener.as_ref().is_dirty() {
@ -629,7 +629,7 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow for GraphicsWindo
// Generate cached rendering data once
crate::item_tree::visit_items(
component,
&component_rc,
crate::item_tree::TraversalOrder::BackToFront,
|_, item, _| {
crate::item_rendering::update_item_rendering_data(
@ -656,7 +656,7 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow for GraphicsWindo
&ARGBColor { red: 255 as u8, green: 255, blue: 255, alpha: 255 }.into(),
);
crate::item_rendering::render_component_items(
component,
&component_rc,
&mut frame,
&window.rendering_cache,
&self,

View file

@ -11,7 +11,7 @@ LICENSE END */
*/
#![warn(missing_docs)]
use crate::component::ComponentRefPin;
use crate::component::{ComponentRc, ComponentRefPin};
use crate::graphics::Point;
use crate::item_tree::{ItemVisitorResult, VisitChildrenResult};
use euclid::default::Vector2D;
@ -480,7 +480,7 @@ pub enum FocusEventResult {
/// the focus_event (assuming it is of type FocusIn). Once located, the focus in
/// even will also be dispatched to the item itself.
pub fn locate_and_activate_focus_item(
component: ComponentRefPin,
component: &ComponentRc,
focus_event: &FocusEvent,
window: &crate::eventloop::ComponentWindow,
) -> (FocusEventResult, VisitChildrenResult) {
@ -522,7 +522,7 @@ pub fn locate_and_activate_focus_item(
/// * `component`: The component to deliver the event to.
/// * `event`: The mouse event to deliver.
pub fn process_ungrabbed_mouse_event(
component: ComponentRefPin,
component: &ComponentRc,
event: MouseEvent,
window: &crate::eventloop::ComponentWindow,
app_component: ComponentRefPin,
@ -596,7 +596,7 @@ pub(crate) mod ffi {
#[no_mangle]
pub extern "C" fn sixtyfps_process_ungrabbed_mouse_event(
component: core::pin::Pin<crate::component::ComponentRef>,
component: &ComponentRc,
event: MouseEvent,
window: &crate::eventloop::ComponentWindow,
app_component: core::pin::Pin<crate::component::ComponentRef>,
@ -620,7 +620,7 @@ pub(crate) mod ffi {
#[no_mangle]
pub extern "C" fn sixtyfps_locate_and_activate_focus_item(
component: core::pin::Pin<crate::component::ComponentRef>,
component: &ComponentRc,
event: &FocusEvent,
window: &crate::eventloop::ComponentWindow,
new_focus_item: &mut crate::item_tree::VisitChildrenResult,

View file

@ -14,8 +14,10 @@ use super::graphics::{
Frame, GraphicsBackend, GraphicsWindow, RenderingCache, RenderingPrimitivesBuilder,
};
use super::items::ItemRef;
use crate::component::ComponentRc;
use crate::eventloop::ComponentWindow;
use crate::item_tree::ItemVisitorResult;
use crate::{eventloop::ComponentWindow, slice::Slice};
use crate::slice::Slice;
use cgmath::{Matrix4, SquareMatrix, Vector3};
use std::cell::{Cell, RefCell};
@ -80,7 +82,7 @@ pub(crate) fn update_item_rendering_data<Backend: GraphicsBackend>(
}
pub(crate) fn render_component_items<Backend: GraphicsBackend>(
component: crate::component::ComponentRefPin,
component: &ComponentRc,
frame: &mut Backend::Frame,
rendering_cache: &RefCell<RenderingCache<Backend>>,
window: &std::rc::Rc<GraphicsWindow<Backend>>,

View file

@ -7,7 +7,7 @@
This file is also available under commercial licensing terms.
Please contact info@sixtyfps.io for more information.
LICENSE END */
use crate::component::{ComponentRefPin, ComponentVTable};
use crate::component::{ComponentRc, ComponentVTable};
use crate::graphics::Point;
use crate::items::{ItemRef, ItemVTable};
use core::pin::Pin;
@ -106,7 +106,7 @@ pub struct ItemVisitorVTable {
/// and `item` is a reference to the item itself
visit_item: fn(
VRefMut<ItemVisitorVTable>,
component: Pin<VRef<ComponentVTable>>,
component: &VRc<ComponentVTable, vtable::Dyn>,
index: isize,
item: Pin<VRef<ItemVTable>>,
) -> VisitChildrenResult,
@ -117,12 +117,10 @@ pub struct ItemVisitorVTable {
/// Type alias to `vtable::VRefMut<ItemVisitorVTable>`
pub type ItemVisitorRefMut<'a> = vtable::VRefMut<'a, ItemVisitorVTable>;
impl<T: FnMut(crate::component::ComponentRefPin, isize, Pin<ItemRef>) -> VisitChildrenResult>
ItemVisitor for T
{
impl<T: FnMut(&ComponentRc, isize, Pin<ItemRef>) -> VisitChildrenResult> ItemVisitor for T {
fn visit_item(
&mut self,
component: crate::component::ComponentRefPin,
component: &ComponentRc,
index: isize,
item: Pin<ItemRef>,
) -> VisitChildrenResult {
@ -140,9 +138,9 @@ pub enum ItemVisitorResult<State> {
///
/// Returns the index of the item that cancelled, or -1 if nobody cancelled
pub fn visit_items<State>(
component: ComponentRefPin,
component: &ComponentRc,
order: TraversalOrder,
mut visitor: impl FnMut(ComponentRefPin, Pin<ItemRef>, &State) -> ItemVisitorResult<State>,
mut visitor: impl FnMut(&ComponentRc, Pin<ItemRef>, &State) -> ItemVisitorResult<State>,
state: State,
) -> VisitChildrenResult {
visit_internal(
@ -161,33 +159,33 @@ pub fn visit_items<State>(
///
/// Returns the index of the item that cancelled, or -1 if nobody cancelled
pub fn visit_items_with_post_visit<State, PostVisitState>(
component: ComponentRefPin,
component: &ComponentRc,
order: TraversalOrder,
mut visitor: impl FnMut(
ComponentRefPin,
&ComponentRc,
Pin<ItemRef>,
&State,
) -> (ItemVisitorResult<State>, PostVisitState),
mut post_visitor: impl FnMut(ComponentRefPin, Pin<ItemRef>, PostVisitState),
mut post_visitor: impl FnMut(&ComponentRc, Pin<ItemRef>, PostVisitState),
state: State,
) -> VisitChildrenResult {
visit_internal(component, order, &mut visitor, &mut post_visitor, -1, &state)
}
fn visit_internal<State, PostVisitState>(
component: ComponentRefPin,
component: &ComponentRc,
order: TraversalOrder,
visitor: &mut impl FnMut(
ComponentRefPin,
&ComponentRc,
Pin<ItemRef>,
&State,
) -> (ItemVisitorResult<State>, PostVisitState),
post_visitor: &mut impl FnMut(ComponentRefPin, Pin<ItemRef>, PostVisitState),
post_visitor: &mut impl FnMut(&ComponentRc, Pin<ItemRef>, PostVisitState),
index: isize,
state: &State,
) -> VisitChildrenResult {
let mut actual_visitor =
|component: ComponentRefPin, index: isize, item: Pin<ItemRef>| -> VisitChildrenResult {
|component: &ComponentRc, index: isize, item: Pin<ItemRef>| -> VisitChildrenResult {
match visitor(component, item, state) {
(ItemVisitorResult::Continue(state), post_visit_state) => {
let result =
@ -199,7 +197,7 @@ fn visit_internal<State, PostVisitState>(
}
};
vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
component.as_ref().visit_children_item(index, order, actual_visitor)
VRc::borrow_pin(component).as_ref().visit_children_item(index, order, actual_visitor)
}
/// Visit the children within an array of ItemTreeNode
@ -212,7 +210,7 @@ fn visit_internal<State, PostVisitState>(
/// Possibly we should generate code that directly call the visitor instead
pub fn visit_item_tree<Base>(
base: Pin<&Base>,
component: ComponentRefPin,
component: &ComponentRc,
item_tree: &[ItemTreeNode<Base>],
index: isize,
order: TraversalOrder,
@ -307,7 +305,7 @@ pub(crate) mod ffi {
/// Safety: Assume a correct implementation of the item_tree array
#[no_mangle]
pub unsafe extern "C" fn sixtyfps_visit_item_tree(
component: Pin<VRef<ComponentVTable>>,
component: &ComponentRc,
item_tree: Slice<ItemTreeNode<u8>>,
index: isize,
order: TraversalOrder,
@ -320,7 +318,7 @@ pub(crate) mod ffi {
) -> VisitChildrenResult,
) -> VisitChildrenResult {
crate::item_tree::visit_item_tree(
Pin::new_unchecked(&*(component.as_ptr() as *const u8)),
Pin::new_unchecked(&*(&**component as *const Dyn as *const u8)),
component,
item_tree.as_slice(),
index,

View file

@ -336,9 +336,10 @@ extern "C" fn visit_children_item(
) -> VisitChildrenResult {
generativity::make_guard!(guard);
let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
let comp_rc = instance_ref.self_weak().get().unwrap().upgrade().unwrap();
sixtyfps_corelib::item_tree::visit_item_tree(
instance_ref.instance,
component,
&vtable::VRc::into_dyn(comp_rc),
instance_ref.component_type.item_tree.as_slice().into(),
index,
order,
@ -1014,6 +1015,7 @@ pub fn instantiate<'id>(
);
}
}
comp_rc
}
@ -1459,8 +1461,12 @@ extern "C" fn input_event(
_ => (res, VisitChildrenResult::CONTINUE),
}
} else {
generativity::make_guard!(guard);
let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
let comp_rc = instance_ref.self_weak().get().unwrap().upgrade().unwrap();
sixtyfps_corelib::input::process_ungrabbed_mouse_event(
component,
&vtable::VRc::into_dyn(comp_rc),
mouse_event,
window,
app_component.clone(),
@ -1508,8 +1514,16 @@ extern "C" fn focus_event(
match event {
FocusEvent::FocusIn(_) => {
generativity::make_guard!(guard);
let instance_ref = unsafe { InstanceRef::from_pin_ref(component, guard) };
let comp_rc = instance_ref.self_weak().get().unwrap().upgrade().unwrap();
let (event_result, visit_result) =
sixtyfps_corelib::input::locate_and_activate_focus_item(component, event, window);
sixtyfps_corelib::input::locate_and_activate_focus_item(
&vtable::VRc::into_dyn(comp_rc),
event,
window,
);
if event_result == FocusEventResult::FocusItemFound {
extra_data.focus_item.set(visit_result)
}