style/values/computed/
corner_shape.rs1use crate::derives::*;
8use crate::values::animated::{Animate, Procedure, ToAnimatedZero};
9use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
10use crate::values::generics::border::GenericCornerShapeRect;
11use std::fmt::{self, Write};
12use style_traits::{CssWriter, ToCss};
13
14#[derive(
20 Clone, Copy, Debug, MallocSizeOf, PartialEq, ToShmem, ToTyped, ToAnimatedValue, ToResolvedValue,
21)]
22#[repr(C)]
23#[typed(todo_derive_fields)]
24pub struct CornerShape {
25 pub k: f32,
27}
28
29impl CornerShape {
30 #[inline]
32 pub fn round() -> Self {
33 Self { k: 1.0 }
34 }
35 #[inline]
37 pub fn bevel() -> Self {
38 Self { k: 0.0 }
39 }
40 #[inline]
42 pub fn square() -> Self {
43 Self { k: f32::INFINITY }
44 }
45 #[inline]
47 pub fn notch() -> Self {
48 Self {
49 k: f32::NEG_INFINITY,
50 }
51 }
52 #[inline]
54 pub fn scoop() -> Self {
55 Self { k: -1.0 }
56 }
57 #[inline]
59 pub fn squircle() -> Self {
60 Self { k: 2.0 }
61 }
62
63 #[inline]
65 pub fn is_round(&self) -> bool {
66 self.k == 1.0
67 }
68}
69
70impl ToCss for CornerShape {
71 fn to_css<W: Write>(&self, dest: &mut CssWriter<W>) -> fmt::Result {
72 dest.write_str("superellipse(")?;
73 if self.k == f32::INFINITY {
74 dest.write_str("infinity")?;
75 } else if self.k == f32::NEG_INFINITY {
76 dest.write_str("-infinity")?;
77 } else {
78 self.k.to_css(dest)?;
79 }
80 dest.write_char(')')
81 }
82}
83
84fn s_to_interpolation_value(s: f32) -> f32 {
88 if s == f32::NEG_INFINITY {
89 return 0.0;
90 }
91 if s == f32::INFINITY {
92 return 1.0;
93 }
94 let k = 0.5f32.powf(s.abs());
95 let convex_half_corner = 0.5f32.powf(k);
96 if s < 0.0 {
97 1.0 - convex_half_corner
98 } else {
99 convex_half_corner
100 }
101}
102
103fn interpolation_value_to_s(v: f32) -> f32 {
105 if v <= 0.0 {
106 return f32::NEG_INFINITY;
107 }
108 if v >= 1.0 {
109 return f32::INFINITY;
110 }
111 let convex_half_corner = if v < 0.5 { 1.0 - v } else { v };
112 let k = 0.5f32.ln() / convex_half_corner.ln();
113 let s = k.log2();
114 if v < 0.5 {
115 -s
116 } else {
117 s
118 }
119}
120
121impl Animate for CornerShape {
122 fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
123 let a = s_to_interpolation_value(self.k);
124 let b = s_to_interpolation_value(other.k);
125 let interp = a.animate(&b, procedure)?;
126 Ok(CornerShape {
127 k: interpolation_value_to_s(interp),
128 })
129 }
130}
131
132impl ComputeSquaredDistance for CornerShape {
133 fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
134 let a = s_to_interpolation_value(self.k);
135 let b = s_to_interpolation_value(other.k);
136 a.compute_squared_distance(&b)
137 }
138}
139
140impl ToAnimatedZero for CornerShape {
141 fn to_animated_zero(&self) -> Result<Self, ()> {
142 Ok(CornerShape::round())
143 }
144}
145
146pub type CornerShapeRect = GenericCornerShapeRect<CornerShape>;
148
149impl CornerShapeRect {
150 #[inline]
152 pub fn round_all() -> Self {
153 Self::all(CornerShape::round())
154 }
155}