slint/internal/compiler/passes/optimize_useless_rectangles.rs
Olivier Goffart f8f61dc2b7 Fix a bunch more issue with PopupWindow
* Make sure that the compiler don't panic if the parent of a PopupWindow
   is optimized (by not optiizing such element)

 * Ensure that we can call popup.show() from within a deeper repeater

 * Ensure that the parent element of the popup is the right one in case of
   repeater (and not the node in the parent component)

This partially revert ad5991f8fa and
6c7a7aed0e because we must do the lower_popup
adter the repeater pass, because otherwise the parent element of the
created component for the PopupWindow might be wrong and it is not easy to
adjust (we would have to make Component::parent_element a RefCell or duplicate
it again.

Fixes #1132
2022-04-01 14:06:38 +02:00

55 lines
1.8 KiB
Rust

// Copyright © SixtyFPS GmbH <info@slint-ui.com>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
//! Remove the rectangles that serves no purposes
//!
//! Rectangles which do not draw anything and have no x or y don't need to be in
//! the item tree, we can just remove them.
use crate::{langtype::Type, object_tree::*};
use std::rc::Rc;
pub fn optimize_useless_rectangles(root_component: &Rc<Component>) {
recurse_elem_including_sub_components(root_component, &(), &mut |parent, _| {
let mut parent = parent.borrow_mut();
let children = std::mem::take(&mut parent.children);
for elem in children {
if !can_optimize(&elem) {
parent.children.push(elem);
continue;
}
parent.children.extend(std::mem::take(&mut elem.borrow_mut().children));
parent
.enclosing_component
.upgrade()
.unwrap()
.optimized_elements
.borrow_mut()
.push(elem);
}
});
}
/// Check that this is a element we can optimize
fn can_optimize(elem: &ElementRc) -> bool {
let e = elem.borrow();
if e.is_flickable_viewport || e.has_popup_child {
return false;
};
let base_type = match &e.base_type {
Type::Builtin(base_type) if base_type.name == "Rectangle" => base_type,
_ => return false,
};
// Check that no Rectangle property other than height and width are set
let analysis = e.property_analysis.borrow();
!e.bindings.keys().chain(analysis.iter().filter(|(_, v)| v.is_set).map(|(k, _)| k)).any(|k| {
!matches!(k.as_str(), "height" | "width")
&& !e.property_declarations.contains_key(k.as_str())
&& base_type.properties.contains_key(k.as_str())
})
}