zng_view/
px_wr.rs

1use webrender::{
2    api::{self as wr},
3    euclid,
4};
5use zng_unit::{Px, PxBox, PxCornerRadius, PxPoint, PxRect, PxSideOffsets, PxSize, PxTransform, PxVector, Rgba};
6use zng_view_api::{
7    AlphaType, BorderSide, BorderStyle, ExtendMode, ImageRendering, LineOrientation, LineStyle, MixBlendMode, ReferenceFrameId, RepeatMode,
8    TransformStyle,
9    config::FontAntiAliasing,
10    display_list::{FilterOp, FrameValue, FrameValueId, FrameValueUpdate},
11    font::FontOptions,
12};
13
14/// Conversion from [`Px`] to `webrender` units.
15///
16/// All conversions are 1 to 1.
17pub trait PxToWr {
18    /// `Self` equivalent in `webrender::units::LayoutPixel` units.
19    type AsLayout;
20    /// `Self` equivalent in `webrender::units::DevicePixel` units.
21    type AsDevice;
22    /// `Self` equivalent in `webrender::units::WorldPixel units.
23    type AsWorld;
24
25    /// Returns `self` in `webrender::units::DevicePixel` units.
26    fn to_wr_device(self) -> Self::AsDevice;
27
28    /// Returns `self` in `webrender::units::WorldPixel` units.
29    fn to_wr_world(self) -> Self::AsWorld;
30
31    /// Returns `self` in `webrender::units::LayoutPixel` units.
32    fn to_wr(self) -> Self::AsLayout;
33}
34
35/// Conversion from `webrender` to [`Px`] units.
36pub trait WrToPx {
37    /// `Self` equivalent in [`Px`] units.
38    type AsPx;
39
40    /// Returns `self` in [`Px`] units.
41    fn to_px(self) -> Self::AsPx;
42}
43
44impl PxToWr for Px {
45    type AsDevice = wr::units::DeviceIntLength;
46
47    type AsWorld = euclid::Length<f32, wr::units::WorldPixel>;
48    type AsLayout = euclid::Length<f32, wr::units::LayoutPixel>;
49
50    fn to_wr_device(self) -> Self::AsDevice {
51        wr::units::DeviceIntLength::new(self.0)
52    }
53
54    fn to_wr_world(self) -> Self::AsWorld {
55        euclid::Length::new(self.0 as f32)
56    }
57
58    fn to_wr(self) -> Self::AsLayout {
59        euclid::Length::new(self.0 as f32)
60    }
61}
62
63impl PxToWr for PxPoint {
64    type AsDevice = wr::units::DeviceIntPoint;
65    type AsWorld = wr::units::WorldPoint;
66    type AsLayout = wr::units::LayoutPoint;
67
68    fn to_wr_device(self) -> Self::AsDevice {
69        wr::units::DeviceIntPoint::new(self.x.to_wr_device().0, self.y.to_wr_device().0)
70    }
71
72    fn to_wr_world(self) -> Self::AsWorld {
73        wr::units::WorldPoint::new(self.x.to_wr_world().0, self.y.to_wr_world().0)
74    }
75
76    fn to_wr(self) -> Self::AsLayout {
77        wr::units::LayoutPoint::new(self.x.to_wr().0, self.y.to_wr().0)
78    }
79}
80impl WrToPx for wr::units::LayoutPoint {
81    type AsPx = PxPoint;
82
83    fn to_px(self) -> Self::AsPx {
84        PxPoint::new(Px(self.x.round() as i32), Px(self.y.round() as i32))
85    }
86}
87
88impl PxToWr for PxSize {
89    type AsDevice = wr::units::DeviceIntSize;
90    type AsWorld = wr::units::WorldSize;
91    type AsLayout = wr::units::LayoutSize;
92
93    fn to_wr_device(self) -> Self::AsDevice {
94        wr::units::DeviceIntSize::new(self.width.to_wr_device().0, self.height.to_wr_device().0)
95    }
96
97    fn to_wr_world(self) -> Self::AsWorld {
98        wr::units::WorldSize::new(self.width.to_wr_world().0, self.height.to_wr_world().0)
99    }
100
101    fn to_wr(self) -> Self::AsLayout {
102        wr::units::LayoutSize::new(self.width.to_wr().0, self.height.to_wr().0)
103    }
104}
105impl WrToPx for wr::units::LayoutSize {
106    type AsPx = PxSize;
107
108    fn to_px(self) -> Self::AsPx {
109        PxSize::new(Px(self.width.round() as i32), Px(self.height.round() as i32))
110    }
111}
112
113impl WrToPx for wr::units::DeviceIntSize {
114    type AsPx = PxSize;
115
116    fn to_px(self) -> Self::AsPx {
117        PxSize::new(Px(self.width), Px(self.height))
118    }
119}
120impl PxToWr for PxVector {
121    type AsDevice = wr::units::DeviceVector2D;
122
123    type AsLayout = wr::units::LayoutVector2D;
124
125    type AsWorld = wr::units::WorldVector2D;
126
127    fn to_wr_device(self) -> Self::AsDevice {
128        wr::units::DeviceVector2D::new(self.x.0 as f32, self.y.0 as f32)
129    }
130
131    fn to_wr_world(self) -> Self::AsWorld {
132        wr::units::WorldVector2D::new(self.x.0 as f32, self.y.0 as f32)
133    }
134
135    fn to_wr(self) -> Self::AsLayout {
136        wr::units::LayoutVector2D::new(self.x.0 as f32, self.y.0 as f32)
137    }
138}
139impl WrToPx for wr::units::LayoutVector2D {
140    type AsPx = PxVector;
141
142    fn to_px(self) -> Self::AsPx {
143        PxVector::new(Px(self.x.round() as i32), Px(self.y.round() as i32))
144    }
145}
146
147impl PxToWr for PxRect {
148    type AsDevice = wr::units::DeviceIntRect;
149
150    type AsWorld = wr::units::WorldRect;
151
152    type AsLayout = wr::units::LayoutRect;
153
154    fn to_wr_device(self) -> Self::AsDevice {
155        wr::units::DeviceIntRect::from_origin_and_size(self.origin.to_wr_device(), self.size.to_wr_device())
156    }
157
158    fn to_wr_world(self) -> Self::AsWorld {
159        wr::units::WorldRect::from_origin_and_size(self.origin.to_wr_world(), self.size.to_wr_world())
160    }
161
162    fn to_wr(self) -> Self::AsLayout {
163        wr::units::LayoutRect::from_origin_and_size(self.origin.to_wr(), self.size.to_wr())
164    }
165}
166impl WrToPx for wr::units::LayoutRect {
167    type AsPx = PxRect;
168
169    fn to_px(self) -> Self::AsPx {
170        self.to_rect().to_px()
171    }
172}
173impl WrToPx for euclid::Rect<f32, wr::units::LayoutPixel> {
174    type AsPx = PxRect;
175
176    fn to_px(self) -> Self::AsPx {
177        PxRect::new(self.origin.to_px(), self.size.to_px())
178    }
179}
180
181impl PxToWr for PxBox {
182    type AsDevice = wr::units::DeviceBox2D;
183
184    type AsLayout = wr::units::LayoutRect;
185
186    type AsWorld = euclid::Box2D<f32, wr::units::WorldPixel>;
187
188    fn to_wr_device(self) -> Self::AsDevice {
189        wr::units::DeviceBox2D::new(self.min.to_wr_device().cast(), self.max.to_wr_device().cast())
190    }
191
192    fn to_wr_world(self) -> Self::AsWorld {
193        euclid::Box2D::new(self.min.to_wr_world(), self.max.to_wr_world())
194    }
195
196    fn to_wr(self) -> Self::AsLayout {
197        wr::units::LayoutRect::new(self.min.to_wr(), self.max.to_wr())
198    }
199}
200
201impl PxToWr for PxSideOffsets {
202    type AsDevice = wr::units::DeviceIntSideOffsets;
203
204    type AsLayout = wr::units::LayoutSideOffsets;
205
206    type AsWorld = euclid::SideOffsets2D<f32, wr::units::WorldPixel>;
207
208    fn to_wr_device(self) -> Self::AsDevice {
209        wr::units::DeviceIntSideOffsets::new(
210            self.top.to_wr_device().0,
211            self.right.to_wr_device().0,
212            self.bottom.to_wr_device().0,
213            self.left.to_wr_device().0,
214        )
215    }
216
217    fn to_wr_world(self) -> Self::AsWorld {
218        euclid::SideOffsets2D::from_lengths(
219            self.top.to_wr_world(),
220            self.right.to_wr_world(),
221            self.bottom.to_wr_world(),
222            self.left.to_wr_world(),
223        )
224    }
225
226    fn to_wr(self) -> Self::AsLayout {
227        wr::units::LayoutSideOffsets::from_lengths(self.top.to_wr(), self.right.to_wr(), self.bottom.to_wr(), self.left.to_wr())
228    }
229}
230
231impl PxToWr for PxCornerRadius {
232    type AsLayout = wr::BorderRadius;
233    type AsDevice = ();
234    type AsWorld = ();
235
236    /// Convert to `webrender` border radius.
237    fn to_wr(self) -> wr::BorderRadius {
238        wr::BorderRadius {
239            top_left: self.top_left.to_wr(),
240            top_right: self.top_right.to_wr(),
241            bottom_left: self.bottom_left.to_wr(),
242            bottom_right: self.bottom_right.to_wr(),
243        }
244    }
245
246    fn to_wr_device(self) -> Self::AsDevice {
247        unimplemented!()
248    }
249
250    fn to_wr_world(self) -> Self::AsWorld {
251        unimplemented!()
252    }
253}
254
255impl PxToWr for PxTransform {
256    type AsDevice = euclid::Transform3D<f32, wr::units::DevicePixel, wr::units::DevicePixel>;
257
258    type AsLayout = wr::units::LayoutTransform;
259
260    type AsWorld = euclid::Transform3D<f32, wr::units::WorldPixel, wr::units::WorldPixel>;
261
262    fn to_wr_device(self) -> Self::AsDevice {
263        self.to_transform().with_source().with_destination()
264    }
265
266    fn to_wr_world(self) -> Self::AsWorld {
267        self.to_transform().with_source().with_destination()
268    }
269
270    fn to_wr(self) -> Self::AsLayout {
271        self.to_transform().with_source().with_destination()
272    }
273}
274
275// to work with to_wr
276impl PxToWr for f32 {
277    type AsDevice = f32;
278
279    type AsLayout = f32;
280
281    type AsWorld = f32;
282
283    fn to_wr_device(self) -> Self::AsDevice {
284        self
285    }
286
287    fn to_wr_world(self) -> Self::AsWorld {
288        self
289    }
290
291    fn to_wr(self) -> Self::AsLayout {
292        self
293    }
294}
295// to work with to_wr
296impl PxToWr for Rgba {
297    type AsDevice = ();
298    type AsWorld = ();
299    type AsLayout = wr::ColorF;
300
301    fn to_wr_device(self) -> Self::AsDevice {
302        unimplemented!()
303    }
304
305    fn to_wr_world(self) -> Self::AsWorld {
306        unimplemented!()
307    }
308
309    fn to_wr(self) -> Self::AsLayout {
310        wr::ColorF::new(self.red, self.green, self.blue, self.alpha)
311    }
312}
313
314impl PxToWr for FilterOp {
315    type AsDevice = ();
316    type AsWorld = ();
317    type AsLayout = wr::FilterOp;
318
319    fn to_wr_device(self) -> Self::AsDevice {
320        unimplemented!()
321    }
322
323    fn to_wr_world(self) -> Self::AsWorld {
324        unimplemented!()
325    }
326
327    fn to_wr(self) -> Self::AsLayout {
328        match self {
329            FilterOp::Blur(w, h) => wr::FilterOp::Blur(w, h),
330            FilterOp::Brightness(b) => wr::FilterOp::Brightness(b),
331            FilterOp::Contrast(c) => wr::FilterOp::Contrast(c),
332            FilterOp::Grayscale(g) => wr::FilterOp::Grayscale(g),
333            FilterOp::HueRotate(h) => wr::FilterOp::HueRotate(h),
334            FilterOp::Invert(i) => wr::FilterOp::Invert(i),
335            FilterOp::Opacity(o) => wr::FilterOp::Opacity(o.to_wr(), *o.value()),
336            FilterOp::Saturate(s) => wr::FilterOp::Saturate(s),
337            FilterOp::Sepia(s) => wr::FilterOp::Sepia(s),
338            FilterOp::DropShadow {
339                offset,
340                color,
341                blur_radius,
342            } => wr::FilterOp::DropShadow(wr::Shadow {
343                offset: offset.cast_unit(),
344                color: color.to_wr(),
345                blur_radius,
346            }),
347            FilterOp::ColorMatrix(m) => wr::FilterOp::ColorMatrix([
348                m[0], m[5], m[10], m[15], m[1], m[6], m[11], m[16], m[2], m[7], m[12], m[17], m[3], m[8], m[13], m[18], m[4], m[9], m[14],
349                m[19],
350            ]),
351            FilterOp::Flood(c) => wr::FilterOp::Flood(c.to_wr()),
352        }
353    }
354}
355
356impl PxToWr for BorderSide {
357    type AsDevice = ();
358    type AsWorld = ();
359    type AsLayout = wr::BorderSide;
360
361    fn to_wr_device(self) -> Self::AsDevice {
362        unimplemented!()
363    }
364
365    fn to_wr_world(self) -> Self::AsWorld {
366        unimplemented!()
367    }
368
369    fn to_wr(self) -> Self::AsLayout {
370        wr::BorderSide {
371            color: self.color.to_wr(),
372            style: self.style.to_wr(),
373        }
374    }
375}
376
377impl PxToWr for BorderStyle {
378    type AsDevice = ();
379    type AsWorld = ();
380    type AsLayout = wr::BorderStyle;
381
382    fn to_wr_device(self) -> Self::AsDevice {
383        unimplemented!()
384    }
385
386    fn to_wr_world(self) -> Self::AsWorld {
387        unimplemented!()
388    }
389
390    fn to_wr(self) -> Self::AsLayout {
391        match self {
392            BorderStyle::None => wr::BorderStyle::None,
393            BorderStyle::Solid => wr::BorderStyle::Solid,
394            BorderStyle::Double => wr::BorderStyle::Double,
395            BorderStyle::Dotted => wr::BorderStyle::Dotted,
396            BorderStyle::Dashed => wr::BorderStyle::Dashed,
397            BorderStyle::Hidden => wr::BorderStyle::Hidden,
398            BorderStyle::Groove => wr::BorderStyle::Groove,
399            BorderStyle::Ridge => wr::BorderStyle::Ridge,
400            BorderStyle::Inset => wr::BorderStyle::Inset,
401            BorderStyle::Outset => wr::BorderStyle::Outset,
402        }
403    }
404}
405
406impl<T: PxToWr> PxToWr for FrameValue<T> {
407    type AsDevice = ();
408    type AsWorld = ();
409    type AsLayout = wr::PropertyBinding<T::AsLayout>;
410
411    fn to_wr_device(self) -> Self::AsDevice {
412        unimplemented!()
413    }
414
415    fn to_wr_world(self) -> Self::AsWorld {
416        unimplemented!()
417    }
418
419    fn to_wr(self) -> Self::AsLayout {
420        match self {
421            FrameValue::Bind {
422                id,
423                value,
424                animating: true,
425            } => wr::PropertyBinding::Binding(
426                wr::PropertyBindingKey {
427                    id: id.to_wr(),
428                    _phantom: std::marker::PhantomData,
429                },
430                value.to_wr(),
431            ),
432            FrameValue::Bind {
433                value, animating: false, ..
434            } => wr::PropertyBinding::Value(value.to_wr()),
435            FrameValue::Value(value) => wr::PropertyBinding::Value(value.to_wr()),
436        }
437    }
438}
439
440impl<T: PxToWr> PxToWr for FrameValueUpdate<T> {
441    type AsDevice = ();
442    type AsWorld = ();
443    type AsLayout = Option<wr::PropertyValue<T::AsLayout>>;
444
445    fn to_wr_device(self) -> Self::AsDevice {
446        unimplemented!()
447    }
448
449    fn to_wr_world(self) -> Self::AsWorld {
450        unimplemented!()
451    }
452
453    fn to_wr(self) -> Self::AsLayout
454    where
455        T: PxToWr,
456    {
457        if self.animating {
458            Some(wr::PropertyValue {
459                key: wr::PropertyBindingKey {
460                    id: self.id.to_wr(),
461                    _phantom: std::marker::PhantomData,
462                },
463                value: self.value.to_wr(),
464            })
465        } else {
466            None
467        }
468    }
469}
470
471impl PxToWr for FontOptions {
472    type AsDevice = ();
473    type AsWorld = Option<wr::GlyphOptions>;
474    type AsLayout = Option<wr::FontInstanceOptions>;
475
476    fn to_wr_device(self) -> Self::AsDevice {
477        unimplemented!()
478    }
479
480    fn to_wr_world(self) -> Self::AsWorld {
481        self.to_wr().map(|o| wr::GlyphOptions {
482            render_mode: o.render_mode,
483            flags: o.flags,
484        })
485    }
486
487    fn to_wr(self) -> Self::AsLayout {
488        if self == FontOptions::default() {
489            None
490        } else {
491            Some(wr::FontInstanceOptions {
492                render_mode: match self.aa {
493                    FontAntiAliasing::Default => wr::FontRenderMode::Subpixel,
494                    FontAntiAliasing::Subpixel => wr::FontRenderMode::Subpixel,
495                    FontAntiAliasing::Alpha => wr::FontRenderMode::Alpha,
496                    FontAntiAliasing::Mono => wr::FontRenderMode::Mono,
497                },
498                flags: if self.synthetic_bold {
499                    wr::FontInstanceFlags::SYNTHETIC_BOLD
500                } else {
501                    wr::FontInstanceFlags::empty()
502                },
503                synthetic_italics: wr::SyntheticItalics::from_degrees(if self.synthetic_oblique { 14.0 } else { 0.0 }),
504                _padding: 0,
505            })
506        }
507    }
508}
509
510impl PxToWr for TransformStyle {
511    type AsDevice = ();
512    type AsWorld = ();
513    type AsLayout = wr::TransformStyle;
514
515    fn to_wr_device(self) -> Self::AsDevice {
516        unimplemented!()
517    }
518
519    fn to_wr_world(self) -> Self::AsWorld {
520        unimplemented!()
521    }
522
523    fn to_wr(self) -> Self::AsLayout {
524        match self {
525            TransformStyle::Flat => wr::TransformStyle::Flat,
526            TransformStyle::Preserve3D => wr::TransformStyle::Preserve3D,
527        }
528    }
529}
530
531impl PxToWr for ReferenceFrameId {
532    type AsDevice = ();
533    type AsWorld = ();
534    type AsLayout = wr::SpatialTreeItemKey;
535
536    fn to_wr_device(self) -> Self::AsDevice {
537        unimplemented!()
538    }
539
540    fn to_wr_world(self) -> Self::AsWorld {
541        unimplemented!()
542    }
543
544    fn to_wr(self) -> Self::AsLayout {
545        wr::SpatialTreeItemKey::new(self.0, self.1)
546    }
547}
548
549impl PxToWr for RepeatMode {
550    type AsDevice = ();
551    type AsWorld = ();
552    type AsLayout = wr::RepeatMode;
553
554    fn to_wr_device(self) -> Self::AsDevice {
555        unimplemented!()
556    }
557
558    fn to_wr_world(self) -> Self::AsWorld {
559        unimplemented!()
560    }
561
562    fn to_wr(self) -> Self::AsLayout {
563        use wr::RepeatMode::*;
564        match self {
565            RepeatMode::Stretch => Stretch,
566            RepeatMode::Repeat => Repeat,
567            RepeatMode::Round => Round,
568            RepeatMode::Space => Space,
569        }
570    }
571}
572
573impl PxToWr for MixBlendMode {
574    type AsDevice = ();
575    type AsWorld = ();
576    type AsLayout = wr::MixBlendMode;
577
578    fn to_wr_device(self) -> Self::AsDevice {
579        unimplemented!()
580    }
581
582    fn to_wr_world(self) -> Self::AsWorld {
583        unimplemented!()
584    }
585
586    fn to_wr(self) -> Self::AsLayout {
587        use wr::MixBlendMode::*;
588        match self {
589            MixBlendMode::Normal => Normal,
590            MixBlendMode::Multiply => Multiply,
591            MixBlendMode::Screen => Screen,
592            MixBlendMode::Overlay => Overlay,
593            MixBlendMode::Darken => Darken,
594            MixBlendMode::Lighten => Lighten,
595            MixBlendMode::ColorDodge => ColorDodge,
596            MixBlendMode::ColorBurn => ColorBurn,
597            MixBlendMode::HardLight => HardLight,
598            MixBlendMode::SoftLight => SoftLight,
599            MixBlendMode::Difference => Difference,
600            MixBlendMode::Exclusion => Exclusion,
601            MixBlendMode::Hue => Hue,
602            MixBlendMode::Saturation => Saturation,
603            MixBlendMode::Color => Color,
604            MixBlendMode::Luminosity => Luminosity,
605            MixBlendMode::PlusLighter => PlusLighter,
606        }
607    }
608}
609
610impl PxToWr for ImageRendering {
611    type AsDevice = ();
612    type AsWorld = ();
613    type AsLayout = wr::ImageRendering;
614
615    fn to_wr_device(self) -> Self::AsDevice {
616        unimplemented!()
617    }
618
619    fn to_wr_world(self) -> Self::AsWorld {
620        unimplemented!()
621    }
622
623    fn to_wr(self) -> Self::AsLayout {
624        use wr::ImageRendering::*;
625        match self {
626            ImageRendering::Auto => Auto,
627            ImageRendering::CrispEdges => CrispEdges,
628            ImageRendering::Pixelated => Pixelated,
629        }
630    }
631}
632
633impl PxToWr for AlphaType {
634    type AsDevice = ();
635    type AsWorld = ();
636    type AsLayout = wr::AlphaType;
637
638    fn to_wr_device(self) -> Self::AsDevice {
639        unimplemented!()
640    }
641
642    fn to_wr_world(self) -> Self::AsWorld {
643        unimplemented!()
644    }
645
646    fn to_wr(self) -> Self::AsLayout {
647        match self {
648            AlphaType::Alpha => wr::AlphaType::Alpha,
649            AlphaType::PremultipliedAlpha => wr::AlphaType::PremultipliedAlpha,
650        }
651    }
652}
653
654impl PxToWr for ExtendMode {
655    type AsDevice = ();
656    type AsWorld = ();
657    type AsLayout = wr::ExtendMode;
658
659    fn to_wr_device(self) -> Self::AsDevice {
660        unimplemented!()
661    }
662
663    fn to_wr_world(self) -> Self::AsWorld {
664        unimplemented!()
665    }
666
667    fn to_wr(self) -> Self::AsLayout {
668        match self {
669            ExtendMode::Clamp => wr::ExtendMode::Clamp,
670            ExtendMode::Repeat => wr::ExtendMode::Repeat,
671        }
672    }
673}
674
675impl PxToWr for LineOrientation {
676    type AsDevice = ();
677    type AsWorld = ();
678    type AsLayout = wr::LineOrientation;
679
680    fn to_wr_device(self) -> Self::AsDevice {
681        unimplemented!()
682    }
683
684    fn to_wr_world(self) -> Self::AsWorld {
685        unimplemented!()
686    }
687
688    fn to_wr(self) -> Self::AsLayout {
689        match self {
690            LineOrientation::Vertical => wr::LineOrientation::Vertical,
691            LineOrientation::Horizontal => wr::LineOrientation::Horizontal,
692        }
693    }
694}
695
696impl PxToWr for LineStyle {
697    type AsDevice = ();
698    type AsWorld = ();
699    type AsLayout = (wr::LineStyle, f32);
700
701    fn to_wr_device(self) -> Self::AsDevice {
702        unimplemented!()
703    }
704
705    fn to_wr_world(self) -> Self::AsWorld {
706        unimplemented!()
707    }
708
709    fn to_wr(self) -> Self::AsLayout {
710        match self {
711            LineStyle::Solid => (wr::LineStyle::Solid, 0.0),
712            LineStyle::Dotted => (wr::LineStyle::Dotted, 0.0),
713            LineStyle::Dashed => (wr::LineStyle::Dashed, 0.0),
714            LineStyle::Wavy(t) => (wr::LineStyle::Wavy, t),
715        }
716    }
717}
718
719impl PxToWr for FrameValueId {
720    type AsDevice = ();
721    type AsWorld = ();
722    type AsLayout = wr::PropertyBindingId;
723
724    fn to_wr_device(self) -> Self::AsDevice {
725        unimplemented!()
726    }
727
728    fn to_wr_world(self) -> Self::AsWorld {
729        unimplemented!()
730    }
731
732    fn to_wr(self) -> Self::AsLayout {
733        wr::PropertyBindingId::new(self.get())
734    }
735}