1#![allow(clippy::mutable_key_type)] use crate::diagnostics::{BuildDiagnostics, Spanned};
9use crate::expression_tree::{BindingExpression, Expression, NamedReference};
10use crate::langtype::{ElementType, Type};
11use crate::object_tree::*;
12use by_address::ByAddress;
13use smol_str::SmolStr;
14use std::cell::RefCell;
15use std::collections::{HashMap, HashSet};
16use std::rc::Rc;
17
18#[derive(Copy, Clone, Eq, PartialEq)]
19pub enum InlineSelection {
20 InlineAllComponents,
21 InlineOnlyRequiredComponents,
22}
23
24pub fn inline(doc: &Document, inline_selection: InlineSelection, diag: &mut BuildDiagnostics) {
25 fn inline_components_recursively(
26 component: &Rc<Component>,
27 roots: &HashSet<ByAddress<Rc<Component>>>,
28 inline_selection: InlineSelection,
29 diag: &mut BuildDiagnostics,
30 ) {
31 recurse_elem_no_borrow(&component.root_element, &(), &mut |elem, _| {
32 let base = elem.borrow().base_type.clone();
33 if let ElementType::Component(c) = base {
34 inline_components_recursively(&c, roots, inline_selection, diag);
36
37 if c.parent_element().is_some() {
38 return;
40 }
41
42 if match inline_selection {
44 InlineSelection::InlineAllComponents => true,
45 InlineSelection::InlineOnlyRequiredComponents => {
46 component_requires_inlining(&c)
47 || element_require_inlining(elem)
48 || component.parent_element().is_none() && Rc::ptr_eq(elem, &component.root_element)
51 || roots.contains(&ByAddress(c.clone()))
53 }
54 } {
55 inline_element(elem, &c, component, diag);
56 }
57 }
58 });
59 component.popup_windows.borrow().iter().for_each(|p| {
60 inline_components_recursively(&p.component, roots, inline_selection, diag)
61 })
62 }
63 let mut roots = HashSet::new();
64 if inline_selection == InlineSelection::InlineOnlyRequiredComponents {
65 for component in doc.exported_roots().chain(doc.popup_menu_impl.iter().cloned()) {
66 roots.insert(ByAddress(component.clone()));
67 }
68 }
69 for component in doc.exported_roots().chain(doc.popup_menu_impl.iter().cloned()) {
70 inline_components_recursively(&component, &roots, inline_selection, diag);
71 let mut init_code = component.init_code.borrow_mut();
72 let inlined_init_code = core::mem::take(&mut init_code.inlined_init_code);
73 init_code.constructor_code.splice(0..0, inlined_init_code.into_values());
74 }
75}
76
77fn element_key(e: ElementRc) -> ByAddress<ElementRc> {
78 ByAddress(e)
79}
80
81type Mapping = HashMap<ByAddress<ElementRc>, ElementRc>;
82
83fn inline_element(
84 elem: &ElementRc,
85 inlined_component: &Rc<Component>,
86 root_component: &Rc<Component>,
87 diag: &mut BuildDiagnostics,
88) {
89 debug_assert_eq!(elem.borrow().base_type, ElementType::Component(inlined_component.clone()));
91 debug_assert!(
92 inlined_component.root_element.borrow().repeated.is_none(),
93 "root element of a component cannot be repeated"
94 );
95 debug_assert!(inlined_component.parent_element().is_none());
96
97 let mut elem_mut = elem.borrow_mut();
98 let priority_delta = 1 + elem_mut.inline_depth;
99 elem_mut.base_type = inlined_component.root_element.borrow().base_type.clone();
100 elem_mut.property_declarations.extend(
101 inlined_component.root_element.borrow().property_declarations.iter().map(|(name, decl)| {
102 let mut decl = decl.clone();
103 decl.expose_in_public_api = false;
104 (name.clone(), decl)
105 }),
106 );
107
108 for (p, a) in inlined_component.root_element.borrow().property_analysis.borrow().iter() {
109 elem_mut.property_analysis.borrow_mut().entry(p.clone()).or_default().merge_with_base(a);
110 }
111
112 debug_assert!(inlined_component.root_element.borrow().states.is_empty());
114 debug_assert!(inlined_component.root_element.borrow().transitions.is_empty());
115
116 let mut mapping = HashMap::new();
118 mapping.insert(element_key(inlined_component.root_element.clone()), elem.clone());
119
120 let mut new_children = Vec::with_capacity(
121 elem_mut.children.len() + inlined_component.root_element.borrow().children.len(),
122 );
123 new_children.extend(
124 inlined_component.root_element.borrow().children.iter().map(|x| {
125 duplicate_element_with_mapping(x, &mut mapping, root_component, priority_delta)
126 }),
127 );
128
129 let mut move_children_into_popup = None;
130
131 match inlined_component.child_insertion_point.borrow().as_ref() {
132 Some(inlined_cip) => {
133 let children = std::mem::take(&mut elem_mut.children);
134 let old_count = children.len();
135 if let Some(insertion_element) = mapping.get(&element_key(inlined_cip.parent.clone())) {
136 if old_count > 0 {
137 if !Rc::ptr_eq(elem, insertion_element) {
138 debug_assert!(std::rc::Weak::ptr_eq(
139 &insertion_element.borrow().enclosing_component,
140 &elem_mut.enclosing_component,
141 ));
142 insertion_element.borrow_mut().children.splice(
143 inlined_cip.insertion_index..inlined_cip.insertion_index,
144 children,
145 );
146 } else {
147 new_children.splice(
148 inlined_cip.insertion_index..inlined_cip.insertion_index,
149 children,
150 );
151 }
152 }
153 let mut cip = root_component.child_insertion_point.borrow_mut();
154 if let Some(cip) = cip.as_mut() {
155 if Rc::ptr_eq(&cip.parent, elem) {
156 *cip = ChildrenInsertionPoint {
157 parent: insertion_element.clone(),
158 insertion_index: inlined_cip.insertion_index + cip.insertion_index,
159 node: inlined_cip.node.clone(),
160 };
161 }
162 } else if Rc::ptr_eq(elem, &root_component.root_element) {
163 *cip = Some(ChildrenInsertionPoint {
164 parent: insertion_element.clone(),
165 insertion_index: inlined_cip.insertion_index + old_count,
166 node: inlined_cip.node.clone(),
167 });
168 };
169 } else if old_count > 0 {
170 debug_assert!(inlined_component.popup_windows.borrow().iter().any(|p| Rc::ptr_eq(
172 &p.component,
173 &inlined_cip.parent.borrow().enclosing_component.upgrade().unwrap()
174 )));
175 move_children_into_popup = Some(children);
176 };
177 }
178 _ => {
179 new_children.append(&mut elem_mut.children);
180 }
181 }
182
183 elem_mut.children = new_children;
184 elem_mut.debug.extend_from_slice(&inlined_component.root_element.borrow().debug);
185
186 if let ElementType::Component(c) = &mut elem_mut.base_type
187 && c.parent_element().is_some()
188 {
189 debug_assert!(Rc::ptr_eq(elem, &c.parent_element().unwrap()));
190 *c = duplicate_sub_component(c, elem, &mut mapping, priority_delta);
191 };
192
193 root_component.optimized_elements.borrow_mut().extend(
194 inlined_component.optimized_elements.borrow().iter().map(|x| {
195 duplicate_element_with_mapping(x, &mut mapping, root_component, priority_delta)
196 }),
197 );
198 root_component.popup_windows.borrow_mut().extend(
199 inlined_component
200 .popup_windows
201 .borrow()
202 .iter()
203 .map(|p| duplicate_popup(p, &mut mapping, priority_delta)),
204 );
205
206 root_component.menu_item_tree.borrow_mut().extend(
207 inlined_component
208 .menu_item_tree
209 .borrow()
210 .iter()
211 .map(|it| duplicate_sub_component(it, elem, &mut mapping, priority_delta)),
212 );
213
214 root_component.timers.borrow_mut().extend(inlined_component.timers.borrow().iter().map(|t| {
215 let inlined_element = mapping.get(&element_key(t.element.upgrade().unwrap())).unwrap();
216
217 Timer { element: Rc::downgrade(inlined_element), ..t.clone() }
218 }));
219
220 let mut moved_into_popup = HashSet::new();
221 if let Some(children) = move_children_into_popup {
222 let child_insertion_point = inlined_component.child_insertion_point.borrow();
223 let inlined_cip = child_insertion_point.as_ref().unwrap();
224
225 let insertion_element = mapping.get(&element_key(inlined_cip.parent.clone())).unwrap();
226 debug_assert!(!std::rc::Weak::ptr_eq(
227 &insertion_element.borrow().enclosing_component,
228 &elem_mut.enclosing_component,
229 ));
230 debug_assert!(root_component.popup_windows.borrow().iter().any(|p| Rc::ptr_eq(
231 &p.component,
232 &insertion_element.borrow().enclosing_component.upgrade().unwrap()
233 )));
234 for c in &children {
235 recurse_elem(c, &(), &mut |e, _| {
236 e.borrow_mut().enclosing_component =
237 insertion_element.borrow().enclosing_component.clone();
238 moved_into_popup.insert(element_key(e.clone()));
239 });
240 }
241 insertion_element
242 .borrow_mut()
243 .children
244 .splice(inlined_cip.insertion_index..inlined_cip.insertion_index, children);
245 let mut cip = root_component.child_insertion_point.borrow_mut();
246 if let Some(cip) = cip.as_mut() {
247 if Rc::ptr_eq(&cip.parent, elem) {
248 *cip = ChildrenInsertionPoint {
249 parent: insertion_element.clone(),
250 insertion_index: inlined_cip.insertion_index + cip.insertion_index,
251 node: inlined_cip.node.clone(),
252 };
253 }
254 } else {
255 *cip = Some(ChildrenInsertionPoint {
256 parent: insertion_element.clone(),
257 insertion_index: inlined_cip.insertion_index,
258 node: inlined_cip.node.clone(),
259 });
260 };
261 }
262
263 for (k, val) in inlined_component.root_element.borrow().bindings.iter() {
264 match elem_mut.bindings.entry(k.clone()) {
265 std::collections::btree_map::Entry::Vacant(entry) => {
266 let priority = &mut entry.insert(val.clone()).get_mut().priority;
267 *priority = priority.saturating_add(priority_delta);
268 }
269 std::collections::btree_map::Entry::Occupied(mut entry) => {
270 let entry = entry.get_mut().get_mut();
271 if entry.merge_with(&val.borrow()) {
272 entry.priority = entry.priority.saturating_add(priority_delta);
273 }
274 }
275 }
276 }
277 for (k, val) in inlined_component.root_element.borrow().change_callbacks.iter() {
278 match elem_mut.change_callbacks.entry(k.clone()) {
279 std::collections::btree_map::Entry::Vacant(entry) => {
280 entry.insert(val.clone());
281 }
282 std::collections::btree_map::Entry::Occupied(mut entry) => {
283 entry.get_mut().get_mut().splice(0..0, val.borrow().iter().cloned());
284 }
285 }
286 }
287
288 if let Some(orig) = &inlined_component.root_element.borrow().layout_info_prop {
289 if let Some(_new) = &mut elem_mut.layout_info_prop {
290 todo!("Merge layout infos");
291 } else {
292 elem_mut.layout_info_prop = Some(orig.clone());
293 }
294 }
295 if let Some(orig) = &inlined_component.root_element.borrow().layout_info_v_with_constraint {
296 if let Some(_new) = &mut elem_mut.layout_info_v_with_constraint {
297 todo!("Merge layout infos");
298 } else {
299 elem_mut.layout_info_v_with_constraint = Some(orig.clone());
300 }
301 }
302 if let Some(orig) = &inlined_component.root_element.borrow().layout_info_h_with_constraint {
303 if let Some(_new) = &mut elem_mut.layout_info_h_with_constraint {
304 todo!("Merge layout infos");
305 } else {
306 elem_mut.layout_info_h_with_constraint = Some(orig.clone());
307 }
308 }
309
310 core::mem::drop(elem_mut);
311
312 let fixup_init_expression = |mut init_code: Expression| {
313 visit_named_references_in_expression(&mut init_code, &mut |nr| {
315 fixup_reference(nr, &mapping)
316 });
317 fixup_element_references(&mut init_code, &mapping);
318 init_code
319 };
320 let inlined_init_code = inlined_component
321 .init_code
322 .borrow()
323 .inlined_init_code
324 .values()
325 .cloned()
326 .chain(inlined_component.init_code.borrow().constructor_code.iter().cloned())
327 .map(fixup_init_expression)
328 .collect();
329
330 root_component
331 .init_code
332 .borrow_mut()
333 .inlined_init_code
334 .insert(elem.borrow().span().offset, Expression::CodeBlock(inlined_init_code));
335
336 for e in mapping.values() {
338 visit_element_expressions(e, |expr, _, _| fixup_element_references(expr, &mapping));
341 for d in &mut e.borrow_mut().debug {
344 if let Some(crate::layout::Layout::GridLayout(grid)) = d.layout.as_mut() {
345 grid.clone_cells();
346 }
347 }
348 visit_all_named_references_in_element(e, |nr| fixup_reference(nr, &mapping));
349 }
350 for p in root_component.popup_windows.borrow_mut().iter_mut() {
351 fixup_reference(&mut p.x, &mapping);
352 fixup_reference(&mut p.y, &mapping);
353 if let Some(is_open) = &mut p.is_open {
354 fixup_reference(is_open, &mapping);
355 }
356 }
357 for t in root_component.timers.borrow_mut().iter_mut() {
358 fixup_reference(&mut t.interval, &mapping);
359 fixup_reference(&mut t.running, &mapping);
360 fixup_reference(&mut t.triggered, &mapping);
361 }
362 if !moved_into_popup.is_empty() {
364 recurse_elem_no_borrow(&root_component.root_element.clone(), &(), &mut |e, _| {
365 if !moved_into_popup.contains(&element_key(e.clone())) {
366 visit_all_named_references_in_element(e, |nr| {
367 if moved_into_popup.contains(&element_key(nr.element())) {
368 diag.push_error(format!("Access to property '{nr:?}' which is inlined into a PopupWindow via @children is forbidden"), &*e.borrow());
369 }
370 });
371 }
372 });
373 }
374}
375
376fn duplicate_element_with_mapping(
378 element: &ElementRc,
379 mapping: &mut Mapping,
380 root_component: &Rc<Component>,
381 priority_delta: i32,
382) -> ElementRc {
383 let elem = element.borrow();
384 let new = Rc::new(RefCell::new(Element {
385 base_type: elem.base_type.clone(),
386 id: elem.id.clone(),
387 property_declarations: elem.property_declarations.clone(),
388 bindings: elem
390 .bindings
391 .iter()
392 .map(|b| duplicate_binding(b, mapping, root_component, priority_delta))
393 .collect(),
394 change_callbacks: elem.change_callbacks.clone(),
395 property_analysis: elem.property_analysis.clone(),
396 children: elem
397 .children
398 .iter()
399 .map(|x| duplicate_element_with_mapping(x, mapping, root_component, priority_delta))
400 .collect(),
401 repeated: elem.repeated.clone(),
402 is_component_placeholder: elem.is_component_placeholder,
403 debug: elem.debug.clone(),
404 enclosing_component: Rc::downgrade(root_component),
405 states: elem.states.clone(),
406 transitions: elem
407 .transitions
408 .iter()
409 .map(|t| duplicate_transition(t, mapping, root_component, priority_delta))
410 .collect(),
411 child_of_layout: elem.child_of_layout,
412 layout_info_prop: elem.layout_info_prop.clone(),
413 layout_info_v_with_constraint: elem.layout_info_v_with_constraint.clone(),
414 layout_info_h_with_constraint: elem.layout_info_h_with_constraint.clone(),
415 default_fill_parent: elem.default_fill_parent,
416 accessibility_props: elem.accessibility_props.clone(),
417 geometry_props: elem.geometry_props.clone(),
418 named_references: Default::default(),
419 item_index: Default::default(), item_index_of_first_children: Default::default(),
421 is_flickable_viewport: elem.is_flickable_viewport,
422 has_popup_child: elem.has_popup_child,
423 is_tooltip: elem.is_tooltip,
424 is_legacy_syntax: elem.is_legacy_syntax,
425 inline_depth: elem.inline_depth + 1,
426 grid_layout_cell: elem
430 .grid_layout_cell
431 .as_ref()
432 .map(|cell| Rc::new(RefCell::new(cell.borrow().clone()))),
433 }));
434 mapping.insert(element_key(element.clone()), new.clone());
435 if let ElementType::Component(c) = &mut new.borrow_mut().base_type
436 && c.parent_element().is_some()
437 {
438 debug_assert!(Rc::ptr_eq(element, &c.parent_element().unwrap()));
439 *c = duplicate_sub_component(c, &new, mapping, priority_delta);
440 };
441
442 new
443}
444
445fn duplicate_sub_component(
447 component_to_duplicate: &Rc<Component>,
448 new_parent: &ElementRc,
449 mapping: &mut Mapping,
450 priority_delta: i32,
451) -> Rc<Component> {
452 debug_assert!(component_to_duplicate.parent_element().is_some());
453 let new_component = Component {
454 node: component_to_duplicate.node.clone(),
455 id: component_to_duplicate.id.clone(),
456 root_element: duplicate_element_with_mapping(
457 &component_to_duplicate.root_element,
458 mapping,
459 component_to_duplicate, priority_delta,
461 ),
462 parent_element: RefCell::new(Rc::downgrade(new_parent)),
463 optimized_elements: RefCell::new(
464 component_to_duplicate
465 .optimized_elements
466 .borrow()
467 .iter()
468 .map(|e| {
469 duplicate_element_with_mapping(
470 e,
471 mapping,
472 component_to_duplicate,
473 priority_delta,
474 )
475 })
476 .collect(),
477 ),
478 root_constraints: component_to_duplicate.root_constraints.clone(),
479 child_insertion_point: component_to_duplicate.child_insertion_point.clone(),
480 init_code: component_to_duplicate.init_code.clone(),
481 popup_windows: Default::default(),
482 timers: component_to_duplicate.timers.clone(),
483 menu_item_tree: Default::default(),
484 exported_global_names: component_to_duplicate.exported_global_names.clone(),
485 used: component_to_duplicate.used.clone(),
486 private_properties: Default::default(),
487 inherits_popup_window: core::cell::Cell::new(false),
488 from_library: core::cell::Cell::new(false),
489 };
490
491 let new_component = Rc::new(new_component);
492 let weak = Rc::downgrade(&new_component);
493 recurse_elem(&new_component.root_element, &(), &mut |e, _| {
494 e.borrow_mut().enclosing_component = weak.clone()
495 });
496 for o in new_component.optimized_elements.borrow().iter() {
497 o.borrow_mut().enclosing_component = weak.clone()
498 }
499 *new_component.popup_windows.borrow_mut() = component_to_duplicate
500 .popup_windows
501 .borrow()
502 .iter()
503 .map(|p| duplicate_popup(p, mapping, priority_delta))
504 .collect();
505 for p in new_component.popup_windows.borrow_mut().iter_mut() {
506 fixup_reference(&mut p.x, mapping);
507 fixup_reference(&mut p.y, mapping);
508 if let Some(is_open) = &mut p.is_open {
509 fixup_reference(is_open, mapping);
510 }
511 }
512 for t in new_component.timers.borrow_mut().iter_mut() {
513 fixup_reference(&mut t.interval, mapping);
514 fixup_reference(&mut t.running, mapping);
515 fixup_reference(&mut t.triggered, mapping);
516 }
517 *new_component.menu_item_tree.borrow_mut() = component_to_duplicate
518 .menu_item_tree
519 .borrow()
520 .iter()
521 .map(|it| {
522 let new_parent =
523 mapping.get(&element_key(it.parent_element().unwrap())).unwrap().clone();
524 duplicate_sub_component(it, &new_parent, mapping, priority_delta)
525 })
526 .collect();
527 new_component
528 .root_constraints
529 .borrow_mut()
530 .visit_named_references(&mut |nr| fixup_reference(nr, mapping));
531 new_component
532}
533
534fn duplicate_popup(p: &PopupWindow, mapping: &mut Mapping, priority_delta: i32) -> PopupWindow {
535 let parent = mapping
536 .get(&element_key(p.component.parent_element().expect("must have a parent")))
537 .expect("Parent must be in the mapping")
538 .clone();
539 PopupWindow {
540 x: p.x.clone(),
541 y: p.y.clone(),
542 close_policy: p.close_policy.clone(),
543 component: duplicate_sub_component(&p.component, &parent, mapping, priority_delta),
544 parent_element: mapping
545 .get(&element_key(p.parent_element.clone()))
546 .expect("Parent element must be in the mapping")
547 .clone(),
548 is_tooltip: p.is_tooltip,
549 is_open: p.is_open.clone(),
550 }
551}
552
553fn duplicate_binding(
556 (k, b): (&SmolStr, &RefCell<BindingExpression>),
557 mapping: &mut Mapping,
558 root_component: &Rc<Component>,
559 priority_delta: i32,
560) -> (SmolStr, RefCell<BindingExpression>) {
561 let b = b.borrow();
562 let b = BindingExpression {
563 expression: b.expression.clone(),
564 span: b.span.clone(),
565 priority: b.priority.saturating_add(priority_delta),
566 animation: b
567 .animation
568 .as_ref()
569 .map(|pa| duplicate_property_animation(pa, mapping, root_component, priority_delta)),
570 analysis: b.analysis.clone(),
571 two_way_bindings: b.two_way_bindings.clone(),
572 };
573 (k.clone(), b.into())
574}
575
576fn duplicate_property_animation(
577 v: &PropertyAnimation,
578 mapping: &mut Mapping,
579 root_component: &Rc<Component>,
580 priority_delta: i32,
581) -> PropertyAnimation {
582 match v {
583 PropertyAnimation::Static(a) => PropertyAnimation::Static(duplicate_element_with_mapping(
584 a,
585 mapping,
586 root_component,
587 priority_delta,
588 )),
589 PropertyAnimation::Transition { state_ref, animations } => PropertyAnimation::Transition {
590 state_ref: state_ref.clone(),
591 animations: animations
592 .iter()
593 .map(|a| TransitionPropertyAnimation {
594 state_id: a.state_id,
595 direction: a.direction,
596 animation: duplicate_element_with_mapping(
597 &a.animation,
598 mapping,
599 root_component,
600 priority_delta,
601 ),
602 })
603 .collect(),
604 },
605 }
606}
607
608fn fixup_reference(nr: &mut NamedReference, mapping: &Mapping) {
609 if let Some(e) = mapping.get(&element_key(nr.element())) {
610 *nr = NamedReference::new(e, nr.name().clone());
611 }
612}
613
614fn fixup_grid_layout(layout: &mut crate::layout::GridLayout, fxe: &impl Fn(&mut ElementRc)) {
617 for e in &mut layout.elems {
618 fxe(&mut e.item.element);
619 }
620 layout.clone_cells();
623 for elem in &mut layout.elems {
624 let mut cell = elem.cell.borrow_mut();
625 let Some(child_items) = &mut cell.child_items else { continue };
626 for child in child_items.iter_mut() {
627 fxe(&mut child.layout_item_mut().element);
628 if let crate::layout::RowChildTemplate::Repeated { repeated_element, .. } = child {
629 fxe(repeated_element);
630 }
631 }
632 }
633}
634
635fn fixup_element_references(expr: &mut Expression, mapping: &Mapping) {
636 let fx = |element: &mut std::rc::Weak<RefCell<Element>>| {
637 if let Some(e) = element.upgrade().and_then(|e| mapping.get(&element_key(e))) {
638 *element = Rc::downgrade(e);
639 }
640 };
641 let fxe = |element: &mut ElementRc| {
642 if let Some(e) = mapping.get(&element_key(element.clone())) {
643 *element = e.clone();
644 }
645 };
646 match expr {
647 Expression::ElementReference(element) => fx(element),
648 Expression::SolveBoxLayout(layout, _) => {
649 for e in &mut layout.elems {
650 fxe(&mut e.element);
651 }
652 }
653 Expression::ComputeBoxLayoutInfo { layout, cross_axis_size, .. } => {
654 for e in &mut layout.elems {
655 fxe(&mut e.element);
656 }
657 if let Some(cas) = cross_axis_size {
658 fixup_element_references(cas, mapping);
659 }
660 }
661 Expression::SolveGridLayout { layout, .. } | Expression::OrganizeGridLayout(layout) => {
662 fixup_grid_layout(layout, &fxe);
663 }
664 Expression::ComputeGridLayoutInfo { layout, cross_axis_size, .. } => {
665 fixup_grid_layout(layout, &fxe);
666 if let Some(cas) = cross_axis_size {
667 fixup_element_references(cas, mapping);
668 }
669 }
670 Expression::SolveFlexboxLayout(layout) => {
671 for e in &mut layout.elems {
672 fxe(&mut e.item.element);
673 }
674 }
675 Expression::ComputeFlexboxLayoutInfo { layout, cross_axis_size, .. } => {
676 for e in &mut layout.elems {
677 fxe(&mut e.item.element);
678 }
679 if let Some(cas) = cross_axis_size {
680 fixup_element_references(cas, mapping);
681 }
682 }
683 Expression::RepeaterModelReference { element }
684 | Expression::RepeaterIndexReference { element } => fx(element),
685 _ => expr.visit_mut(|e| fixup_element_references(e, mapping)),
686 }
687}
688
689fn duplicate_transition(
690 t: &Transition,
691 mapping: &mut HashMap<ByAddress<ElementRc>, Rc<RefCell<Element>>>,
692 root_component: &Rc<Component>,
693 priority_delta: i32,
694) -> Transition {
695 Transition {
696 direction: t.direction,
697 state_id: t.state_id.clone(),
698 property_animations: t
699 .property_animations
700 .iter()
701 .map(|(r, loc, anim)| {
702 (
703 r.clone(),
704 loc.clone(),
705 duplicate_element_with_mapping(anim, mapping, root_component, priority_delta),
706 )
707 })
708 .collect(),
709 node: t.node.clone(),
710 }
711}
712
713fn component_requires_inlining(component: &Rc<Component>) -> bool {
716 let root_element = &component.root_element;
717 if super::flickable::is_flickable_element(root_element) {
718 return true;
719 }
720
721 for (prop, binding) in &root_element.borrow().bindings {
722 let binding = binding.borrow();
723 if prop.starts_with("drop-shadow-")
726 || prop.starts_with("inner-shadow-")
727 || prop == "opacity"
728 || prop == "cache-rendering-hint"
729 || prop == "visible"
730 {
731 return true;
732 }
733 if (prop == "height" || prop == "width") && binding.expression.ty() == Type::Percent {
734 return true;
736 }
737 if binding.animation.is_some() {
738 let lookup_result = root_element.borrow().lookup_property(prop);
739 if !lookup_result.is_valid()
740 || !lookup_result.is_local_to_component
741 || !matches!(
742 lookup_result.property_visibility,
743 PropertyVisibility::Private | PropertyVisibility::Output
744 )
745 {
746 return true;
749 }
750 }
751 }
752
753 false
754}
755
756fn element_require_inlining(elem: &ElementRc) -> bool {
757 if !elem.borrow().children.is_empty() {
758 return true;
760 }
761
762 if super::lower_popups::is_popup_window(elem) {
764 return true;
765 }
766
767 for (prop, binding) in &elem.borrow().bindings {
768 if prop == "clip" {
769 return true;
771 }
772
773 if (prop == "padding"
774 || prop == "spacing"
775 || prop.starts_with("padding-")
776 || prop.starts_with("spacing-")
777 || prop == "alignment")
778 && let ElementType::Component(base) = &elem.borrow().base_type
779 && crate::layout::is_layout(&base.root_element.borrow().base_type)
780 && !base.root_element.borrow().is_binding_set(prop, false)
781 {
782 return true;
784 }
785
786 let binding = binding.borrow();
787 if binding.animation.is_some() && matches!(binding.expression, Expression::Invalid) {
788 return true;
790 }
791 }
792
793 false
794}