1use super::*;
4use crate::abi;
5use crate::resolve;
6use core::ffi::c_void;
7use crate::mangle;
8mangle::modifier_types! {
9 pub(crate) MATERIAL_BG_T = ty("_BackgroundStyleModifier").of(vec![ty("Material")]);
12 pub(crate) GRADIENT_BG_T = ty("_BackgroundStyleModifier").of(vec![ty("AnyGradient")]);
15 pub(crate) TINT_T = ty("_EnvironmentKeyWritingModifier").of(vec![opt(ty("AnyShapeStyle"))]);
18 pub(crate) COLOR_SCHEME_T = ty("_PreferenceWritingModifier").of(vec![ty("PreferredColorSchemeKey")]);
21 pub(crate) CONTROL_SIZE_T = ty("_EnvironmentKeyWritingModifier").of(vec![ty_enum("ControlSize")]);
24 pub(crate) GLASS_BUTTON_T = ty("PrimitiveButtonStyleContainerModifier").of(vec![ty("GlassButtonStyle")]);
27 pub(crate) BORDERED_BUTTON_T = ty("PrimitiveButtonStyleContainerModifier").of(vec![ty("BorderedButtonStyle")]);
30 pub(crate) BORDERED_PROMINENT_T = ty("PrimitiveButtonStyleContainerModifier").of(vec![ty("BorderedProminentButtonStyle")]);
32}
33
34
35
36
37
38
39#[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#[derive(Clone, Copy, PartialEq, Eq, Debug)]
65#[repr(u8)]
66pub enum ColorScheme {
67 Light = 0,
68 Dark = 1,
69}
70
71#[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 pub enum Glass {
85 Regular = c"$s7SwiftUI5GlassV7regularACvgZ",
86 Clear = c"$s7SwiftUI5GlassV5clearACvgZ",
87 Identity = c"$s7SwiftUI5GlassV8identityACvgZ",
88 }
89}
90
91#[derive(Clone, Copy, PartialEq, Eq, Debug)]
93pub enum ButtonStyle {
94 Glass,
96 Bordered,
97 BorderedProminent,
99}
100
101pub(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
127pub(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, 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
160pub 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
168pub 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
180pub fn background_material(view: &ViewHandle, kind: MaterialKind) -> ViewHandle {
182 unsafe {
183 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
198pub fn glass_effect(view: &ViewHandle) -> ViewHandle {
204 glass_effect_kind(view, Glass::Regular)
205}
206
207pub 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 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 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
265pub 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 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 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
335pub(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 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
364pub 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 let mut style: u64 = color_value(c.r, c.g, c.b, c.a);
372 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
392pub 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
411pub 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 let mut style: u64 = tint;
420 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
440pub fn preferred_color_scheme(view: &ViewHandle, scheme: ColorScheme) -> ViewHandle {
442 unsafe {
443 let (_, _, size) = COLOR_SCHEME_T.applied_to(view.meta);
444 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
455pub 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
469pub 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 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 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}