1use super::*;
6use crate::abi;
7use crate::resolve;
8use crate::mangle::{self, swift_type};
9
10pub(crate) unsafe fn shape_view(bytes: &[u8], mangled: &[u8]) -> ViewHandle {
15 let meta = unsafe { abi::resolve_type_by_mangled_name(mangled) };
16 assert!(!meta.is_null(), "shape metadata: {}", crate::diag::demangle_type(mangled));
17 let wt = unsafe { abi::get_view_wt(meta) };
18 assert!(!wt.is_null(), "{} !: View", crate::diag::demangle_type(mangled));
19 unsafe { wrap_buf(bytes, meta, wt) }
20}
21
22pub fn rectangle() -> ViewHandle {
24 unsafe { shape_view(&[], swift_type!(SwiftUI.Rectangle).as_bytes()) }
25}
26
27pub fn circle() -> ViewHandle {
29 unsafe { shape_view(&[], swift_type!(SwiftUI.Circle).as_bytes()) }
30}
31
32pub fn ellipse() -> ViewHandle {
34 unsafe { shape_view(&[], swift_type!(SwiftUI.Ellipse).as_bytes()) }
35}
36
37pub fn capsule() -> ViewHandle {
39 unsafe { shape_view(&[0u8], swift_type!(SwiftUI.Capsule).as_bytes()) }
40}
41
42pub fn rounded_rectangle_styled(radius: f64, continuous: bool) -> ViewHandle {
53 let mut buf = [0u8; 17];
54 buf[..8].copy_from_slice(&radius.to_le_bytes());
55 buf[8..16].copy_from_slice(&radius.to_le_bytes());
56 buf[16] = u8::from(continuous);
57 unsafe { shape_view(&buf, swift_type!(SwiftUI.RoundedRectangle).as_bytes()) }
58}
59
60pub fn rounded_rectangle(radius: f64) -> ViewHandle {
63 rounded_rectangle_styled(radius, true)
64}
65
66mangle::modifier_types! {
69 pub(crate) LINEAR_GRADIENT_BG_T = ty("_BackgroundStyleModifier").of(vec![ty("LinearGradient")]);
72 pub(crate) RADIAL_GRADIENT_BG_T = ty("_BackgroundStyleModifier").of(vec![ty("RadialGradient")]);
75}
76
77
78pub(crate) unsafe fn color_array(colors: &[u64]) -> u64 {
84 let (array, buf): (u64, u64);
85 unsafe {
86 core::arch::asm!("blr {f}", f = in(reg) resolve::array_alloc_uninit(),
91 in("x0") colors.len() as u64,
92 in("x1") resolve::color_meta(),
93 lateout("x0") array, lateout("x1") buf,
94 lateout("x2") _, lateout("x3") _, lateout("x4") _, lateout("x5") _,
95 lateout("x6") _, lateout("x7") _, lateout("x8") _, lateout("x9") _,
96 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
97 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
98 lateout("lr") _, lateout("x20") _, lateout("x21") _, clobber_abi("C"),
99 );
100 let dst = buf as *mut u64;
101 for (i, c) in colors.iter().enumerate() {
102 *dst.add(i) = *c;
103 }
104 }
105 array
106}
107
108pub(crate) unsafe fn gradient(colors: &[crate::Color]) -> u64 {
110 let raw: Vec<u64> =
111 colors.iter().map(|c| unsafe { color_value(c.r, c.g, c.b, c.a) }).collect();
112 unsafe { gradient_of(&raw) }
113}
114
115pub(crate) unsafe fn gradient_of(raw: &[u64]) -> u64 {
121 let array = unsafe { color_array(raw) };
122 let g: u64;
123 unsafe {
124 core::arch::asm!("blr {f}", f = in(reg) resolve::gradient_init(),
125 in("x0") array,
126 in("x20") resolve::gradient_meta(),
127 lateout("x0") g,
128 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
129 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x8") _,
130 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
131 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
132 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
133 );
134 }
135 g
136}
137
138pub fn color_meta_for_style() -> *const c_void {
140 resolve::color_meta()
141}
142
143pub fn color_shapestyle_wt_for_style() -> *const c_void {
145 resolve::color_shapestyle_wt()
146}
147
148#[derive(Clone, Copy, Debug, PartialEq, Eq)]
150pub enum Hierarchical {
151 Primary,
152 Secondary,
153 Tertiary,
154 Quaternary,
155 Quinary,
156}
157
158pub fn hierarchical_style(level: Hierarchical) -> (Vec<u8>, *const c_void, *const c_void) {
165 unsafe {
166 let getter = match level {
167 Hierarchical::Primary => resolve::hierarchical_primary(),
168 Hierarchical::Secondary => resolve::hierarchical_secondary(),
169 Hierarchical::Tertiary => resolve::hierarchical_tertiary(),
170 Hierarchical::Quaternary => resolve::hierarchical_quaternary(),
171 Hierarchical::Quinary => resolve::hierarchical_quinary(),
172 };
173 let meta = abi::metadata0(resolve::hierarchical_ma());
174 assert!(!meta.is_null(), "HierarchicalShapeStyle metadata");
175 let r = abi::static_regs(getter, meta);
176 let mut bytes = vec![0u8; abi::type_bytes(meta)];
177 let n = bytes.len().min(8);
178 bytes[..n].copy_from_slice(&r[0].to_le_bytes()[..n]);
179 let wt = abi::get_view_wt_for_proto(meta, resolve::shape_style_proto());
184 assert!(!wt.is_null(), "HierarchicalShapeStyle !: ShapeStyle");
185 (bytes, meta, wt)
186 }
187}
188
189pub fn opacity_of_style(
194 base: &[u8],
195 base_ty: mangle::Type,
196 opacity: f64,
197) -> (Vec<u8>, *const c_void, *const c_void) {
198 unsafe {
199 let ty = mangle::ty("_OpacityShapeStyle").of(vec![base_ty]).mangle();
200 let meta = abi::resolve_type_by_mangled_name(ty.as_bytes());
201 assert!(!meta.is_null(), "_OpacityShapeStyle metadata: {ty}");
202 let wt = abi::get_view_wt_for_proto(meta, resolve::shape_style_proto());
203 assert!(!wt.is_null(), "_OpacityShapeStyle !: ShapeStyle");
204 let mut bytes = vec![0u8; abi::type_bytes(meta)];
205 bytes[..base.len()].copy_from_slice(base);
206 let at = base.len().next_multiple_of(4);
207 bytes[at..at + 4].copy_from_slice(&(opacity as f32).to_le_bytes());
208 (bytes, meta, wt)
209 }
210}
211
212pub fn implicit_opacity_style(opacity: f64) -> (Vec<u8>, *const c_void, *const c_void) {
225 unsafe {
226 let ty = mangle::ty("_OpacityShapeStyle")
227 .of(vec![mangle::ty("_ImplicitShapeStyle")])
228 .mangle();
229 let meta = abi::resolve_type_by_mangled_name(ty.as_bytes());
230 assert!(!meta.is_null(), "_OpacityShapeStyle<_ImplicitShapeStyle> metadata");
231 let wt = abi::get_view_wt_for_proto(meta, resolve::shape_style_proto());
232 assert!(!wt.is_null(), "_OpacityShapeStyle !: ShapeStyle");
233 let mut bytes = vec![0u8; abi::type_bytes(meta)];
234 bytes[..4].copy_from_slice(&(opacity as f32).to_le_bytes());
235 (bytes, meta, wt)
236 }
237}
238
239pub fn shadow_style(
251 drop: bool,
252 color: Option<u64>,
253 radius: f64,
254 x: f64,
255 y: f64,
256) -> Vec<u8> {
257 unsafe {
258 let meta = abi::metadata0(resolve::shadow_style_ma());
259 assert!(!meta.is_null(), "ShadowStyle metadata");
260 let colour = color.unwrap_or_else(|| default_shadow_colour(if drop { 0.33 } else { 0.55 }));
261 let mut out = vec![0u8; abi::type_bytes(meta)];
262 let f = if drop { resolve::shadow_style_drop() } else { resolve::shadow_style_inner() };
263 core::arch::asm!("blr {f}", f = in(reg) f,
264 in("x0") colour,
265 in("d0") radius, in("d1") x, in("d2") y,
266 in("x8") out.as_mut_ptr(),
267 in("x20") meta,
268 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
269 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
270 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
271 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
272 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
273 );
274 out
275 }
276}
277
278fn default_shadow_colour(opacity: f64) -> u64 {
282 unsafe {
283 let mut space: u8 = 1;
284 let out: u64;
285 core::arch::asm!("blr {f}", f = in(reg) resolve::color_white_init(),
286 in("x0") &mut space as *mut u8,
287 in("d0") 0.0f64, in("d1") opacity,
288 in("x20") resolve::color_meta(),
289 lateout("x0") out,
290 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
291 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x8") _,
292 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
293 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
294 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
295 );
296 out
297 }
298}
299
300pub fn implicit_shadow_style(shadow: &[u8]) -> (Vec<u8>, *const c_void, *const c_void) {
305 unsafe {
306 let ty = mangle::ty("_ShadowShapeStyle")
307 .of(vec![mangle::ty("_ImplicitShapeStyle")])
308 .mangle();
309 let meta = abi::resolve_type_by_mangled_name(ty.as_bytes());
310 assert!(!meta.is_null(), "_ShadowShapeStyle<_ImplicitShapeStyle> metadata");
311 let wt = abi::get_view_wt_for_proto(meta, resolve::shape_style_proto());
312 assert!(!wt.is_null(), "_ShadowShapeStyle !: ShapeStyle");
313 let mut bytes = vec![0u8; abi::type_bytes(meta)];
314 let n = shadow.len().min(bytes.len());
315 bytes[..n].copy_from_slice(&shadow[..n]);
316 (bytes, meta, wt)
317 }
318}
319
320pub fn color_shadow_style(color: u64, shadow: &[u8]) -> (Vec<u8>, *const c_void, *const c_void) {
322 unsafe {
323 let subst = [resolve::color_meta(), resolve::color_shapestyle_wt()];
324 let (meta, _, size) =
325 super::opaque_result_type(resolve::shape_style_shadow_oret(), &subst);
326 let wt = abi::get_view_wt_for_proto(meta, resolve::shape_style_proto());
327 assert!(!wt.is_null(), "shadowed style !: ShapeStyle");
328
329 let mut out = vec![0u8; size];
330 let mut arg = shadow.to_vec();
331 let mut receiver = color;
332 core::arch::asm!("blr {f}", f = in(reg) resolve::shape_style_shadow_fn(),
333 in("x0") arg.as_mut_ptr(),
334 in("x1") subst[0], in("x2") subst[1],
335 in("x8") out.as_mut_ptr(),
336 in("x20") &mut receiver as *mut u64,
337 lateout("x3") _, lateout("x4") _, lateout("x5") _, lateout("x6") _,
338 lateout("x7") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
339 lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
340 lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x21") _,
341 clobber_abi("C"),
342 );
343 (out, meta, wt)
344 }
345}
346
347pub fn implicit_blend_mode_style(mode: u8) -> (Vec<u8>, *const c_void, *const c_void) {
354 unsafe {
355 let ty = mangle::ty("_BlendModeShapeStyle")
356 .of(vec![mangle::ty("_ImplicitShapeStyle")])
357 .mangle();
358 let meta = abi::resolve_type_by_mangled_name(ty.as_bytes());
359 assert!(!meta.is_null(), "_BlendModeShapeStyle<_ImplicitShapeStyle> metadata");
360 let wt = abi::get_view_wt_for_proto(meta, resolve::shape_style_proto());
361 assert!(!wt.is_null(), "_BlendModeShapeStyle !: ShapeStyle");
362 let mut bytes = vec![0u8; abi::type_bytes(meta)];
363 bytes[0] = mode;
364 (bytes, meta, wt)
365 }
366}
367
368swift_statics! {
369 pub enum GradientColorSpace {
376 Device = c"$s7SwiftUI8GradientV10ColorSpaceV6deviceAEvgZ",
377 Perceptual = c"$s7SwiftUI8GradientV10ColorSpaceV10perceptualAEvgZ",
378 }
379}
380
381pub fn gradient_color_space_perceptual(
387 colors: &[u64],
388) -> (Vec<u8>, *const c_void, *const c_void) {
389 gradient_color_space(colors, GradientColorSpace::Perceptual)
390}
391
392pub fn gradient_color_space(
394 colors: &[u64],
395 space: GradientColorSpace,
396) -> (Vec<u8>, *const c_void, *const c_void) {
397 unsafe {
398 let g = gradient_of(colors);
399 let space_meta = abi::metadata0(resolve::gradient_color_space_ma());
400 assert!(!space_meta.is_null(), "Gradient.ColorSpace metadata");
401 let mut space = super::static_getter_indirect(
402 space.resolved(),
403 space_meta,
404 abi::type_bytes(space_meta),
405 );
406 let out: u64;
407 core::arch::asm!("blr {f}", f = in(reg) resolve::gradient_color_space_fn(),
408 in("x0") space.as_mut_ptr(),
409 in("x1") g,
410 lateout("x0") out,
411 lateout("x2") _, lateout("x3") _, lateout("x4") _, lateout("x5") _,
412 lateout("x6") _, lateout("x7") _, lateout("x8") _, lateout("x9") _,
413 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
414 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
415 lateout("lr") _, lateout("x20") _, lateout("x21") _, clobber_abi("C"),
416 );
417 (out.to_le_bytes().to_vec(), resolve::any_gradient_meta(), resolve::any_gradient_wt())
418 }
419}
420
421pub fn linear_gradient_style(
427 colors: &[crate::Color],
428 start: (f64, f64),
429 end: (f64, f64),
430) -> (Vec<u8>, *const c_void, *const c_void) {
431 let raw: Vec<u64> = colors.iter().map(|c| super::color_value_of(*c)).collect();
432 linear_gradient_style_of(&raw, start, end)
433}
434
435pub fn angular_gradient_style(
440 colors: &[crate::Color],
441 center: (f64, f64),
442 start_degrees: f64,
443) -> (Vec<u8>, *const c_void, *const c_void) {
444 let raw: Vec<u64> = colors.iter().map(|c| super::color_value_of(*c)).collect();
445 unsafe {
446 let g = gradient_of(&raw);
447 let meta = crate::type_by_name!(swift_type!(SwiftUI.AngularGradient).as_bytes());
448 assert!(!meta.is_null(), "AngularGradient metadata");
449 let mut value = vec![0u8; abi::type_bytes(meta)];
450 core::arch::asm!("blr {f}", f = in(reg) resolve::angular_gradient_init(),
453 in("x0") g,
454 in("d0") center.0, in("d1") center.1,
455 in("d2") start_degrees * core::f64::consts::PI / 180.0,
456 in("x8") value.as_mut_ptr(),
457 in("x20") meta,
458 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
459 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
460 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
461 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
462 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
463 );
464 (value, meta, resolve::angular_gradient_wt())
465 }
466}
467
468pub fn elliptical_gradient_style(
474 colors: &[crate::Color],
475 center: (f64, f64),
476 start_fraction: f64,
477 end_fraction: f64,
478) -> (Vec<u8>, *const c_void, *const c_void) {
479 let raw: Vec<u64> = colors.iter().map(|c| super::color_value_of(*c)).collect();
480 unsafe {
481 let array = color_array(&raw);
482 let meta = crate::type_by_name!(swift_type!(SwiftUI.EllipticalGradient).as_bytes());
483 assert!(!meta.is_null(), "EllipticalGradient metadata");
484 let mut value = vec![0u8; abi::type_bytes(meta)];
485 core::arch::asm!("blr {f}", f = in(reg) resolve::elliptical_gradient_init(),
486 in("x0") array,
487 in("d0") center.0, in("d1") center.1,
488 in("d2") start_fraction, in("d3") end_fraction,
489 in("x8") value.as_mut_ptr(),
490 in("x20") meta,
491 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
492 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
493 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
494 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
495 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
496 );
497 (value, meta, resolve::elliptical_gradient_wt())
498 }
499}
500
501pub fn linear_gradient_style_of(
503 colors: &[u64],
504 start: (f64, f64),
505 end: (f64, f64),
506) -> (Vec<u8>, *const c_void, *const c_void) {
507 unsafe {
508 let g = gradient_of(colors);
509 let meta = crate::type_by_name!(swift_type!(SwiftUI.LinearGradient).as_bytes());
510 assert!(!meta.is_null(), "LinearGradient metadata");
511 let mut value = vec![0u8; abi::type_bytes(meta)];
512 core::arch::asm!("blr {f}", f = in(reg) resolve::linear_gradient_init(),
513 in("x0") g,
514 in("d0") start.0, in("d1") start.1, in("d2") end.0, in("d3") end.1,
515 in("x8") value.as_mut_ptr(),
516 in("x20") meta,
517 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
518 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
519 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
520 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
521 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
522 );
523 (value, meta, resolve::linear_gradient_wt())
524 }
525}
526
527pub fn background_linear_gradient(
529 view: &ViewHandle,
530 colors: &[crate::Color],
531 start: (f64, f64),
532 end: (f64, f64),
533) -> ViewHandle {
534 unsafe {
535 let g = gradient(colors);
536 let meta = crate::type_by_name!(swift_type!(SwiftUI.LinearGradient).as_bytes());
537 assert!(!meta.is_null(), "LinearGradient metadata");
538 let mut value = vec![0u8; abi::type_bytes(meta)];
539 core::arch::asm!("blr {f}", f = in(reg) resolve::linear_gradient_init(),
541 in("x0") g,
542 in("d0") start.0, in("d1") start.1, in("d2") end.0, in("d3") end.1,
543 in("x8") value.as_mut_ptr(),
544 in("x20") meta,
545 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
546 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
547 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
548 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
549 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
550 );
551 background_style(
552 view,
553 value.as_mut_ptr(),
554 meta,
555 resolve::linear_gradient_wt(),
556 &LINEAR_GRADIENT_BG_T,
557 )
558 }
559}
560
561pub fn background_radial_gradient(
563 view: &ViewHandle,
564 colors: &[crate::Color],
565 center: (f64, f64),
566 start_radius: f64,
567 end_radius: f64,
568) -> ViewHandle {
569 unsafe {
570 let g = gradient(colors);
571 let meta = crate::type_by_name!(swift_type!(SwiftUI.RadialGradient).as_bytes());
572 assert!(!meta.is_null(), "RadialGradient metadata");
573 let mut value = vec![0u8; abi::type_bytes(meta)];
574 core::arch::asm!("blr {f}", f = in(reg) resolve::radial_gradient_init(),
575 in("x0") g,
576 in("d0") center.0, in("d1") center.1, in("d2") start_radius, in("d3") end_radius,
577 in("x8") value.as_mut_ptr(),
578 in("x20") meta,
579 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
580 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
581 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
582 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
583 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
584 );
585 background_style(
586 view,
587 value.as_mut_ptr(),
588 meta,
589 resolve::radial_gradient_wt(),
590 &RADIAL_GRADIENT_BG_T,
591 )
592 }
593}
594
595pub struct Shape {
610 bytes: Vec<u8>,
611 meta: *const c_void,
612 wt: *const c_void,
613 ty: mangle::Type,
622}
623
624impl Shape {
625 pub(crate) unsafe fn of_metadata(
639 bytes: Vec<u8>,
640 meta: *const c_void,
641 wt: *const c_void,
642 ty: mangle::Type,
643 ) -> Self {
644 Self { bytes, meta, wt, ty }
645 }
646
647 unsafe fn of(bytes: Vec<u8>, ty: mangle::Type) -> Self {
648 unsafe {
649 let mangled = ty.mangle();
650 let meta = abi::resolve_type_by_mangled_name(mangled.as_bytes());
651 assert!(!meta.is_null(), "shape metadata: {}", mangle::demangle(&mangled));
652 let wt = abi::get_view_wt_for_proto(meta, resolve::shape_proto());
653 assert!(!wt.is_null(), "{} !: Shape", mangle::demangle(&mangled));
654 Self { bytes, meta, wt, ty }
655 }
656 }
657
658 pub fn circle() -> Self {
660 unsafe { Self::empty(mangle::ty("Circle"), resolve::circle_init()) }
661 }
662
663 pub fn rectangle() -> Self {
665 unsafe { Self::empty(mangle::ty("Rectangle"), resolve::rectangle_init()) }
666 }
667
668 pub fn ellipse() -> Self {
670 unsafe { Self::empty(mangle::ty("Ellipse"), resolve::ellipse_init()) }
671 }
672
673 unsafe fn empty(ty: mangle::Type, init: *const c_void) -> Self {
683 unsafe {
684 let mut me = Self::of(Vec::new(), ty);
685 let size = abi::type_bytes(me.meta);
686 let mut bytes = vec![0u8; size.max(1)];
687 core::arch::asm!("blr {f}", f = in(reg) init,
688 in("x8") bytes.as_mut_ptr(),
689 in("x20") me.meta,
690 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
691 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
692 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
693 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
694 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
695 );
696 bytes.truncate(size);
697 me.bytes = bytes;
698 me
699 }
700 }
701
702 pub fn capsule() -> Self {
709 unsafe { Self::of(vec![1u8], mangle::ty("Capsule")) }
710 }
711
712 pub fn rounded_rectangle(radius: f64, continuous: bool) -> Self {
719 let mut bytes = Vec::with_capacity(24);
720 bytes.extend_from_slice(&radius.to_le_bytes());
721 bytes.extend_from_slice(&radius.to_le_bytes());
722 bytes.push(u8::from(continuous));
723 unsafe { Self::of(bytes, mangle::ty("RoundedRectangle")) }
724 }
725
726 pub(crate) fn ty(&self) -> &mangle::Type {
734 &self.ty
735 }
736
737 pub fn view(&self) -> ViewHandle {
738 unsafe {
739 let wt = abi::get_view_wt(self.meta);
740 ViewHandle::wrap(self.bytes.as_ptr() as _, self.meta, wt)
741 }
742 }
743
744 pub fn path() -> PathBuilder {
750 let mut bytes = vec![0u8; 40]; unsafe {
752 core::arch::asm!("blr {f}", f = in(reg) resolve::path_init(),
753 in("x8") bytes.as_mut_ptr(),
754 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
755 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
756 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
757 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
758 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
759 clobber_abi("C"),
760 );
761 }
762 PathBuilder { bytes }
763 }
764
765 fn base_name(&self) -> Option<&'static str> {
767 match &self.ty {
768 mangle::Type::Nominal { path, .. } => path.last().copied(),
769 _ => None,
770 }
771 }
772
773 pub fn inset(&self, amount: f64) -> Self {
782 let name = self.base_name().expect("inset needs a plain shape");
783 let symbol: &core::ffi::CStr = match name {
784 "Circle" => c"$s7SwiftUI6CircleV5inset2byQr12CoreGraphics7CGFloatV_tF",
785 "Capsule" => c"$s7SwiftUI7CapsuleV5inset2byQr12CoreGraphics7CGFloatV_tF",
786 "Ellipse" => c"$s7SwiftUI7EllipseV5inset2byQr12CoreGraphics7CGFloatV_tF",
787 "Rectangle" => c"$s7SwiftUI9RectangleV5inset2byQr12CoreGraphics7CGFloatV_tF",
788 "RoundedRectangle" => c"$s7SwiftUI16RoundedRectangleV5inset2byQr12CoreGraphics7CGFloatV_tF",
789 other => panic!("no exported inset(by:) for {other}"),
790 };
791 let oret: &core::ffi::CStr = match name {
792 "Circle" => c"$s7SwiftUI6CircleV5inset2byQr12CoreGraphics7CGFloatV_tFQOMQ",
793 "Capsule" => c"$s7SwiftUI7CapsuleV5inset2byQr12CoreGraphics7CGFloatV_tFQOMQ",
794 "Ellipse" => c"$s7SwiftUI7EllipseV5inset2byQr12CoreGraphics7CGFloatV_tFQOMQ",
795 "RoundedRectangle" => c"$s7SwiftUI16RoundedRectangleV5inset2byQr12CoreGraphics7CGFloatV_tFQOMQ",
796 _ => c"$s7SwiftUI9RectangleV5inset2byQr12CoreGraphics7CGFloatV_tFQOMQ",
797 };
798 unsafe {
799 let (meta, _, size) = super::opaque_result_type(resolve::sym(oret), &[]);
800 let wt = abi::get_view_wt_for_proto(meta, resolve::shape_proto());
801 assert!(!wt.is_null(), "inset shape !: Shape");
802 let mut bytes = vec![0u8; size.max(1)];
803 let mut receiver = self.receiver();
804 core::arch::asm!("blr {f}", f = in(reg) resolve::sym(symbol),
805 in("d0") amount,
806 in("x8") bytes.as_mut_ptr(),
807 in("x20") receiver.as_mut_ptr(),
808 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
809 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
810 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
811 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
812 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
813 );
814 let ty = mangle::Type::Nominal {
829 module: "SwiftUI",
830 path: vec![name, "_Inset"],
831 kind: mangle::Kind::Struct,
832 };
833 debug_assert_eq!(
834 abi::mangled_type_name(meta).as_deref(),
835 Some(ty.mangle().as_bytes()),
836 "{name}.inset(by:) does not return {name}._Inset",
837 );
838 Self { bytes, meta, wt, ty }
839 }
840 }
841
842 pub fn offset(&self, x: f64, y: f64) -> Self {
848 let ty = mangle::ty("OffsetShape").of(vec![self.ty.clone()]);
849 unsafe { self.wrapped(resolve::shape_offset_fn(), ty, [x, y, 0.0, 0.0]) }
850 }
851
852 pub fn rotation(&self, degrees: f64) -> Self {
856 let ty = mangle::ty("RotatedShape").of(vec![self.ty.clone()]);
857 let radians = degrees * std::f64::consts::PI / 180.0;
858 unsafe { self.wrapped(resolve::shape_rotation_fn(), ty, [radians, 0.5, 0.5, 0.0]) }
859 }
860
861 unsafe fn wrapped(&self, func: *const c_void, ty: mangle::Type, floats: [f64; 4]) -> Self {
867 unsafe {
868 let mangled = ty.mangle();
869 let meta = abi::resolve_type_by_mangled_name(mangled.as_bytes());
870 assert!(!meta.is_null(), "shape metadata: {}", mangle::demangle(&mangled));
871 let wt = abi::get_view_wt_for_proto(meta, resolve::shape_proto());
872 assert!(!wt.is_null(), "{} !: Shape", mangle::demangle(&mangled));
873
874 let mut bytes = vec![0u8; abi::type_bytes(meta).max(1)];
875 let mut receiver = self.receiver();
876 core::arch::asm!("blr {f}", f = in(reg) func,
877 in("x0") self.meta,
878 in("x1") self.wt,
879 in("d0") floats[0], in("d1") floats[1],
880 in("d2") floats[2], in("d3") floats[3],
881 in("x8") bytes.as_mut_ptr(),
882 in("x20") receiver.as_mut_ptr(),
883 lateout("x2") _, lateout("x3") _, lateout("x4") _, lateout("x5") _,
884 lateout("x6") _, lateout("x7") _, lateout("x9") _, lateout("x10") _,
885 lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
886 lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
887 lateout("x21") _, clobber_abi("C"),
888 );
889 Self { bytes, meta, wt, ty }
890 }
891 }
892
893 pub unsafe fn fill_style(&self, style: &[u8], meta: *const c_void, wt: *const c_void) -> ViewHandle {
899 unsafe { self.filled(style, meta, wt) }
900 }
901
902 unsafe fn filled(
919 &self,
920 style: &[u8],
921 style_meta: *const c_void,
922 style_wt: *const c_void,
923 ) -> ViewHandle {
924 unsafe {
925 let meta = abi::generic_metadata_from_descriptor(
926 resolve::shape_view_desc(),
927 &[self.meta, style_meta, self.wt, style_wt],
928 );
929 assert!(!meta.is_null(), "_ShapeView metadata");
930 let wt = abi::get_view_wt(meta);
931 assert!(!wt.is_null(), "_ShapeView !: View");
932
933 let mut arg = style.to_vec();
934 arg.resize(abi::type_bytes(style_meta).max(style.len()).max(1), 0);
935 let mut receiver = self.receiver();
936 let mut result = vec![0u8; abi::type_bytes(meta)];
937 core::arch::asm!("blr {f}", f = in(reg) resolve::shape_view_init(),
941 in("x0") receiver.as_mut_ptr(),
942 in("x1") arg.as_mut_ptr(),
943 in("x2") FILL_STYLE_DEFAULT,
944 in("x3") self.meta,
945 in("x4") style_meta,
946 in("x5") self.wt,
947 in("x6") style_wt,
948 in("x8") result.as_mut_ptr(),
949 lateout("x7") _, lateout("x9") _, lateout("x10") _,
950 lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
951 lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
952 lateout("x20") _, lateout("x21") _, clobber_abi("C"),
953 );
954 wrap_owned(result, meta, wt)
955 }
956 }
957
958 pub(crate) fn fill_parts(
966 &self,
967 style: &[u8],
968 meta: *const c_void,
969 wt: *const c_void,
970 ) -> (Vec<u8>, *const c_void) {
971 unsafe {
972 let subst = [self.meta, meta, self.wt, wt];
973 let (ty, _, size) = super::opaque_result_type(resolve::shape_fill_oret(), &subst);
974 let mut result = vec![0u8; size];
975 let mut arg = style.to_vec();
976 arg.resize(abi::type_bytes(meta).max(style.len()).max(1), 0);
977 let mut receiver = self.receiver();
978 core::arch::asm!("blr {f}", f = in(reg) resolve::shape_fill_fn(),
979 in("x0") arg.as_mut_ptr(),
980 in("x1") FILL_STYLE_DEFAULT as *const c_void,
981 in("x2") subst[0], in("x3") subst[1], in("x4") subst[2], in("x5") subst[3],
982 in("d0") 0.0f64,
983 in("x8") result.as_mut_ptr(),
984 in("x20") receiver.as_mut_ptr(),
985 lateout("x6") _, lateout("x7") _, lateout("x9") _, lateout("x10") _,
986 lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
987 lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
988 lateout("x21") _, clobber_abi("C"),
989 );
990 (result, ty)
991 }
992 }
993
994 pub unsafe fn stroke_style(
999 &self,
1000 style: &[u8],
1001 meta: *const c_void,
1002 wt: *const c_void,
1003 line_width: f64,
1004 ) -> ViewHandle {
1005 unsafe {
1006 let inner = self.styled(
1007 resolve::shape_stroke_fn(),
1008 resolve::shape_stroke_oret(),
1009 style,
1010 meta,
1011 wt,
1012 false,
1013 line_width,
1014 );
1015 self.as_stroke_shape_view(inner, meta, wt)
1019 }
1020 }
1021
1022 pub fn fill(&self, color: u64) -> ViewHandle {
1024 let bytes = color.to_le_bytes();
1025 unsafe { self.fill_style(&bytes, resolve::color_meta(), resolve::color_shapestyle_wt()) }
1027 }
1028
1029 pub fn stroked(&self, line_width: f64) -> Self {
1034 unsafe {
1035 let subst = [self.meta, self.wt];
1036 let (meta, _, size) =
1037 super::opaque_result_type(resolve::shape_stroke_plain_oret(), &subst);
1038 let wt = abi::get_view_wt_for_proto(meta, resolve::shape_proto());
1039 assert!(!wt.is_null(), "stroked shape !: Shape");
1040 let mut bytes = vec![0u8; size.max(1)];
1041 let mut receiver = self.receiver();
1042 core::arch::asm!("blr {f}", f = in(reg) resolve::shape_stroke_plain_fn(),
1043 in("x0") subst[0], in("x1") subst[1],
1044 in("d0") line_width,
1045 in("x8") bytes.as_mut_ptr(),
1046 in("x20") receiver.as_mut_ptr(),
1047 lateout("x2") _, lateout("x3") _, lateout("x4") _, lateout("x5") _,
1048 lateout("x6") _, lateout("x7") _, lateout("x9") _, lateout("x10") _,
1049 lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
1050 lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
1051 lateout("x21") _, clobber_abi("C"),
1052 );
1053 Self { bytes, meta, wt, ty: self.ty.clone() }
1054 }
1055 }
1056
1057 pub fn parts(&self) -> (Vec<u8>, *const c_void, *const c_void) {
1059 (self.bytes.clone(), self.meta, self.wt)
1060 }
1061
1062 pub fn stroke_default(&self, line_width: f64) -> ViewHandle {
1068 unsafe {
1069 let subst = [self.meta, self.wt];
1070 let (meta, _, size) =
1076 super::opaque_result_type(resolve::shape_stroke_plain_oret(), &subst);
1077 let wt = abi::get_view_wt(meta);
1078 assert!(!wt.is_null(), "stroked shape !: View");
1079 let mut result = vec![0u8; size];
1080 let mut receiver = self.receiver();
1081 core::arch::asm!("blr {f}", f = in(reg) resolve::shape_stroke_plain_fn(),
1082 in("x0") subst[0], in("x1") subst[1],
1083 in("d0") line_width,
1084 in("x8") result.as_mut_ptr(),
1085 in("x20") receiver.as_mut_ptr(),
1086 lateout("x2") _, lateout("x3") _, lateout("x4") _, lateout("x5") _,
1087 lateout("x6") _, lateout("x7") _, lateout("x9") _, lateout("x10") _,
1088 lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
1089 lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
1090 lateout("x21") _, clobber_abi("C"),
1091 );
1092 wrap_owned(result, meta, wt)
1093 }
1094 }
1095
1096 pub fn stroke(&self, color: u64, line_width: f64) -> ViewHandle {
1098 let bytes = color.to_le_bytes();
1099 unsafe {
1101 self.stroke_style(&bytes, resolve::color_meta(), resolve::color_shapestyle_wt(), line_width)
1102 }
1103 }
1104
1105 unsafe fn as_stroke_shape_view(
1124 &self,
1125 inner: ViewHandle,
1126 style_meta: *const c_void,
1127 style_wt: *const c_void,
1128 ) -> ViewHandle {
1129 unsafe {
1130 let empty = super::empty_view();
1131 let bg = super::background_content(&inner, &empty, super::Alignment::Center);
1132
1133 let desc = resolve::stroke_shape_view_desc();
1134 if desc.is_null() {
1135 return inner;
1136 }
1137 let args = [
1140 self.meta,
1141 style_meta,
1142 resolve::emptyview_meta(),
1143 self.wt,
1144 style_wt,
1145 resolve::emptyview_view_wt(),
1146 ];
1147 let meta = abi::generic_metadata_from_descriptor(desc, &args);
1148 if meta.is_null() {
1149 return inner;
1150 }
1151 if abi::struct_field_offsets(meta).as_deref() != Some(&[0][..])
1156 || abi::type_bytes(meta) != abi::type_bytes(bg.meta)
1157 {
1158 return inner;
1159 }
1160 if !crate::diag::type_name(meta).starts_with("SwiftUI.StrokeShapeView<") {
1161 return inner;
1162 }
1163 let wt = abi::get_view_wt(meta);
1164 if wt.is_null() {
1165 return inner;
1166 }
1167 let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(bg.meta);
1170 let mut out = vec![0u8; abi::type_bytes(meta)];
1171 if vwt.size > 0 {
1172 (vwt.initialize_with_copy)(
1173 out.as_mut_ptr() as *mut c_void,
1174 bg.value_ptr() as *mut c_void,
1175 bg.meta,
1176 );
1177 }
1178 super::wrap_owned(out, meta, wt)
1179 }
1180 }
1181
1182 #[allow(clippy::too_many_arguments)]
1191 unsafe fn styled(
1192 &self,
1193 func: *const c_void,
1194 oret: *const c_void,
1195 style: &[u8],
1196 style_meta: *const c_void,
1197 style_wt: *const c_void,
1198 filling: bool,
1199 line_width: f64,
1200 ) -> ViewHandle {
1201 unsafe {
1202 let subst = [self.meta, style_meta, self.wt, style_wt];
1206 let (meta, wt, size) = super::opaque_result_type(oret, &subst);
1207
1208 let mut result = vec![0u8; size];
1209 let mut arg = style.to_vec();
1210 arg.resize(abi::type_bytes(style_meta).max(style.len()).max(1), 0);
1211 let mut receiver = self.receiver();
1212 let (x1, x2, x3, x4, x5) = if filling {
1213 (FILL_STYLE_DEFAULT as *const c_void, subst[0], subst[1], subst[2], subst[3])
1214 } else {
1215 (subst[0], subst[1], subst[2], subst[3], core::ptr::null())
1216 };
1217 core::arch::asm!("blr {f}", f = in(reg) func,
1218 in("x0") arg.as_mut_ptr(),
1219 in("x1") x1, in("x2") x2, in("x3") x3, in("x4") x4, in("x5") x5,
1220 in("d0") line_width,
1221 in("x8") result.as_mut_ptr(),
1222 in("x20") receiver.as_mut_ptr(),
1223 lateout("x6") _, lateout("x7") _, lateout("x9") _, lateout("x10") _,
1224 lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
1225 lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
1226 lateout("x21") _, clobber_abi("C"),
1227 );
1228 wrap_owned(result, meta, wt)
1229 }
1230 }
1231
1232 fn receiver(&self) -> Vec<u8> {
1238 let mut v = self.bytes.clone();
1239 v.push(0);
1240 v
1241 }
1242}
1243
1244pub struct PathBuilder {
1250 bytes: Vec<u8>,
1251}
1252
1253impl PathBuilder {
1254 pub(crate) unsafe fn move_into(self, out: *mut u8) {
1264 let me = core::mem::ManuallyDrop::new(self);
1265 unsafe { core::ptr::copy_nonoverlapping(me.bytes.as_ptr(), out, me.bytes.len()) };
1266 }
1267
1268 pub fn move_to(&mut self, x: f64, y: f64) -> &mut Self {
1270 unsafe { self.point(resolve::path_move_to(), x, y, 0.0, 0.0) }
1271 }
1272
1273 pub fn line_to(&mut self, x: f64, y: f64) -> &mut Self {
1275 unsafe { self.point(resolve::path_add_line(), x, y, 0.0, 0.0) }
1276 }
1277
1278 pub fn quad_curve_to(&mut self, x: f64, y: f64, cx: f64, cy: f64) -> &mut Self {
1281 unsafe { self.point(resolve::path_add_quad_curve(), x, y, cx, cy) }
1282 }
1283
1284 pub fn close(&mut self) -> &mut Self {
1286 unsafe { self.point(resolve::path_close_subpath(), 0.0, 0.0, 0.0, 0.0) }
1287 }
1288
1289 unsafe fn point(&mut self, f: *const c_void, a: f64, b: f64, c: f64, d: f64) -> &mut Self {
1290 unsafe {
1291 core::arch::asm!("blr {f}", f = in(reg) f,
1292 in("d0") a, in("d1") b, in("d2") c, in("d3") d,
1293 in("x20") self.bytes.as_mut_ptr(),
1294 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
1295 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
1296 lateout("x8") _, lateout("x9") _, lateout("x10") _, lateout("x11") _,
1297 lateout("x12") _, lateout("x13") _, lateout("x14") _, lateout("x15") _,
1298 lateout("x16") _, lateout("x17") _, lateout("lr") _, lateout("x21") _,
1299 clobber_abi("C"),
1300 );
1301 }
1302 self
1303 }
1304
1305 pub fn shape(&self) -> Shape {
1307 unsafe { Shape::of(self.bytes.clone(), mangle::ty("Path")) }
1308 }
1309}
1310
1311const FILL_STYLE_DEFAULT: u64 = 0x0100;
1314
1315pub fn stroke_border(
1325 shape: super::InsettableShape,
1326 color: u64,
1327 line_width: f64,
1328) -> ViewHandle {
1329 unsafe {
1330 let (ma, _insettable_wt, init) = shape.parts();
1331 let shape_meta = abi::metadata0(ma);
1332 let mut receiver = vec![0u8; abi::type_bytes(shape_meta).max(1)];
1333 core::arch::asm!("blr {f}", f = in(reg) init,
1334 in("x8") receiver.as_mut_ptr(),
1335 in("x20") shape_meta,
1336 lateout("x0") _, lateout("x1") _, lateout("x2") _, lateout("x3") _,
1337 lateout("x4") _, lateout("x5") _, lateout("x6") _, lateout("x7") _,
1338 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1339 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1340 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
1341 );
1342
1343 let subst = [shape_meta, resolve::color_meta(), _insettable_wt, resolve::color_shapestyle_wt()];
1344 let (meta, wt, size) =
1345 super::opaque_result_type(resolve::stroke_border_oret(), &subst);
1346 let style = color.to_le_bytes();
1347 let mut result = vec![0u8; size.max(1)];
1348 core::arch::asm!("blr {f}", f = in(reg) resolve::stroke_border_fn(),
1349 in("x0") style.as_ptr(),
1350 in("d0") line_width,
1351 in("x1") 1u64,
1352 in("x2") subst[0], in("x3") subst[1], in("x4") subst[2], in("x5") subst[3],
1353 in("x8") result.as_mut_ptr(),
1354 in("x20") receiver.as_mut_ptr(),
1355 lateout("x6") _, lateout("x7") _, lateout("x9") _, lateout("x10") _,
1356 lateout("x11") _, lateout("x12") _, lateout("x13") _, lateout("x14") _,
1357 lateout("x15") _, lateout("x16") _, lateout("x17") _, lateout("lr") _,
1358 lateout("x21") _, clobber_abi("C"),
1359 );
1360 let outer_mangled = format!(
1367 "7SwiftUI21StrokeBorderShapeViewVy{}7SwiftUI5ColorV7SwiftUI9EmptyViewVG",
1368 shape.type_mangling()
1369 );
1370 let outer = abi::resolve_type_by_mangled_name(outer_mangled.as_bytes());
1371 assert!(!outer.is_null(), "{}", crate::diag::demangle_type(outer_mangled.as_bytes()));
1372 let outer_wt = abi::get_view_wt(outer);
1373 assert!(!outer_wt.is_null(), "StrokeBorderShapeView !: View");
1374
1375 let (ah, av) = super::static_getter(resolve::alignment_center(), resolve::alignment_meta());
1380
1381 let mut bytes = vec![0u8; abi::type_bytes(outer)];
1382 let inner = abi::type_size(meta);
1383 bytes[..inner].copy_from_slice(&result[..inner]);
1384 let align_at = border_view_offsets(outer)
1393 .map(|(_, _, _, align)| align)
1394 .unwrap_or_else(|| inner.next_multiple_of(8));
1395 bytes[align_at..align_at + 8].copy_from_slice(&ah.to_le_bytes());
1396 bytes[align_at + 8..align_at + 16].copy_from_slice(&av.to_le_bytes());
1397 let _ = wt;
1398 wrap_buf(&bytes, outer, outer_wt)
1399 }
1400}
1401
1402pub fn fill_then_stroke(
1411 shape: &Shape,
1412 fill: u64,
1413 stroke: u64,
1414 line_width: f64,
1415 result_mangled: &[u8],
1416) -> ViewHandle {
1417 unsafe {
1418 let color_meta = resolve::color_meta();
1419 let color_wt = resolve::color_shapestyle_wt();
1420 let (background, bg_ty) = shape.fill_parts(&fill.to_le_bytes(), color_meta, color_wt);
1421 let (content, content_ty) =
1422 shape.stroked(line_width).fill_parts(&stroke.to_le_bytes(), color_meta, color_wt);
1423
1424 let meta = abi::resolve_type_by_mangled_name(result_mangled);
1425 assert!(!meta.is_null(), "{}", crate::diag::demangle_type(result_mangled));
1426 let wt = abi::get_view_wt(meta);
1427 assert!(!wt.is_null(), "StrokeShapeView !: View");
1428
1429 let (ah, av) = super::static_getter(resolve::alignment_center(), resolve::alignment_meta());
1430 let content_size = abi::type_size(content_ty);
1431 let bg_size = abi::type_size(bg_ty);
1432 let (content_at, bg_at, align_at) =
1433 stroke_view_offsets(meta)
1434 .unwrap_or_else(|| {
1435 let bg_at = content_size.next_multiple_of(8);
1439 (0, bg_at, (bg_at + bg_size).next_multiple_of(8))
1440 });
1441
1442 let mut bytes = vec![0u8; abi::type_bytes(meta)];
1443 assert!(
1444 align_at + 16 <= bytes.len() && bg_at + bg_size <= bytes.len(),
1445 "{} lays out its fields differently than expected: content at {content_at} \
1446 ({content_size} bytes), background at {bg_at} ({bg_size}), alignment at \
1447 {align_at} — but the type is only {} bytes.",
1448 crate::diag::type_name(meta),
1449 bytes.len(),
1450 );
1451 bytes[content_at..content_at + content_size].copy_from_slice(&content[..content_size]);
1452 bytes[bg_at..bg_at + bg_size].copy_from_slice(&background[..bg_size]);
1453 bytes[align_at..align_at + 8].copy_from_slice(&ah.to_le_bytes());
1454 bytes[align_at + 8..align_at + 16].copy_from_slice(&av.to_le_bytes());
1455 wrap_buf(&bytes, meta, wt)
1456 }
1457}
1458
1459unsafe fn stroke_view_offsets(meta: *const c_void) -> Option<(usize, usize, usize)> {
1475 unsafe {
1476 let &[view_at] = abi::struct_field_offsets(meta)?.as_slice() else { return None };
1477 let modified = abi::field_type_metadata(meta, 0);
1478 if modified.is_null() {
1479 return None;
1480 }
1481 let &[content_at, modifier_at] = abi::struct_field_offsets(modified)?.as_slice() else {
1482 return None;
1483 };
1484 let background = abi::field_type_metadata(modified, 1);
1485 if background.is_null() {
1486 return None;
1487 }
1488 let &[bg_at, align_at] = abi::struct_field_offsets(background)?.as_slice() else {
1489 return None;
1490 };
1491 Some((
1492 view_at + content_at,
1493 view_at + modifier_at + bg_at,
1494 view_at + modifier_at + align_at,
1495 ))
1496 }
1497}
1498
1499unsafe fn border_view_offsets(meta: *const c_void) -> Option<(usize, usize, usize, usize)> {
1507 unsafe {
1508 let &[shape_at, view_at] = abi::struct_field_offsets(meta)?.as_slice() else {
1509 return None;
1510 };
1511 let modified = abi::field_type_metadata(meta, 1);
1512 if modified.is_null() {
1513 return None;
1514 }
1515 let &[content_at, modifier_at] = abi::struct_field_offsets(modified)?.as_slice() else {
1516 return None;
1517 };
1518 let background = abi::field_type_metadata(modified, 1);
1519 if background.is_null() {
1520 return None;
1521 }
1522 let &[bg_at, align_at] = abi::struct_field_offsets(background)?.as_slice() else {
1523 return None;
1524 };
1525 Some((
1526 shape_at,
1527 view_at + content_at,
1528 view_at + modifier_at + bg_at,
1529 view_at + modifier_at + align_at,
1530 ))
1531 }
1532}
1533
1534pub fn fill_then_stroke_border(
1544 shape: &Shape,
1545 fill: u64,
1546 border: u64,
1547 line_width: f64,
1548 result_mangled: &[u8],
1549) -> ViewHandle {
1550 unsafe {
1551 let color_meta = resolve::color_meta();
1552 let color_wt = resolve::color_shapestyle_wt();
1553 let (background, bg_ty) = shape.fill_parts(&fill.to_le_bytes(), color_meta, color_wt);
1554 let (content, content_ty) = shape
1555 .inset(line_width / 2.0)
1556 .stroked(line_width)
1557 .fill_parts(&border.to_le_bytes(), color_meta, color_wt);
1558
1559 let meta = abi::resolve_type_by_mangled_name(result_mangled);
1560 assert!(!meta.is_null(), "{}", crate::diag::demangle_type(result_mangled));
1561 let wt = abi::get_view_wt(meta);
1562 assert!(!wt.is_null(), "StrokeBorderShapeView !: View");
1563
1564 let (ah, av) = super::static_getter(resolve::alignment_center(), resolve::alignment_meta());
1565 let shape_size = abi::type_size(shape.meta);
1566 let content_size = abi::type_size(content_ty);
1567 let bg_size = abi::type_size(bg_ty);
1568 let (shape_at, content_at, bg_at, align_at) = border_view_offsets(meta)
1572 .unwrap_or_else(|| {
1573 let content_at = shape_size.next_multiple_of(8);
1574 let bg_at = (content_at + content_size).next_multiple_of(8);
1575 (0, content_at, bg_at, (bg_at + bg_size).next_multiple_of(8))
1576 });
1577
1578 let mut bytes = vec![0u8; abi::type_bytes(meta)];
1579 assert!(
1580 align_at + 16 <= bytes.len(),
1581 "{} lays out its fields differently than expected",
1582 crate::diag::type_name(meta),
1583 );
1584 bytes[shape_at..shape_at + shape_size].copy_from_slice(&shape.bytes[..shape_size]);
1585 bytes[content_at..content_at + content_size].copy_from_slice(&content[..content_size]);
1586 bytes[bg_at..bg_at + bg_size].copy_from_slice(&background[..bg_size]);
1587 bytes[align_at..align_at + 8].copy_from_slice(&ah.to_le_bytes());
1588 bytes[align_at + 8..align_at + 16].copy_from_slice(&av.to_le_bytes());
1589 wrap_buf(&bytes, meta, wt)
1590 }
1591}
1592
1593pub fn linear_gradient_stops(
1600 stops: &[(u64, f64)],
1601 start: (f64, f64),
1602 end: (f64, f64),
1603) -> (Vec<u8>, *const c_void, *const c_void) {
1604 unsafe {
1605 let stop_meta = abi::metadata0(resolve::gradient_stop_ma());
1606 let stride = abi::type_stride(stop_meta);
1607 let mut bytes = vec![0u8; stride * stops.len()];
1608 for (i, (color, location)) in stops.iter().enumerate() {
1609 let (word, loc): (u64, f64);
1616 core::arch::asm!("blr {f}", f = in(reg) resolve::gradient_stop_init(),
1617 inout("x0") *color => word,
1618 inout("d0") *location => loc,
1619 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
1620 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x8") _,
1621 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1622 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1623 lateout("x17") _, lateout("lr") _, lateout("x20") _, lateout("x21") _,
1624 clobber_abi("C"),
1625 );
1626 bytes[i * stride..i * stride + 8].copy_from_slice(&word.to_le_bytes());
1627 bytes[i * stride + 8..i * stride + 16].copy_from_slice(&loc.to_le_bytes());
1628 }
1629 let array = abi::swift_array(stop_meta, stops.len(), &bytes);
1630
1631 let g: u64;
1632 core::arch::asm!("blr {f}", f = in(reg) resolve::gradient_stops_init(),
1633 in("x0") array,
1634 in("x20") resolve::gradient_meta(),
1635 lateout("x0") g,
1636 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
1637 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x8") _,
1638 lateout("x9") _, lateout("x10") _, lateout("x11") _, lateout("x12") _,
1639 lateout("x13") _, lateout("x14") _, lateout("x15") _, lateout("x16") _,
1640 lateout("x17") _, lateout("lr") _, lateout("x21") _, clobber_abi("C"),
1641 );
1642
1643 let meta = crate::type_by_name!(swift_type!(SwiftUI.LinearGradient).as_bytes());
1644 assert!(!meta.is_null(), "LinearGradient metadata");
1645 let mut value = vec![0u8; abi::type_bytes(meta)];
1646 core::arch::asm!("blr {f}", f = in(reg) resolve::linear_gradient_init(),
1647 in("x0") g,
1648 in("d0") start.0, in("d1") start.1, in("d2") end.0, in("d3") end.1,
1649 in("x8") value.as_mut_ptr(),
1650 in("x20") meta,
1651 lateout("x1") _, lateout("x2") _, lateout("x3") _, lateout("x4") _,
1652 lateout("x5") _, lateout("x6") _, lateout("x7") _, lateout("x9") _,
1653 lateout("x10") _, lateout("x11") _, lateout("x12") _, lateout("x13") _,
1654 lateout("x14") _, lateout("x15") _, lateout("x16") _, lateout("x17") _,
1655 lateout("lr") _, lateout("x21") _, clobber_abi("C"),
1656 );
1657 (value, meta, resolve::linear_gradient_wt())
1658 }
1659}
1660
1661pub fn linear_gradient_stops_view(
1663 stops: &[(u64, f64)],
1664 start: (f64, f64),
1665 end: (f64, f64),
1666) -> ViewHandle {
1667 let (bytes, meta, _) = linear_gradient_stops(stops, start, end);
1668 unsafe {
1669 let wt = abi::get_view_wt(meta);
1670 assert!(!wt.is_null(), "LinearGradient !: View");
1671 wrap_buf(&bytes, meta, wt)
1672 }
1673}
1674
1675pub fn shadow_over_style(
1682 base: &[u8],
1683 base_ty: &str,
1684 shadow: &[u8],
1685) -> (Vec<u8>, *const c_void, *const c_void) {
1686 unsafe {
1687 let ty = mangle::ty("_ShadowShapeStyle")
1688 .of(vec![mangle::Type::Verbatim(base_ty.into())])
1689 .mangle();
1690 let meta = abi::resolve_type_by_mangled_name(ty.as_bytes());
1691 assert!(!meta.is_null(), "{}", mangle::demangle(&ty));
1692 let wt = abi::get_view_wt_for_proto(meta, resolve::shape_style_proto());
1693 assert!(!wt.is_null(), "_ShadowShapeStyle !: ShapeStyle");
1694 let mut bytes = vec![0u8; abi::type_bytes(meta)];
1695 let offsets = abi::struct_field_offsets(meta).expect("two stored fields");
1699 let &[base_at, shadow_at] = offsets.as_slice() else {
1700 panic!("_ShadowShapeStyle is {} fields, not 2", offsets.len());
1701 };
1702 bytes[base_at..base_at + base.len()].copy_from_slice(base);
1703 let n = shadow.len().min(bytes.len() - shadow_at);
1704 bytes[shadow_at..shadow_at + n].copy_from_slice(&shadow[..n]);
1705 (bytes, meta, wt)
1706 }
1707}
1708
1709pub fn opacity_over_style(
1715 base: &[u8],
1716 base_ty: &str,
1717 opacity: f64,
1718) -> (Vec<u8>, *const c_void, *const c_void) {
1719 unsafe {
1720 let ty = mangle::ty("_OpacityShapeStyle")
1721 .of(vec![mangle::Type::Verbatim(base_ty.into())])
1722 .mangle();
1723 let meta = abi::resolve_type_by_mangled_name(ty.as_bytes());
1724 assert!(!meta.is_null(), "{}", mangle::demangle(&ty));
1725 let wt = abi::get_view_wt_for_proto(meta, resolve::shape_style_proto());
1726 assert!(!wt.is_null(), "_OpacityShapeStyle !: ShapeStyle");
1727 let mut bytes = vec![0u8; abi::type_bytes(meta)];
1728 bytes[..base.len()].copy_from_slice(base);
1729 let at = base.len().next_multiple_of(4);
1730 bytes[at..at + 4].copy_from_slice(&(opacity as f32).to_le_bytes());
1731 (bytes, meta, wt)
1732 }
1733}
1734
1735impl Shape {
1736 pub fn trim(&self, from: f64, to: f64) -> Self {
1746 unsafe {
1747 let desc = resolve::trimmed_shape_desc();
1748 let meta = if desc.is_null() {
1749 core::ptr::null()
1750 } else {
1751 abi::generic_metadata_from_descriptor(desc, &[self.meta, self.wt])
1752 };
1753 let offsets = if meta.is_null() {
1754 None
1755 } else {
1756 abi::struct_field_offsets(meta)
1757 };
1758 let same = || Self {
1761 bytes: self.bytes.clone(),
1762 meta: self.meta,
1763 wt: self.wt,
1764 ty: self.ty.clone(),
1765 };
1766 let Some(offs) = offsets.filter(|o| o.len() == 3) else {
1767 return same();
1768 };
1769 let wt = abi::get_view_wt_for_proto(meta, resolve::shape_proto());
1770 if wt.is_null() {
1771 return same();
1772 }
1773
1774 let mut bytes = vec![0u8; abi::type_bytes(meta)];
1775 let vwt = &*swift_runtime_sys::SwiftABI::get_value_witness_table(self.meta);
1776 if vwt.size > 0 {
1777 (vwt.initialize_with_copy)(
1778 bytes.as_mut_ptr().add(offs[0]) as *mut c_void,
1779 self.bytes.as_ptr() as *mut c_void,
1780 self.meta,
1781 );
1782 }
1783 bytes[offs[1]..offs[1] + 8].copy_from_slice(&from.to_le_bytes());
1784 bytes[offs[2]..offs[2] + 8].copy_from_slice(&to.to_le_bytes());
1785
1786 Self {
1787 bytes,
1788 meta,
1789 wt,
1790 ty: mangle::ty("_TrimmedShape").of(vec![self.ty.clone()]),
1791 }
1792 }
1793 }
1794}