Skip to main content

swiftui_native/views/
materials.rs

1//! Materials, Liquid Glass and theming.
2
3use super::*;
4use crate::abi;
5use crate::resolve;
6use core::ffi::c_void;
7use crate::mangle;
8mangle::modifier_types! {
9    /// `.background(_: Material)`
10    /// `ModifiedContent<AnyView, _BackgroundStyleModifier<Material>>`
11    pub(crate) MATERIAL_BG_T = ty("_BackgroundStyleModifier").of(vec![ty("Material")]);
12    /// `.background(_: AnyGradient)`
13    /// `ModifiedContent<AnyView, _BackgroundStyleModifier<AnyGradient>>`
14    pub(crate) GRADIENT_BG_T = ty("_BackgroundStyleModifier").of(vec![ty("AnyGradient")]);
15    /// `.tint(_:)`
16    /// `ModifiedContent<AnyView, _EnvironmentKeyWritingModifier<AnyShapeStyle?>>`
17    pub(crate) TINT_T = ty("_EnvironmentKeyWritingModifier").of(vec![opt(ty("AnyShapeStyle"))]);
18    /// `.preferredColorScheme(_:)`
19    /// `ModifiedContent<AnyView, _PreferenceWritingModifier<PreferredColorSchemeKey>>`
20    pub(crate) COLOR_SCHEME_T = ty("_PreferenceWritingModifier").of(vec![ty("PreferredColorSchemeKey")]);
21    /// `.controlSize(_:)`
22    /// `ModifiedContent<AnyView, _EnvironmentKeyWritingModifier<ControlSize>>`
23    pub(crate) CONTROL_SIZE_T = ty("_EnvironmentKeyWritingModifier").of(vec![ty_enum("ControlSize")]);
24    /// `.buttonStyle(.glass)`
25    /// `ModifiedContent<AnyView, PrimitiveButtonStyleContainerModifier<GlassButtonStyle>>`
26    pub(crate) GLASS_BUTTON_T = ty("PrimitiveButtonStyleContainerModifier").of(vec![ty("GlassButtonStyle")]);
27    /// `.buttonStyle(.bordered)`
28    /// `ModifiedContent<AnyView, PrimitiveButtonStyleContainerModifier<BorderedButtonStyle>>`
29    pub(crate) BORDERED_BUTTON_T = ty("PrimitiveButtonStyleContainerModifier").of(vec![ty("BorderedButtonStyle")]);
30    /// `.buttonStyle(.borderedProminent)`
31    pub(crate) BORDERED_PROMINENT_T = ty("PrimitiveButtonStyleContainerModifier").of(vec![ty("BorderedProminentButtonStyle")]);
32}
33
34
35
36
37
38
39/// The blur materials SwiftUI exposes as `ShapeStyle`s.
40#[derive(Clone, Copy, PartialEq, Eq, Debug)]
41pub enum MaterialKind {
42    UltraThin,
43    Thin,
44    Regular,
45    Thick,
46    UltraThick,
47    Bar,
48}
49
50impl MaterialKind {
51    pub(crate) fn getter(self) -> &'static core::ffi::CStr {
52        match self {
53            MaterialKind::UltraThin => c"$s7SwiftUI8MaterialV9ultraThinACvgZ",
54            MaterialKind::Thin => c"$s7SwiftUI8MaterialV4thinACvgZ",
55            MaterialKind::Regular => c"$s7SwiftUI8MaterialV7regularACvgZ",
56            MaterialKind::Thick => c"$s7SwiftUI8MaterialV5thickACvgZ",
57            MaterialKind::UltraThick => c"$s7SwiftUI8MaterialV10ultraThickACvgZ",
58            MaterialKind::Bar => c"$s7SwiftUI8MaterialV3barACvgZ",
59        }
60    }
61}
62
63/// `SwiftUI.ColorScheme`, in declaration order.
64#[derive(Clone, Copy, PartialEq, Eq, Debug)]
65#[repr(u8)]
66pub enum ColorScheme {
67    Light = 0,
68    Dark = 1,
69}
70
71/// `SwiftUI.ControlSize`, in declaration order.
72#[derive(Clone, Copy, PartialEq, Eq, Debug)]
73#[repr(u8)]
74pub enum ControlSize {
75    Mini = 0,
76    Small = 1,
77    Regular = 2,
78    Large = 3,
79    ExtraLarge = 4,
80}
81
82swift_statics! {
83    /// `SwiftUI.Glass` — which Liquid Glass variant an effect uses.
84    pub enum Glass {
85        Regular = c"$s7SwiftUI5GlassV7regularACvgZ",
86        Clear = c"$s7SwiftUI5GlassV5clearACvgZ",
87        Identity = c"$s7SwiftUI5GlassV8identityACvgZ",
88    }
89}
90
91/// Which primitive button style to apply.
92#[derive(Clone, Copy, PartialEq, Eq, Debug)]
93pub enum ButtonStyle {
94    /// The Liquid Glass button style.
95    Glass,
96    Bordered,
97    /// `.borderedProminent` — the filled, tinted button.
98    BorderedProminent,
99}
100
101/// Read a static getter for a resilient struct, which returns indirectly in x8.
102///
103/// The buffer is sized by *stride*, not size: a callee may write the full
104/// stride including tail padding, and a size-sized buffer overflows the
105/// allocation. That corrupts the heap quietly and only crashes several
106/// allocations later, a long way from the cause.
107pub(crate) unsafe fn static_getter_indirect(
108    getter: *const c_void,
109    meta: *const c_void,
110    _size: usize,
111) -> Vec<u8> {
112    let mut buf = vec![0u8; unsafe { abi::type_bytes(meta) }];
113    unsafe {
114        core::arch::asm!("blr {f}", f = in(reg) getter,
115            in("x8") buf.as_mut_ptr(),
116            in("x20") meta,
117            lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
118            lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
119            lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
120            lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
121            lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
122        );
123    }
124    buf
125}
126
127/// `.background(_:ignoresSafeAreaEdges:)` with an arbitrary `ShapeStyle`.
128///
129///   x0 = @in style, x1 = Edge.Set, x2 = Self.Type, x3 = S.Type,
130///   x4 = Self: View WT, x5 = S: ShapeStyle WT, x8 = @out, x20 = self
131pub(crate) unsafe fn background_style(
132    view: &ViewHandle,
133    style: *mut u8,
134    style_meta: *const c_void,
135    style_wt: *const c_void,
136    modifier: &ModifierType,
137) -> ViewHandle {
138    unsafe {
139        let (_, _, size) = modifier.applied_to(view.meta);
140        let mut result = vec![0u8; size];
141        let this = view.value_ptr();
142        core::arch::asm!("blr {f}", f = in(reg) resolve::bg_fn(),
143            in("x0") style,
144            in("x1") EDGE_SET_ALL, // ignoresSafeAreaEdges: .all
145            in("x2") view.meta,
146            in("x3") style_meta,
147            in("x4") view.wt,
148            in("x5") style_wt,
149            in("x8") result.as_mut_ptr(),
150            in("x20") this,
151            lateout("x6") _, lateout("x7") _,
152            lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
153            lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
154            lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
155        );
156        wrap_modified(result, modifier, view)
157    }
158}
159
160/// Apply `.background(_:)` with an `AnyGradient` — what `.indigo.gradient` is.
161pub fn background_any_gradient(view: &ViewHandle, color: u64) -> ViewHandle {
162    unsafe {
163        let (mut value, meta, wt) = super::color_gradient(color);
164        background_style(view, value.as_mut_ptr(), meta, wt, &GRADIENT_BG_T)
165    }
166}
167
168/// A `Material`'s value, metadata and `ShapeStyle` witness.
169///
170/// What [`super::Shape::fill_style`] wants, for `Rectangle().fill(.regularMaterial)`
171/// — the same material that `.background(_:)` takes, used as a fill instead.
172pub fn material_parts(kind: MaterialKind) -> (Vec<u8>, *const c_void, *const c_void) {
173    unsafe {
174        let meta = abi::metadata0(resolve::material_ma());
175        let value = static_getter_indirect(resolve::require(kind.getter()), meta, 0);
176        (value, meta, resolve::material_shapestyle_wt())
177    }
178}
179
180/// Apply `.background(_: Material)` — the blur materials.
181pub fn background_material(view: &ViewHandle, kind: MaterialKind) -> ViewHandle {
182    unsafe {
183        // Material is resilient, so both its size and its static getters are
184        // only knowable at runtime.
185        let meta = abi::metadata0(resolve::material_ma());
186        let mut value =
187            static_getter_indirect(resolve::require(kind.getter()), meta, 0);
188        background_style(
189            view,
190            value.as_mut_ptr(),
191            meta,
192            resolve::material_shapestyle_wt(),
193            &MATERIAL_BG_T,
194        )
195    }
196}
197
198/// Apply `.glassEffect()` — Liquid Glass, in its default shape.
199///
200/// The result type is a `StaticIf<GlassEnabledPredicate, ...>`: SwiftUI picks
201/// between the glass-modified view and the original at runtime depending on
202/// whether the platform has Liquid Glass enabled.
203pub fn glass_effect(view: &ViewHandle) -> ViewHandle {
204    glass_effect_kind(view, Glass::Regular)
205}
206
207/// The same, with the variant named.
208///
209/// `Identity` is the no-op: it still builds the `StaticIf`, so the view's type
210/// is the one a glass effect gives it, with nothing drawn. That is what makes
211/// it usable as the "off" end of a condition without the two branches
212/// disagreeing about their type.
213pub fn glass_effect_kind(view: &ViewHandle, glass: Glass) -> ViewHandle {
214    unsafe {
215        let glass_meta = abi::metadata0(resolve::glass_ma());
216        let mut glass = static_getter_indirect(
217            glass.resolved(),
218            glass_meta,
219            0,
220        );
221
222        let shape_meta = abi::metadata0(resolve::glass_shape_ma());
223        let shape_wt = abi::get_view_wt_for_proto(shape_meta, resolve::shape_proto());
224        assert!(!shape_wt.is_null(), "DefaultGlassEffectShape: Shape");
225        // `DefaultGlassEffectShape` is not zero-size and not all-zero: it holds
226        // a `RoundedCornerStyle`, whose zero case is `.circular` while the
227        // initialiser picks `.continuous`. Both render as a capsule at this
228        // size, so only reflecting over the value shows the difference — call
229        // the initialiser rather than assuming an empty buffer.
230        let mut shape = vec![0u8; abi::type_bytes(shape_meta)];
231        core::arch::asm!("blr {f}", f = in(reg) resolve::glass_shape_init(),
232            in("x8") shape.as_mut_ptr(),
233            in("x20") shape_meta,
234            lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
235            lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
236            lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
237            lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
238            lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
239        );
240
241        let (meta, wt, size) = glass_result_type(view.meta, view.wt);
242        let mut result = vec![0u8; size];
243        let this = view.value_ptr();
244        // glassEffect<S: Shape>(_ glass: Glass, in shape: S)
245        //   x0 = @in Glass, x1 = @in S, x2 = Self.Type, x3 = S.Type,
246        //   x4 = Self: View WT, x5 = S: Shape WT, x8 = @out, x20 = self
247        core::arch::asm!("blr {f}", f = in(reg) resolve::glass_effect_fn2(),
248            in("x0") glass.as_mut_ptr(),
249            in("x1") shape.as_mut_ptr(),
250            in("x2") view.meta,
251            in("x3") shape_meta,
252            in("x4") view.wt,
253            in("x5") shape_wt,
254            in("x8") result.as_mut_ptr(),
255            in("x20") this,
256            lateout("x6") _, lateout("x7") _,
257            lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
258            lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
259            lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
260        );
261        wrap_owned(result, meta, wt)
262    }
263}
264
265/// The concrete type behind a `-> some View`, with its `View` witness and size.
266///
267/// Cached, and it was not. Every opaque-returning modifier — most of them — came
268/// through here and paid two `dlsym`s, a metadata instantiation and a
269/// conformance search, on every view built. Swift pays that once per site and
270/// keeps the answer in a `…Md` word; this keeps it in a map, because the
271/// substitutions are not always fixed at the site — a modifier generic over its
272/// style resolves a different type for each style it is handed.
273///
274/// The key is the descriptor plus its substitutions, all of them already
275/// resolved pointers, in a fixed array so a lookup allocates nothing.
276/// # Safety
277/// `oret` must be an opaque type descriptor, and `subst` must be the whole
278/// generic signature's substitutions in declaration order — parameters, then
279/// conformances. One missing entry reads the next off the end of the slice.
280pub unsafe fn opaque_result_type(
281    oret: *const c_void,
282    subst: &[*const c_void],
283) -> (*const c_void, *const c_void, usize) {
284    use std::collections::HashMap;
285    use std::sync::{Mutex, OnceLock};
286
287    /// Descriptor, then substitutions. Eight is the longest list this crate
288    /// builds; the assert says so rather than truncating quietly into a key that
289    /// collides with a shorter one.
290    type Key = [usize; 9];
291    assert!(subst.len() < 9, "opaque substitution list longer than the cache key");
292    let mut key: Key = [0; 9];
293    key[0] = oret as usize;
294    for (slot, p) in key[1..].iter_mut().zip(subst) {
295        *slot = *p as usize;
296    }
297
298    static CACHE: OnceLock<Mutex<HashMap<Key, super::Resolved>>> = OnceLock::new();
299    let cache = CACHE.get_or_init(|| Mutex::new(HashMap::new()));
300    if let Ok(map) = cache.lock() {
301        if let Some(&(m, w, n)) = map.get(&key) {
302            return (m as *const c_void, w as *const c_void, n);
303        }
304    }
305
306    unsafe {
307        type GetMeta =
308            unsafe extern "C" fn(usize, *const c_void, *const c_void, usize) -> *const c_void;
309        type GetConf = unsafe extern "C" fn(*const c_void, *const c_void, usize) -> *const c_void;
310        // Resolved once. These were two `dlsym` calls per modifier.
311        static SYMS: OnceLock<(usize, usize)> = OnceLock::new();
312        let (meta_fn, conf_fn) = *SYMS.get_or_init(|| {
313            (
314                libc::dlsym((-2isize) as *mut c_void, c"swift_getOpaqueTypeMetadata".as_ptr())
315                    as usize,
316                libc::dlsym((-2isize) as *mut c_void, c"swift_getOpaqueTypeConformance2".as_ptr())
317                    as usize,
318            )
319        });
320        let get_meta: GetMeta = core::mem::transmute(meta_fn as *const c_void);
321        let get_conf: GetConf = core::mem::transmute(conf_fn as *const c_void);
322
323        let meta = get_meta(0, subst.as_ptr() as *const c_void, oret, 0);
324        assert!(!meta.is_null(), "opaque result metadata");
325        let wt = get_conf(subst.as_ptr() as *const c_void, oret, 1);
326        assert!(!wt.is_null(), "opaque result View conformance");
327        let n = abi::type_bytes(meta);
328        if let Ok(mut map) = cache.lock() {
329            map.insert(key, (meta as usize, wt as usize, n));
330        }
331        (meta, wt, n)
332    }
333}
334
335/// Resolve `glassEffect`'s opaque result type.
336pub(crate) unsafe fn glass_result_type(
337    recv_meta: *const c_void,
338    recv_wt: *const c_void,
339) -> (*const c_void, *const c_void, usize) {
340    unsafe {
341        let oret = resolve::require(
342            c"$s7SwiftUI4ViewPAAE11glassEffect_2inQrAA5GlassV_qd__tAA5ShapeRd__lFQOMQ",
343        );
344        let shape_meta = abi::metadata0(resolve::glass_shape_ma());
345        let shape_wt = abi::get_view_wt_for_proto(shape_meta, resolve::shape_proto());
346        // An opaque return is a function of `Self`; describing it as `AnyView`
347        // while the call passes a concrete receiver sizes the result for a type
348        // that was never built.
349        let subst: [*const c_void; 4] = [recv_meta, shape_meta, recv_wt, shape_wt];
350        type GetMeta = unsafe extern "C" fn(usize, *const c_void, *const c_void, usize) -> *const c_void;
351        type GetConf = unsafe extern "C" fn(*const c_void, *const c_void, usize) -> *const c_void;
352        let get_meta: GetMeta = core::mem::transmute(libc::dlsym(
353            (-2isize) as *mut c_void, c"swift_getOpaqueTypeMetadata".as_ptr()));
354        let get_conf: GetConf = core::mem::transmute(libc::dlsym(
355            (-2isize) as *mut c_void, c"swift_getOpaqueTypeConformance2".as_ptr()));
356        let meta = get_meta(0, subst.as_ptr() as *const c_void, oret, 0);
357        assert!(!meta.is_null(), "glassEffect opaque metadata");
358        let wt = get_conf(subst.as_ptr() as *const c_void, oret, 1);
359        assert!(!wt.is_null(), "glassEffect opaque View conformance");
360        (meta, wt, abi::type_bytes(meta))
361    }
362}
363
364/// Apply `.tint(_:)`.
365pub fn tint(view: &ViewHandle, c: crate::Color) -> ViewHandle {
366    unsafe {
367        let (_, _, size) = TINT_T.applied_to(view.meta);
368        let mut result = vec![0u8; size];
369        let this = view.value_ptr();
370        // Optional<Color> is one class reference; nil is a null pointer.
371        let mut style: u64 = color_value(c.r, c.g, c.b, c.a);
372        // tint<S: ShapeStyle>(_: S?)
373        //   x0 = @in S?, x1 = Self.Type, x2 = S.Type,
374        //   x3 = Self: View WT, x4 = S: ShapeStyle WT
375        core::arch::asm!("blr {f}", f = in(reg) resolve::tint_fn(),
376            in("x0") &mut style as *mut u64,
377            in("x1") view.meta,
378            in("x2") resolve::color_meta(),
379            in("x3") view.wt,
380            in("x4") resolve::color_shapestyle_wt(),
381            in("x8") result.as_mut_ptr(),
382            in("x20") this,
383            lateout("x5") _, lateout("x6") _, lateout("x7") _,
384            lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
385            lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
386            lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
387        );
388        wrap_modified(result, &TINT_T, view)
389    }
390}
391
392/// Apply `.tint(_:)` through the `Color?` overload.
393///
394/// `View.tint` has two: one generic over `ShapeStyle`, which [`tint`] calls and
395/// which yields `_EnvironmentKeyWritingModifier<AnyShapeStyle?>`, and one taking
396/// a plain `Color?`, which yields `…<Color?>`. Swift picks the second for
397/// `.tint(.white)`, so a reference written that way disagrees with the first on
398/// both type and value.
399pub fn tint_color(view: &ViewHandle, color: u64) -> ViewHandle {
400    unsafe {
401        super::opaque_modifier(
402            resolve::tint_color_fn(),
403            resolve::tint_color_oret(),
404            view,
405            &[color],
406            [0.0; 4],
407        )
408    }
409}
410
411/// Apply `.tint(_:)` to a `Color` that is already built — one of SwiftUI's
412/// named colours, which no set of components spells.
413pub fn tint_value(view: &ViewHandle, tint: u64) -> ViewHandle {
414    unsafe {
415        let (_, _, size) = TINT_T.applied_to(view.meta);
416        let mut result = vec![0u8; size];
417        let this = view.value_ptr();
418        // Optional<Color> is one class reference; nil is a null pointer.
419        let mut style: u64 = tint;
420        // tint<S: ShapeStyle>(_: S?)
421        //   x0 = @in S?, x1 = Self.Type, x2 = S.Type,
422        //   x3 = Self: View WT, x4 = S: ShapeStyle WT
423        core::arch::asm!("blr {f}", f = in(reg) resolve::tint_fn(),
424            in("x0") &mut style as *mut u64,
425            in("x1") view.meta,
426            in("x2") resolve::color_meta(),
427            in("x3") view.wt,
428            in("x4") resolve::color_shapestyle_wt(),
429            in("x8") result.as_mut_ptr(),
430            in("x20") this,
431            lateout("x5") _, lateout("x6") _, lateout("x7") _,
432            lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
433            lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
434            lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
435        );
436        wrap_modified(result, &TINT_T, view)
437    }
438}
439
440/// Apply `.preferredColorScheme(_:)` — light or dark for this subtree.
441pub fn preferred_color_scheme(view: &ViewHandle, scheme: ColorScheme) -> ViewHandle {
442    unsafe {
443        let (_, _, size) = COLOR_SCHEME_T.applied_to(view.meta);
444        // ColorScheme is resilient, so the optional is passed by pointer.
445        let mut buf = [scheme as u8];
446        let r = abi::call_modifier(resolve::color_scheme_fn(), view.value_ptr(), view.meta, view.wt,
447            &[buf.as_mut_ptr() as u64],
448            [0.0; 4],
449            size,
450        );
451        wrap_modified(r, &COLOR_SCHEME_T, view)
452    }
453}
454
455/// Apply `.controlSize(_:)`.
456pub fn control_size(view: &ViewHandle, size_kind: ControlSize) -> ViewHandle {
457    unsafe {
458        let (_, _, size) = CONTROL_SIZE_T.applied_to(view.meta);
459        let mut buf = [size_kind as u8];
460        let r = abi::call_modifier(resolve::control_size_fn(), view.value_ptr(), view.meta, view.wt,
461            &[buf.as_mut_ptr() as u64],
462            [0.0; 4],
463            size,
464        );
465        wrap_modified(r, &CONTROL_SIZE_T, view)
466    }
467}
468
469/// Apply `.buttonStyle(_:)` to a subtree.
470pub fn button_style(view: &ViewHandle, style: ButtonStyle) -> ViewHandle {
471    unsafe {
472        let (accessor, init, modifier) = match style {
473            ButtonStyle::Glass => {
474                (resolve::glass_button_ma(), resolve::glass_button_init(), &GLASS_BUTTON_T)
475            }
476            ButtonStyle::Bordered => {
477                (resolve::bordered_button_ma(), resolve::bordered_button_init(), &BORDERED_BUTTON_T)
478            }
479            ButtonStyle::BorderedProminent => (
480                resolve::bordered_prominent_ma(),
481                resolve::bordered_prominent_init(),
482                &BORDERED_PROMINENT_T,
483            ),
484        };
485        let style_meta = abi::metadata0(accessor);
486        let style_wt =
487            abi::get_view_wt_for_proto(style_meta, resolve::primitive_button_style_proto());
488        assert!(!style_wt.is_null(), "button style: PrimitiveButtonStyle");
489
490        // The styles are resilient structs, so `init()` writes through x8.
491        let mut value = vec![0u8; abi::type_bytes(style_meta)];
492        core::arch::asm!("blr {f}", f = in(reg) init,
493            in("x8") value.as_mut_ptr(),
494            in("x20") style_meta,
495            lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
496            lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
497            lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
498            lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
499            lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
500        );
501
502        let (_, _, size) = modifier.applied_to(view.meta);
503        let mut result = vec![0u8; size];
504        let this = view.value_ptr();
505        // buttonStyle<S: PrimitiveButtonStyle>(_: S)
506        //   x0 = @in S, x1 = Self.Type, x2 = S.Type,
507        //   x3 = Self: View WT, x4 = S: PrimitiveButtonStyle WT
508        core::arch::asm!("blr {f}", f = in(reg) resolve::button_style_fn(),
509            in("x0") value.as_mut_ptr(),
510            in("x1") view.meta,
511            in("x2") style_meta,
512            in("x3") view.wt,
513            in("x4") style_wt,
514            in("x8") result.as_mut_ptr(),
515            in("x20") this,
516            lateout("x5") _, lateout("x6") _, lateout("x7") _,
517            lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
518            lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
519            lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
520        );
521        wrap_modified(result, modifier, view)
522    }
523}