mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 06:41:14 +00:00
Prepare for optional inlining
Even if we make inlining optional, there are *some* situations where we just need to do the inlining anyway to avoid needless complexity.
This commit is contained in:
parent
72f022b3ed
commit
a318df522b
8 changed files with 144 additions and 43 deletions
|
@ -23,8 +23,8 @@ use crate::parser;
|
||||||
use crate::parser::{syntax_nodes, SyntaxKind, SyntaxNode};
|
use crate::parser::{syntax_nodes, SyntaxKind, SyntaxNode};
|
||||||
use crate::typeloader::ImportedTypes;
|
use crate::typeloader::ImportedTypes;
|
||||||
use crate::typeregister::TypeRegister;
|
use crate::typeregister::TypeRegister;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::btree_map::Entry;
|
use std::collections::btree_map::Entry;
|
||||||
|
use std::cell::{Cell, RefCell};
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::rc::{Rc, Weak};
|
use std::rc::{Rc, Weak};
|
||||||
|
@ -225,6 +225,7 @@ pub struct Component {
|
||||||
/// The names under which this component should be accessible
|
/// The names under which this component should be accessible
|
||||||
/// if it is a global singleton and exported.
|
/// if it is a global singleton and exported.
|
||||||
pub exported_global_names: RefCell<Vec<ExportedName>>,
|
pub exported_global_names: RefCell<Vec<ExportedName>>,
|
||||||
|
pub requires_inlining: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component {
|
impl Component {
|
||||||
|
|
|
@ -67,55 +67,64 @@ pub async fn run_passes(
|
||||||
check_public_api::check_public_api(doc, diag);
|
check_public_api::check_public_api(doc, diag);
|
||||||
|
|
||||||
collect_subcomponents::collect_subcomponents(root_component);
|
collect_subcomponents::collect_subcomponents(root_component);
|
||||||
for component in root_component
|
|
||||||
|
let components = root_component
|
||||||
.used_types
|
.used_types
|
||||||
.borrow()
|
.borrow()
|
||||||
.sub_components
|
.sub_components
|
||||||
.iter()
|
.iter()
|
||||||
.chain(std::iter::once(root_component))
|
.cloned()
|
||||||
{
|
.chain(std::iter::once(root_component.clone()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for component in &components {
|
||||||
compile_paths::compile_paths(component, &doc.local_registry, diag);
|
compile_paths::compile_paths(component, &doc.local_registry, diag);
|
||||||
lower_tabwidget::lower_tabwidget(component, &mut type_loader, diag).await;
|
lower_tabwidget::lower_tabwidget(component, &mut type_loader, diag).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
embed_images::embed_images(root_component, compiler_config.embed_resources, diag);
|
embed_images::embed_images(root_component, compiler_config.embed_resources, diag);
|
||||||
|
|
||||||
inlining::inline(doc);
|
inlining::inline(doc, inlining::InlineSelection::InlineOnlyRequiredComponents);
|
||||||
focus_item::resolve_element_reference_in_set_focus_calls(root_component, diag);
|
|
||||||
focus_item::determine_initial_focus_item(root_component, diag);
|
for component in &components {
|
||||||
focus_item::erase_forward_focus_properties(root_component);
|
focus_item::resolve_element_reference_in_set_focus_calls(component, diag);
|
||||||
flickable::handle_flickable(root_component, &global_type_registry.borrow());
|
focus_item::determine_initial_focus_item(component, diag);
|
||||||
lower_states::lower_states(root_component, &doc.local_registry, diag);
|
focus_item::erase_forward_focus_properties(component);
|
||||||
repeater_component::process_repeater_components(root_component);
|
flickable::handle_flickable(component, &global_type_registry.borrow());
|
||||||
lower_popups::lower_popups(root_component, &doc.local_registry, diag);
|
lower_states::lower_states(component, &doc.local_registry, diag);
|
||||||
lower_layout::lower_layouts(root_component, &mut type_loader, diag).await;
|
repeater_component::process_repeater_components(component);
|
||||||
z_order::reorder_by_z_order(root_component, diag);
|
lower_popups::lower_popups(component, &doc.local_registry, diag);
|
||||||
lower_shadows::lower_shadow_properties(root_component, &doc.local_registry, diag);
|
lower_layout::lower_layouts(component, &mut type_loader, diag).await;
|
||||||
clip::handle_clip(root_component, &global_type_registry.borrow(), diag);
|
z_order::reorder_by_z_order(component, diag);
|
||||||
transform_and_opacity::handle_transform_and_opacity(
|
lower_shadows::lower_shadow_properties(component, &doc.local_registry, diag);
|
||||||
root_component,
|
clip::handle_clip(component, &global_type_registry.borrow(), diag);
|
||||||
&global_type_registry.borrow(),
|
transform_and_opacity::handle_transform_and_opacity(
|
||||||
diag,
|
component,
|
||||||
);
|
&global_type_registry.borrow(),
|
||||||
default_geometry::default_geometry(root_component, diag);
|
diag,
|
||||||
visible::handle_visible(root_component, &global_type_registry.borrow());
|
);
|
||||||
materialize_fake_properties::materialize_fake_properties(root_component);
|
default_geometry::default_geometry(component, diag);
|
||||||
ensure_window::ensure_window(root_component, &doc.local_registry);
|
materialize_fake_properties::materialize_fake_properties(component);
|
||||||
apply_default_properties_from_style::apply_default_properties_from_style(
|
apply_default_properties_from_style::apply_default_properties_from_style(
|
||||||
root_component,
|
component,
|
||||||
&mut type_loader,
|
&mut type_loader,
|
||||||
diag,
|
diag,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
collect_globals::collect_globals(doc, diag);
|
ensure_window::ensure_window(component, &doc.local_registry);
|
||||||
unique_id::assign_unique_id(root_component);
|
unique_id::assign_unique_id(component);
|
||||||
binding_analysis::binding_analysis(root_component, diag);
|
collect_globals::collect_globals(&doc, diag);
|
||||||
|
|
||||||
|
binding_analysis::binding_analysis(component, diag);
|
||||||
|
}
|
||||||
|
|
||||||
deduplicate_property_read::deduplicate_property_read(root_component);
|
deduplicate_property_read::deduplicate_property_read(root_component);
|
||||||
optimize_useless_rectangles::optimize_useless_rectangles(root_component);
|
optimize_useless_rectangles::optimize_useless_rectangles(root_component);
|
||||||
move_declarations::move_declarations(root_component, diag);
|
move_declarations::move_declarations(root_component, diag);
|
||||||
remove_aliases::remove_aliases(root_component, diag);
|
remove_aliases::remove_aliases(root_component, diag);
|
||||||
resolve_native_classes::resolve_native_classes(root_component);
|
resolve_native_classes::resolve_native_classes(root_component);
|
||||||
remove_unused_properties::remove_unused_properties(root_component);
|
remove_unused_properties::remove_unused_properties(root_component);
|
||||||
|
|
||||||
collect_structs::collect_structs(root_component, diag);
|
collect_structs::collect_structs(root_component, diag);
|
||||||
generate_item_indices::generate_item_indices(root_component);
|
generate_item_indices::generate_item_indices(root_component);
|
||||||
collect_custom_fonts::collect_custom_fonts(
|
collect_custom_fonts::collect_custom_fonts(
|
||||||
|
|
|
@ -44,6 +44,8 @@ fn collect_subcomponents_recursive(
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
collect_subcomponents_recursive(&base_comp, result, hash);
|
collect_subcomponents_recursive(&base_comp, result, hash);
|
||||||
result.push(base_comp);
|
if !base_comp.requires_inlining.get() {
|
||||||
|
result.push(base_comp);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,3 +275,31 @@ fn make_default_aspect_ratio_preserving_binding(
|
||||||
|
|
||||||
elem.borrow_mut().bindings.insert(missing_size_property.to_string(), binding.into());
|
elem.borrow_mut().bindings.insert(missing_size_property.to_string(), binding.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn implicit_layout_info_call(elem: &ElementRc, orientation: Orientation) -> Expression {
|
||||||
|
Expression::FunctionCall {
|
||||||
|
function: Box::new(Expression::BuiltinFunctionReference(
|
||||||
|
BuiltinFunction::ImplicitLayoutInfo(orientation),
|
||||||
|
None,
|
||||||
|
)),
|
||||||
|
arguments: vec![Expression::ElementReference(Rc::downgrade(elem))],
|
||||||
|
source_location: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn element_requires_parent_for_geometry(element: &ElementRc) -> bool {
|
||||||
|
for property in ["width", "height"] {
|
||||||
|
if !element.borrow().bindings.get(property).map_or(false, |b| b.ty() == Type::Percent) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Type::Builtin(builtin_type) = &element.borrow().base_type {
|
||||||
|
if matches!(builtin_type.default_size_binding, DefaultSizeBinding::ExpandsToParentGeometry)
|
||||||
|
{
|
||||||
|
// FIXME: this does not apply to children of layouts
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,10 @@ use crate::langtype::{NativeClass, Type};
|
||||||
use crate::object_tree::{Component, Element, ElementRc};
|
use crate::object_tree::{Component, Element, ElementRc};
|
||||||
use crate::typeregister::TypeRegister;
|
use crate::typeregister::TypeRegister;
|
||||||
|
|
||||||
|
pub fn is_flickable_element(element: &ElementRc) -> bool {
|
||||||
|
matches!(&element.borrow().base_type, Type::Builtin(n) if n.name == "Flickable")
|
||||||
|
}
|
||||||
|
|
||||||
pub fn handle_flickable(root_component: &Rc<Component>, tr: &TypeRegister) {
|
pub fn handle_flickable(root_component: &Rc<Component>, tr: &TypeRegister) {
|
||||||
let mut native_rect = tr.lookup("Rectangle").as_builtin().native_class.clone();
|
let mut native_rect = tr.lookup("Rectangle").as_builtin().native_class.clone();
|
||||||
while let Some(p) = native_rect.parent.clone() {
|
while let Some(p) = native_rect.parent.clone() {
|
||||||
|
@ -37,7 +41,7 @@ pub fn handle_flickable(root_component: &Rc<Component>, tr: &TypeRegister) {
|
||||||
root_component,
|
root_component,
|
||||||
&(),
|
&(),
|
||||||
&mut |elem: &ElementRc, _| {
|
&mut |elem: &ElementRc, _| {
|
||||||
if !matches!(&elem.borrow().base_type, Type::Builtin(n) if n.name == "Flickable") {
|
if !is_flickable_element(elem) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ LICENSE END */
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::diagnostics::{BuildDiagnostics, SourceLocation, Spanned};
|
use crate::diagnostics::{BuildDiagnostics, SourceLocation, Spanned};
|
||||||
use crate::expression_tree::{BuiltinFunction, Expression};
|
use crate::expression_tree::{BindingExpression, BuiltinFunction, Expression};
|
||||||
use crate::langtype::Type;
|
use crate::langtype::Type;
|
||||||
use crate::object_tree::*;
|
use crate::object_tree::*;
|
||||||
|
|
||||||
|
@ -23,8 +23,19 @@ enum FocusCheckResult {
|
||||||
ElementIsNotFocusable,
|
ElementIsNotFocusable,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_explicit_forward_focus(
|
||||||
|
element: &ElementRc,
|
||||||
|
) -> Option<std::cell::Ref<BindingExpression>> {
|
||||||
|
let element = element.borrow();
|
||||||
|
if element.bindings.contains_key("forward_focus") {
|
||||||
|
Some(std::cell::Ref::map(element, |elem| &elem.bindings["forward_focus"]))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn element_focus_check(element: &ElementRc) -> FocusCheckResult {
|
fn element_focus_check(element: &ElementRc) -> FocusCheckResult {
|
||||||
if let Some(forwarded_focus_binding) = element.borrow().bindings.get("forward-focus") {
|
if let Some(forwarded_focus_binding) = get_explicit_forward_focus(element) {
|
||||||
if let Expression::ElementReference(target) = &forwarded_focus_binding.expression {
|
if let Expression::ElementReference(target) = &forwarded_focus_binding.expression {
|
||||||
return FocusCheckResult::FocusForwarded(
|
return FocusCheckResult::FocusForwarded(
|
||||||
target.upgrade().unwrap(),
|
target.upgrade().unwrap(),
|
||||||
|
|
|
@ -17,19 +17,37 @@ use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub fn inline(doc: &Document) {
|
#[derive(Copy, Clone)]
|
||||||
fn inline_components_recursively(component: &Rc<Component>) {
|
pub enum InlineSelection {
|
||||||
|
InlineAllComponents,
|
||||||
|
#[allow(dead_code)] // allow until it's an option globally used in the compiler
|
||||||
|
InlineOnlyRequiredComponents,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inline(doc: &Document, inline_selection: InlineSelection) {
|
||||||
|
fn inline_components_recursively(component: &Rc<Component>, inline_selection: InlineSelection) {
|
||||||
recurse_elem(&component.root_element, &(), &mut |elem, _| {
|
recurse_elem(&component.root_element, &(), &mut |elem, _| {
|
||||||
let base = elem.borrow().base_type.clone();
|
let base = elem.borrow().base_type.clone();
|
||||||
if let Type::Component(c) = base {
|
if let Type::Component(c) = base {
|
||||||
// First, make sure that the component itself is properly inlined
|
// First, make sure that the component itself is properly inlined
|
||||||
inline_components_recursively(&c);
|
inline_components_recursively(&c, inline_selection);
|
||||||
// Inline this component.
|
// Inline this component.
|
||||||
inline_element(elem, &c, component);
|
if match inline_selection {
|
||||||
|
InlineSelection::InlineAllComponents => true,
|
||||||
|
InlineSelection::InlineOnlyRequiredComponents
|
||||||
|
if component_requires_inlining(&c) =>
|
||||||
|
{
|
||||||
|
c.requires_inlining.set(true);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
} {
|
||||||
|
inline_element(elem, &c, component);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
inline_components_recursively(&doc.root_component)
|
inline_components_recursively(&doc.root_component, inline_selection)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clone_tuple<U: Clone, V: Clone>((u, v): (&U, &V)) -> (U, V) {
|
fn clone_tuple<U: Clone, V: Clone>((u, v): (&U, &V)) -> (U, V) {
|
||||||
|
@ -261,3 +279,27 @@ fn duplicate_transition(
|
||||||
node: t.node.clone(),
|
node: t.node.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some components need to be inlined to avoid increased complexity in handling them
|
||||||
|
// in the code generators and subsequent passes.
|
||||||
|
fn component_requires_inlining(component: &Rc<Component>) -> bool {
|
||||||
|
if component.child_insertion_point.borrow().is_some() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let root_element = &component.root_element;
|
||||||
|
if super::flickable::is_flickable_element(root_element)
|
||||||
|
|| super::focus_item::get_explicit_forward_focus(root_element).is_some()
|
||||||
|
|| super::lower_layout::is_layout_element(root_element)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For now any implicit bindings to the parent geometry require inlining, but this should
|
||||||
|
// be changed to instead create the bindings on the use-site instead.
|
||||||
|
if super::default_geometry::element_requires_parent_for_geometry(root_element) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
|
@ -94,6 +94,10 @@ fn lower_element_layout(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_layout_element(element: &ElementRc) -> bool {
|
||||||
|
matches!(&element.borrow().base_type, Type::Builtin(n) if n.name == "GridLayout" || n.name == "HorizontalLayout" || n.name == "VerticalLayout" || n.name == "PathLayout")
|
||||||
|
}
|
||||||
|
|
||||||
fn lower_grid_layout(
|
fn lower_grid_layout(
|
||||||
component: &Rc<Component>,
|
component: &Rc<Component>,
|
||||||
grid_layout_element: &ElementRc,
|
grid_layout_element: &ElementRc,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue