1use bitflags::bitflags;
8use crate::Vector3D;
9use crate::media::Color;
10use crate::rendering::composition::CompositionDropShadowSourcePolicy;
11use crate::rendering::composition::ICompositionObject;
12use crate::rendering::composition::ICompositionObjectHost;
13use crate::rendering::composition::animations::AnimationInstanceFactory;
14use crate::rendering::composition::animations::ICompositionAnimation;
15use crate::rendering::composition::expressions::ExpressionVariant;
16use crate::rendering::composition::server::AsServerRenderResource;
17use crate::rendering::composition::server::CompositionProperty;
18use crate::rendering::composition::server::CompositionPropertyOf;
19use crate::rendering::composition::server::IServerAnimatedPropertyHost;
20use crate::rendering::composition::server::IServerObject;
21use crate::rendering::composition::server::ServerPropertyValue;
22use crate::rendering::composition::server::ServerValueChange;
23use crate::rendering::composition::server::props_of;
24use crate::rendering::composition::server::read_server_object;
25use crate::rendering::composition::transport::BatchStreamReader;
26use crate::rendering::composition::transport::BatchStreamWriter;
27use crate::rendering::composition::transport::BatchValue;
28use crate::rendering::composition::transport::BatchValueReader;
29use std::any::Any;
30use std::any::TypeId;
31use std::cell::Cell;
32use std::cell::RefCell;
33use std::rc::Rc;
34use std::sync::OnceLock;
35use std::time::Duration;
36
37bitflags! {
38 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
40 pub struct DropShadowChangedFields: u16 {
41 const BLUR_RADIUS = 1;
42 const BLUR_RADIUS_ANIMATED = 2;
43 const COLOR = 4;
44 const COLOR_ANIMATED = 8;
45 const MASK = 16;
46 const OFFSET = 32;
47 const OFFSET_ANIMATED = 64;
48 const OPACITY = 128;
49 const OPACITY_ANIMATED = 256;
50 const SOURCE_POLICY = 512;
51 }
52}
53
54impl BatchValue for DropShadowChangedFields {
55 #[inline]
56 fn write_to(&self, out: &mut Vec<u8>) {
57 self.bits().write_to(out);
58 }
59
60 #[inline]
61 fn read_from(input: &mut BatchValueReader<'_>) -> Self {
62 DropShadowChangedFields::from_bits_retain(u16::read_from(input))
63 }
64}
65
66pub trait DropShadowHooks: ICompositionObjectHost {
69 fn initialize_defaults_extra(&self) {}
70
71 fn validate_blur_radius_change(&self, _old_value: f32, _new_value: f32) {}
72 fn on_blur_radius_changed(&self) {}
73 fn on_blur_radius_changing(&self) {}
74
75 fn validate_color_change(&self, _old_value: Color, _new_value: Color) {}
76 fn on_color_changed(&self) {}
77 fn on_color_changing(&self) {}
78
79 fn validate_mask_change(&self, _old_value: &Option<Rc<dyn ICompositionObject>>, _new_value: &Option<Rc<dyn ICompositionObject>>) {}
80 fn on_mask_changed(&self) {}
81 fn on_mask_changing(&self) {}
82
83 fn validate_offset_change(&self, _old_value: Vector3D, _new_value: Vector3D) {}
84 fn on_offset_changed(&self) {}
85 fn on_offset_changing(&self) {}
86
87 fn validate_opacity_change(&self, _old_value: f32, _new_value: f32) {}
88 fn on_opacity_changed(&self) {}
89 fn on_opacity_changing(&self) {}
90
91 fn validate_source_policy_change(&self, _old_value: CompositionDropShadowSourcePolicy, _new_value: CompositionDropShadowSourcePolicy) {}
92 fn on_source_policy_changed(&self) {}
93 fn on_source_policy_changing(&self) {}
94}
95
96pub struct DropShadowProps {
98 changed_fields_of_drop_shadow: Cell<DropShadowChangedFields>,
99 blur_radius: Cell<f32>,
100 color: Cell<Color>,
101 mask: RefCell<Option<Rc<dyn ICompositionObject>>>,
102 offset: Cell<Vector3D>,
103 opacity: Cell<f32>,
104 source_policy: Cell<CompositionDropShadowSourcePolicy>,
105}
106
107impl Default for DropShadowProps {
108 fn default() -> Self {
109 Self::new()
110 }
111}
112
113impl DropShadowProps {
114 pub fn new() -> Self {
118 Self {
119 changed_fields_of_drop_shadow: Cell::new(DropShadowChangedFields::empty()),
120 blur_radius: Cell::new(Default::default()),
121 color: Cell::new(Default::default()),
122 mask: RefCell::new(None),
123 offset: Cell::new(Default::default()),
124 opacity: Cell::new(Default::default()),
125 source_policy: Cell::new(Default::default()),
126 }
127 }
128
129 pub fn initialize_defaults(&self, host: &dyn DropShadowHooks) {
132 self.initialize_own_defaults(host);
133 }
134
135 pub fn initialize_own_defaults(&self, host: &dyn DropShadowHooks) {
137 DropShadowHooks::initialize_defaults_extra(host);
138 self.set_blur_radius(host, 9.0);
139 self.set_color(host, crate::media::Colors::BLACK);
140 self.set_opacity(host, 1.0);
141 }
142
143 pub fn blur_radius(&self) -> f32 {
145 self.blur_radius.get()
146 }
147
148 pub fn set_blur_radius(&self, host: &dyn DropShadowHooks, value: f32) {
150 let mut changed = false;
151 let old_value = self.blur_radius.get();
152 if old_value.differs(&value) {
153 DropShadowHooks::validate_blur_radius_change(host, old_value, value);
154 DropShadowHooks::on_blur_radius_changing(host);
155 changed = true;
156 self.blur_radius.set(value);
158 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() | DropShadowChangedFields::BLUR_RADIUS);
160 host.register_for_serialization();
161 host.pending_animations().remove(ServerDropShadowProps::id_of_blur_radius_property().base());
163 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() & !DropShadowChangedFields::BLUR_RADIUS_ANIMATED);
164 if let Some(animation) = host.implicit_animation("BlurRadius") {
166 if let Some(a) = animation.as_composition_animation() {
168 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() | DropShadowChangedFields::BLUR_RADIUS_ANIMATED);
169 host.pending_animations().set(
170 ServerDropShadowProps::id_of_blur_radius_property().base(),
171 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
172 );
173 }
174 host.start_animation_group(&animation, "BlurRadius", ExpressionVariant::create(value));
176 }
177 }
178 self.blur_radius.set(value);
179 if changed {
180 DropShadowHooks::on_blur_radius_changed(host);
181 }
182 }
183
184 pub fn color(&self) -> Color {
186 self.color.get()
187 }
188
189 pub fn set_color(&self, host: &dyn DropShadowHooks, value: Color) {
191 let mut changed = false;
192 let old_value = self.color.get();
193 if old_value.differs(&value) {
194 DropShadowHooks::validate_color_change(host, old_value, value);
195 DropShadowHooks::on_color_changing(host);
196 changed = true;
197 self.color.set(value);
199 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() | DropShadowChangedFields::COLOR);
201 host.register_for_serialization();
202 host.pending_animations().remove(ServerDropShadowProps::id_of_color_property().base());
204 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() & !DropShadowChangedFields::COLOR_ANIMATED);
205 if let Some(animation) = host.implicit_animation("Color") {
207 if let Some(a) = animation.as_composition_animation() {
209 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() | DropShadowChangedFields::COLOR_ANIMATED);
210 host.pending_animations().set(
211 ServerDropShadowProps::id_of_color_property().base(),
212 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
213 );
214 }
215 host.start_animation_group(&animation, "Color", ExpressionVariant::create(value));
217 }
218 }
219 self.color.set(value);
220 if changed {
221 DropShadowHooks::on_color_changed(host);
222 }
223 }
224
225 pub fn mask(&self) -> Option<Rc<dyn ICompositionObject>> {
227 self.mask.borrow().clone()
228 }
229
230 pub fn set_mask(&self, host: &dyn DropShadowHooks, value: Option<Rc<dyn ICompositionObject>>) {
232 let mut changed = false;
233 let old_value = self.mask.borrow().clone();
234 if old_value.differs(&value) {
235 DropShadowHooks::validate_mask_change(host, &old_value, &value);
236 DropShadowHooks::on_mask_changing(host);
237 changed = true;
238 *self.mask.borrow_mut() = value.clone();
240 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() | DropShadowChangedFields::MASK);
242 host.register_for_serialization();
243 }
244 *self.mask.borrow_mut() = value;
245 if changed {
246 DropShadowHooks::on_mask_changed(host);
247 }
248 }
249
250 pub fn offset(&self) -> Vector3D {
252 self.offset.get()
253 }
254
255 pub fn set_offset(&self, host: &dyn DropShadowHooks, value: Vector3D) {
257 let mut changed = false;
258 let old_value = self.offset.get();
259 if old_value.differs(&value) {
260 DropShadowHooks::validate_offset_change(host, old_value, value);
261 DropShadowHooks::on_offset_changing(host);
262 changed = true;
263 self.offset.set(value);
265 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() | DropShadowChangedFields::OFFSET);
267 host.register_for_serialization();
268 host.pending_animations().remove(ServerDropShadowProps::id_of_offset_property().base());
270 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() & !DropShadowChangedFields::OFFSET_ANIMATED);
271 if let Some(animation) = host.implicit_animation("Offset") {
273 if let Some(a) = animation.as_composition_animation() {
275 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() | DropShadowChangedFields::OFFSET_ANIMATED);
276 host.pending_animations().set(
277 ServerDropShadowProps::id_of_offset_property().base(),
278 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
279 );
280 }
281 host.start_animation_group(&animation, "Offset", ExpressionVariant::create(value));
283 }
284 }
285 self.offset.set(value);
286 if changed {
287 DropShadowHooks::on_offset_changed(host);
288 }
289 }
290
291 pub fn opacity(&self) -> f32 {
293 self.opacity.get()
294 }
295
296 pub fn set_opacity(&self, host: &dyn DropShadowHooks, value: f32) {
298 let mut changed = false;
299 let old_value = self.opacity.get();
300 if old_value.differs(&value) {
301 DropShadowHooks::validate_opacity_change(host, old_value, value);
302 DropShadowHooks::on_opacity_changing(host);
303 changed = true;
304 self.opacity.set(value);
306 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() | DropShadowChangedFields::OPACITY);
308 host.register_for_serialization();
309 host.pending_animations().remove(ServerDropShadowProps::id_of_opacity_property().base());
311 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() & !DropShadowChangedFields::OPACITY_ANIMATED);
312 if let Some(animation) = host.implicit_animation("Opacity") {
314 if let Some(a) = animation.as_composition_animation() {
316 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() | DropShadowChangedFields::OPACITY_ANIMATED);
317 host.pending_animations().set(
318 ServerDropShadowProps::id_of_opacity_property().base(),
319 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
320 );
321 }
322 host.start_animation_group(&animation, "Opacity", ExpressionVariant::create(value));
324 }
325 }
326 self.opacity.set(value);
327 if changed {
328 DropShadowHooks::on_opacity_changed(host);
329 }
330 }
331
332 pub fn source_policy(&self) -> CompositionDropShadowSourcePolicy {
334 self.source_policy.get()
335 }
336
337 pub fn set_source_policy(&self, host: &dyn DropShadowHooks, value: CompositionDropShadowSourcePolicy) {
339 let mut changed = false;
340 let old_value = self.source_policy.get();
341 if old_value.differs(&value) {
342 DropShadowHooks::validate_source_policy_change(host, old_value, value);
343 DropShadowHooks::on_source_policy_changing(host);
344 changed = true;
345 self.source_policy.set(value);
347 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() | DropShadowChangedFields::SOURCE_POLICY);
349 host.register_for_serialization();
350 }
351 self.source_policy.set(value);
352 if changed {
353 DropShadowHooks::on_source_policy_changed(host);
354 }
355 }
356
357 pub fn start_animation(
361 &self,
362 host: &dyn DropShadowHooks,
363 property_name: &str,
364 animation: &dyn ICompositionAnimation,
365 final_value: Option<ExpressionVariant>,
366 ) -> bool {
367 if property_name == "BlurRadius" {
368 let server = animation.create_instance(host.server(), final_value);
369 host.pending_animations().set(ServerDropShadowProps::id_of_blur_radius_property().base(), server);
370 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() | DropShadowChangedFields::BLUR_RADIUS_ANIMATED);
371 host.register_for_serialization();
372 return true;
373 }
374 if property_name == "Color" {
375 let server = animation.create_instance(host.server(), final_value);
376 host.pending_animations().set(ServerDropShadowProps::id_of_color_property().base(), server);
377 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() | DropShadowChangedFields::COLOR_ANIMATED);
378 host.register_for_serialization();
379 return true;
380 }
381 if property_name == "Offset" {
382 let server = animation.create_instance(host.server(), final_value);
383 host.pending_animations().set(ServerDropShadowProps::id_of_offset_property().base(), server);
384 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() | DropShadowChangedFields::OFFSET_ANIMATED);
385 host.register_for_serialization();
386 return true;
387 }
388 if property_name == "Opacity" {
389 let server = animation.create_instance(host.server(), final_value);
390 host.pending_animations().set(ServerDropShadowProps::id_of_opacity_property().base(), server);
391 self.changed_fields_of_drop_shadow.set(self.changed_fields_of_drop_shadow.get() | DropShadowChangedFields::OPACITY_ANIMATED);
392 host.register_for_serialization();
393 return true;
394 }
395 false
396 }
397
398 pub fn serialize_changes_core(&self, host: &dyn DropShadowHooks, writer: &mut BatchStreamWriter<'_>) {
401 let changed = self.changed_fields_of_drop_shadow.get();
402 writer.write(changed);
403 if changed.contains(DropShadowChangedFields::BLUR_RADIUS_ANIMATED) {
404 writer.write_value(host.pending_animations().get_and_remove(ServerDropShadowProps::id_of_blur_radius_property().base()));
405 } else if changed.contains(DropShadowChangedFields::BLUR_RADIUS) {
406 writer.write(self.blur_radius.get());
407 }
408 if changed.contains(DropShadowChangedFields::COLOR_ANIMATED) {
409 writer.write_value(host.pending_animations().get_and_remove(ServerDropShadowProps::id_of_color_property().base()));
410 } else if changed.contains(DropShadowChangedFields::COLOR) {
411 writer.write(self.color.get());
412 }
413 if changed.contains(DropShadowChangedFields::MASK) {
414 writer.write_server_object(self.mask.borrow().clone().map(|o| o.server()));
415 }
416 if changed.contains(DropShadowChangedFields::OFFSET_ANIMATED) {
417 writer.write_value(host.pending_animations().get_and_remove(ServerDropShadowProps::id_of_offset_property().base()));
418 } else if changed.contains(DropShadowChangedFields::OFFSET) {
419 writer.write(self.offset.get());
420 }
421 if changed.contains(DropShadowChangedFields::OPACITY_ANIMATED) {
422 writer.write_value(host.pending_animations().get_and_remove(ServerDropShadowProps::id_of_opacity_property().base()));
423 } else if changed.contains(DropShadowChangedFields::OPACITY) {
424 writer.write(self.opacity.get());
425 }
426 if changed.contains(DropShadowChangedFields::SOURCE_POLICY) {
427 writer.write(self.source_policy.get());
428 }
429 self.changed_fields_of_drop_shadow.set(DropShadowChangedFields::empty());
430 }
431}
432
433pub trait ServerDropShadowHooks: IServerAnimatedPropertyHost {
436 fn deserialize_changes_extra(&self, _reader: &mut BatchStreamReader<'_>) {}
437 fn on_fields_deserialized(&self, _changed: DropShadowChangedFields) {}
438
439 fn on_mask_changed(&self) {}
440 fn on_mask_changing(&self) {}
441
442 fn on_source_policy_changed(&self) {}
443 fn on_source_policy_changing(&self) {}
444}
445
446pub struct ServerDropShadowProps {
448 blur_radius: Cell<f32>,
449 color: Cell<Color>,
450 mask: RefCell<Option<Rc<dyn IServerObject>>>,
451 offset: Cell<Vector3D>,
452 opacity: Cell<f32>,
453 source_policy: Cell<CompositionDropShadowSourcePolicy>,
454}
455
456impl Default for ServerDropShadowProps {
457 fn default() -> Self {
458 Self::new()
459 }
460}
461
462impl ServerDropShadowProps {
463 pub fn new() -> Self {
466 Self {
467 blur_radius: Cell::new(Default::default()),
468 color: Cell::new(Default::default()),
469 mask: RefCell::new(None),
470 offset: Cell::new(Default::default()),
471 opacity: Cell::new(Default::default()),
472 source_policy: Cell::new(Default::default()),
473 }
474 }
475
476 pub fn find_props(&self, type_id: TypeId) -> Option<&dyn Any> {
479 if type_id == TypeId::of::<Self>() {
480 return Some(self);
481 }
482 None
483 }
484
485 pub fn id_of_blur_radius_property() -> &'static CompositionPropertyOf<f32> {
487 static PROPERTY: OnceLock<CompositionPropertyOf<f32>> = OnceLock::new();
488 PROPERTY.get_or_init(|| {
489 CompositionProperty::register::<ServerDropShadowProps, f32>(
490 "BlurRadius",
491 "ServerDropShadow",
492 |obj| props_of::<ServerDropShadowProps>(obj).blur_radius.get(),
493 |obj, v| props_of::<ServerDropShadowProps>(obj).blur_radius.set(v),
494 Some(|obj| ExpressionVariant::create(props_of::<ServerDropShadowProps>(obj).blur_radius.get())),
495 Some(|obj, v: ExpressionVariant| props_of::<ServerDropShadowProps>(obj).blur_radius.set(v.cast_or_default::<f32>())),
496 )
497 })
498 }
499
500 pub fn blur_radius(&self) -> f32 {
502 self.blur_radius.get()
503 }
504
505 pub fn set_blur_radius(&self, host: &dyn ServerDropShadowHooks, value: f32) {
506 self.blur_radius.set(value);
507 host.remove_animation_for_property(Self::id_of_blur_radius_property().base());
508 }
509
510 pub fn id_of_color_property() -> &'static CompositionPropertyOf<Color> {
512 static PROPERTY: OnceLock<CompositionPropertyOf<Color>> = OnceLock::new();
513 PROPERTY.get_or_init(|| {
514 CompositionProperty::register::<ServerDropShadowProps, Color>(
515 "Color",
516 "ServerDropShadow",
517 |obj| props_of::<ServerDropShadowProps>(obj).color.get(),
518 |obj, v| props_of::<ServerDropShadowProps>(obj).color.set(v),
519 Some(|obj| ExpressionVariant::create(props_of::<ServerDropShadowProps>(obj).color.get())),
520 Some(|obj, v: ExpressionVariant| props_of::<ServerDropShadowProps>(obj).color.set(v.cast_or_default::<Color>())),
521 )
522 })
523 }
524
525 pub fn color(&self) -> Color {
527 self.color.get()
528 }
529
530 pub fn set_color(&self, host: &dyn ServerDropShadowHooks, value: Color) {
531 self.color.set(value);
532 host.remove_animation_for_property(Self::id_of_color_property().base());
533 }
534
535 pub fn id_of_mask_property() -> &'static CompositionPropertyOf<Option<Rc<dyn IServerObject>>> {
537 static PROPERTY: OnceLock<CompositionPropertyOf<Option<Rc<dyn IServerObject>>>> = OnceLock::new();
538 PROPERTY.get_or_init(|| {
539 CompositionProperty::register::<ServerDropShadowProps, Option<Rc<dyn IServerObject>>>(
540 "Mask",
541 "ServerDropShadow",
542 |obj| props_of::<ServerDropShadowProps>(obj).mask.borrow().clone(),
543 |obj, v| *props_of::<ServerDropShadowProps>(obj).mask.borrow_mut() = v,
544 None,
545 None,
546 )
547 })
548 }
549
550 pub fn mask(&self) -> Option<Rc<dyn IServerObject>> {
552 self.mask.borrow().clone()
553 }
554
555 pub fn set_mask(&self, host: &dyn ServerDropShadowHooks, value: Option<Rc<dyn IServerObject>>) {
556 let old_value = self.mask.borrow().clone();
557 let mut changed = false;
558 if old_value.differs(&value) {
559 ServerDropShadowHooks::on_mask_changing(host);
560 changed = true;
561 }
562 host.set_value(
563 Self::id_of_mask_property().base(),
564 ServerValueChange {
565 equal: old_value.default_equals(&value),
566 old_resource: old_value.as_server_render_resource(),
567 new_resource: value.as_server_render_resource(),
568 assign: &mut || *self.mask.borrow_mut() = value.clone(),
569 },
570 );
571 if changed {
572 ServerDropShadowHooks::on_mask_changed(host);
573 }
574 }
575
576 pub fn id_of_offset_property() -> &'static CompositionPropertyOf<Vector3D> {
578 static PROPERTY: OnceLock<CompositionPropertyOf<Vector3D>> = OnceLock::new();
579 PROPERTY.get_or_init(|| {
580 CompositionProperty::register::<ServerDropShadowProps, Vector3D>(
581 "Offset",
582 "ServerDropShadow",
583 |obj| props_of::<ServerDropShadowProps>(obj).offset.get(),
584 |obj, v| props_of::<ServerDropShadowProps>(obj).offset.set(v),
585 Some(|obj| ExpressionVariant::create(props_of::<ServerDropShadowProps>(obj).offset.get())),
586 Some(|obj, v: ExpressionVariant| props_of::<ServerDropShadowProps>(obj).offset.set(v.cast_or_default::<Vector3D>())),
587 )
588 })
589 }
590
591 pub fn offset(&self) -> Vector3D {
593 self.offset.get()
594 }
595
596 pub fn set_offset(&self, host: &dyn ServerDropShadowHooks, value: Vector3D) {
597 self.offset.set(value);
598 host.remove_animation_for_property(Self::id_of_offset_property().base());
599 }
600
601 pub fn id_of_opacity_property() -> &'static CompositionPropertyOf<f32> {
603 static PROPERTY: OnceLock<CompositionPropertyOf<f32>> = OnceLock::new();
604 PROPERTY.get_or_init(|| {
605 CompositionProperty::register::<ServerDropShadowProps, f32>(
606 "Opacity",
607 "ServerDropShadow",
608 |obj| props_of::<ServerDropShadowProps>(obj).opacity.get(),
609 |obj, v| props_of::<ServerDropShadowProps>(obj).opacity.set(v),
610 Some(|obj| ExpressionVariant::create(props_of::<ServerDropShadowProps>(obj).opacity.get())),
611 Some(|obj, v: ExpressionVariant| props_of::<ServerDropShadowProps>(obj).opacity.set(v.cast_or_default::<f32>())),
612 )
613 })
614 }
615
616 pub fn opacity(&self) -> f32 {
618 self.opacity.get()
619 }
620
621 pub fn set_opacity(&self, host: &dyn ServerDropShadowHooks, value: f32) {
622 self.opacity.set(value);
623 host.remove_animation_for_property(Self::id_of_opacity_property().base());
624 }
625
626 pub fn id_of_source_policy_property() -> &'static CompositionPropertyOf<CompositionDropShadowSourcePolicy> {
628 static PROPERTY: OnceLock<CompositionPropertyOf<CompositionDropShadowSourcePolicy>> = OnceLock::new();
629 PROPERTY.get_or_init(|| {
630 CompositionProperty::register::<ServerDropShadowProps, CompositionDropShadowSourcePolicy>(
631 "SourcePolicy",
632 "ServerDropShadow",
633 |obj| props_of::<ServerDropShadowProps>(obj).source_policy.get(),
634 |obj, v| props_of::<ServerDropShadowProps>(obj).source_policy.set(v),
635 None,
636 None,
637 )
638 })
639 }
640
641 pub fn source_policy(&self) -> CompositionDropShadowSourcePolicy {
643 self.source_policy.get()
644 }
645
646 pub fn set_source_policy(&self, host: &dyn ServerDropShadowHooks, value: CompositionDropShadowSourcePolicy) {
647 let old_value = self.source_policy.get();
648 let mut changed = false;
649 if old_value.differs(&value) {
650 ServerDropShadowHooks::on_source_policy_changing(host);
651 changed = true;
652 }
653 host.set_value(
654 Self::id_of_source_policy_property().base(),
655 ServerValueChange {
656 equal: old_value.default_equals(&value),
657 old_resource: None,
658 new_resource: None,
659 assign: &mut || self.source_policy.set(value),
660 },
661 );
662 if changed {
663 ServerDropShadowHooks::on_source_policy_changed(host);
664 }
665 }
666
667 pub fn deserialize_changes_core(
670 &self,
671 host: &dyn ServerDropShadowHooks,
672 reader: &mut BatchStreamReader<'_>,
673 committed_at: Duration,
674 ) {
675 let compositor = host.server_compositor();
676 ServerDropShadowHooks::deserialize_changes_extra(host, reader);
677 let changed = reader.read::<DropShadowChangedFields>();
678 if changed.contains(DropShadowChangedFields::BLUR_RADIUS_ANIMATED) {
679 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
680 panic!("a batch starts an animation of `BlurRadius` without an animation instance");
681 };
682 host.set_animated_value(
683 Self::id_of_blur_radius_property().base(),
684 ExpressionVariant::create(self.blur_radius.get()),
685 committed_at,
686 animation,
687 );
688 } else if changed.contains(DropShadowChangedFields::BLUR_RADIUS) {
689 let value = reader.read::<f32>();
690 self.set_blur_radius(host, value);
691 }
692 if changed.contains(DropShadowChangedFields::COLOR_ANIMATED) {
693 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
694 panic!("a batch starts an animation of `Color` without an animation instance");
695 };
696 host.set_animated_value(
697 Self::id_of_color_property().base(),
698 ExpressionVariant::create(self.color.get()),
699 committed_at,
700 animation,
701 );
702 } else if changed.contains(DropShadowChangedFields::COLOR) {
703 let value = reader.read::<Color>();
704 self.set_color(host, value);
705 }
706 if changed.contains(DropShadowChangedFields::MASK) {
707 let value = read_server_object(reader, compositor.as_ref());
708 self.set_mask(host, value);
709 }
710 if changed.contains(DropShadowChangedFields::OFFSET_ANIMATED) {
711 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
712 panic!("a batch starts an animation of `Offset` without an animation instance");
713 };
714 host.set_animated_value(
715 Self::id_of_offset_property().base(),
716 ExpressionVariant::create(self.offset.get()),
717 committed_at,
718 animation,
719 );
720 } else if changed.contains(DropShadowChangedFields::OFFSET) {
721 let value = reader.read::<Vector3D>();
722 self.set_offset(host, value);
723 }
724 if changed.contains(DropShadowChangedFields::OPACITY_ANIMATED) {
725 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
726 panic!("a batch starts an animation of `Opacity` without an animation instance");
727 };
728 host.set_animated_value(
729 Self::id_of_opacity_property().base(),
730 ExpressionVariant::create(self.opacity.get()),
731 committed_at,
732 animation,
733 );
734 } else if changed.contains(DropShadowChangedFields::OPACITY) {
735 let value = reader.read::<f32>();
736 self.set_opacity(host, value);
737 }
738 if changed.contains(DropShadowChangedFields::SOURCE_POLICY) {
739 let value = reader.read::<CompositionDropShadowSourcePolicy>();
740 self.set_source_policy(host, value);
741 }
742 ServerDropShadowHooks::on_fields_deserialized(host, changed);
743 }
744
745 pub fn get_composition_property(name: &str) -> Option<&'static CompositionProperty> {
748 if name == "BlurRadius" {
749 return Some(Self::id_of_blur_radius_property().base());
750 }
751 if name == "Color" {
752 return Some(Self::id_of_color_property().base());
753 }
754 if name == "Offset" {
755 return Some(Self::id_of_offset_property().base());
756 }
757 if name == "Opacity" {
758 return Some(Self::id_of_opacity_property().base());
759 }
760 None
761 }
762}