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 }
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}