1use super::{
14 ServerCompositionConicGradientBrush, ServerCompositionLinearGradientBrush, ServerCompositionRadialGradientBrush,
15 ServerCompositionSolidColorBrush, ServerCompositionSurfaceBrush,
16};
17use crate::collections::FerroList;
18use crate::media::immutable::ImmutableGradientStop;
19use crate::media::{
20 Color, GradientSpreadMethod, IBrush, IConicGradientBrush, IGradientBrush, IGradientStop, ILinearGradientBrush,
21 IRadialGradientBrush, ISolidColorBrush, ITransform,
22};
23use crate::rendering::composition::animations::{
24 ICompositionAnimation, ICompositionAnimationBase, ImplicitAnimationCollection,
25};
26use crate::rendering::composition::drawing::transform_get_server;
27use crate::rendering::composition::expressions::ExpressionVariant;
28use crate::rendering::composition::generated::{
29 CompositionBrushHooks, CompositionBrushProps, CompositionConicGradientBrushHooks,
30 CompositionConicGradientBrushProps, CompositionLinearGradientBrushHooks, CompositionLinearGradientBrushProps,
31 CompositionRadialGradientBrushHooks, CompositionRadialGradientBrushProps, CompositionSolidColorBrushHooks,
32 CompositionSolidColorBrushProps, CompositionSurfaceBrushHooks, CompositionSurfaceBrushProps,
33 ServerCompositionBrushProps, ServerCompositionConicGradientBrushProps, ServerCompositionLinearGradientBrushProps,
34 ServerCompositionRadialGradientBrushProps, ServerCompositionSolidColorBrushProps,
35 ServerCompositionSurfaceBrushProps,
36};
37use crate::rendering::composition::generated::{
38 CompositionMaskBrushHooks, CompositionMaskBrushProps, CompositionNineGridBrushHooks,
39 CompositionNineGridBrushProps, ServerCompositionMaskBrushProps, ServerCompositionNineGridBrushProps,
40};
41use crate::rendering::composition::animations::{parse_subchannel, CompositionColorSpace};
42use super::composition_effect_brush::CompositionEffectBrushData;
43use crate::rendering::composition::CompositionMappingMode;
44use crate::rendering::composition::server::{CompositionProperty, IServerObject, ServerCompositor, ServerObjectId};
45use crate::rendering::composition::transport::{BatchResource, BatchStreamWriter, IRegisterForSerialization};
46use crate::rendering::composition::{
47 AsCompositionObject, CompositionBitmapInterpolationMode, CompositionObject, CompositionStretch, Compositor,
48 ICompositionObject, ICompositionObjectAnimations, ICompositionObjectHost, ICompositionSurface,
49 ICompositorSerializable, PendingAnimations,
50};
51use crate::{Matrix, RelativePoint, RelativeScalar, Vector};
52use std::any::Any;
53use std::cell::{Cell, RefCell};
54use std::ops::Deref;
55use std::rc::{Rc, Weak};
56
57pub(crate) struct CompositionGradientBrushData {
60 brush: CompositionBrushProps,
61 gradient_stops: RefCell<FerroList<Rc<dyn IGradientStop>>>,
62 spread_method: Cell<GradientSpreadMethod>,
63 pub(super) mapping_mode: Cell<CompositionMappingMode>,
65 pub(super) interpolation_space: Cell<CompositionColorSpace>,
67}
68
69impl CompositionGradientBrushData {
70 fn new() -> Self {
71 Self {
72 brush: CompositionBrushProps::new(),
73 gradient_stops: RefCell::new(FerroList::new()),
74 spread_method: Cell::new(GradientSpreadMethod::default()),
75 mapping_mode: Cell::new(CompositionMappingMode::Relative),
76 interpolation_space: Cell::new(CompositionColorSpace::Auto),
77 }
78 }
79
80 fn serialize_changes_core(&self, host: &dyn CompositionBrushHooks, writer: &mut BatchStreamWriter<'_>) {
83 self.brush.serialize_changes_core(host, writer);
84 writer.write(self.spread_method.get());
85 let stops = self.gradient_stops.borrow().clone();
86 writer.write(stops.count() as i32);
87 for stop in stops.to_vec() {
88 let item: BatchResource<dyn IGradientStop> = match stop.as_composition_gradient_stop() {
89 Some(comp) => BatchResource::Server(comp.server()),
90 None if stop.is_immutable_gradient_stop() => BatchResource::Value(stop.clone()),
93 None => BatchResource::Value(Rc::new(ImmutableGradientStop::new(stop.offset(), stop.color()))),
94 };
95 writer.write_resource(Some(item));
96 }
97 }
98}
99
100pub(crate) struct CompositionSurfaceBrushData {
105 props: CompositionSurfaceBrushProps,
106 surface: RefCell<Option<Rc<dyn ICompositionSurface>>>,
107}
108
109pub(crate) enum CompositionBrushKind {
112 SolidColor(CompositionSolidColorBrushProps),
113 LinearGradient(CompositionGradientBrushData, CompositionLinearGradientBrushProps),
114 RadialGradient(CompositionGradientBrushData, CompositionRadialGradientBrushProps),
115 ConicGradient(CompositionGradientBrushData, CompositionConicGradientBrushProps),
116 Surface(CompositionSurfaceBrushData),
117 NineGrid(CompositionNineGridBrushProps),
119 Mask(CompositionMaskBrushProps),
121 Effect(CompositionEffectBrushData),
123 Backdrop(CompositionBrushProps),
125 HostBackdrop(CompositionBrushProps),
127}
128
129pub struct CompositionBrush {
131 this: Weak<CompositionBrush>,
132 object: CompositionObject,
133 pub(super) kind: CompositionBrushKind,
134 transform: RefCell<Option<Rc<dyn ITransform>>>,
135 relative_transform: RefCell<Option<Rc<dyn ITransform>>>,
136}
137
138impl CompositionBrush {
139 pub(super) fn create(
140 compositor: &Rc<Compositor>,
141 kind: CompositionBrushKind,
142 server: impl FnOnce(&Rc<ServerCompositor>) -> Rc<dyn IServerObject> + Send + 'static,
143 ) -> Rc<CompositionBrush> {
144 let server = compositor.create_server_object(move |compositor, _| server(compositor));
145 Rc::new_cyclic(|this: &Weak<CompositionBrush>| CompositionBrush {
146 this: this.clone(),
147 object: CompositionObject::new(compositor, Some(server)),
148 kind,
149 transform: RefCell::new(None),
150 relative_transform: RefCell::new(None),
151 })
152 }
153
154 pub(super) fn initialize_defaults(&self) {
157 match &self.kind {
158 CompositionBrushKind::SolidColor(props) => props.initialize_defaults(self),
159 CompositionBrushKind::LinearGradient(data, props) => {
160 data.brush.initialize_defaults(self);
161 props.initialize_defaults(self);
162 }
163 CompositionBrushKind::RadialGradient(data, props) => {
164 data.brush.initialize_defaults(self);
165 props.initialize_defaults(self);
166 }
167 CompositionBrushKind::ConicGradient(data, props) => {
168 data.brush.initialize_defaults(self);
169 props.initialize_defaults(self);
170 }
171 CompositionBrushKind::Surface(data) => data.props.initialize_defaults(self),
172 CompositionBrushKind::NineGrid(props) => props.initialize_defaults(self),
173 CompositionBrushKind::Mask(props) => props.initialize_defaults(self),
174 CompositionBrushKind::Effect(data) => data.brush.initialize_defaults(self),
175 CompositionBrushKind::Backdrop(props) | CompositionBrushKind::HostBackdrop(props) => props.initialize_defaults(self),
176 }
177 }
178
179 pub fn brush_props(&self) -> &CompositionBrushProps {
181 match &self.kind {
182 CompositionBrushKind::SolidColor(props) => props.base(),
183 CompositionBrushKind::LinearGradient(data, _)
184 | CompositionBrushKind::RadialGradient(data, _)
185 | CompositionBrushKind::ConicGradient(data, _) => &data.brush,
186 CompositionBrushKind::Surface(data) => data.props.base(),
187 CompositionBrushKind::NineGrid(props) => props.base(),
188 CompositionBrushKind::Mask(props) => props.base(),
189 CompositionBrushKind::Effect(data) => &data.brush,
190 CompositionBrushKind::Backdrop(props) | CompositionBrushKind::HostBackdrop(props) => props,
191 }
192 }
193
194 fn gradient_data(&self) -> Option<&CompositionGradientBrushData> {
195 match &self.kind {
196 CompositionBrushKind::SolidColor(_)
197 | CompositionBrushKind::Surface(_)
198 | CompositionBrushKind::NineGrid(_)
199 | CompositionBrushKind::Mask(_)
200 | CompositionBrushKind::Effect(_)
201 | CompositionBrushKind::Backdrop(_) | CompositionBrushKind::HostBackdrop(_) => None,
202 CompositionBrushKind::LinearGradient(data, _)
203 | CompositionBrushKind::RadialGradient(data, _)
204 | CompositionBrushKind::ConicGradient(data, _) => Some(data),
205 }
206 }
207
208 pub fn compositor(&self) -> &Rc<Compositor> {
209 self.object.compositor()
210 }
211
212 pub fn object(&self) -> &CompositionObject {
214 &self.object
215 }
216
217 pub fn server(&self) -> ServerObjectId {
219 self.object.required_server()
220 }
221
222 pub fn is_disposed(&self) -> bool {
223 self.object.is_disposed()
224 }
225
226 pub fn type_name(&self) -> &'static str {
228 match &self.kind {
229 CompositionBrushKind::SolidColor(_) => "CompositionSolidColorBrush",
230 CompositionBrushKind::LinearGradient(..) => "CompositionLinearGradientBrush",
231 CompositionBrushKind::RadialGradient(..) => "CompositionRadialGradientBrush",
232 CompositionBrushKind::ConicGradient(..) => "CompositionConicGradientBrush",
233 CompositionBrushKind::Surface(_) => "CompositionSurfaceBrush",
234 CompositionBrushKind::NineGrid(_) => "CompositionNineGridBrush",
235 CompositionBrushKind::Mask(_) => "CompositionMaskBrush",
236 CompositionBrushKind::Effect(_) => "CompositionEffectBrush",
237 CompositionBrushKind::Backdrop(_) => "CompositionBackdropBrush",
238 CompositionBrushKind::HostBackdrop(_) => "CompositionHostBackdropBrush",
239 }
240 }
241
242 pub fn to_rc(&self) -> Rc<CompositionBrush> {
245 self.this.upgrade().expect("the brush is alive while it is used")
246 }
247
248 pub fn as_brush(&self) -> Rc<dyn IBrush> {
250 self.this.upgrade().expect("the brush is alive while it is used") as Rc<dyn IBrush>
251 }
252
253 pub fn implicit_animations(&self) -> Option<Rc<ImplicitAnimationCollection>> {
255 self.object.implicit_animations()
256 }
257
258 pub fn set_implicit_animations(&self, value: Option<Rc<ImplicitAnimationCollection>>) {
259 self.object.set_implicit_animations(value)
260 }
261
262 pub fn opacity(&self) -> f64 {
263 self.brush_props().opacity()
264 }
265
266 pub fn set_opacity(&self, value: f64) {
267 self.brush_props().set_opacity(self, value)
268 }
269
270 pub fn transform_origin(&self) -> RelativePoint {
271 self.brush_props().transform_origin()
272 }
273
274 pub fn set_transform_origin(&self, value: RelativePoint) {
275 self.brush_props().set_transform_origin(self, value)
276 }
277
278 pub fn transform(&self) -> Option<Rc<dyn ITransform>> {
279 self.transform.borrow().clone()
280 }
281
282 pub fn set_transform(&self, value: Option<Rc<dyn ITransform>>) {
286 let transport = transform_get_server(value.as_ref(), Some(self.compositor()));
287 *self.transform.borrow_mut() = value;
288 self.brush_props().set_transform(self, transport)
289 }
290
291 pub fn relative_transform(&self) -> Option<Rc<dyn ITransform>> {
292 self.relative_transform.borrow().clone()
293 }
294
295 pub fn set_relative_transform(&self, value: Option<Rc<dyn ITransform>>) {
297 let transport = transform_get_server(value.as_ref(), Some(self.compositor()));
298 *self.relative_transform.borrow_mut() = value;
299 self.brush_props().set_relative_transform(self, transport)
300 }
301
302 fn serialize_changes_core(&self, writer: &mut BatchStreamWriter<'_>) {
303 match &self.kind {
304 CompositionBrushKind::SolidColor(props) => props.serialize_changes_core(self, writer),
305 CompositionBrushKind::LinearGradient(_, props) => props.serialize_changes_core(self, writer),
306 CompositionBrushKind::RadialGradient(_, props) => props.serialize_changes_core(self, writer),
307 CompositionBrushKind::ConicGradient(_, props) => props.serialize_changes_core(self, writer),
308 CompositionBrushKind::Surface(data) => data.props.serialize_changes_core(self, writer),
309 CompositionBrushKind::NineGrid(props) => props.serialize_changes_core(self, writer),
310 CompositionBrushKind::Mask(props) => props.serialize_changes_core(self, writer),
311 CompositionBrushKind::Effect(data) => data.serialize_changes_core(self, writer),
312 CompositionBrushKind::Backdrop(props) | CompositionBrushKind::HostBackdrop(props) => props.serialize_changes_core(self, writer),
313 }
314 }
315
316 fn serialize_gradient_base(&self, writer: &mut BatchStreamWriter<'_>) {
318 if let Some(data) = self.gradient_data() {
319 data.serialize_changes_core(self, writer);
320 }
321 }
322}
323
324impl CompositionBrushHooks for CompositionBrush {}
327
328impl CompositionSolidColorBrushHooks for CompositionBrush {}
329
330impl CompositionSurfaceBrushHooks for CompositionBrush {}
331
332impl CompositionNineGridBrushHooks for CompositionBrush {}
333
334impl CompositionMaskBrushHooks for CompositionBrush {}
335
336impl CompositionLinearGradientBrushHooks for CompositionBrush {
337 fn base_serialize_changes_core(&self, writer: &mut BatchStreamWriter<'_>) {
338 self.serialize_gradient_base(writer)
339 }
340}
341
342impl CompositionRadialGradientBrushHooks for CompositionBrush {
343 fn base_serialize_changes_core(&self, writer: &mut BatchStreamWriter<'_>) {
344 self.serialize_gradient_base(writer)
345 }
346}
347
348impl CompositionConicGradientBrushHooks for CompositionBrush {
349 fn base_serialize_changes_core(&self, writer: &mut BatchStreamWriter<'_>) {
350 self.serialize_gradient_base(writer)
351 }
352}
353
354impl IRegisterForSerialization for CompositionBrush {
355 fn register_for_serialization(&self) {
356 self.object
357 .register_for_serialization(|| self.this.upgrade().map(|this| this as Rc<dyn ICompositorSerializable>));
358 }
359}
360
361impl ICompositionObjectHost for CompositionBrush {
362 fn server(&self) -> ServerObjectId {
363 self.object.required_server()
364 }
365
366 fn pending_animations(&self) -> &PendingAnimations {
367 self.object.pending_animations()
368 }
369
370 fn implicit_animation(&self, property_name: &str) -> Option<Rc<dyn ICompositionAnimationBase>> {
371 self.object.implicit_animation(property_name)
372 }
373
374 fn start_animation_group(
375 &self,
376 grp: &Rc<dyn ICompositionAnimationBase>,
377 target: &str,
378 final_value: ExpressionVariant,
379 ) -> bool {
380 self.start_animation_group_for(&**grp, target, final_value)
381 }
382}
383
384impl ICompositionObjectAnimations for CompositionBrush {
385 fn try_start_animation(
386 &self,
387 property_name: &str,
388 animation: &dyn ICompositionAnimation,
389 final_value: Option<ExpressionVariant>,
390 ) -> bool {
391 match &self.kind {
395 CompositionBrushKind::SolidColor(props) => props.start_animation(self, property_name, animation, final_value),
396 CompositionBrushKind::LinearGradient(data, props) => {
397 props.start_animation(self, property_name, animation, final_value)
398 || data.brush.start_animation(self, property_name, animation, final_value)
399 }
400 CompositionBrushKind::RadialGradient(data, props) => {
401 props.start_animation(self, property_name, animation, final_value)
402 || data.brush.start_animation(self, property_name, animation, final_value)
403 }
404 CompositionBrushKind::ConicGradient(data, props) => {
405 props.start_animation(self, property_name, animation, final_value)
406 || data.brush.start_animation(self, property_name, animation, final_value)
407 }
408 CompositionBrushKind::Surface(data) => {
410 data.props.start_animation(self, property_name, animation, final_value)
411 }
412 CompositionBrushKind::NineGrid(props) => props.start_animation(self, property_name, animation, final_value),
413 CompositionBrushKind::Mask(props) => props.start_animation(self, property_name, animation, final_value),
414 CompositionBrushKind::Effect(data) if data.graph.is_animatable(property_name) => {
417 self.object.properties().try_start_animation(property_name, animation, final_value)
418 }
419 CompositionBrushKind::Effect(data) => data.brush.start_animation(self, property_name, animation, final_value),
420 CompositionBrushKind::Backdrop(props) | CompositionBrushKind::HostBackdrop(props) => props.start_animation(self, property_name, animation, final_value),
421 }
422 }
423
424 fn get_composition_property(&self, property_name: &str) -> Option<&'static CompositionProperty> {
425 match &self.kind {
426 CompositionBrushKind::SolidColor(_) => {
427 ServerCompositionSolidColorBrushProps::get_composition_property(property_name)
428 }
429 CompositionBrushKind::LinearGradient(..) => {
430 ServerCompositionLinearGradientBrushProps::get_composition_property(property_name)
431 }
432 CompositionBrushKind::RadialGradient(..) => {
433 ServerCompositionRadialGradientBrushProps::get_composition_property(property_name)
434 }
435 CompositionBrushKind::ConicGradient(..) => {
436 ServerCompositionConicGradientBrushProps::get_composition_property(property_name)
437 }
438 CompositionBrushKind::Surface(_) => {
439 ServerCompositionSurfaceBrushProps::get_composition_property(property_name)
440 }
441 CompositionBrushKind::NineGrid(_) => {
442 ServerCompositionNineGridBrushProps::get_composition_property(property_name)
443 }
444 CompositionBrushKind::Mask(_) => {
445 ServerCompositionMaskBrushProps::get_composition_property(property_name)
446 }
447 CompositionBrushKind::Effect(_) | CompositionBrushKind::Backdrop(_) | CompositionBrushKind::HostBackdrop(_) => None,
450 }
451 .or_else(|| ServerCompositionBrushProps::get_composition_property(property_name))
452 }
453
454 fn composition_object(&self) -> &CompositionObject {
455 &self.object
456 }
457
458 fn stop_animation(&self, property_name: &str) {
462 if let CompositionBrushKind::Effect(data) = &self.kind {
463 if data.graph.is_animatable(property_name) {
464 self.object.note_animation_stopped(property_name);
465 self.object.properties().stop_animation(property_name);
466 return;
467 }
468 }
469 self.object.note_animation_stopped(property_name);
471 if let Some((property, components)) = parse_subchannel(property_name) {
472 let Some(property) = self.get_composition_property(property) else {
473 panic!("Unknown property {property_name}");
474 };
475 self.object.stop_subchannel_animation(property, components);
476 return;
477 }
478 let Some(property) = self.get_composition_property(property_name) else {
479 panic!("Unknown property {property_name}");
480 };
481 self.object.stop_animation(property);
482 }
483}
484
485impl AsCompositionObject for CompositionBrush {
486 fn as_composition_object(&self) -> &CompositionObject {
487 &self.object
488 }
489
490 fn composition_type_name(&self) -> &'static str {
491 self.type_name()
492 }
493}
494
495impl ICompositionObject for CompositionBrush {
496 fn server(&self) -> ServerObjectId {
497 self.object.required_server()
498 }
499
500 fn as_any(&self) -> &dyn Any {
501 self
502 }
503
504 fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
505 self
506 }
507}
508
509impl ICompositorSerializable for CompositionBrush {
510 fn try_get_server(&self, c: &Compositor) -> Option<ServerObjectId> {
511 self.object.try_get_server(c)
512 }
513
514 fn serialize_changes(&self, c: &Compositor, writer: &mut BatchStreamWriter<'_>) {
515 self.object.begin_serialize_changes(c);
516 self.serialize_changes_core(writer);
517 }
518}
519
520impl IBrush for CompositionBrush {
528 fn opacity(&self) -> f64 {
529 CompositionBrush::opacity(self)
530 }
531
532 fn transform(&self) -> Option<Rc<dyn ITransform>> {
533 CompositionBrush::transform(self)
534 }
535
536 fn transform_origin(&self) -> RelativePoint {
537 CompositionBrush::transform_origin(self)
538 }
539
540 fn relative_transform(&self) -> Option<Rc<dyn ITransform>> {
541 CompositionBrush::relative_transform(self)
542 }
543
544 fn as_any(&self) -> &dyn Any {
545 self
546 }
547
548 fn as_solid_color_brush(&self) -> Option<&dyn ISolidColorBrush> {
549 matches!(self.kind, CompositionBrushKind::SolidColor(_)).then_some(self as &dyn ISolidColorBrush)
550 }
551
552 fn as_gradient_brush(&self) -> Option<&dyn IGradientBrush> {
553 self.gradient_data().map(|_| self as &dyn IGradientBrush)
554 }
555
556 fn as_linear_gradient_brush(&self) -> Option<&dyn ILinearGradientBrush> {
557 matches!(self.kind, CompositionBrushKind::LinearGradient(..)).then_some(self as &dyn ILinearGradientBrush)
558 }
559
560 fn as_radial_gradient_brush(&self) -> Option<&dyn IRadialGradientBrush> {
561 matches!(self.kind, CompositionBrushKind::RadialGradient(..)).then_some(self as &dyn IRadialGradientBrush)
562 }
563
564 fn as_conic_gradient_brush(&self) -> Option<&dyn IConicGradientBrush> {
565 matches!(self.kind, CompositionBrushKind::ConicGradient(..)).then_some(self as &dyn IConicGradientBrush)
566 }
567
568 fn as_composition_brush(&self) -> Option<&CompositionBrush> {
569 Some(self)
570 }
571}
572
573fn not_of_kind(member: &str) -> ! {
574 panic!("{member} is not a member of this composition brush");
575}
576
577impl ISolidColorBrush for CompositionBrush {
578 fn color(&self) -> Color {
579 match &self.kind {
580 CompositionBrushKind::SolidColor(props) => props.color(),
581 _ => not_of_kind("Color"),
582 }
583 }
584}
585
586impl IGradientBrush for CompositionBrush {
587 fn gradient_stops(&self) -> Vec<Rc<dyn IGradientStop>> {
588 match self.gradient_data() {
589 Some(data) => data.gradient_stops.borrow().to_vec(),
590 None => not_of_kind("GradientStops"),
591 }
592 }
593
594 fn spread_method(&self) -> GradientSpreadMethod {
595 match self.gradient_data() {
596 Some(data) => data.spread_method.get(),
597 None => not_of_kind("SpreadMethod"),
598 }
599 }
600}
601
602impl ILinearGradientBrush for CompositionBrush {
603 fn start_point(&self) -> RelativePoint {
604 match &self.kind {
605 CompositionBrushKind::LinearGradient(_, props) => props.start_point(),
606 _ => not_of_kind("StartPoint"),
607 }
608 }
609
610 fn end_point(&self) -> RelativePoint {
611 match &self.kind {
612 CompositionBrushKind::LinearGradient(_, props) => props.end_point(),
613 _ => not_of_kind("EndPoint"),
614 }
615 }
616}
617
618impl IRadialGradientBrush for CompositionBrush {
619 fn center(&self) -> RelativePoint {
620 match &self.kind {
621 CompositionBrushKind::RadialGradient(_, props) => props.center(),
622 _ => not_of_kind("Center"),
623 }
624 }
625
626 fn gradient_origin(&self) -> RelativePoint {
627 match &self.kind {
628 CompositionBrushKind::RadialGradient(_, props) => props.gradient_origin(),
629 _ => not_of_kind("GradientOrigin"),
630 }
631 }
632
633 fn radius_x(&self) -> RelativeScalar {
634 match &self.kind {
635 CompositionBrushKind::RadialGradient(_, props) => props.radius_x(),
636 _ => not_of_kind("RadiusX"),
637 }
638 }
639
640 fn radius_y(&self) -> RelativeScalar {
641 match &self.kind {
642 CompositionBrushKind::RadialGradient(_, props) => props.radius_y(),
643 _ => not_of_kind("RadiusY"),
644 }
645 }
646}
647
648impl IConicGradientBrush for CompositionBrush {
649 fn center(&self) -> RelativePoint {
650 match &self.kind {
651 CompositionBrushKind::ConicGradient(_, props) => props.center(),
652 _ => not_of_kind("Center"),
653 }
654 }
655
656 fn angle(&self) -> f64 {
657 match &self.kind {
658 CompositionBrushKind::ConicGradient(_, props) => props.angle(),
659 _ => not_of_kind("Angle"),
660 }
661 }
662}
663
664#[derive(Clone)]
668pub struct CompositionSolidColorBrush(Rc<CompositionBrush>);
669
670impl Deref for CompositionSolidColorBrush {
671 type Target = Rc<CompositionBrush>;
672
673 fn deref(&self) -> &Rc<CompositionBrush> {
674 &self.0
675 }
676}
677
678impl CompositionSolidColorBrush {
679 fn create(compositor: &Rc<Compositor>) -> Rc<CompositionBrush> {
680 CompositionBrush::create(
681 compositor,
682 CompositionBrushKind::SolidColor(CompositionSolidColorBrushProps::new()),
683 |c| ServerCompositionSolidColorBrush::new(c),
684 )
685 }
686
687 pub(crate) fn new(compositor: &Rc<Compositor>) -> CompositionSolidColorBrush {
688 let brush = Self::create(compositor);
689 brush.initialize_defaults();
690 CompositionSolidColorBrush(brush)
691 }
692
693 pub(crate) fn with_color(compositor: &Rc<Compositor>, color: Color) -> CompositionSolidColorBrush {
694 let brush = Self::create(compositor);
695 let this = CompositionSolidColorBrush(brush);
696 this.props().base().initialize_defaults(&*this.0);
699 this.set_color(color);
700 this.props().initialize_own_defaults(&*this.0);
701 this
702 }
703
704 pub fn from_brush(brush: &Rc<CompositionBrush>) -> Option<CompositionSolidColorBrush> {
706 matches!(brush.kind, CompositionBrushKind::SolidColor(_)).then(|| CompositionSolidColorBrush(brush.clone()))
707 }
708
709 fn props(&self) -> &CompositionSolidColorBrushProps {
710 match &self.0.kind {
711 CompositionBrushKind::SolidColor(props) => props,
712 _ => unreachable!("a solid color brush handle wraps a solid color brush"),
713 }
714 }
715
716 pub fn color(&self) -> Color {
717 self.props().color()
718 }
719
720 pub fn set_color(&self, value: Color) {
721 self.props().set_color(&*self.0, value)
722 }
723}
724
725#[derive(Clone)]
728pub struct CompositionGradientBrush(Rc<CompositionBrush>);
729
730impl Deref for CompositionGradientBrush {
731 type Target = Rc<CompositionBrush>;
732
733 fn deref(&self) -> &Rc<CompositionBrush> {
734 &self.0
735 }
736}
737
738impl CompositionGradientBrush {
739 pub fn from_brush(brush: &Rc<CompositionBrush>) -> Option<CompositionGradientBrush> {
741 brush.gradient_data().map(|_| CompositionGradientBrush(brush.clone()))
742 }
743
744 fn data(&self) -> &CompositionGradientBrushData {
745 match self.0.gradient_data() {
746 Some(data) => data,
747 None => unreachable!("a gradient brush handle wraps a gradient brush"),
748 }
749 }
750
751 pub fn gradient_stops(&self) -> FerroList<Rc<dyn IGradientStop>> {
757 self.data().gradient_stops.borrow().clone()
758 }
759
760 pub fn set_gradient_stops(&self, value: FerroList<Rc<dyn IGradientStop>>) {
761 if self.data().gradient_stops.borrow().ptr_eq(&value) {
762 return;
763 }
764 *self.data().gradient_stops.borrow_mut() = value;
765 self.0.register_for_serialization();
766 }
767
768 pub fn spread_method(&self) -> GradientSpreadMethod {
770 self.data().spread_method.get()
771 }
772
773 pub fn set_spread_method(&self, value: GradientSpreadMethod) {
774 if self.data().spread_method.get() == value {
775 return;
776 }
777 self.data().spread_method.set(value);
778 self.0.register_for_serialization();
779 }
780}
781
782macro_rules! gradient_brush_class {
783 ($(#[$meta:meta])* $name:ident, $variant:ident, $props:ident, $server:ident) => {
784 $(#[$meta])*
785 #[derive(Clone)]
786 pub struct $name(CompositionGradientBrush);
787
788 impl Deref for $name {
789 type Target = CompositionGradientBrush;
790
791 fn deref(&self) -> &CompositionGradientBrush {
792 &self.0
793 }
794 }
795
796 impl $name {
797 pub(crate) fn new(compositor: &Rc<Compositor>) -> $name {
798 let brush = CompositionBrush::create(
799 compositor,
800 CompositionBrushKind::$variant(CompositionGradientBrushData::new(), $props::new()),
801 |c| $server::new(c),
802 );
803 brush.initialize_defaults();
804 $name(CompositionGradientBrush(brush))
805 }
806
807 pub fn from_brush(brush: &Rc<CompositionBrush>) -> Option<$name> {
809 matches!(brush.kind, CompositionBrushKind::$variant(..))
810 .then(|| $name(CompositionGradientBrush(brush.clone())))
811 }
812
813 fn props(&self) -> &$props {
814 match &self.0 .0.kind {
815 CompositionBrushKind::$variant(_, props) => props,
816 _ => unreachable!("the handle wraps a brush of its class"),
817 }
818 }
819
820 fn host(&self) -> &CompositionBrush {
821 &self.0 .0
822 }
823 }
824 };
825}
826
827gradient_brush_class!(
828 CompositionLinearGradientBrush,
830 LinearGradient,
831 CompositionLinearGradientBrushProps,
832 ServerCompositionLinearGradientBrush
833);
834
835impl CompositionLinearGradientBrush {
836 pub fn start_point(&self) -> RelativePoint {
837 self.props().start_point()
838 }
839
840 pub fn set_start_point(&self, value: RelativePoint) {
841 self.props().set_start_point(self.host(), value)
842 }
843
844 pub fn end_point(&self) -> RelativePoint {
845 self.props().end_point()
846 }
847
848 pub fn set_end_point(&self, value: RelativePoint) {
849 self.props().set_end_point(self.host(), value)
850 }
851}
852
853gradient_brush_class!(
854 CompositionRadialGradientBrush,
856 RadialGradient,
857 CompositionRadialGradientBrushProps,
858 ServerCompositionRadialGradientBrush
859);
860
861impl CompositionRadialGradientBrush {
862 pub fn center(&self) -> RelativePoint {
863 self.props().center()
864 }
865
866 pub fn set_center(&self, value: RelativePoint) {
867 self.props().set_center(self.host(), value)
868 }
869
870 pub fn gradient_origin(&self) -> RelativePoint {
871 self.props().gradient_origin()
872 }
873
874 pub fn set_gradient_origin(&self, value: RelativePoint) {
875 self.props().set_gradient_origin(self.host(), value)
876 }
877
878 pub fn radius_x(&self) -> RelativeScalar {
879 self.props().radius_x()
880 }
881
882 pub fn set_radius_x(&self, value: RelativeScalar) {
883 self.props().set_radius_x(self.host(), value)
884 }
885
886 pub fn radius_y(&self) -> RelativeScalar {
887 self.props().radius_y()
888 }
889
890 pub fn set_radius_y(&self, value: RelativeScalar) {
891 self.props().set_radius_y(self.host(), value)
892 }
893
894 pub fn radius(&self) -> f64 {
895 self.radius_x().scalar
896 }
897}
898
899gradient_brush_class!(
900 CompositionConicGradientBrush,
902 ConicGradient,
903 CompositionConicGradientBrushProps,
904 ServerCompositionConicGradientBrush
905);
906
907impl CompositionConicGradientBrush {
908 pub fn angle(&self) -> f64 {
909 self.props().angle()
910 }
911
912 pub fn set_angle(&self, value: f64) {
913 self.props().set_angle(self.host(), value)
914 }
915
916 pub fn center(&self) -> RelativePoint {
917 self.props().center()
918 }
919
920 pub fn set_center(&self, value: RelativePoint) {
921 self.props().set_center(self.host(), value)
922 }
923}
924
925#[derive(Clone)]
942pub struct CompositionSurfaceBrush(Rc<CompositionBrush>);
943
944impl Deref for CompositionSurfaceBrush {
945 type Target = Rc<CompositionBrush>;
946
947 fn deref(&self) -> &Rc<CompositionBrush> {
948 &self.0
949 }
950}
951
952impl CompositionSurfaceBrush {
953 pub(crate) fn new(compositor: &Rc<Compositor>) -> CompositionSurfaceBrush {
954 let brush = CompositionBrush::create(
955 compositor,
956 CompositionBrushKind::Surface(CompositionSurfaceBrushData {
957 props: CompositionSurfaceBrushProps::new(),
958 surface: RefCell::new(None),
959 }),
960 |c| ServerCompositionSurfaceBrush::new(c),
961 );
962 brush.initialize_defaults();
963 CompositionSurfaceBrush(brush)
964 }
965
966 pub(crate) fn with_surface(compositor: &Rc<Compositor>, surface: Rc<dyn ICompositionSurface>) -> CompositionSurfaceBrush {
967 let brush = Self::new(compositor);
968 brush.set_surface(Some(surface));
969 brush
970 }
971
972 pub fn from_brush(brush: &Rc<CompositionBrush>) -> Option<CompositionSurfaceBrush> {
974 matches!(brush.kind, CompositionBrushKind::Surface(_)).then(|| CompositionSurfaceBrush(brush.clone()))
975 }
976
977 fn data(&self) -> &CompositionSurfaceBrushData {
978 match &self.0.kind {
979 CompositionBrushKind::Surface(data) => data,
980 _ => unreachable!("a surface brush handle wraps a surface brush"),
981 }
982 }
983
984 fn host(&self) -> &CompositionBrush {
985 &self.0
986 }
987
988 pub fn props(&self) -> &CompositionSurfaceBrushProps {
990 &self.data().props
991 }
992
993 pub fn surface(&self) -> Option<Rc<dyn ICompositionSurface>> {
995 self.data().surface.borrow().clone()
996 }
997
998 pub fn set_surface(&self, value: Option<Rc<dyn ICompositionSurface>>) {
999 *self.data().surface.borrow_mut() = value.clone();
1000 self.props().set_surface(self.host(), value.map(|surface| surface as Rc<dyn ICompositionObject>))
1001 }
1002
1003 pub fn stretch(&self) -> CompositionStretch {
1005 self.props().stretch()
1006 }
1007
1008 pub fn set_stretch(&self, value: CompositionStretch) {
1009 self.props().set_stretch(self.host(), value)
1010 }
1011
1012 pub fn horizontal_alignment_ratio(&self) -> f32 {
1015 self.props().horizontal_alignment_ratio()
1016 }
1017
1018 pub fn set_horizontal_alignment_ratio(&self, value: f32) {
1019 self.props().set_horizontal_alignment_ratio(self.host(), value)
1020 }
1021
1022 pub fn vertical_alignment_ratio(&self) -> f32 {
1025 self.props().vertical_alignment_ratio()
1026 }
1027
1028 pub fn set_vertical_alignment_ratio(&self, value: f32) {
1029 self.props().set_vertical_alignment_ratio(self.host(), value)
1030 }
1031
1032 pub fn bitmap_interpolation_mode(&self) -> CompositionBitmapInterpolationMode {
1034 self.props().bitmap_interpolation_mode()
1035 }
1036
1037 pub fn set_bitmap_interpolation_mode(&self, value: CompositionBitmapInterpolationMode) {
1038 self.props().set_bitmap_interpolation_mode(self.host(), value)
1039 }
1040
1041 pub fn anchor_point(&self) -> Vector {
1044 self.props().anchor_point()
1045 }
1046
1047 pub fn set_anchor_point(&self, value: Vector) {
1048 self.props().set_anchor_point(self.host(), value)
1049 }
1050
1051 pub fn center_point(&self) -> Vector {
1053 self.props().center_point()
1054 }
1055
1056 pub fn set_center_point(&self, value: Vector) {
1057 self.props().set_center_point(self.host(), value)
1058 }
1059
1060 pub fn offset(&self) -> Vector {
1062 self.props().offset()
1063 }
1064
1065 pub fn set_offset(&self, value: Vector) {
1066 self.props().set_offset(self.host(), value)
1067 }
1068
1069 pub fn rotation_angle(&self) -> f32 {
1071 self.props().rotation_angle()
1072 }
1073
1074 pub fn set_rotation_angle(&self, value: f32) {
1075 self.props().set_rotation_angle(self.host(), value)
1076 }
1077
1078 pub fn rotation_angle_in_degrees(&self) -> f32 {
1081 self.rotation_angle().to_degrees()
1082 }
1083
1084 pub fn set_rotation_angle_in_degrees(&self, value: f32) {
1085 self.set_rotation_angle(value.to_radians())
1086 }
1087
1088 pub fn scale(&self) -> Vector {
1090 self.props().scale()
1091 }
1092
1093 pub fn set_scale(&self, value: Vector) {
1094 self.props().set_scale(self.host(), value)
1095 }
1096
1097 pub fn transform_matrix(&self) -> Matrix {
1099 self.props().transform_matrix()
1100 }
1101
1102 pub fn set_transform_matrix(&self, value: Matrix) {
1103 self.props().set_transform_matrix(self.host(), value)
1104 }
1105
1106 pub fn snap_to_pixels(&self) -> bool {
1108 self.props().snap_to_pixels()
1109 }
1110
1111 pub fn set_snap_to_pixels(&self, value: bool) {
1112 self.props().set_snap_to_pixels(self.host(), value)
1113 }
1114}