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
14pub trait PxToWr {
18 type AsLayout;
20 type AsDevice;
22 type AsWorld;
24
25 fn to_wr_device(self) -> Self::AsDevice;
27
28 fn to_wr_world(self) -> Self::AsWorld;
30
31 fn to_wr(self) -> Self::AsLayout;
33}
34
35pub trait WrToPx {
37 type AsPx;
39
40 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 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
275impl 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}
295impl 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 _ => wr::FilterOp::Identity,
353 }
354 }
355}
356
357impl PxToWr for BorderSide {
358 type AsDevice = ();
359 type AsWorld = ();
360 type AsLayout = wr::BorderSide;
361
362 fn to_wr_device(self) -> Self::AsDevice {
363 unimplemented!()
364 }
365
366 fn to_wr_world(self) -> Self::AsWorld {
367 unimplemented!()
368 }
369
370 fn to_wr(self) -> Self::AsLayout {
371 wr::BorderSide {
372 color: self.color.to_wr(),
373 style: self.style.to_wr(),
374 }
375 }
376}
377
378impl PxToWr for BorderStyle {
379 type AsDevice = ();
380 type AsWorld = ();
381 type AsLayout = wr::BorderStyle;
382
383 fn to_wr_device(self) -> Self::AsDevice {
384 unimplemented!()
385 }
386
387 fn to_wr_world(self) -> Self::AsWorld {
388 unimplemented!()
389 }
390
391 fn to_wr(self) -> Self::AsLayout {
392 match self {
393 BorderStyle::None => wr::BorderStyle::None,
394 BorderStyle::Solid => wr::BorderStyle::Solid,
395 BorderStyle::Double => wr::BorderStyle::Double,
396 BorderStyle::Dotted => wr::BorderStyle::Dotted,
397 BorderStyle::Dashed => wr::BorderStyle::Dashed,
398 BorderStyle::Hidden => wr::BorderStyle::Hidden,
399 BorderStyle::Groove => wr::BorderStyle::Groove,
400 BorderStyle::Ridge => wr::BorderStyle::Ridge,
401 BorderStyle::Inset => wr::BorderStyle::Inset,
402 BorderStyle::Outset => wr::BorderStyle::Outset,
403 _ => wr::BorderStyle::None,
404 }
405 }
406}
407
408impl<T: PxToWr> PxToWr for FrameValue<T> {
409 type AsDevice = ();
410 type AsWorld = ();
411 type AsLayout = wr::PropertyBinding<T::AsLayout>;
412
413 fn to_wr_device(self) -> Self::AsDevice {
414 unimplemented!()
415 }
416
417 fn to_wr_world(self) -> Self::AsWorld {
418 unimplemented!()
419 }
420
421 fn to_wr(self) -> Self::AsLayout {
422 match self {
423 FrameValue::Bind {
424 id,
425 value,
426 animating: true,
427 } => wr::PropertyBinding::Binding(
428 wr::PropertyBindingKey {
429 id: id.to_wr(),
430 _phantom: std::marker::PhantomData,
431 },
432 value.to_wr(),
433 ),
434 FrameValue::Bind {
435 value, animating: false, ..
436 } => wr::PropertyBinding::Value(value.to_wr()),
437 FrameValue::Value(value) => wr::PropertyBinding::Value(value.to_wr()),
438 _ => unimplemented!(),
439 }
440 }
441}
442
443impl<T: PxToWr> PxToWr for FrameValueUpdate<T> {
444 type AsDevice = ();
445 type AsWorld = ();
446 type AsLayout = Option<wr::PropertyValue<T::AsLayout>>;
447
448 fn to_wr_device(self) -> Self::AsDevice {
449 unimplemented!()
450 }
451
452 fn to_wr_world(self) -> Self::AsWorld {
453 unimplemented!()
454 }
455
456 fn to_wr(self) -> Self::AsLayout
457 where
458 T: PxToWr,
459 {
460 if self.animating {
461 Some(wr::PropertyValue {
462 key: wr::PropertyBindingKey {
463 id: self.id.to_wr(),
464 _phantom: std::marker::PhantomData,
465 },
466 value: self.value.to_wr(),
467 })
468 } else {
469 None
470 }
471 }
472}
473
474impl PxToWr for FontOptions {
475 type AsDevice = ();
476 type AsWorld = Option<wr::GlyphOptions>;
477 type AsLayout = Option<wr::FontInstanceOptions>;
478
479 fn to_wr_device(self) -> Self::AsDevice {
480 unimplemented!()
481 }
482
483 fn to_wr_world(self) -> Self::AsWorld {
484 self.to_wr().map(|o| wr::GlyphOptions {
485 render_mode: o.render_mode,
486 flags: o.flags,
487 })
488 }
489
490 fn to_wr(self) -> Self::AsLayout {
491 if self == FontOptions::default() {
492 None
493 } else {
494 Some(wr::FontInstanceOptions {
495 render_mode: match self.aa {
496 FontAntiAliasing::Default => wr::FontRenderMode::Subpixel,
497 FontAntiAliasing::Subpixel => wr::FontRenderMode::Subpixel,
498 FontAntiAliasing::Alpha => wr::FontRenderMode::Alpha,
499 FontAntiAliasing::Mono => wr::FontRenderMode::Mono,
500 _ => wr::FontRenderMode::default(),
501 },
502 flags: if self.synthetic_bold {
503 wr::FontInstanceFlags::SYNTHETIC_BOLD
504 } else {
505 wr::FontInstanceFlags::empty()
506 },
507 synthetic_italics: wr::SyntheticItalics::from_degrees(if self.synthetic_oblique { 14.0 } else { 0.0 }),
508 _padding: 0,
509 })
510 }
511 }
512}
513
514impl PxToWr for TransformStyle {
515 type AsDevice = ();
516 type AsWorld = ();
517 type AsLayout = wr::TransformStyle;
518
519 fn to_wr_device(self) -> Self::AsDevice {
520 unimplemented!()
521 }
522
523 fn to_wr_world(self) -> Self::AsWorld {
524 unimplemented!()
525 }
526
527 fn to_wr(self) -> Self::AsLayout {
528 match self {
529 TransformStyle::Flat => wr::TransformStyle::Flat,
530 TransformStyle::Preserve3D => wr::TransformStyle::Preserve3D,
531 }
532 }
533}
534
535impl PxToWr for ReferenceFrameId {
536 type AsDevice = ();
537 type AsWorld = ();
538 type AsLayout = wr::SpatialTreeItemKey;
539
540 fn to_wr_device(self) -> Self::AsDevice {
541 unimplemented!()
542 }
543
544 fn to_wr_world(self) -> Self::AsWorld {
545 unimplemented!()
546 }
547
548 fn to_wr(self) -> Self::AsLayout {
549 wr::SpatialTreeItemKey::new(self.0, self.1)
550 }
551}
552
553impl PxToWr for RepeatMode {
554 type AsDevice = ();
555 type AsWorld = ();
556 type AsLayout = wr::RepeatMode;
557
558 fn to_wr_device(self) -> Self::AsDevice {
559 unimplemented!()
560 }
561
562 fn to_wr_world(self) -> Self::AsWorld {
563 unimplemented!()
564 }
565
566 fn to_wr(self) -> Self::AsLayout {
567 use wr::RepeatMode::*;
568 match self {
569 RepeatMode::Stretch => Stretch,
570 RepeatMode::Repeat => Repeat,
571 RepeatMode::Round => Round,
572 RepeatMode::Space => Space,
573 }
574 }
575}
576
577impl PxToWr for MixBlendMode {
578 type AsDevice = ();
579 type AsWorld = ();
580 type AsLayout = wr::MixBlendMode;
581
582 fn to_wr_device(self) -> Self::AsDevice {
583 unimplemented!()
584 }
585
586 fn to_wr_world(self) -> Self::AsWorld {
587 unimplemented!()
588 }
589
590 fn to_wr(self) -> Self::AsLayout {
591 use wr::MixBlendMode::*;
592 match self {
593 MixBlendMode::Normal => Normal,
594 MixBlendMode::Multiply => Multiply,
595 MixBlendMode::Screen => Screen,
596 MixBlendMode::Overlay => Overlay,
597 MixBlendMode::Darken => Darken,
598 MixBlendMode::Lighten => Lighten,
599 MixBlendMode::ColorDodge => ColorDodge,
600 MixBlendMode::ColorBurn => ColorBurn,
601 MixBlendMode::HardLight => HardLight,
602 MixBlendMode::SoftLight => SoftLight,
603 MixBlendMode::Difference => Difference,
604 MixBlendMode::Exclusion => Exclusion,
605 MixBlendMode::Hue => Hue,
606 MixBlendMode::Saturation => Saturation,
607 MixBlendMode::Color => Color,
608 MixBlendMode::Luminosity => Luminosity,
609 MixBlendMode::PlusLighter => PlusLighter,
610 _ => Normal,
611 }
612 }
613}
614
615impl PxToWr for ImageRendering {
616 type AsDevice = ();
617 type AsWorld = ();
618 type AsLayout = wr::ImageRendering;
619
620 fn to_wr_device(self) -> Self::AsDevice {
621 unimplemented!()
622 }
623
624 fn to_wr_world(self) -> Self::AsWorld {
625 unimplemented!()
626 }
627
628 fn to_wr(self) -> Self::AsLayout {
629 use wr::ImageRendering::*;
630 match self {
631 ImageRendering::Auto => Auto,
632 ImageRendering::CrispEdges => CrispEdges,
633 ImageRendering::Pixelated => Pixelated,
634 _ => Auto,
635 }
636 }
637}
638
639impl PxToWr for AlphaType {
640 type AsDevice = ();
641 type AsWorld = ();
642 type AsLayout = wr::AlphaType;
643
644 fn to_wr_device(self) -> Self::AsDevice {
645 unimplemented!()
646 }
647
648 fn to_wr_world(self) -> Self::AsWorld {
649 unimplemented!()
650 }
651
652 fn to_wr(self) -> Self::AsLayout {
653 match self {
654 AlphaType::Alpha => wr::AlphaType::Alpha,
655 AlphaType::PremultipliedAlpha => wr::AlphaType::PremultipliedAlpha,
656 }
657 }
658}
659
660impl PxToWr for ExtendMode {
661 type AsDevice = ();
662 type AsWorld = ();
663 type AsLayout = wr::ExtendMode;
664
665 fn to_wr_device(self) -> Self::AsDevice {
666 unimplemented!()
667 }
668
669 fn to_wr_world(self) -> Self::AsWorld {
670 unimplemented!()
671 }
672
673 fn to_wr(self) -> Self::AsLayout {
674 match self {
675 ExtendMode::Clamp => wr::ExtendMode::Clamp,
676 ExtendMode::Repeat => wr::ExtendMode::Repeat,
677 }
678 }
679}
680
681impl PxToWr for LineOrientation {
682 type AsDevice = ();
683 type AsWorld = ();
684 type AsLayout = wr::LineOrientation;
685
686 fn to_wr_device(self) -> Self::AsDevice {
687 unimplemented!()
688 }
689
690 fn to_wr_world(self) -> Self::AsWorld {
691 unimplemented!()
692 }
693
694 fn to_wr(self) -> Self::AsLayout {
695 match self {
696 LineOrientation::Vertical => wr::LineOrientation::Vertical,
697 LineOrientation::Horizontal => wr::LineOrientation::Horizontal,
698 }
699 }
700}
701
702impl PxToWr for LineStyle {
703 type AsDevice = ();
704 type AsWorld = ();
705 type AsLayout = (wr::LineStyle, f32);
706
707 fn to_wr_device(self) -> Self::AsDevice {
708 unimplemented!()
709 }
710
711 fn to_wr_world(self) -> Self::AsWorld {
712 unimplemented!()
713 }
714
715 fn to_wr(self) -> Self::AsLayout {
716 match self {
717 LineStyle::Solid => (wr::LineStyle::Solid, 0.0),
718 LineStyle::Dotted => (wr::LineStyle::Dotted, 0.0),
719 LineStyle::Dashed => (wr::LineStyle::Dashed, 0.0),
720 LineStyle::Wavy(t) => (wr::LineStyle::Wavy, t),
721 _ => (wr::LineStyle::Solid, 0.0),
722 }
723 }
724}
725
726impl PxToWr for FrameValueId {
727 type AsDevice = ();
728 type AsWorld = ();
729 type AsLayout = wr::PropertyBindingId;
730
731 fn to_wr_device(self) -> Self::AsDevice {
732 unimplemented!()
733 }
734
735 fn to_wr_world(self) -> Self::AsWorld {
736 unimplemented!()
737 }
738
739 fn to_wr(self) -> Self::AsLayout {
740 wr::PropertyBindingId::new(self.get())
741 }
742}