1use super::*;
6use crate::abi;
7use crate::resolve;
8use core::ffi::c_void;
9use crate::mangle::{self, swift_type};
10
11mangle::result_types! {
14 pub(crate) GEOMETRY_T = ty("GeometryReader").of(vec![ty("AnyView")]);
16}
17mangle::modifier_types! {
18 pub(crate) A11Y_T = ty("AccessibilityAttachmentModifier");
20 pub(crate) FOCUSABLE_T = ty("_FocusableModifier");
22 pub(crate) LONG_PRESS_T = ty("AddGestureModifier").of(vec![ty("LongPressGesture"), ty("DefaultGestureCombiner")]);
24}
25
26
27
28
29pub fn accessibility_label(view: &ViewHandle, label: &str) -> ViewHandle {
31 unsafe {
32 let ss = abi::swift_string(label);
33 let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
34 let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
35 let (k0, k1, k2, k3) = localized_string_key(s0, s1);
36 let (_, _, size) = A11Y_T.applied_to(view.meta);
37 let r = abi::call_modifier(resolve::a11y_label_fn(), view.value_ptr(), view.meta, view.wt, &[k0, k1, k2, k3], [0.0; 4], size);
38 wrap_modified(r, &A11Y_T, view)
39 }
40}
41
42pub fn accessibility_hidden(view: &ViewHandle, hidden: bool) -> ViewHandle {
44 unsafe {
45 let (_, _, size) = A11Y_T.applied_to(view.meta);
46 let r =
47 abi::call_modifier(resolve::a11y_hidden_fn(), view.value_ptr(), view.meta, view.wt, &[u64::from(hidden)], [0.0; 4], size);
48 wrap_modified(r, &A11Y_T, view)
49 }
50}
51
52pub fn focusable(view: &ViewHandle, value: bool) -> ViewHandle {
54 unsafe {
55 let (_, _, size) = FOCUSABLE_T.applied_to(view.meta);
56 let r =
57 abi::call_modifier(resolve::focusable_fn(), view.value_ptr(), view.meta, view.wt, &[u64::from(value)], [0.0; 4], size);
58 wrap_modified(r, &FOCUSABLE_T, view)
59 }
60}
61
62pub fn on_disappear(view: &ViewHandle, action: impl Fn() + 'static) -> ViewHandle {
64 unsafe {
65 let ctx = Box::leak(Box::new(abi::ClosureCtx::new(
66 invoke_action,
67 boxed_ctx(Box::new(action) as Box<dyn Fn()>),
68 ))) as *mut abi::ClosureCtx;
69 let (_, _, size) = ON_APPEAR_T.applied_to(view.meta);
70 let r = abi::call_modifier(resolve::on_disappear_fn(), view.value_ptr(), view.meta, view.wt,
71 &[abi::swift_closure_thunk as *const () as u64, ctx as u64],
72 [0.0; 4],
73 size,
74 );
75 wrap_modified(r, &ON_APPEAR_T, view)
76 }
77}
78
79pub fn long_press_gesture(view: &ViewHandle, duration: f64, max_distance: f64) -> ViewHandle {
81 unsafe {
82 let g_meta = abi::metadata0(resolve::long_press_ma());
83 let mut gesture = vec![0u8; abi::type_bytes(g_meta)];
84 core::arch::asm!("blr {f}", f = in(reg) resolve::long_press_init(),
86 in("d0") duration, in("d1") max_distance,
87 in("x8") gesture.as_mut_ptr(),
88 in("x20") g_meta,
89 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
90 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
91 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
92 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
93 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
94 );
95
96 let g_wt = abi::get_view_wt_for_proto(g_meta, resolve::gesture_proto());
97 assert!(!g_wt.is_null(), "LongPressGesture: Gesture");
98
99 let (_, _, size) = LONG_PRESS_T.applied_to(view.meta);
100 let mut result = vec![0u8; size];
101 let this = view.value_ptr();
102 core::arch::asm!("blr {f}", f = in(reg) resolve::gesture_fn(),
106 in("x0") gesture.as_mut_ptr(),
107 in("x1") 3u64,
108 in("x2") view.meta,
109 in("x3") g_meta,
110 in("x4") view.wt,
111 in("x5") g_wt,
112 in("x8") result.as_mut_ptr(),
113 in("x20") this,
114 lateout("x6") _, lateout("x7") _,
115 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
116 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
117 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
118 );
119 wrap_modified(result, &LONG_PRESS_T, view)
120 }
121}
122
123pub(crate) type GeometryBuilder = Box<dyn Fn(f64, f64) -> ViewHandle>;
125
126pub(crate) unsafe fn geometry_proxy_size(proxy: *const u8) -> (f64, f64) {
131 let (w, h): (f64, f64);
132 unsafe {
133 core::arch::asm!("blr {f}", f = in(reg) resolve::geometry_proxy_size(),
134 in("x20") proxy,
135 lateout("d0") w, lateout("d1") h,
136 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
137 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
138 lateout("x8") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
139 lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
140 lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x21") _,
141 clobber_abi("C"),
142 );
143 }
144 (w, h)
145}
146
147pub(crate) struct TypedBuilder {
157 pub(crate) builder: GeometryBuilder,
158 pub(crate) meta: *const c_void,
160}
161
162pub(crate) unsafe extern "C" fn emit_geometry_view(out: *mut u8, proxy: i64, payload: *mut c_void) {
164 let typed = unsafe { &*(payload as *const TypedBuilder) };
165 let (w, h) = unsafe { geometry_proxy_size(proxy as *const u8) };
166 let view = (typed.builder)(w, h);
167 unsafe {
168 if typed.meta.is_null() {
169 *(out as *mut u64) = view.into_anyview_word();
172 return;
173 }
174 assert_eq!(
179 view.meta, typed.meta,
180 "a GeometryReader's builder returned {} after returning {} — SwiftUI \
181 sized the reader for the first. Use `view_if!` for a branch, which \
182 builds a `_ConditionalContent` and so stays one type.",
183 crate::diag::type_name(view.meta),
184 crate::diag::type_name(typed.meta),
185 );
186 let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(view.meta);
187 if vwt.size > 0 {
188 (vwt.initialize_with_copy)(out as *mut c_void, view.value_ptr() as *mut c_void, view.meta);
189 }
190 }
191}
192
193pub fn geometry_reader(builder: impl Fn(f64, f64) -> ViewHandle + 'static) -> ViewHandle {
200 unsafe {
201 let boxed: GeometryBuilder = Box::new(builder);
202 let probe = boxed(0.0, 0.0);
207 let (known_meta, known_wt, _) = result_type(&GEOMETRY_T);
208 let typed = abi::generic_metadata_from(known_meta, &[probe.meta, probe.wt]);
209 let typed_wt = if typed.is_null() { core::ptr::null() } else { abi::get_view_wt(typed) };
210 let promised = if typed_wt.is_null() { core::ptr::null() } else { probe.meta };
211 let (meta, wt) = if promised.is_null() {
212 (known_meta, known_wt)
213 } else {
214 (typed, typed_wt)
215 };
216 let content_meta = if promised.is_null() { resolve::anyview_meta() } else { probe.meta };
217 let content_wt = if promised.is_null() { resolve::anyview_wt() } else { probe.wt };
218 drop(probe);
219
220 let payload =
221 Box::into_raw(Box::new(TypedBuilder { builder: boxed, meta: promised })) as *mut c_void;
222 let ctx = Box::leak(Box::new(abi::IndexClosureCtx::new(emit_geometry_view, payload)))
223 as *mut abi::IndexClosureCtx;
224
225 let (r0, r1): (u64, u64);
229 core::arch::asm!("blr {f}", f = in(reg) resolve::geometry_reader_init(),
230 inout("x0") abi::index_closure_thunk as *const () as u64 => r0,
231 inout("x1") ctx as u64 => r1,
232 in("x2") content_meta,
233 in("x3") content_wt,
234 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
235 lateout("x8") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
236 lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
237 lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x20") _,
238 lateout("x21") _, clobber_abi("C"),
239 );
240 let mut result = [0u8; 16];
241 result[..8].copy_from_slice(&r0.to_le_bytes());
242 result[8..].copy_from_slice(&r1.to_le_bytes());
243 wrap_buf(&result, meta, wt)
246 }
247}
248
249pub(crate) unsafe fn confirmation_dialog_with_binding(
258 view: &ViewHandle,
259 title: &str, actions: &ViewHandle,
260 binding: &[u8],
261) -> ViewHandle {
262 unsafe {
263 let ss = abi::swift_string(title);
264 let s0 = u64::from_le_bytes(ss[..8].try_into().unwrap());
265 let s1 = u64::from_le_bytes(ss[8..].try_into().unwrap());
266 let (k0, k1, k2, k3) = localized_string_key(s0, s1);
267 let b0 = u64::from_le_bytes(binding[0..8].try_into().unwrap());
268 let b1 = u64::from_le_bytes(binding[8..16].try_into().unwrap());
269 let b2 = binding[16] as u64;
270
271 let ctx = Box::leak(Box::new(abi::ClosureCtx::new(
272 emit_tuple,
273 Child::leak(actions, Content::Concrete),
274 ))) as *mut abi::ClosureCtx;
275
276 let subst = [
277 view.meta, actions.meta, view.wt, actions.wt, ];
282 let (meta, wt, size) = opaque_result_type(resolve::confirm_oret(), &subst);
283 let mut result = vec![0u8; size];
284 let this = view.value_ptr();
285 core::arch::asm!(
290 "sub sp, sp, #48",
291 "stp {fnp}, {cx}, [sp]",
292 "stp {sm}, {am}, [sp, #16]",
293 "stp {sw}, {aw}, [sp, #32]",
294 "blr {f}",
295 "add sp, sp, #48",
296 f = in(reg) resolve::confirm_fn(),
297 fnp = in(reg) abi::swift_closure_thunk as *const c_void,
298 cx = in(reg) ctx,
299 sm = in(reg) view.meta,
300 am = in(reg) actions.meta,
301 sw = in(reg) view.wt,
302 aw = in(reg) actions.wt,
303 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
304 in("x4") b0, in("x5") b1, in("x6") b2,
305 in("x7") 0u64,
306 in("x8") result.as_mut_ptr(),
307 in("x20") this,
308 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
309 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
310 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
311 );
312 wrap_owned(result, meta, wt)
313 }
314}
315
316pub(crate) unsafe fn confirmation_message_with_binding(
326 view: &ViewHandle,
327 title: &str,
328 actions: &ViewHandle,
329 message: &ViewHandle,
330 binding: &[u8],
331) -> ViewHandle {
332 unsafe {
333 let ss = abi::swift_string(title);
334 let s0 = u64::from_le_bytes(ss[..8].try_into().expect("title lo"));
335 let s1 = u64::from_le_bytes(ss[8..].try_into().expect("title hi"));
336 let (k0, k1, k2, k3) = super::primitives::localized_string_key(s0, s1);
337 let b0 = u64::from_le_bytes(binding[0..8].try_into().expect("binding 0"));
338 let b1 = u64::from_le_bytes(binding[8..16].try_into().expect("binding 1"));
339 let b2 = binding[16] as u64;
340
341 let actions_ctx = Box::leak(Box::new(abi::ClosureCtx::new(
342 emit_tuple,
343 Child::leak(actions, Content::Concrete),
344 ))) as *mut abi::ClosureCtx;
345 let message_ctx = Box::leak(Box::new(abi::ClosureCtx::new(
346 emit_tuple,
347 Child::leak(message, Content::Concrete),
348 ))) as *mut abi::ClosureCtx;
349
350 let subst = [view.meta, actions.meta, message.meta, view.wt, actions.wt, message.wt];
351 let (meta, wt, size) = opaque_result_type(resolve::confirm_msg_oret(), &subst);
352 let mut result = vec![0u8; size];
353 let this = view.value_ptr();
354 core::arch::asm!(
361 "sub sp, sp, #80",
362 "stp {af}, {ac}, [sp]",
363 "stp {mf}, {mc}, [sp, #16]",
364 "stp {sm}, {am}, [sp, #32]",
365 "stp {mm}, {sw}, [sp, #48]",
366 "stp {aw}, {mw}, [sp, #64]",
367 "blr {f}",
368 "add sp, sp, #80",
369 f = in(reg) resolve::confirm_msg_fn(),
370 af = in(reg) abi::swift_closure_thunk as *const c_void,
371 ac = in(reg) actions_ctx,
372 mf = in(reg) abi::swift_closure_thunk as *const c_void,
373 mc = in(reg) message_ctx,
374 sm = in(reg) subst[0],
375 am = in(reg) subst[1],
376 mm = in(reg) subst[2],
377 sw = in(reg) subst[3],
378 aw = in(reg) subst[4],
379 mw = in(reg) subst[5],
380 in("x0") k0, in("x1") k1, in("x2") k2, in("x3") k3,
381 in("x4") b0, in("x5") b1, in("x6") b2,
382 in("x7") 0u64,
383 in("x8") result.as_mut_ptr(),
384 in("x20") this,
385 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
386 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
387 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
388 );
389 wrap_owned(result, meta, wt)
390 }
391}
392
393pub fn confirmation_message(
396 view: &ViewHandle,
397 title: &str,
398 actions: &ViewHandle,
399 message: &ViewHandle,
400 presented: bool,
401) -> ViewHandle {
402 unsafe {
403 let binding = constant_binding(
404 &[u8::from(presented)],
405 resolve::bool_meta(),
406 mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::BOOL]).as_bytes(),
407 );
408 confirmation_message_with_binding(view, title, actions, message, &binding)
409 }
410}
411
412pub fn confirmation_message_bound(
414 view: &ViewHandle,
415 title: &str,
416 actions: &ViewHandle,
417 message: &ViewHandle,
418 state: &BoundState<bool>,
419) -> ViewHandle {
420 unsafe {
421 let binding = bool_binding_of(state);
422 confirmation_message_with_binding(view, title, actions, message, &binding)
423 }
424}
425
426pub fn confirmation_dialog(view: &ViewHandle, title: &str, actions: &ViewHandle, presented: bool) -> ViewHandle {
430 unsafe {
431 let binding = constant_binding(
432 &[u8::from(presented)],
433 resolve::bool_meta(),
434 mangle::bound(&swift_type!(SwiftUI.Binding), &[mangle::BOOL]).as_bytes(),
435 );
436 confirmation_dialog_with_binding(view, title, actions, &binding)
437 }
438}
439
440pub fn confirmation_dialog_bound(view: &ViewHandle, title: &str, actions: &ViewHandle, state: &BoundState<bool>) -> ViewHandle {
442 unsafe {
443 let binding = bool_binding_of(state);
444 confirmation_dialog_with_binding(view, title, actions, &binding)
445 }
446}
447
448
449pub(crate) unsafe fn a11y_modifier(
458 f: *const c_void,
459 v: &ViewHandle,
460 ints: &[u64],
461 floats: [f64; 4],
462) -> ViewHandle {
463 unsafe {
464 let (_, _, size) = A11Y_T.applied_to(v.meta);
465 let r = abi::call_modifier(f, v.value_ptr(), v.meta, v.wt, ints, floats, size);
466 wrap_modified(r, &A11Y_T, v)
467 }
468}
469
470pub(crate) unsafe fn resilient_static(meta: *const c_void, getter: &'static core::ffi::CStr) -> Vec<u8> {
478 unsafe {
479 let f = resolve::sym(getter);
480 assert!(!f.is_null(), "missing static: {}", crate::diag::symbol_name(getter));
481 abi::static_out(f, meta, abi::type_bytes(meta))
482 }
483}
484
485#[derive(Clone, Copy, Debug, PartialEq, Eq)]
487pub enum AccessibilityTrait {
488 IsButton,
489 IsHeader,
490 IsLink,
491 IsImage,
492 IsModal,
493 IsSwitch,
494 IsTabBar,
495 IsToggle,
496 IsSelected,
497 PlaysSound,
498 IsTabButton,
499 IsBackButton,
500 IsStaticText,
501 IsKeyboardKey,
502 IsSearchField,
503 CausesPageTurn,
504 IsMathEquation,
505 IsSummaryElement,
506 UpdatesFrequently,
507 StartsMediaSession,
508 AllowsDirectInteraction,
509}
510
511impl AccessibilityTrait {
512 pub(crate) fn getter(self) -> &'static core::ffi::CStr {
514 match self {
515 Self::IsButton => c"$s7SwiftUI19AccessibilityTraitsV8isButtonACvgZ",
516 Self::IsHeader => c"$s7SwiftUI19AccessibilityTraitsV8isHeaderACvgZ",
517 Self::IsLink => c"$s7SwiftUI19AccessibilityTraitsV6isLinkACvgZ",
518 Self::IsImage => c"$s7SwiftUI19AccessibilityTraitsV7isImageACvgZ",
519 Self::IsModal => c"$s7SwiftUI19AccessibilityTraitsV7isModalACvgZ",
520 Self::IsSwitch => c"$s7SwiftUI19AccessibilityTraitsV8isSwitchACvgZ",
521 Self::IsTabBar => c"$s7SwiftUI19AccessibilityTraitsV8isTabBarACvgZ",
522 Self::IsToggle => c"$s7SwiftUI19AccessibilityTraitsV8isToggleACvgZ",
523 Self::IsSelected => c"$s7SwiftUI19AccessibilityTraitsV10isSelectedACvgZ",
524 Self::PlaysSound => c"$s7SwiftUI19AccessibilityTraitsV10playsSoundACvgZ",
525 Self::IsTabButton => c"$s7SwiftUI19AccessibilityTraitsV11isTabButtonACvgZ",
526 Self::IsBackButton => c"$s7SwiftUI19AccessibilityTraitsV12isBackButtonACvgZ",
527 Self::IsStaticText => c"$s7SwiftUI19AccessibilityTraitsV12isStaticTextACvgZ",
528 Self::IsKeyboardKey => c"$s7SwiftUI19AccessibilityTraitsV13isKeyboardKeyACvgZ",
529 Self::IsSearchField => c"$s7SwiftUI19AccessibilityTraitsV13isSearchFieldACvgZ",
530 Self::CausesPageTurn => c"$s7SwiftUI19AccessibilityTraitsV14causesPageTurnACvgZ",
531 Self::IsMathEquation => c"$s7SwiftUI19AccessibilityTraitsV14isMathEquationACvgZ",
532 Self::IsSummaryElement => c"$s7SwiftUI19AccessibilityTraitsV16isSummaryElementACvgZ",
533 Self::UpdatesFrequently => c"$s7SwiftUI19AccessibilityTraitsV17updatesFrequentlyACvgZ",
534 Self::StartsMediaSession => c"$s7SwiftUI19AccessibilityTraitsV18startsMediaSessionACvgZ",
535 Self::AllowsDirectInteraction => {
536 c"$s7SwiftUI19AccessibilityTraitsV23allowsDirectInteractionACvgZ"
537 }
538 }
539 }
540}
541
542pub(crate) unsafe fn traits_value(traits: &[AccessibilityTrait]) -> Vec<u8> {
548 unsafe {
549 let meta = abi::metadata0(resolve::a11y_traits_ma());
550 let mut acc = vec![0u8; abi::type_bytes(meta)];
551 let union = resolve::a11y_traits_form_union();
552 for t in traits {
553 let one = resilient_static(meta, t.getter());
554 abi::call_out(
555 union,
556 abi::ints(&[one.as_ptr() as u64]),
557 [0.0; 4],
558 acc.as_mut_ptr() as u64,
559 core::ptr::null_mut(),
560 );
561 }
562 acc
563 }
564}
565
566swift_cases! {
567 pub enum HeadingLevel {
569 Unspecified = 0,
570 H1 = 1,
571 H2 = 2,
572 H3 = 3,
573 H4 = 4,
574 H5 = 5,
575 H6 = 6,
576 }
577}
578
579swift_statics! {
580 pub enum TextContentType {
582 Plain = c"$s7SwiftUI28AccessibilityTextContentTypeV5plainACvgZ",
583 Console = c"$s7SwiftUI28AccessibilityTextContentTypeV7consoleACvgZ",
584 FileSystem = c"$s7SwiftUI28AccessibilityTextContentTypeV10fileSystemACvgZ",
585 Messaging = c"$s7SwiftUI28AccessibilityTextContentTypeV9messagingACvgZ",
586 Narrative = c"$s7SwiftUI28AccessibilityTextContentTypeV9narrativeACvgZ",
587 SourceCode = c"$s7SwiftUI28AccessibilityTextContentTypeV10sourceCodeACvgZ",
588 Spreadsheet = c"$s7SwiftUI28AccessibilityTextContentTypeV11spreadsheetACvgZ",
589 WordProcessing = c"$s7SwiftUI28AccessibilityTextContentTypeV14wordProcessingACvgZ",
590 }
591}
592
593swift_statics! {
594 pub enum DirectTouchOption {
596 SilentOnTouch = c"$s7SwiftUI31AccessibilityDirectTouchOptionsV08silentOnE0ACvgZ",
597 RequiresActivation = c"$s7SwiftUI31AccessibilityDirectTouchOptionsV18requiresActivationACvgZ",
598 }
599}
600
601pub fn accessibility_deprecated_identifier(view: &ViewHandle, id: &str) -> ViewHandle {
603 unsafe {
604 let s = abi::swift_string(id);
605 let w0 = u64::from_le_bytes(s[..8].try_into().expect("string lo"));
606 let w1 = u64::from_le_bytes(s[8..].try_into().expect("string hi"));
607 a11y_modifier(resolve::a11y_deprecated_identifier_fn(), view, &[w0, w1], [0.0; 4])
608 }
609}
610
611pub fn accessibility_identifier(view: &ViewHandle, id: &str) -> ViewHandle {
613 unsafe {
614 let s = abi::swift_string(id);
615 let w0 = u64::from_le_bytes(s[..8].try_into().expect("string lo"));
616 let w1 = u64::from_le_bytes(s[8..].try_into().expect("string hi"));
617 a11y_modifier(resolve::a11y_identifier_fn(), view, &[w0, w1], [0.0; 4])
618 }
619}
620
621pub fn accessibility_sort_priority(view: &ViewHandle, priority: f64) -> ViewHandle {
623 unsafe { a11y_modifier(resolve::a11y_sort_priority_fn(), view, &[], [priority, 0.0, 0.0, 0.0]) }
624}
625
626pub fn accessibility_value(view: &ViewHandle, value: &str, enabled: bool) -> ViewHandle {
628 unsafe {
629 let (k0, k1, k2, k3) = lsk_words(value);
630 a11y_modifier(resolve::a11y_value_fn(), view, &[k0, k1, k2, k3, u64::from(enabled)], [0.0; 4])
631 }
632}
633
634pub fn accessibility_responds_to_user_interaction(view: &ViewHandle, responds: bool) -> ViewHandle {
636 unsafe {
637 a11y_modifier(resolve::a11y_responds_fn(), view, &[u64::from(responds)], [0.0; 4])
638 }
639}
640
641pub fn accessibility_hint(view: &ViewHandle, hint: &str) -> ViewHandle {
643 unsafe {
644 let (k0, k1, k2, k3) = lsk_words(hint);
645 a11y_modifier(resolve::a11y_hint_fn(), view, &[k0, k1, k2, k3], [0.0; 4])
646 }
647}
648
649pub fn accessibility_scroll_status(view: &ViewHandle, status: &str, enabled: bool) -> ViewHandle {
651 unsafe {
652 let (k0, k1, k2, k3) = lsk_words(status);
653 a11y_modifier(
654 resolve::a11y_scroll_status_fn(),
655 view,
656 &[k0, k1, k2, k3, u64::from(enabled)],
657 [0.0; 4],
658 )
659 }
660}
661
662pub fn accessibility_activation_point(view: &ViewHandle, x: f64, y: f64) -> ViewHandle {
667 unsafe { a11y_modifier(resolve::a11y_activation_point_fn(), view, &[], [x, y, 0.0, 0.0]) }
668}
669
670pub fn accessibility_drag_point(
672 view: &ViewHandle,
673 x: f64,
674 y: f64,
675 description: &str,
676 enabled: bool,
677) -> ViewHandle {
678 unsafe {
679 let (k0, k1, k2, k3) = lsk_words(description);
680 a11y_modifier(
681 resolve::a11y_drag_point_fn(),
682 view,
683 &[k0, k1, k2, k3, u64::from(enabled)],
684 [x, y, 0.0, 0.0],
685 )
686 }
687}
688
689pub fn accessibility_drop_point(
691 view: &ViewHandle,
692 x: f64,
693 y: f64,
694 description: &str,
695 enabled: bool,
696) -> ViewHandle {
697 unsafe {
698 let (k0, k1, k2, k3) = lsk_words(description);
699 a11y_modifier(
700 resolve::a11y_drop_point_fn(),
701 view,
702 &[k0, k1, k2, k3, u64::from(enabled)],
703 [x, y, 0.0, 0.0],
704 )
705 }
706}
707
708pub fn accessibility_add_traits(view: &ViewHandle, traits: &[AccessibilityTrait]) -> ViewHandle {
710 unsafe {
711 let v = traits_value(traits);
712 a11y_modifier(resolve::a11y_add_traits_fn(), view, &[v.as_ptr() as u64], [0.0; 4])
713 }
714}
715
716pub fn accessibility_remove_traits(view: &ViewHandle, traits: &[AccessibilityTrait]) -> ViewHandle {
718 unsafe {
719 let v = traits_value(traits);
720 a11y_modifier(resolve::a11y_remove_traits_fn(), view, &[v.as_ptr() as u64], [0.0; 4])
721 }
722}
723
724pub fn accessibility_heading(view: &ViewHandle, level: HeadingLevel) -> ViewHandle {
726 unsafe {
727 let meta = abi::metadata0(resolve::a11y_heading_level_ma());
728 let arg = abi::enum_argument(meta, level.tag());
729 a11y_modifier(resolve::a11y_heading_fn(), view, &[arg], [0.0; 4])
730 }
731}
732
733pub fn accessibility_text_content_type(view: &ViewHandle, kind: TextContentType) -> ViewHandle {
735 unsafe {
736 let meta = abi::metadata0(resolve::a11y_text_content_type_ma());
737 let v = resilient_static(meta, kind.getter());
738 a11y_modifier(
739 resolve::a11y_text_content_type_fn(),
740 view,
741 &[v.as_ptr() as u64],
742 [0.0; 4],
743 )
744 }
745}
746
747pub(crate) unsafe fn any_hashable(
758 bytes: &[u8],
759 meta: *const c_void,
760 wt: *const c_void,
761) -> Vec<u8> {
762 unsafe {
763 let any_meta = abi::metadata0(resolve::any_hashable_ma());
764 assert!(!any_meta.is_null(), "AnyHashable metadata");
765 let mut out = vec![0u8; abi::type_bytes(any_meta)];
766 core::arch::asm!("blr {f}", f = in(reg) resolve::convert_to_any_hashable(),
767 in("x0") bytes.as_ptr(),
768 in("x1") meta,
769 in("x2") wt,
770 in("x8") out.as_mut_ptr(),
771 lateout("x3") _, lateout("x4") _, lateout("x5") _, lateout("x6") _,
772 lateout("x7") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
773 lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
774 lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x20") _,
775 lateout("x21") _, clobber_abi("C"),
776 );
777 out
778 }
779}
780
781pub fn accessibility_selection_identifier(
791 view: &ViewHandle,
792 id: super::HashableValue<'_>,
793) -> ViewHandle {
794 unsafe {
795 let (bytes, meta, wt) = id.parts();
796 let any = any_hashable(&bytes, meta, wt);
797 a11y_modifier(resolve::a11y_selection_identifier_fn(), view, &[any.as_ptr() as u64], [0.0; 4])
798 }
799}
800
801pub fn accessibility_input_labels(
802 view: &ViewHandle,
803 labels: &[&str],
804 enabled: bool,
805) -> ViewHandle {
806 unsafe {
807 let meta = resolve::lsk_meta();
808 let stride = abi::type_bytes(meta);
809 let mut bytes = vec![0u8; stride * labels.len()];
810 for (i, l) in labels.iter().enumerate() {
811 let (k0, k1, k2, k3) = lsk_words(l);
812 let at = &mut bytes[i * stride..];
813 at[..8].copy_from_slice(&k0.to_le_bytes());
814 at[8..16].copy_from_slice(&k1.to_le_bytes());
815 at[16..24].copy_from_slice(&k2.to_le_bytes());
816 at[24..32].copy_from_slice(&k3.to_le_bytes());
817 }
818 let array = abi::swift_array(meta, labels.len(), &bytes);
819 a11y_modifier(
820 resolve::a11y_input_labels_fn(),
821 view,
822 &[array, u64::from(enabled)],
823 [0.0; 4],
824 )
825 }
826}
827
828pub fn accessibility_direct_touch(
830 view: &ViewHandle,
831 enabled: bool,
832 options: &[DirectTouchOption],
833) -> ViewHandle {
834 unsafe {
835 let meta = abi::metadata0(resolve::a11y_direct_touch_options_ma());
836 let mut v = vec![0u8; abi::type_bytes(meta)];
837 for o in options {
840 let one = resilient_static(meta, o.getter());
841 for (dst, src) in v.iter_mut().zip(one.iter()) {
842 *dst |= *src;
843 }
844 }
845 a11y_modifier(
846 resolve::a11y_direct_touch_fn(),
847 view,
848 &[u64::from(enabled), v.as_ptr() as u64],
849 [0.0; 4],
850 )
851 }
852}
853
854pub(crate) unsafe fn lsk_words(s: &str) -> (u64, u64, u64, u64) {
856 unsafe {
857 let ss = abi::swift_string(s);
858 localized_string_key(
859 u64::from_le_bytes(ss[..8].try_into().expect("string lo")),
860 u64::from_le_bytes(ss[8..].try_into().expect("string hi")),
861 )
862 }
863}
864
865#[derive(Clone, Copy, Debug, PartialEq, Eq)]
870pub enum CustomContentImportance {
871 Default = 0,
872 High = 1,
873}
874
875pub fn accessibility_custom_content(
883 view: &ViewHandle,
884 key_label: &str,
885 id: &str,
886 value: &str,
887 importance: CustomContentImportance,
888) -> ViewHandle {
889 unsafe {
890 let (kk0, kk1, kk2, kk3) = lsk_words(key_label);
891 let ids = abi::swift_string(id);
892 let i0 = u64::from_le_bytes(ids[..8].try_into().expect("id lo"));
893 let i1 = u64::from_le_bytes(ids[8..].try_into().expect("id hi"));
894 let key_meta = abi::metadata0(resolve::a11y_custom_content_key_ma());
895 let mut key = vec![0u8; abi::type_bytes(key_meta)];
896 core::arch::asm!("blr {f}", f = in(reg) resolve::a11y_custom_content_key_init(),
897 in("x0") kk0, in("x1") kk1, in("x2") kk2, in("x3") kk3,
898 in("x4") i0, in("x5") i1,
899 in("x8") key.as_mut_ptr(), in("x20") key_meta,
900 lateout("x6") _, lateout("x7") _, lateout("x9") _, lateout("x10") _,
901 lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
902 lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
903 lateout("x21") _, clobber_abi("C"),
904 );
905 let (v0, v1, v2, v3) = lsk_words(value);
906 let (_, _, size) = A11Y_T.applied_to(view.meta);
907 let r = abi::call_modifier(resolve::a11y_custom_content_fn(), view.value_ptr(), view.meta, view.wt,
908 &[key.as_ptr() as u64, v0, v1, v2, v3, importance as u64],
909 [0.0; 4],
910 size,
911 );
912 wrap_modified(r, &A11Y_T, view)
913 }
914}
915
916unsafe fn string_bound(text: &str, getter: *const c_void) -> u64 {
922 unsafe {
923 let s = abi::swift_string(text);
924 let index: u64;
925 core::arch::asm!("blr {f}", f = in(reg) getter,
926 in("x20") s.as_ptr(),
927 lateout("x0") index,
928 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
929 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x8") _,
930 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
931 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
932 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
933 );
934 index
935 }
936}
937
938pub fn accessibility_rotor(view: &ViewHandle, label: &str, text: &str) -> ViewHandle {
945 unsafe {
946 let lower = string_bound(text, resolve::string_start_index());
947 let upper = string_bound(text, resolve::string_end_index());
948 let range = abi::resolve_type_by_mangled_name(mangle::range(&mangle::nested(mangle::STRING, "Index", mangle::Kind::Struct)).as_bytes());
949 assert!(!range.is_null(), "Range<String.Index>");
950 let stride = abi::type_bytes(range);
951 let mut bytes = vec![0u8; stride];
952 bytes[..8].copy_from_slice(&lower.to_le_bytes());
953 bytes[8..16].copy_from_slice(&upper.to_le_bytes());
954 let array = abi::swift_array(range, 1, &bytes);
955 let (k0, k1, k2, k3) = lsk_words(label);
956 let subst = [view.meta, view.wt];
957 let (m, wt, size) = opaque_result_type(resolve::a11y_rotor_oret(), &subst);
958 let r = abi::call_modifier(resolve::a11y_rotor_fn(), view.value_ptr(), view.meta, view.wt,
959 &[k0, k1, k2, k3, array],
960 [0.0; 4],
961 size,
962 );
963 wrap_owned(r, m, wt)
964 }
965}
966
967pub fn accessibility_chart_descriptor(view: &ViewHandle) -> ViewHandle {
973 unsafe {
974 let meta = abi::metadata0(resolve::edge_insets_ma());
975 let wt = crate::conformance::chart_descriptor_representable().witness_table();
976 let value = vec![0u8; abi::type_bytes(meta)];
977 generic1_modifier_ints(
978 resolve::a11y_chart_descriptor_fn(),
979 resolve::a11y_chart_descriptor_oret(),
980 view,
981 meta,
982 wt,
983 &[value.as_ptr() as u64],
984 [0.0; 4],
985 )
986 }
987}