ferroui_base/rendering/composition/generated/
composition_bitmap_cache.rs1use bitflags::bitflags;
8use crate::rendering::composition::animations::AnimationInstanceFactory;
9use crate::rendering::composition::animations::ICompositionAnimation;
10use crate::rendering::composition::expressions::ExpressionVariant;
11use crate::rendering::composition::server::CompositionProperty;
12use crate::rendering::composition::server::CompositionPropertyOf;
13use crate::rendering::composition::server::ServerPropertyValue;
14use crate::rendering::composition::server::props_of;
15use crate::rendering::composition::transport::BatchStreamReader;
16use crate::rendering::composition::transport::BatchStreamWriter;
17use crate::rendering::composition::transport::BatchValue;
18use crate::rendering::composition::transport::BatchValueReader;
19use std::any::Any;
20use std::any::TypeId;
21use std::cell::Cell;
22use std::sync::OnceLock;
23use std::time::Duration;
24use super::CompositionCacheModeHooks;
25use super::CompositionCacheModeProps;
26use super::ServerCompositionCacheModeHooks;
27use super::ServerCompositionCacheModeProps;
28
29bitflags! {
30 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
32 pub struct CompositionBitmapCacheChangedFields: u8 {
33 const RENDER_AT_SCALE = 1;
34 const RENDER_AT_SCALE_ANIMATED = 2;
35 const SNAPS_TO_DEVICE_PIXELS = 4;
36 const SNAPS_TO_DEVICE_PIXELS_ANIMATED = 8;
37 const ENABLE_CLEAR_TYPE = 16;
38 const ENABLE_CLEAR_TYPE_ANIMATED = 32;
39 }
40}
41
42impl BatchValue for CompositionBitmapCacheChangedFields {
43 #[inline]
44 fn write_to(&self, out: &mut Vec<u8>) {
45 self.bits().write_to(out);
46 }
47
48 #[inline]
49 fn read_from(input: &mut BatchValueReader<'_>) -> Self {
50 CompositionBitmapCacheChangedFields::from_bits_retain(u8::read_from(input))
51 }
52}
53
54pub trait CompositionBitmapCacheHooks: CompositionCacheModeHooks {
57 fn initialize_defaults_extra(&self) {}
58
59 fn validate_render_at_scale_change(&self, _old_value: f64, _new_value: f64) {}
60 fn on_render_at_scale_changed(&self) {}
61 fn on_render_at_scale_changing(&self) {}
62
63 fn validate_snaps_to_device_pixels_change(&self, _old_value: bool, _new_value: bool) {}
64 fn on_snaps_to_device_pixels_changed(&self) {}
65 fn on_snaps_to_device_pixels_changing(&self) {}
66
67 fn validate_enable_clear_type_change(&self, _old_value: bool, _new_value: bool) {}
68 fn on_enable_clear_type_changed(&self) {}
69 fn on_enable_clear_type_changing(&self) {}
70}
71
72pub struct CompositionBitmapCacheProps {
74 base: CompositionCacheModeProps,
75 changed_fields_of_composition_bitmap_cache: Cell<CompositionBitmapCacheChangedFields>,
76 render_at_scale: Cell<f64>,
77 snaps_to_device_pixels: Cell<bool>,
78 enable_clear_type: Cell<bool>,
79}
80
81impl Default for CompositionBitmapCacheProps {
82 fn default() -> Self {
83 Self::new()
84 }
85}
86
87impl CompositionBitmapCacheProps {
88 pub fn new() -> Self {
92 Self {
93 base: CompositionCacheModeProps::new(),
94 changed_fields_of_composition_bitmap_cache: Cell::new(CompositionBitmapCacheChangedFields::empty()),
95 render_at_scale: Cell::new(Default::default()),
96 snaps_to_device_pixels: Cell::new(Default::default()),
97 enable_clear_type: Cell::new(Default::default()),
98 }
99 }
100
101 pub fn base(&self) -> &CompositionCacheModeProps {
103 &self.base
104 }
105
106 pub fn initialize_defaults(&self, host: &dyn CompositionBitmapCacheHooks) {
109 self.base.initialize_defaults(host);
110 self.initialize_own_defaults(host);
111 }
112
113 pub fn initialize_own_defaults(&self, host: &dyn CompositionBitmapCacheHooks) {
115 CompositionBitmapCacheHooks::initialize_defaults_extra(host);
116 self.set_render_at_scale(host, 1.0);
117 self.set_snaps_to_device_pixels(host, false);
118 self.set_enable_clear_type(host, false);
119 }
120
121 pub fn render_at_scale(&self) -> f64 {
123 self.render_at_scale.get()
124 }
125
126 pub fn set_render_at_scale(&self, host: &dyn CompositionBitmapCacheHooks, value: f64) {
128 let mut changed = false;
129 let old_value = self.render_at_scale.get();
130 if old_value.differs(&value) {
131 CompositionBitmapCacheHooks::validate_render_at_scale_change(host, old_value, value);
132 CompositionBitmapCacheHooks::on_render_at_scale_changing(host);
133 changed = true;
134 self.render_at_scale.set(value);
136 self.changed_fields_of_composition_bitmap_cache.set(self.changed_fields_of_composition_bitmap_cache.get() | CompositionBitmapCacheChangedFields::RENDER_AT_SCALE);
138 host.register_for_serialization();
139 host.pending_animations().remove(ServerCompositionBitmapCacheProps::id_of_render_at_scale_property().base());
141 self.changed_fields_of_composition_bitmap_cache.set(self.changed_fields_of_composition_bitmap_cache.get() & !CompositionBitmapCacheChangedFields::RENDER_AT_SCALE_ANIMATED);
142 if let Some(animation) = host.implicit_animation("RenderAtScale") {
144 if let Some(a) = animation.as_composition_animation() {
146 self.changed_fields_of_composition_bitmap_cache.set(self.changed_fields_of_composition_bitmap_cache.get() | CompositionBitmapCacheChangedFields::RENDER_AT_SCALE_ANIMATED);
147 host.pending_animations().set(
148 ServerCompositionBitmapCacheProps::id_of_render_at_scale_property().base(),
149 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
150 );
151 }
152 host.start_animation_group(&animation, "RenderAtScale", ExpressionVariant::create(value));
154 }
155 }
156 self.render_at_scale.set(value);
157 if changed {
158 CompositionBitmapCacheHooks::on_render_at_scale_changed(host);
159 }
160 }
161
162 pub fn snaps_to_device_pixels(&self) -> bool {
164 self.snaps_to_device_pixels.get()
165 }
166
167 pub fn set_snaps_to_device_pixels(&self, host: &dyn CompositionBitmapCacheHooks, value: bool) {
169 let mut changed = false;
170 let old_value = self.snaps_to_device_pixels.get();
171 if old_value.differs(&value) {
172 CompositionBitmapCacheHooks::validate_snaps_to_device_pixels_change(host, old_value, value);
173 CompositionBitmapCacheHooks::on_snaps_to_device_pixels_changing(host);
174 changed = true;
175 self.snaps_to_device_pixels.set(value);
177 self.changed_fields_of_composition_bitmap_cache.set(self.changed_fields_of_composition_bitmap_cache.get() | CompositionBitmapCacheChangedFields::SNAPS_TO_DEVICE_PIXELS);
179 host.register_for_serialization();
180 host.pending_animations().remove(ServerCompositionBitmapCacheProps::id_of_snaps_to_device_pixels_property().base());
182 self.changed_fields_of_composition_bitmap_cache.set(self.changed_fields_of_composition_bitmap_cache.get() & !CompositionBitmapCacheChangedFields::SNAPS_TO_DEVICE_PIXELS_ANIMATED);
183 if let Some(animation) = host.implicit_animation("SnapsToDevicePixels") {
185 if let Some(a) = animation.as_composition_animation() {
187 self.changed_fields_of_composition_bitmap_cache.set(self.changed_fields_of_composition_bitmap_cache.get() | CompositionBitmapCacheChangedFields::SNAPS_TO_DEVICE_PIXELS_ANIMATED);
188 host.pending_animations().set(
189 ServerCompositionBitmapCacheProps::id_of_snaps_to_device_pixels_property().base(),
190 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
191 );
192 }
193 host.start_animation_group(&animation, "SnapsToDevicePixels", ExpressionVariant::create(value));
195 }
196 }
197 self.snaps_to_device_pixels.set(value);
198 if changed {
199 CompositionBitmapCacheHooks::on_snaps_to_device_pixels_changed(host);
200 }
201 }
202
203 pub fn enable_clear_type(&self) -> bool {
205 self.enable_clear_type.get()
206 }
207
208 pub fn set_enable_clear_type(&self, host: &dyn CompositionBitmapCacheHooks, value: bool) {
210 let mut changed = false;
211 let old_value = self.enable_clear_type.get();
212 if old_value.differs(&value) {
213 CompositionBitmapCacheHooks::validate_enable_clear_type_change(host, old_value, value);
214 CompositionBitmapCacheHooks::on_enable_clear_type_changing(host);
215 changed = true;
216 self.enable_clear_type.set(value);
218 self.changed_fields_of_composition_bitmap_cache.set(self.changed_fields_of_composition_bitmap_cache.get() | CompositionBitmapCacheChangedFields::ENABLE_CLEAR_TYPE);
220 host.register_for_serialization();
221 host.pending_animations().remove(ServerCompositionBitmapCacheProps::id_of_enable_clear_type_property().base());
223 self.changed_fields_of_composition_bitmap_cache.set(self.changed_fields_of_composition_bitmap_cache.get() & !CompositionBitmapCacheChangedFields::ENABLE_CLEAR_TYPE_ANIMATED);
224 if let Some(animation) = host.implicit_animation("EnableClearType") {
226 if let Some(a) = animation.as_composition_animation() {
228 self.changed_fields_of_composition_bitmap_cache.set(self.changed_fields_of_composition_bitmap_cache.get() | CompositionBitmapCacheChangedFields::ENABLE_CLEAR_TYPE_ANIMATED);
229 host.pending_animations().set(
230 ServerCompositionBitmapCacheProps::id_of_enable_clear_type_property().base(),
231 a.create_instance(host.server(), Some(ExpressionVariant::create(value))),
232 );
233 }
234 host.start_animation_group(&animation, "EnableClearType", ExpressionVariant::create(value));
236 }
237 }
238 self.enable_clear_type.set(value);
239 if changed {
240 CompositionBitmapCacheHooks::on_enable_clear_type_changed(host);
241 }
242 }
243
244 pub fn start_animation(
248 &self,
249 host: &dyn CompositionBitmapCacheHooks,
250 property_name: &str,
251 animation: &dyn ICompositionAnimation,
252 final_value: Option<ExpressionVariant>,
253 ) -> bool {
254 if property_name == "RenderAtScale" {
255 let server = animation.create_instance(host.server(), final_value);
256 host.pending_animations().set(ServerCompositionBitmapCacheProps::id_of_render_at_scale_property().base(), server);
257 self.changed_fields_of_composition_bitmap_cache.set(self.changed_fields_of_composition_bitmap_cache.get() | CompositionBitmapCacheChangedFields::RENDER_AT_SCALE_ANIMATED);
258 host.register_for_serialization();
259 return true;
260 }
261 if property_name == "SnapsToDevicePixels" {
262 let server = animation.create_instance(host.server(), final_value);
263 host.pending_animations().set(ServerCompositionBitmapCacheProps::id_of_snaps_to_device_pixels_property().base(), server);
264 self.changed_fields_of_composition_bitmap_cache.set(self.changed_fields_of_composition_bitmap_cache.get() | CompositionBitmapCacheChangedFields::SNAPS_TO_DEVICE_PIXELS_ANIMATED);
265 host.register_for_serialization();
266 return true;
267 }
268 if property_name == "EnableClearType" {
269 let server = animation.create_instance(host.server(), final_value);
270 host.pending_animations().set(ServerCompositionBitmapCacheProps::id_of_enable_clear_type_property().base(), server);
271 self.changed_fields_of_composition_bitmap_cache.set(self.changed_fields_of_composition_bitmap_cache.get() | CompositionBitmapCacheChangedFields::ENABLE_CLEAR_TYPE_ANIMATED);
272 host.register_for_serialization();
273 return true;
274 }
275 false
276 }
277
278 pub fn serialize_changes_core(&self, host: &dyn CompositionBitmapCacheHooks, writer: &mut BatchStreamWriter<'_>) {
281 self.base.serialize_changes_core(host, writer);
282 let changed = self.changed_fields_of_composition_bitmap_cache.get();
283 writer.write(changed);
284 if changed.contains(CompositionBitmapCacheChangedFields::RENDER_AT_SCALE_ANIMATED) {
285 writer.write_value(host.pending_animations().get_and_remove(ServerCompositionBitmapCacheProps::id_of_render_at_scale_property().base()));
286 } else if changed.contains(CompositionBitmapCacheChangedFields::RENDER_AT_SCALE) {
287 writer.write(self.render_at_scale.get());
288 }
289 if changed.contains(CompositionBitmapCacheChangedFields::SNAPS_TO_DEVICE_PIXELS_ANIMATED) {
290 writer.write_value(host.pending_animations().get_and_remove(ServerCompositionBitmapCacheProps::id_of_snaps_to_device_pixels_property().base()));
291 } else if changed.contains(CompositionBitmapCacheChangedFields::SNAPS_TO_DEVICE_PIXELS) {
292 writer.write(self.snaps_to_device_pixels.get());
293 }
294 if changed.contains(CompositionBitmapCacheChangedFields::ENABLE_CLEAR_TYPE_ANIMATED) {
295 writer.write_value(host.pending_animations().get_and_remove(ServerCompositionBitmapCacheProps::id_of_enable_clear_type_property().base()));
296 } else if changed.contains(CompositionBitmapCacheChangedFields::ENABLE_CLEAR_TYPE) {
297 writer.write(self.enable_clear_type.get());
298 }
299 self.changed_fields_of_composition_bitmap_cache.set(CompositionBitmapCacheChangedFields::empty());
300 }
301}
302
303pub trait ServerCompositionBitmapCacheHooks: ServerCompositionCacheModeHooks {
306 fn deserialize_changes_extra(&self, _reader: &mut BatchStreamReader<'_>) {}
307 fn on_fields_deserialized(&self, _changed: CompositionBitmapCacheChangedFields) {}
308}
309
310pub struct ServerCompositionBitmapCacheProps {
312 base: ServerCompositionCacheModeProps,
313 render_at_scale: Cell<f64>,
314 snaps_to_device_pixels: Cell<bool>,
315 enable_clear_type: Cell<bool>,
316}
317
318impl Default for ServerCompositionBitmapCacheProps {
319 fn default() -> Self {
320 Self::new()
321 }
322}
323
324impl ServerCompositionBitmapCacheProps {
325 pub fn new() -> Self {
328 Self {
329 base: ServerCompositionCacheModeProps::new(),
330 render_at_scale: Cell::new(Default::default()),
331 snaps_to_device_pixels: Cell::new(Default::default()),
332 enable_clear_type: Cell::new(Default::default()),
333 }
334 }
335
336 pub fn base(&self) -> &ServerCompositionCacheModeProps {
338 &self.base
339 }
340
341 pub fn find_props(&self, type_id: TypeId) -> Option<&dyn Any> {
344 if type_id == TypeId::of::<Self>() {
345 return Some(self);
346 }
347 self.base.find_props(type_id)
348 }
349
350 pub fn id_of_render_at_scale_property() -> &'static CompositionPropertyOf<f64> {
352 static PROPERTY: OnceLock<CompositionPropertyOf<f64>> = OnceLock::new();
353 PROPERTY.get_or_init(|| {
354 CompositionProperty::register::<ServerCompositionBitmapCacheProps, f64>(
355 "RenderAtScale",
356 "ServerCompositionBitmapCache",
357 |obj| props_of::<ServerCompositionBitmapCacheProps>(obj).render_at_scale.get(),
358 |obj, v| props_of::<ServerCompositionBitmapCacheProps>(obj).render_at_scale.set(v),
359 Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionBitmapCacheProps>(obj).render_at_scale.get())),
360 Some(|obj, v: ExpressionVariant| props_of::<ServerCompositionBitmapCacheProps>(obj).render_at_scale.set(v.cast_or_default::<f64>())),
361 )
362 })
363 }
364
365 pub fn render_at_scale(&self) -> f64 {
367 self.render_at_scale.get()
368 }
369
370 pub fn set_render_at_scale(&self, host: &dyn ServerCompositionBitmapCacheHooks, value: f64) {
371 self.render_at_scale.set(value);
372 host.remove_animation_for_property(Self::id_of_render_at_scale_property().base());
373 }
374
375 pub fn id_of_snaps_to_device_pixels_property() -> &'static CompositionPropertyOf<bool> {
377 static PROPERTY: OnceLock<CompositionPropertyOf<bool>> = OnceLock::new();
378 PROPERTY.get_or_init(|| {
379 CompositionProperty::register::<ServerCompositionBitmapCacheProps, bool>(
380 "SnapsToDevicePixels",
381 "ServerCompositionBitmapCache",
382 |obj| props_of::<ServerCompositionBitmapCacheProps>(obj).snaps_to_device_pixels.get(),
383 |obj, v| props_of::<ServerCompositionBitmapCacheProps>(obj).snaps_to_device_pixels.set(v),
384 Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionBitmapCacheProps>(obj).snaps_to_device_pixels.get())),
385 Some(|obj, v: ExpressionVariant| props_of::<ServerCompositionBitmapCacheProps>(obj).snaps_to_device_pixels.set(v.cast_or_default::<bool>())),
386 )
387 })
388 }
389
390 pub fn snaps_to_device_pixels(&self) -> bool {
392 self.snaps_to_device_pixels.get()
393 }
394
395 pub fn set_snaps_to_device_pixels(&self, host: &dyn ServerCompositionBitmapCacheHooks, value: bool) {
396 self.snaps_to_device_pixels.set(value);
397 host.remove_animation_for_property(Self::id_of_snaps_to_device_pixels_property().base());
398 }
399
400 pub fn id_of_enable_clear_type_property() -> &'static CompositionPropertyOf<bool> {
402 static PROPERTY: OnceLock<CompositionPropertyOf<bool>> = OnceLock::new();
403 PROPERTY.get_or_init(|| {
404 CompositionProperty::register::<ServerCompositionBitmapCacheProps, bool>(
405 "EnableClearType",
406 "ServerCompositionBitmapCache",
407 |obj| props_of::<ServerCompositionBitmapCacheProps>(obj).enable_clear_type.get(),
408 |obj, v| props_of::<ServerCompositionBitmapCacheProps>(obj).enable_clear_type.set(v),
409 Some(|obj| ExpressionVariant::create(props_of::<ServerCompositionBitmapCacheProps>(obj).enable_clear_type.get())),
410 Some(|obj, v: ExpressionVariant| props_of::<ServerCompositionBitmapCacheProps>(obj).enable_clear_type.set(v.cast_or_default::<bool>())),
411 )
412 })
413 }
414
415 pub fn enable_clear_type(&self) -> bool {
417 self.enable_clear_type.get()
418 }
419
420 pub fn set_enable_clear_type(&self, host: &dyn ServerCompositionBitmapCacheHooks, value: bool) {
421 self.enable_clear_type.set(value);
422 host.remove_animation_for_property(Self::id_of_enable_clear_type_property().base());
423 }
424
425 pub fn deserialize_changes_core(
428 &self,
429 host: &dyn ServerCompositionBitmapCacheHooks,
430 reader: &mut BatchStreamReader<'_>,
431 committed_at: Duration,
432 ) {
433 self.base.deserialize_changes_core(host, reader, committed_at);
434 ServerCompositionBitmapCacheHooks::deserialize_changes_extra(host, reader);
435 let changed = reader.read::<CompositionBitmapCacheChangedFields>();
436 if changed.contains(CompositionBitmapCacheChangedFields::RENDER_AT_SCALE_ANIMATED) {
437 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
438 panic!("a batch starts an animation of `RenderAtScale` without an animation instance");
439 };
440 host.set_animated_value(
441 Self::id_of_render_at_scale_property().base(),
442 ExpressionVariant::create(self.render_at_scale.get()),
443 committed_at,
444 animation,
445 );
446 } else if changed.contains(CompositionBitmapCacheChangedFields::RENDER_AT_SCALE) {
447 let value = reader.read::<f64>();
448 self.set_render_at_scale(host, value);
449 }
450 if changed.contains(CompositionBitmapCacheChangedFields::SNAPS_TO_DEVICE_PIXELS_ANIMATED) {
451 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
452 panic!("a batch starts an animation of `SnapsToDevicePixels` without an animation instance");
453 };
454 host.set_animated_value(
455 Self::id_of_snaps_to_device_pixels_property().base(),
456 ExpressionVariant::create(self.snaps_to_device_pixels.get()),
457 committed_at,
458 animation,
459 );
460 } else if changed.contains(CompositionBitmapCacheChangedFields::SNAPS_TO_DEVICE_PIXELS) {
461 let value = reader.read::<bool>();
462 self.set_snaps_to_device_pixels(host, value);
463 }
464 if changed.contains(CompositionBitmapCacheChangedFields::ENABLE_CLEAR_TYPE_ANIMATED) {
465 let Some(animation) = reader.read_value::<AnimationInstanceFactory>().map(AnimationInstanceFactory::create) else {
466 panic!("a batch starts an animation of `EnableClearType` without an animation instance");
467 };
468 host.set_animated_value(
469 Self::id_of_enable_clear_type_property().base(),
470 ExpressionVariant::create(self.enable_clear_type.get()),
471 committed_at,
472 animation,
473 );
474 } else if changed.contains(CompositionBitmapCacheChangedFields::ENABLE_CLEAR_TYPE) {
475 let value = reader.read::<bool>();
476 self.set_enable_clear_type(host, value);
477 }
478 ServerCompositionBitmapCacheHooks::on_fields_deserialized(host, changed);
479 }
480
481 pub fn get_composition_property(name: &str) -> Option<&'static CompositionProperty> {
484 if name == "RenderAtScale" {
485 return Some(Self::id_of_render_at_scale_property().base());
486 }
487 if name == "SnapsToDevicePixels" {
488 return Some(Self::id_of_snaps_to_device_pixels_property().base());
489 }
490 if name == "EnableClearType" {
491 return Some(Self::id_of_enable_clear_type_property().base());
492 }
493 None
494 }
495}