1use bitflags::bitflags;
8use crate::rendering::composition::CompositionStrokeCap;
9use crate::rendering::composition::CompositionStrokeLineJoin;
10use crate::rendering::composition::ICompositionObject;
11use crate::rendering::composition::animations::AnimationInstanceFactory;
12use crate::rendering::composition::animations::ICompositionAnimation;
13use crate::rendering::composition::expressions::ExpressionVariant;
14use crate::rendering::composition::server::AsServerRenderResource;
15use crate::rendering::composition::server::CompositionProperty;
16use crate::rendering::composition::server::CompositionPropertyOf;
17use crate::rendering::composition::server::IServerObject;
18use crate::rendering::composition::server::ServerPropertyValue;
19use crate::rendering::composition::server::ServerValueChange;
20use crate::rendering::composition::server::props_of;
21use crate::rendering::composition::server::read_server_object;
22use crate::rendering::composition::transport::BatchStreamReader;
23use crate::rendering::composition::transport::BatchStreamWriter;
24use crate::rendering::composition::transport::BatchValue;
25use crate::rendering::composition::transport::BatchValueReader;
26use std::any::Any;
27use std::any::TypeId;
28use std::cell::Cell;
29use std::cell::RefCell;
30use std::rc::Rc;
31use std::sync::Arc;
32use std::sync::OnceLock;
33use std::time::Duration;
34use super::CompositionShapeHooks;
35use super::CompositionShapeProps;
36use super::ServerCompositionShapeHooks;
37use super::ServerCompositionShapeProps;
38
39bitflags! {
40 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
42 pub struct CompositionSpriteShapeChangedFields: u16 {
43 const FILL_BRUSH = 1;
44 const GEOMETRY = 2;
45 const IS_STROKE_NON_SCALING = 4;
46 const STROKE_BRUSH = 8;
47 const STROKE_DASH_ARRAY = 16;
48 const STROKE_DASH_CAP = 32;
49 const STROKE_DASH_OFFSET = 64;
50 const STROKE_DASH_OFFSET_ANIMATED = 128;
51 const STROKE_END_CAP = 256;
52 const STROKE_LINE_JOIN = 512;
53 const STROKE_MITER_LIMIT = 1024;
54 const STROKE_MITER_LIMIT_ANIMATED = 2048;
55 const STROKE_START_CAP = 4096;
56 const STROKE_THICKNESS = 8192;
57 const STROKE_THICKNESS_ANIMATED = 16384;
58 }
59}
60
61impl BatchValue for CompositionSpriteShapeChangedFields {
62 #[inline]
63 fn write_to(&self, out: &mut Vec<u8>) {
64 self.bits().write_to(out);
65 }
66
67 #[inline]
68 fn read_from(input: &mut BatchValueReader<'_>) -> Self {
69 CompositionSpriteShapeChangedFields::from_bits_retain(u16::read_from(input))
70 }
71}
72
73pub trait CompositionSpriteShapeHooks: CompositionShapeHooks {
76 fn initialize_defaults_extra(&self) {}
77
78 fn validate_fill_brush_change(&self, _old_value: &Option<Rc<dyn ICompositionObject>>, _new_value: &Option<Rc<dyn ICompositionObject>>) {}
79 fn on_fill_brush_changed(&self) {}
80 fn on_fill_brush_changing(&self) {}
81
82 fn validate_geometry_change(&self, _old_value: &Option<Rc<dyn ICompositionObject>>, _new_value: &Option<Rc<dyn ICompositionObject>>) {}
83 fn on_geometry_changed(&self) {}
84 fn on_geometry_changing(&self) {}
85
86 fn validate_is_stroke_non_scaling_change(&self, _old_value: bool, _new_value: bool) {}
87 fn on_is_stroke_non_scaling_changed(&self) {}
88 fn on_is_stroke_non_scaling_changing(&self) {}
89
90 fn validate_stroke_brush_change(&self, _old_value: &Option<Rc<dyn ICompositionObject>>, _new_value: &Option<Rc<dyn ICompositionObject>>) {}
91 fn on_stroke_brush_changed(&self) {}
92 fn on_stroke_brush_changing(&self) {}
93
94 fn validate_stroke_dash_array_change(&self, _old_value: &Option<Arc<Vec<f32>>>, _new_value: &Option<Arc<Vec<f32>>>) {}
95 fn on_stroke_dash_array_changed(&self) {}
96 fn on_stroke_dash_array_changing(&self) {}
97
98 fn validate_stroke_dash_cap_change(&self, _old_value: CompositionStrokeCap, _new_value: CompositionStrokeCap) {}
99 fn on_stroke_dash_cap_changed(&self) {}
100 fn on_stroke_dash_cap_changing(&self) {}
101
102 fn validate_stroke_dash_offset_change(&self, _old_value: f32, _new_value: f32) {}
103 fn on_stroke_dash_offset_changed(&self) {}
104 fn on_stroke_dash_offset_changing(&self) {}
105
106 fn validate_stroke_end_cap_change(&self, _old_value: CompositionStrokeCap, _new_value: CompositionStrokeCap) {}
107 fn on_stroke_end_cap_changed(&self) {}
108 fn on_stroke_end_cap_changing(&self) {}
109
110 fn validate_stroke_line_join_change(&self, _old_value: CompositionStrokeLineJoin, _new_value: CompositionStrokeLineJoin) {}
111 fn on_stroke_line_join_changed(&self) {}
112 fn on_stroke_line_join_changing(&self) {}
113
114 fn validate_stroke_miter_limit_change(&self, _old_value: f32, _new_value: f32) {}
115 fn on_stroke_miter_limit_changed(&self) {}
116 fn on_stroke_miter_limit_changing(&self) {}
117
118 fn validate_stroke_start_cap_change(&self, _old_value: CompositionStrokeCap, _new_value: CompositionStrokeCap) {}
119 fn on_stroke_start_cap_changed(&self) {}
120 fn on_stroke_start_cap_changing(&self) {}
121
122 fn validate_stroke_thickness_change(&self, _old_value: f32, _new_value: f32) {}
123 fn on_stroke_thickness_changed(&self) {}
124 fn on_stroke_thickness_changing(&self) {}
125}
126
127pub struct CompositionSpriteShapeProps {
129 base: CompositionShapeProps,
130 changed_fields_of_composition_sprite_shape: Cell<CompositionSpriteShapeChangedFields>,
131 fill_brush: RefCell<Option<Rc<dyn ICompositionObject>>>,
132 geometry: RefCell<Option<Rc<dyn ICompositionObject>>>,
133 is_stroke_non_scaling: Cell<bool>,
134 stroke_brush: RefCell<Option<Rc<dyn ICompositionObject>>>,
135 stroke_dash_array: RefCell<Option<Arc<Vec<f32>>>>,
136 stroke_dash_cap: Cell<CompositionStrokeCap>,
137 stroke_dash_offset: Cell<f32>,
138 stroke_end_cap: Cell<CompositionStrokeCap>,
139 stroke_line_join: Cell<CompositionStrokeLineJoin>,
140 stroke_miter_limit: Cell<f32>,
141 stroke_start_cap: Cell<CompositionStrokeCap>,
142 stroke_thickness: Cell<f32>,
143}
144
145impl Default for CompositionSpriteShapeProps {
146 fn default() -> Self {
147 Self::new()
148 }
149}
150
151impl CompositionSpriteShapeProps {
152 pub fn new() -> Self {
156 Self {
157 base: CompositionShapeProps::new(),
158 changed_fields_of_composition_sprite_shape: Cell::new(CompositionSpriteShapeChangedFields::empty()),
159 fill_brush: RefCell::new(None),
160 geometry: RefCell::new(None),
161 is_stroke_non_scaling: Cell::new(Default::default()),
162 stroke_brush: RefCell::new(None),
163 stroke_dash_array: RefCell::new(None),
164 stroke_dash_cap: Cell::new(Default::default()),
165 stroke_dash_offset: Cell::new(Default::default()),
166 stroke_end_cap: Cell::new(Default::default()),
167 stroke_line_join: Cell::new(Default::default()),
168 stroke_miter_limit: Cell::new(Default::default()),
169 stroke_start_cap: Cell::new(Default::default()),
170 stroke_thickness: Cell::new(Default::default()),
171 }
172 }
173
174 pub fn base(&self) -> &CompositionShapeProps {
176 &self.base
177 }
178
179 pub fn initialize_defaults(&self, host: &dyn CompositionSpriteShapeHooks) {
182 self.base.initialize_defaults(host);
183 self.initialize_own_defaults(host);
184 }
185
186 pub fn initialize_own_defaults(&self, host: &dyn CompositionSpriteShapeHooks) {
188 CompositionSpriteShapeHooks::initialize_defaults_extra(host);
189 self.set_stroke_miter_limit(host, 2.0);
190 self.set_stroke_thickness(host, 1.0);
191 }
192
193 pub fn fill_brush(&self) -> Option<Rc<dyn ICompositionObject>> {
195 self.fill_brush.borrow().clone()
196 }
197
198 pub fn set_fill_brush(&self, host: &dyn CompositionSpriteShapeHooks, value: Option<Rc<dyn ICompositionObject>>) {
200 let mut changed = false;
201 let old_value = self.fill_brush.borrow().clone();
202 if old_value.differs(&value) {
203 CompositionSpriteShapeHooks::validate_fill_brush_change(host, &old_value, &value);
204 CompositionSpriteShapeHooks::on_fill_brush_changing(host);
205 changed = true;
206 *self.fill_brush.borrow_mut() = value.clone();
208 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::FILL_BRUSH);
210 host.register_for_serialization();
211 }
212 *self.fill_brush.borrow_mut() = value;
213 if changed {
214 CompositionSpriteShapeHooks::on_fill_brush_changed(host);
215 }
216 }
217
218 pub fn geometry(&self) -> Option<Rc<dyn ICompositionObject>> {
220 self.geometry.borrow().clone()
221 }
222
223 pub fn set_geometry(&self, host: &dyn CompositionSpriteShapeHooks, value: Option<Rc<dyn ICompositionObject>>) {
225 let mut changed = false;
226 let old_value = self.geometry.borrow().clone();
227 if old_value.differs(&value) {
228 CompositionSpriteShapeHooks::validate_geometry_change(host, &old_value, &value);
229 CompositionSpriteShapeHooks::on_geometry_changing(host);
230 changed = true;
231 *self.geometry.borrow_mut() = value.clone();
233 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::GEOMETRY);
235 host.register_for_serialization();
236 }
237 *self.geometry.borrow_mut() = value;
238 if changed {
239 CompositionSpriteShapeHooks::on_geometry_changed(host);
240 }
241 }
242
243 pub fn is_stroke_non_scaling(&self) -> bool {
245 self.is_stroke_non_scaling.get()
246 }
247
248 pub fn set_is_stroke_non_scaling(&self, host: &dyn CompositionSpriteShapeHooks, value: bool) {
250 let mut changed = false;
251 let old_value = self.is_stroke_non_scaling.get();
252 if old_value.differs(&value) {
253 CompositionSpriteShapeHooks::validate_is_stroke_non_scaling_change(host, old_value, value);
254 CompositionSpriteShapeHooks::on_is_stroke_non_scaling_changing(host);
255 changed = true;
256 self.is_stroke_non_scaling.set(value);
258 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::IS_STROKE_NON_SCALING);
260 host.register_for_serialization();
261 }
262 self.is_stroke_non_scaling.set(value);
263 if changed {
264 CompositionSpriteShapeHooks::on_is_stroke_non_scaling_changed(host);
265 }
266 }
267
268 pub fn stroke_brush(&self) -> Option<Rc<dyn ICompositionObject>> {
270 self.stroke_brush.borrow().clone()
271 }
272
273 pub fn set_stroke_brush(&self, host: &dyn CompositionSpriteShapeHooks, value: Option<Rc<dyn ICompositionObject>>) {
275 let mut changed = false;
276 let old_value = self.stroke_brush.borrow().clone();
277 if old_value.differs(&value) {
278 CompositionSpriteShapeHooks::validate_stroke_brush_change(host, &old_value, &value);
279 CompositionSpriteShapeHooks::on_stroke_brush_changing(host);
280 changed = true;
281 *self.stroke_brush.borrow_mut() = value.clone();
283 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_BRUSH);
285 host.register_for_serialization();
286 }
287 *self.stroke_brush.borrow_mut() = value;
288 if changed {
289 CompositionSpriteShapeHooks::on_stroke_brush_changed(host);
290 }
291 }
292
293 pub fn stroke_dash_array(&self) -> Option<Arc<Vec<f32>>> {
295 self.stroke_dash_array.borrow().clone()
296 }
297
298 pub fn set_stroke_dash_array(&self, host: &dyn CompositionSpriteShapeHooks, value: Option<Arc<Vec<f32>>>) {
300 let mut changed = false;
301 let old_value = self.stroke_dash_array.borrow().clone();
302 if old_value.differs(&value) {
303 CompositionSpriteShapeHooks::validate_stroke_dash_array_change(host, &old_value, &value);
304 CompositionSpriteShapeHooks::on_stroke_dash_array_changing(host);
305 changed = true;
306 *self.stroke_dash_array.borrow_mut() = value.clone();
308 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_DASH_ARRAY);
310 host.register_for_serialization();
311 }
312 *self.stroke_dash_array.borrow_mut() = value;
313 if changed {
314 CompositionSpriteShapeHooks::on_stroke_dash_array_changed(host);
315 }
316 }
317
318 pub fn stroke_dash_cap(&self) -> CompositionStrokeCap {
320 self.stroke_dash_cap.get()
321 }
322
323 pub fn set_stroke_dash_cap(&self, host: &dyn CompositionSpriteShapeHooks, value: CompositionStrokeCap) {
325 let mut changed = false;
326 let old_value = self.stroke_dash_cap.get();
327 if old_value.differs(&value) {
328 CompositionSpriteShapeHooks::validate_stroke_dash_cap_change(host, old_value, value);
329 CompositionSpriteShapeHooks::on_stroke_dash_cap_changing(host);
330 changed = true;
331 self.stroke_dash_cap.set(value);
333 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_DASH_CAP);
335 host.register_for_serialization();
336 }
337 self.stroke_dash_cap.set(value);
338 if changed {
339 CompositionSpriteShapeHooks::on_stroke_dash_cap_changed(host);
340 }
341 }
342
343 pub fn stroke_dash_offset(&self) -> f32 {
345 self.stroke_dash_offset.get()
346 }
347
348 pub fn set_stroke_dash_offset(&self, host: &dyn CompositionSpriteShapeHooks, value: f32) {
350 let mut changed = false;
351 let old_value = self.stroke_dash_offset.get();
352 if old_value.differs(&value) {
353 CompositionSpriteShapeHooks::validate_stroke_dash_offset_change(host, old_value, value);
354 CompositionSpriteShapeHooks::on_stroke_dash_offset_changing(host);
355 changed = true;
356 self.stroke_dash_offset.set(value);
358 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_DASH_OFFSET);
360 host.register_for_serialization();
361 host.pending_animations().remove(ServerCompositionSpriteShapeProps::id_of_stroke_dash_offset_property().base());
363 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() & !CompositionSpriteShapeChangedFields::STROKE_DASH_OFFSET_ANIMATED);
364 if let Some(animation) = host.implicit_animation("StrokeDashOffset") {
366 if let Some(a) = animation.as_composition_animation() {
368 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_DASH_OFFSET_ANIMATED);
369 host.pending_animations().set(
370 ServerCompositionSpriteShapeProps::id_of_stroke_dash_offset_property().base(),
371 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
372 );
373 }
374 host.start_animation_group(&animation, "StrokeDashOffset", ExpressionVariant::create(value));
376 }
377 }
378 self.stroke_dash_offset.set(value);
379 if changed {
380 CompositionSpriteShapeHooks::on_stroke_dash_offset_changed(host);
381 }
382 }
383
384 pub fn stroke_end_cap(&self) -> CompositionStrokeCap {
386 self.stroke_end_cap.get()
387 }
388
389 pub fn set_stroke_end_cap(&self, host: &dyn CompositionSpriteShapeHooks, value: CompositionStrokeCap) {
391 let mut changed = false;
392 let old_value = self.stroke_end_cap.get();
393 if old_value.differs(&value) {
394 CompositionSpriteShapeHooks::validate_stroke_end_cap_change(host, old_value, value);
395 CompositionSpriteShapeHooks::on_stroke_end_cap_changing(host);
396 changed = true;
397 self.stroke_end_cap.set(value);
399 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_END_CAP);
401 host.register_for_serialization();
402 }
403 self.stroke_end_cap.set(value);
404 if changed {
405 CompositionSpriteShapeHooks::on_stroke_end_cap_changed(host);
406 }
407 }
408
409 pub fn stroke_line_join(&self) -> CompositionStrokeLineJoin {
411 self.stroke_line_join.get()
412 }
413
414 pub fn set_stroke_line_join(&self, host: &dyn CompositionSpriteShapeHooks, value: CompositionStrokeLineJoin) {
416 let mut changed = false;
417 let old_value = self.stroke_line_join.get();
418 if old_value.differs(&value) {
419 CompositionSpriteShapeHooks::validate_stroke_line_join_change(host, old_value, value);
420 CompositionSpriteShapeHooks::on_stroke_line_join_changing(host);
421 changed = true;
422 self.stroke_line_join.set(value);
424 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_LINE_JOIN);
426 host.register_for_serialization();
427 }
428 self.stroke_line_join.set(value);
429 if changed {
430 CompositionSpriteShapeHooks::on_stroke_line_join_changed(host);
431 }
432 }
433
434 pub fn stroke_miter_limit(&self) -> f32 {
436 self.stroke_miter_limit.get()
437 }
438
439 pub fn set_stroke_miter_limit(&self, host: &dyn CompositionSpriteShapeHooks, value: f32) {
441 let mut changed = false;
442 let old_value = self.stroke_miter_limit.get();
443 if old_value.differs(&value) {
444 CompositionSpriteShapeHooks::validate_stroke_miter_limit_change(host, old_value, value);
445 CompositionSpriteShapeHooks::on_stroke_miter_limit_changing(host);
446 changed = true;
447 self.stroke_miter_limit.set(value);
449 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_MITER_LIMIT);
451 host.register_for_serialization();
452 host.pending_animations().remove(ServerCompositionSpriteShapeProps::id_of_stroke_miter_limit_property().base());
454 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() & !CompositionSpriteShapeChangedFields::STROKE_MITER_LIMIT_ANIMATED);
455 if let Some(animation) = host.implicit_animation("StrokeMiterLimit") {
457 if let Some(a) = animation.as_composition_animation() {
459 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_MITER_LIMIT_ANIMATED);
460 host.pending_animations().set(
461 ServerCompositionSpriteShapeProps::id_of_stroke_miter_limit_property().base(),
462 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
463 );
464 }
465 host.start_animation_group(&animation, "StrokeMiterLimit", ExpressionVariant::create(value));
467 }
468 }
469 self.stroke_miter_limit.set(value);
470 if changed {
471 CompositionSpriteShapeHooks::on_stroke_miter_limit_changed(host);
472 }
473 }
474
475 pub fn stroke_start_cap(&self) -> CompositionStrokeCap {
477 self.stroke_start_cap.get()
478 }
479
480 pub fn set_stroke_start_cap(&self, host: &dyn CompositionSpriteShapeHooks, value: CompositionStrokeCap) {
482 let mut changed = false;
483 let old_value = self.stroke_start_cap.get();
484 if old_value.differs(&value) {
485 CompositionSpriteShapeHooks::validate_stroke_start_cap_change(host, old_value, value);
486 CompositionSpriteShapeHooks::on_stroke_start_cap_changing(host);
487 changed = true;
488 self.stroke_start_cap.set(value);
490 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_START_CAP);
492 host.register_for_serialization();
493 }
494 self.stroke_start_cap.set(value);
495 if changed {
496 CompositionSpriteShapeHooks::on_stroke_start_cap_changed(host);
497 }
498 }
499
500 pub fn stroke_thickness(&self) -> f32 {
502 self.stroke_thickness.get()
503 }
504
505 pub fn set_stroke_thickness(&self, host: &dyn CompositionSpriteShapeHooks, value: f32) {
507 let mut changed = false;
508 let old_value = self.stroke_thickness.get();
509 if old_value.differs(&value) {
510 CompositionSpriteShapeHooks::validate_stroke_thickness_change(host, old_value, value);
511 CompositionSpriteShapeHooks::on_stroke_thickness_changing(host);
512 changed = true;
513 self.stroke_thickness.set(value);
515 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_THICKNESS);
517 host.register_for_serialization();
518 host.pending_animations().remove(ServerCompositionSpriteShapeProps::id_of_stroke_thickness_property().base());
520 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() & !CompositionSpriteShapeChangedFields::STROKE_THICKNESS_ANIMATED);
521 if let Some(animation) = host.implicit_animation("StrokeThickness") {
523 if let Some(a) = animation.as_composition_animation() {
525 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_THICKNESS_ANIMATED);
526 host.pending_animations().set(
527 ServerCompositionSpriteShapeProps::id_of_stroke_thickness_property().base(),
528 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
529 );
530 }
531 host.start_animation_group(&animation, "StrokeThickness", ExpressionVariant::create(value));
533 }
534 }
535 self.stroke_thickness.set(value);
536 if changed {
537 CompositionSpriteShapeHooks::on_stroke_thickness_changed(host);
538 }
539 }
540
541 pub fn start_animation(
545 &self,
546 host: &dyn CompositionSpriteShapeHooks,
547 property_name: &str,
548 animation: &dyn ICompositionAnimation,
549 final_value: Option<ExpressionVariant>,
550 ) -> bool {
551 if property_name == "StrokeDashOffset" {
552 let server = animation.create_instance(host.server(), final_value);
553 host.pending_animations().set(ServerCompositionSpriteShapeProps::id_of_stroke_dash_offset_property().base(), server);
554 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_DASH_OFFSET_ANIMATED);
555 host.register_for_serialization();
556 return true;
557 }
558 if property_name == "StrokeMiterLimit" {
559 let server = animation.create_instance(host.server(), final_value);
560 host.pending_animations().set(ServerCompositionSpriteShapeProps::id_of_stroke_miter_limit_property().base(), server);
561 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_MITER_LIMIT_ANIMATED);
562 host.register_for_serialization();
563 return true;
564 }
565 if property_name == "StrokeThickness" {
566 let server = animation.create_instance(host.server(), final_value);
567 host.pending_animations().set(ServerCompositionSpriteShapeProps::id_of_stroke_thickness_property().base(), server);
568 self.changed_fields_of_composition_sprite_shape.set(self.changed_fields_of_composition_sprite_shape.get() | CompositionSpriteShapeChangedFields::STROKE_THICKNESS_ANIMATED);
569 host.register_for_serialization();
570 return true;
571 }
572 self.base.start_animation(host, property_name, animation, final_value)
573 }
574
575 pub fn serialize_changes_core(&self, host: &dyn CompositionSpriteShapeHooks, writer: &mut BatchStreamWriter<'_>) {
578 self.base.serialize_changes_core(host, writer);
579 let changed = self.changed_fields_of_composition_sprite_shape.get();
580 writer.write(changed);
581 if changed.contains(CompositionSpriteShapeChangedFields::FILL_BRUSH) {
582 writer.write_server_object(self.fill_brush.borrow().clone().map(|o| o.server()));
583 }
584 if changed.contains(CompositionSpriteShapeChangedFields::GEOMETRY) {
585 writer.write_server_object(self.geometry.borrow().clone().map(|o| o.server()));
586 }
587 if changed.contains(CompositionSpriteShapeChangedFields::IS_STROKE_NON_SCALING) {
588 writer.write(self.is_stroke_non_scaling.get());
589 }
590 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_BRUSH) {
591 writer.write_server_object(self.stroke_brush.borrow().clone().map(|o| o.server()));
592 }
593 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_DASH_ARRAY) {
594 writer.write_value(self.stroke_dash_array.borrow().clone());
595 }
596 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_DASH_CAP) {
597 writer.write(self.stroke_dash_cap.get());
598 }
599 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_DASH_OFFSET_ANIMATED) {
600 writer.write_value(host.pending_animations().get_and_remove(ServerCompositionSpriteShapeProps::id_of_stroke_dash_offset_property().base()));
601 } else if changed.contains(CompositionSpriteShapeChangedFields::STROKE_DASH_OFFSET) {
602 writer.write(self.stroke_dash_offset.get());
603 }
604 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_END_CAP) {
605 writer.write(self.stroke_end_cap.get());
606 }
607 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_LINE_JOIN) {
608 writer.write(self.stroke_line_join.get());
609 }
610 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_MITER_LIMIT_ANIMATED) {
611 writer.write_value(host.pending_animations().get_and_remove(ServerCompositionSpriteShapeProps::id_of_stroke_miter_limit_property().base()));
612 } else if changed.contains(CompositionSpriteShapeChangedFields::STROKE_MITER_LIMIT) {
613 writer.write(self.stroke_miter_limit.get());
614 }
615 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_START_CAP) {
616 writer.write(self.stroke_start_cap.get());
617 }
618 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_THICKNESS_ANIMATED) {
619 writer.write_value(host.pending_animations().get_and_remove(ServerCompositionSpriteShapeProps::id_of_stroke_thickness_property().base()));
620 } else if changed.contains(CompositionSpriteShapeChangedFields::STROKE_THICKNESS) {
621 writer.write(self.stroke_thickness.get());
622 }
623 self.changed_fields_of_composition_sprite_shape.set(CompositionSpriteShapeChangedFields::empty());
624 }
625}
626
627pub trait ServerCompositionSpriteShapeHooks: ServerCompositionShapeHooks {
630 fn deserialize_changes_extra(&self, _reader: &mut BatchStreamReader<'_>) {}
631 fn on_fields_deserialized(&self, _changed: CompositionSpriteShapeChangedFields) {}
632
633 fn on_fill_brush_changed(&self) {}
634 fn on_fill_brush_changing(&self) {}
635
636 fn on_geometry_changed(&self) {}
637 fn on_geometry_changing(&self) {}
638
639 fn on_is_stroke_non_scaling_changed(&self) {}
640 fn on_is_stroke_non_scaling_changing(&self) {}
641
642 fn on_stroke_brush_changed(&self) {}
643 fn on_stroke_brush_changing(&self) {}
644
645 fn on_stroke_dash_array_changed(&self) {}
646 fn on_stroke_dash_array_changing(&self) {}
647
648 fn on_stroke_dash_cap_changed(&self) {}
649 fn on_stroke_dash_cap_changing(&self) {}
650
651 fn on_stroke_end_cap_changed(&self) {}
652 fn on_stroke_end_cap_changing(&self) {}
653
654 fn on_stroke_line_join_changed(&self) {}
655 fn on_stroke_line_join_changing(&self) {}
656
657 fn on_stroke_start_cap_changed(&self) {}
658 fn on_stroke_start_cap_changing(&self) {}
659}
660
661pub struct ServerCompositionSpriteShapeProps {
663 base: ServerCompositionShapeProps,
664 fill_brush: RefCell<Option<Rc<dyn IServerObject>>>,
665 geometry: RefCell<Option<Rc<dyn IServerObject>>>,
666 is_stroke_non_scaling: Cell<bool>,
667 stroke_brush: RefCell<Option<Rc<dyn IServerObject>>>,
668 stroke_dash_array: RefCell<Option<Arc<Vec<f32>>>>,
669 stroke_dash_cap: Cell<CompositionStrokeCap>,
670 stroke_dash_offset: Cell<f32>,
671 stroke_end_cap: Cell<CompositionStrokeCap>,
672 stroke_line_join: Cell<CompositionStrokeLineJoin>,
673 stroke_miter_limit: Cell<f32>,
674 stroke_start_cap: Cell<CompositionStrokeCap>,
675 stroke_thickness: Cell<f32>,
676}
677
678impl Default for ServerCompositionSpriteShapeProps {
679 fn default() -> Self {
680 Self::new()
681 }
682}
683
684impl ServerCompositionSpriteShapeProps {
685 pub fn new() -> Self {
688 Self {
689 base: ServerCompositionShapeProps::new(),
690 fill_brush: RefCell::new(None),
691 geometry: RefCell::new(None),
692 is_stroke_non_scaling: Cell::new(Default::default()),
693 stroke_brush: RefCell::new(None),
694 stroke_dash_array: RefCell::new(None),
695 stroke_dash_cap: Cell::new(Default::default()),
696 stroke_dash_offset: Cell::new(Default::default()),
697 stroke_end_cap: Cell::new(Default::default()),
698 stroke_line_join: Cell::new(Default::default()),
699 stroke_miter_limit: Cell::new(Default::default()),
700 stroke_start_cap: Cell::new(Default::default()),
701 stroke_thickness: Cell::new(Default::default()),
702 }
703 }
704
705 pub fn base(&self) -> &ServerCompositionShapeProps {
707 &self.base
708 }
709
710 pub fn find_props(&self, type_id: TypeId) -> Option<&dyn Any> {
713 if type_id == TypeId::of::<Self>() {
714 return Some(self);
715 }
716 self.base.find_props(type_id)
717 }
718
719 pub fn id_of_fill_brush_property() -> &'static CompositionPropertyOf<Option<Rc<dyn IServerObject>>> {
721 static PROPERTY: OnceLock<CompositionPropertyOf<Option<Rc<dyn IServerObject>>>> = OnceLock::new();
722 PROPERTY.get_or_init(|| {
723 CompositionProperty::register::<ServerCompositionSpriteShapeProps, Option<Rc<dyn IServerObject>>>(
724 "FillBrush",
725 "ServerCompositionSpriteShape",
726 |obj| props_of::<ServerCompositionSpriteShapeProps>(obj).fill_brush.borrow().clone(),
727 |obj, v| *props_of::<ServerCompositionSpriteShapeProps>(obj).fill_brush.borrow_mut() = v,
728 None,
729 None,
730 )
731 })
732 }
733
734 pub fn fill_brush(&self) -> Option<Rc<dyn IServerObject>> {
736 self.fill_brush.borrow().clone()
737 }
738
739 pub fn set_fill_brush(&self, host: &dyn ServerCompositionSpriteShapeHooks, value: Option<Rc<dyn IServerObject>>) {
740 let old_value = self.fill_brush.borrow().clone();
741 let mut changed = false;
742 if old_value.differs(&value) {
743 ServerCompositionSpriteShapeHooks::on_fill_brush_changing(host);
744 changed = true;
745 }
746 host.set_value(
747 Self::id_of_fill_brush_property().base(),
748 ServerValueChange {
749 equal: old_value.default_equals(&value),
750 old_resource: old_value.as_server_render_resource(),
751 new_resource: value.as_server_render_resource(),
752 assign: &mut || *self.fill_brush.borrow_mut() = value.clone(),
753 },
754 );
755 if changed {
756 ServerCompositionSpriteShapeHooks::on_fill_brush_changed(host);
757 }
758 }
759
760 pub fn id_of_geometry_property() -> &'static CompositionPropertyOf<Option<Rc<dyn IServerObject>>> {
762 static PROPERTY: OnceLock<CompositionPropertyOf<Option<Rc<dyn IServerObject>>>> = OnceLock::new();
763 PROPERTY.get_or_init(|| {
764 CompositionProperty::register::<ServerCompositionSpriteShapeProps, Option<Rc<dyn IServerObject>>>(
765 "Geometry",
766 "ServerCompositionSpriteShape",
767 |obj| props_of::<ServerCompositionSpriteShapeProps>(obj).geometry.borrow().clone(),
768 |obj, v| *props_of::<ServerCompositionSpriteShapeProps>(obj).geometry.borrow_mut() = v,
769 None,
770 None,
771 )
772 })
773 }
774
775 pub fn geometry(&self) -> Option<Rc<dyn IServerObject>> {
777 self.geometry.borrow().clone()
778 }
779
780 pub fn set_geometry(&self, host: &dyn ServerCompositionSpriteShapeHooks, value: Option<Rc<dyn IServerObject>>) {
781 let old_value = self.geometry.borrow().clone();
782 let mut changed = false;
783 if old_value.differs(&value) {
784 ServerCompositionSpriteShapeHooks::on_geometry_changing(host);
785 changed = true;
786 }
787 host.set_value(
788 Self::id_of_geometry_property().base(),
789 ServerValueChange {
790 equal: old_value.default_equals(&value),
791 old_resource: old_value.as_server_render_resource(),
792 new_resource: value.as_server_render_resource(),
793 assign: &mut || *self.geometry.borrow_mut() = value.clone(),
794 },
795 );
796 if changed {
797 ServerCompositionSpriteShapeHooks::on_geometry_changed(host);
798 }
799 }
800
801 pub fn id_of_is_stroke_non_scaling_property() -> &'static CompositionPropertyOf<bool> {
803 static PROPERTY: OnceLock<CompositionPropertyOf<bool>> = OnceLock::new();
804 PROPERTY.get_or_init(|| {
805 CompositionProperty::register::<ServerCompositionSpriteShapeProps, bool>(
806 "IsStrokeNonScaling",
807 "ServerCompositionSpriteShape",
808 |obj| props_of::<ServerCompositionSpriteShapeProps>(obj).is_stroke_non_scaling.get(),
809 |obj, v| props_of::<ServerCompositionSpriteShapeProps>(obj).is_stroke_non_scaling.set(v),
810 Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionSpriteShapeProps>(obj).is_stroke_non_scaling.get())),
811 None,
812 )
813 })
814 }
815
816 pub fn is_stroke_non_scaling(&self) -> bool {
818 self.is_stroke_non_scaling.get()
819 }
820
821 pub fn set_is_stroke_non_scaling(&self, host: &dyn ServerCompositionSpriteShapeHooks, value: bool) {
822 let old_value = self.is_stroke_non_scaling.get();
823 let mut changed = false;
824 if old_value.differs(&value) {
825 ServerCompositionSpriteShapeHooks::on_is_stroke_non_scaling_changing(host);
826 changed = true;
827 }
828 host.set_value(
829 Self::id_of_is_stroke_non_scaling_property().base(),
830 ServerValueChange {
831 equal: old_value.default_equals(&value),
832 old_resource: None,
833 new_resource: None,
834 assign: &mut || self.is_stroke_non_scaling.set(value),
835 },
836 );
837 if changed {
838 ServerCompositionSpriteShapeHooks::on_is_stroke_non_scaling_changed(host);
839 }
840 }
841
842 pub fn id_of_stroke_brush_property() -> &'static CompositionPropertyOf<Option<Rc<dyn IServerObject>>> {
844 static PROPERTY: OnceLock<CompositionPropertyOf<Option<Rc<dyn IServerObject>>>> = OnceLock::new();
845 PROPERTY.get_or_init(|| {
846 CompositionProperty::register::<ServerCompositionSpriteShapeProps, Option<Rc<dyn IServerObject>>>(
847 "StrokeBrush",
848 "ServerCompositionSpriteShape",
849 |obj| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_brush.borrow().clone(),
850 |obj, v| *props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_brush.borrow_mut() = v,
851 None,
852 None,
853 )
854 })
855 }
856
857 pub fn stroke_brush(&self) -> Option<Rc<dyn IServerObject>> {
859 self.stroke_brush.borrow().clone()
860 }
861
862 pub fn set_stroke_brush(&self, host: &dyn ServerCompositionSpriteShapeHooks, value: Option<Rc<dyn IServerObject>>) {
863 let old_value = self.stroke_brush.borrow().clone();
864 let mut changed = false;
865 if old_value.differs(&value) {
866 ServerCompositionSpriteShapeHooks::on_stroke_brush_changing(host);
867 changed = true;
868 }
869 host.set_value(
870 Self::id_of_stroke_brush_property().base(),
871 ServerValueChange {
872 equal: old_value.default_equals(&value),
873 old_resource: old_value.as_server_render_resource(),
874 new_resource: value.as_server_render_resource(),
875 assign: &mut || *self.stroke_brush.borrow_mut() = value.clone(),
876 },
877 );
878 if changed {
879 ServerCompositionSpriteShapeHooks::on_stroke_brush_changed(host);
880 }
881 }
882
883 pub fn id_of_stroke_dash_array_property() -> &'static CompositionPropertyOf<Option<Arc<Vec<f32>>>> {
885 static PROPERTY: OnceLock<CompositionPropertyOf<Option<Arc<Vec<f32>>>>> = OnceLock::new();
886 PROPERTY.get_or_init(|| {
887 CompositionProperty::register::<ServerCompositionSpriteShapeProps, Option<Arc<Vec<f32>>>>(
888 "StrokeDashArray",
889 "ServerCompositionSpriteShape",
890 |obj| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_dash_array.borrow().clone(),
891 |obj, v| *props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_dash_array.borrow_mut() = v,
892 None,
893 None,
894 )
895 })
896 }
897
898 pub fn stroke_dash_array(&self) -> Option<Arc<Vec<f32>>> {
900 self.stroke_dash_array.borrow().clone()
901 }
902
903 pub fn set_stroke_dash_array(&self, host: &dyn ServerCompositionSpriteShapeHooks, value: Option<Arc<Vec<f32>>>) {
904 let old_value = self.stroke_dash_array.borrow().clone();
905 let mut changed = false;
906 if old_value.differs(&value) {
907 ServerCompositionSpriteShapeHooks::on_stroke_dash_array_changing(host);
908 changed = true;
909 }
910 host.set_value(
911 Self::id_of_stroke_dash_array_property().base(),
912 ServerValueChange {
913 equal: old_value.default_equals(&value),
914 old_resource: None,
915 new_resource: None,
916 assign: &mut || *self.stroke_dash_array.borrow_mut() = value.clone(),
917 },
918 );
919 if changed {
920 ServerCompositionSpriteShapeHooks::on_stroke_dash_array_changed(host);
921 }
922 }
923
924 pub fn id_of_stroke_dash_cap_property() -> &'static CompositionPropertyOf<CompositionStrokeCap> {
926 static PROPERTY: OnceLock<CompositionPropertyOf<CompositionStrokeCap>> = OnceLock::new();
927 PROPERTY.get_or_init(|| {
928 CompositionProperty::register::<ServerCompositionSpriteShapeProps, CompositionStrokeCap>(
929 "StrokeDashCap",
930 "ServerCompositionSpriteShape",
931 |obj| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_dash_cap.get(),
932 |obj, v| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_dash_cap.set(v),
933 None,
934 None,
935 )
936 })
937 }
938
939 pub fn stroke_dash_cap(&self) -> CompositionStrokeCap {
941 self.stroke_dash_cap.get()
942 }
943
944 pub fn set_stroke_dash_cap(&self, host: &dyn ServerCompositionSpriteShapeHooks, value: CompositionStrokeCap) {
945 let old_value = self.stroke_dash_cap.get();
946 let mut changed = false;
947 if old_value.differs(&value) {
948 ServerCompositionSpriteShapeHooks::on_stroke_dash_cap_changing(host);
949 changed = true;
950 }
951 host.set_value(
952 Self::id_of_stroke_dash_cap_property().base(),
953 ServerValueChange {
954 equal: old_value.default_equals(&value),
955 old_resource: None,
956 new_resource: None,
957 assign: &mut || self.stroke_dash_cap.set(value),
958 },
959 );
960 if changed {
961 ServerCompositionSpriteShapeHooks::on_stroke_dash_cap_changed(host);
962 }
963 }
964
965 pub fn id_of_stroke_dash_offset_property() -> &'static CompositionPropertyOf<f32> {
967 static PROPERTY: OnceLock<CompositionPropertyOf<f32>> = OnceLock::new();
968 PROPERTY.get_or_init(|| {
969 CompositionProperty::register::<ServerCompositionSpriteShapeProps, f32>(
970 "StrokeDashOffset",
971 "ServerCompositionSpriteShape",
972 |obj| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_dash_offset.get(),
973 |obj, v| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_dash_offset.set(v),
974 Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_dash_offset.get())),
975 Some(|obj, v: ExpressionVariant| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_dash_offset.set(v.cast_or_default::<f32>())),
976 )
977 })
978 }
979
980 pub fn stroke_dash_offset(&self) -> f32 {
982 self.stroke_dash_offset.get()
983 }
984
985 pub fn set_stroke_dash_offset(&self, host: &dyn ServerCompositionSpriteShapeHooks, value: f32) {
986 self.stroke_dash_offset.set(value);
987 host.remove_animation_for_property(Self::id_of_stroke_dash_offset_property().base());
988 }
989
990 pub fn id_of_stroke_end_cap_property() -> &'static CompositionPropertyOf<CompositionStrokeCap> {
992 static PROPERTY: OnceLock<CompositionPropertyOf<CompositionStrokeCap>> = OnceLock::new();
993 PROPERTY.get_or_init(|| {
994 CompositionProperty::register::<ServerCompositionSpriteShapeProps, CompositionStrokeCap>(
995 "StrokeEndCap",
996 "ServerCompositionSpriteShape",
997 |obj| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_end_cap.get(),
998 |obj, v| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_end_cap.set(v),
999 None,
1000 None,
1001 )
1002 })
1003 }
1004
1005 pub fn stroke_end_cap(&self) -> CompositionStrokeCap {
1007 self.stroke_end_cap.get()
1008 }
1009
1010 pub fn set_stroke_end_cap(&self, host: &dyn ServerCompositionSpriteShapeHooks, value: CompositionStrokeCap) {
1011 let old_value = self.stroke_end_cap.get();
1012 let mut changed = false;
1013 if old_value.differs(&value) {
1014 ServerCompositionSpriteShapeHooks::on_stroke_end_cap_changing(host);
1015 changed = true;
1016 }
1017 host.set_value(
1018 Self::id_of_stroke_end_cap_property().base(),
1019 ServerValueChange {
1020 equal: old_value.default_equals(&value),
1021 old_resource: None,
1022 new_resource: None,
1023 assign: &mut || self.stroke_end_cap.set(value),
1024 },
1025 );
1026 if changed {
1027 ServerCompositionSpriteShapeHooks::on_stroke_end_cap_changed(host);
1028 }
1029 }
1030
1031 pub fn id_of_stroke_line_join_property() -> &'static CompositionPropertyOf<CompositionStrokeLineJoin> {
1033 static PROPERTY: OnceLock<CompositionPropertyOf<CompositionStrokeLineJoin>> = OnceLock::new();
1034 PROPERTY.get_or_init(|| {
1035 CompositionProperty::register::<ServerCompositionSpriteShapeProps, CompositionStrokeLineJoin>(
1036 "StrokeLineJoin",
1037 "ServerCompositionSpriteShape",
1038 |obj| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_line_join.get(),
1039 |obj, v| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_line_join.set(v),
1040 None,
1041 None,
1042 )
1043 })
1044 }
1045
1046 pub fn stroke_line_join(&self) -> CompositionStrokeLineJoin {
1048 self.stroke_line_join.get()
1049 }
1050
1051 pub fn set_stroke_line_join(&self, host: &dyn ServerCompositionSpriteShapeHooks, value: CompositionStrokeLineJoin) {
1052 let old_value = self.stroke_line_join.get();
1053 let mut changed = false;
1054 if old_value.differs(&value) {
1055 ServerCompositionSpriteShapeHooks::on_stroke_line_join_changing(host);
1056 changed = true;
1057 }
1058 host.set_value(
1059 Self::id_of_stroke_line_join_property().base(),
1060 ServerValueChange {
1061 equal: old_value.default_equals(&value),
1062 old_resource: None,
1063 new_resource: None,
1064 assign: &mut || self.stroke_line_join.set(value),
1065 },
1066 );
1067 if changed {
1068 ServerCompositionSpriteShapeHooks::on_stroke_line_join_changed(host);
1069 }
1070 }
1071
1072 pub fn id_of_stroke_miter_limit_property() -> &'static CompositionPropertyOf<f32> {
1074 static PROPERTY: OnceLock<CompositionPropertyOf<f32>> = OnceLock::new();
1075 PROPERTY.get_or_init(|| {
1076 CompositionProperty::register::<ServerCompositionSpriteShapeProps, f32>(
1077 "StrokeMiterLimit",
1078 "ServerCompositionSpriteShape",
1079 |obj| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_miter_limit.get(),
1080 |obj, v| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_miter_limit.set(v),
1081 Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_miter_limit.get())),
1082 Some(|obj, v: ExpressionVariant| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_miter_limit.set(v.cast_or_default::<f32>())),
1083 )
1084 })
1085 }
1086
1087 pub fn stroke_miter_limit(&self) -> f32 {
1089 self.stroke_miter_limit.get()
1090 }
1091
1092 pub fn set_stroke_miter_limit(&self, host: &dyn ServerCompositionSpriteShapeHooks, value: f32) {
1093 self.stroke_miter_limit.set(value);
1094 host.remove_animation_for_property(Self::id_of_stroke_miter_limit_property().base());
1095 }
1096
1097 pub fn id_of_stroke_start_cap_property() -> &'static CompositionPropertyOf<CompositionStrokeCap> {
1099 static PROPERTY: OnceLock<CompositionPropertyOf<CompositionStrokeCap>> = OnceLock::new();
1100 PROPERTY.get_or_init(|| {
1101 CompositionProperty::register::<ServerCompositionSpriteShapeProps, CompositionStrokeCap>(
1102 "StrokeStartCap",
1103 "ServerCompositionSpriteShape",
1104 |obj| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_start_cap.get(),
1105 |obj, v| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_start_cap.set(v),
1106 None,
1107 None,
1108 )
1109 })
1110 }
1111
1112 pub fn stroke_start_cap(&self) -> CompositionStrokeCap {
1114 self.stroke_start_cap.get()
1115 }
1116
1117 pub fn set_stroke_start_cap(&self, host: &dyn ServerCompositionSpriteShapeHooks, value: CompositionStrokeCap) {
1118 let old_value = self.stroke_start_cap.get();
1119 let mut changed = false;
1120 if old_value.differs(&value) {
1121 ServerCompositionSpriteShapeHooks::on_stroke_start_cap_changing(host);
1122 changed = true;
1123 }
1124 host.set_value(
1125 Self::id_of_stroke_start_cap_property().base(),
1126 ServerValueChange {
1127 equal: old_value.default_equals(&value),
1128 old_resource: None,
1129 new_resource: None,
1130 assign: &mut || self.stroke_start_cap.set(value),
1131 },
1132 );
1133 if changed {
1134 ServerCompositionSpriteShapeHooks::on_stroke_start_cap_changed(host);
1135 }
1136 }
1137
1138 pub fn id_of_stroke_thickness_property() -> &'static CompositionPropertyOf<f32> {
1140 static PROPERTY: OnceLock<CompositionPropertyOf<f32>> = OnceLock::new();
1141 PROPERTY.get_or_init(|| {
1142 CompositionProperty::register::<ServerCompositionSpriteShapeProps, f32>(
1143 "StrokeThickness",
1144 "ServerCompositionSpriteShape",
1145 |obj| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_thickness.get(),
1146 |obj, v| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_thickness.set(v),
1147 Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_thickness.get())),
1148 Some(|obj, v: ExpressionVariant| props_of::<ServerCompositionSpriteShapeProps>(obj).stroke_thickness.set(v.cast_or_default::<f32>())),
1149 )
1150 })
1151 }
1152
1153 pub fn stroke_thickness(&self) -> f32 {
1155 self.stroke_thickness.get()
1156 }
1157
1158 pub fn set_stroke_thickness(&self, host: &dyn ServerCompositionSpriteShapeHooks, value: f32) {
1159 self.stroke_thickness.set(value);
1160 host.remove_animation_for_property(Self::id_of_stroke_thickness_property().base());
1161 }
1162
1163 pub fn deserialize_changes_core(
1166 &self,
1167 host: &dyn ServerCompositionSpriteShapeHooks,
1168 reader: &mut BatchStreamReader<'_>,
1169 committed_at: Duration,
1170 ) {
1171 let compositor = host.server_compositor();
1172 self.base.deserialize_changes_core(host, reader, committed_at);
1173 ServerCompositionSpriteShapeHooks::deserialize_changes_extra(host, reader);
1174 let changed = reader.read::<CompositionSpriteShapeChangedFields>();
1175 if changed.contains(CompositionSpriteShapeChangedFields::FILL_BRUSH) {
1176 let value = read_server_object(reader, compositor.as_ref());
1177 self.set_fill_brush(host, value);
1178 }
1179 if changed.contains(CompositionSpriteShapeChangedFields::GEOMETRY) {
1180 let value = read_server_object(reader, compositor.as_ref());
1181 self.set_geometry(host, value);
1182 }
1183 if changed.contains(CompositionSpriteShapeChangedFields::IS_STROKE_NON_SCALING) {
1184 let value = reader.read::<bool>();
1185 self.set_is_stroke_non_scaling(host, value);
1186 }
1187 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_BRUSH) {
1188 let value = read_server_object(reader, compositor.as_ref());
1189 self.set_stroke_brush(host, value);
1190 }
1191 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_DASH_ARRAY) {
1192 let value = reader.read_value::<Arc<Vec<f32>>>();
1193 self.set_stroke_dash_array(host, value);
1194 }
1195 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_DASH_CAP) {
1196 let value = reader.read::<CompositionStrokeCap>();
1197 self.set_stroke_dash_cap(host, value);
1198 }
1199 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_DASH_OFFSET_ANIMATED) {
1200 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
1201 panic!("a batch starts an animation of `StrokeDashOffset` without an animation instance");
1202 };
1203 host.set_animated_value(
1204 Self::id_of_stroke_dash_offset_property().base(),
1205 ExpressionVariant::create(self.stroke_dash_offset.get()),
1206 committed_at,
1207 animation,
1208 );
1209 } else if changed.contains(CompositionSpriteShapeChangedFields::STROKE_DASH_OFFSET) {
1210 let value = reader.read::<f32>();
1211 self.set_stroke_dash_offset(host, value);
1212 }
1213 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_END_CAP) {
1214 let value = reader.read::<CompositionStrokeCap>();
1215 self.set_stroke_end_cap(host, value);
1216 }
1217 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_LINE_JOIN) {
1218 let value = reader.read::<CompositionStrokeLineJoin>();
1219 self.set_stroke_line_join(host, value);
1220 }
1221 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_MITER_LIMIT_ANIMATED) {
1222 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
1223 panic!("a batch starts an animation of `StrokeMiterLimit` without an animation instance");
1224 };
1225 host.set_animated_value(
1226 Self::id_of_stroke_miter_limit_property().base(),
1227 ExpressionVariant::create(self.stroke_miter_limit.get()),
1228 committed_at,
1229 animation,
1230 );
1231 } else if changed.contains(CompositionSpriteShapeChangedFields::STROKE_MITER_LIMIT) {
1232 let value = reader.read::<f32>();
1233 self.set_stroke_miter_limit(host, value);
1234 }
1235 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_START_CAP) {
1236 let value = reader.read::<CompositionStrokeCap>();
1237 self.set_stroke_start_cap(host, value);
1238 }
1239 if changed.contains(CompositionSpriteShapeChangedFields::STROKE_THICKNESS_ANIMATED) {
1240 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
1241 panic!("a batch starts an animation of `StrokeThickness` without an animation instance");
1242 };
1243 host.set_animated_value(
1244 Self::id_of_stroke_thickness_property().base(),
1245 ExpressionVariant::create(self.stroke_thickness.get()),
1246 committed_at,
1247 animation,
1248 );
1249 } else if changed.contains(CompositionSpriteShapeChangedFields::STROKE_THICKNESS) {
1250 let value = reader.read::<f32>();
1251 self.set_stroke_thickness(host, value);
1252 }
1253 ServerCompositionSpriteShapeHooks::on_fields_deserialized(host, changed);
1254 }
1255
1256 pub fn get_composition_property(name: &str) -> Option<&'static CompositionProperty> {
1259 if name == "IsStrokeNonScaling" {
1260 return Some(Self::id_of_is_stroke_non_scaling_property().base());
1261 }
1262 if name == "StrokeDashOffset" {
1263 return Some(Self::id_of_stroke_dash_offset_property().base());
1264 }
1265 if name == "StrokeMiterLimit" {
1266 return Some(Self::id_of_stroke_miter_limit_property().base());
1267 }
1268 if name == "StrokeThickness" {
1269 return Some(Self::id_of_stroke_thickness_property().base());
1270 }
1271 ServerCompositionShapeProps::get_composition_property(name)
1272 }
1273}