i_slint_compiler/passes/
deprecated_rotation_origin.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4//! This pass handles the deprecated `rotation-origin-*` properties on Text and Image that were replaced by `transform-origin`
5
6use crate::diagnostics::{BuildDiagnostics, Spanned};
7use crate::expression_tree::Expression;
8use crate::langtype::ElementType;
9use crate::namedreference::NamedReference;
10use crate::object_tree::{Component, Element, ElementRc};
11use core::cell::RefCell;
12use smol_str::SmolStr;
13
14pub fn handle_rotation_origin(component: &Component, diag: &mut BuildDiagnostics) {
15    let transform_origin = crate::typeregister::transform_origin_property();
16
17    crate::object_tree::recurse_elem_including_sub_components_no_borrow(
18        component,
19        &(),
20        &mut |elem, _| {
21            let mut must_materialize = false;
22            let mut seen = false;
23            for (prop, _) in crate::typeregister::DEPRECATED_ROTATION_ORIGIN_PROPERTIES {
24                if is_property_set(&elem.borrow(), prop) {
25                    let span = match elem
26                        .borrow()
27                        .bindings
28                        .get(prop)
29                        .and_then(|b| b.borrow().span.clone())
30                    {
31                        Some(span) => span,
32                        None => {
33                            if seen {
34                                return;
35                            }
36                            elem.borrow().to_source_location()
37                        }
38                    };
39
40                    seen = true;
41
42                    if !is_image_or_text(elem) {
43                        diag.push_error(format!("'{prop}' cannot be set on this element"), &span);
44                    } else {
45                        diag.push_property_deprecation_warning(prop, transform_origin.0, &span);
46                        must_materialize = true;
47                    }
48                }
49            }
50            if !must_materialize {
51                return;
52            }
53
54            let expr = Expression::Struct {
55                ty: transform_origin.1.clone(),
56                values: crate::typeregister::DEPRECATED_ROTATION_ORIGIN_PROPERTIES
57                    .iter()
58                    .map(|(prop, _)| {
59                        (
60                            SmolStr::new_static(&prop[prop.len() - 1..]),
61                            Expression::PropertyReference(NamedReference::new(
62                                elem,
63                                SmolStr::new_static(prop),
64                            )),
65                        )
66                    })
67                    .collect(),
68            };
69
70            match elem.borrow_mut().bindings.entry(transform_origin.0.into()) {
71                std::collections::btree_map::Entry::Occupied(occupied_entry) => {
72                    diag.push_error(
73                        "Can't specify transform-origin if rotation-origin-x or rotation-origin-y is used on this element".into(),
74                        &occupied_entry.get().borrow().span
75                    );
76                }
77                std::collections::btree_map::Entry::Vacant(vacant_entry) => {
78                    vacant_entry.insert(RefCell::new(expr.into()));
79                }
80            }
81        },
82    );
83}
84
85/// true if this element had a rotation-origin property
86fn is_image_or_text(e: &ElementRc) -> bool {
87    e.borrow().builtin_type().is_some_and(|bt| matches!(bt.name.as_str(), "Image" | "Text"))
88}
89
90/// Returns true if the property is set by a biinding or an assignment expression
91fn is_property_set(e: &Element, property_name: &str) -> bool {
92    e.bindings.contains_key(property_name)
93        || e.property_analysis.borrow().get(property_name).is_some_and(|a| a.is_set || a.is_linked)
94        || matches!(&e.base_type, ElementType::Component(base) if is_property_set(&base.root_element.borrow(), property_name))
95}