1#[derive(Copy, Default, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2#[repr(C)]
3pub struct LogicalRect {
4 pub origin: LogicalPosition,
5 pub size: LogicalSize,
6}
7
8impl core::fmt::Debug for LogicalRect {
9 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
10 write!(f, "{} @ {}", self.size, self.origin)
11 }
12}
13
14impl core::fmt::Display for LogicalRect {
15 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
16 write!(f, "{} @ {}", self.size, self.origin)
17 }
18}
19
20impl LogicalRect {
21 pub const fn zero() -> Self {
22 Self::new(LogicalPosition::zero(), LogicalSize::zero())
23 }
24 pub const fn new(origin: LogicalPosition, size: LogicalSize) -> Self {
25 Self { origin, size }
26 }
27
28 #[inline]
29 pub fn scale_for_dpi(&mut self, scale_factor: f32) {
30 self.origin.x *= scale_factor;
31 self.origin.y *= scale_factor;
32 self.size.width *= scale_factor;
33 self.size.height *= scale_factor;
34 }
35
36 #[inline(always)]
37 pub fn max_x(&self) -> f32 {
38 self.origin.x + self.size.width
39 }
40 #[inline(always)]
41 pub fn min_x(&self) -> f32 {
42 self.origin.x
43 }
44 #[inline(always)]
45 pub fn max_y(&self) -> f32 {
46 self.origin.y + self.size.height
47 }
48 #[inline(always)]
49 pub fn min_y(&self) -> f32 {
50 self.origin.y
51 }
52
53 #[inline]
55 pub fn intersects(&self, other: Self) -> bool {
56 if self.max_x() <= other.min_x() || other.max_x() <= self.min_x() {
58 return false;
59 }
60
61 if self.max_y() <= other.min_y() || other.max_y() <= self.min_y() {
63 return false;
64 }
65
66 true
68 }
69
70 #[inline]
72 pub fn contains(&self, point: LogicalPosition) -> bool {
73 point.x >= self.min_x()
74 && point.x < self.max_x()
75 && point.y >= self.min_y()
76 && point.y < self.max_y()
77 }
78
79 #[inline]
81 pub fn union<I: Iterator<Item = Self>>(mut rects: I) -> Option<Self> {
82 let first = rects.next()?;
83
84 let mut max_width = first.size.width;
85 let mut max_height = first.size.height;
86 let mut min_x = first.origin.x;
87 let mut min_y = first.origin.y;
88
89 while let Some(Self {
90 origin: LogicalPosition { x, y },
91 size: LogicalSize { width, height },
92 }) = rects.next()
93 {
94 let cur_lower_right_x = x + width;
95 let cur_lower_right_y = y + height;
96 max_width = max_width.max(cur_lower_right_x - min_x);
97 max_height = max_height.max(cur_lower_right_y - min_y);
98 min_x = min_x.min(x);
99 min_y = min_y.min(y);
100 }
101
102 Some(Self {
103 origin: LogicalPosition { x: min_x, y: min_y },
104 size: LogicalSize {
105 width: max_width,
106 height: max_height,
107 },
108 })
109 }
110
111 #[inline]
115 pub fn hit_test(&self, other: &LogicalPosition) -> Option<LogicalPosition> {
116 let dx_left_edge = other.x - self.min_x();
117 let dx_right_edge = self.max_x() - other.x;
118 let dy_top_edge = other.y - self.min_y();
119 let dy_bottom_edge = self.max_y() - other.y;
120 if dx_left_edge > 0.0 && dx_right_edge > 0.0 && dy_top_edge > 0.0 && dy_bottom_edge > 0.0 {
121 Some(LogicalPosition::new(dx_left_edge, dy_top_edge))
122 } else {
123 None
124 }
125 }
126
127 pub fn to_layout_rect(&self) -> LayoutRect {
128 LayoutRect {
129 origin: LayoutPoint::new(
130 libm::roundf(self.origin.x) as isize,
131 libm::roundf(self.origin.y) as isize,
132 ),
133 size: LayoutSize::new(
134 libm::roundf(self.size.width) as isize,
135 libm::roundf(self.size.height) as isize,
136 ),
137 }
138 }
139}
140
141impl_vec!(
142 LogicalRect,
143 LogicalRectVec,
144 LogicalRectVecDestructor,
145 LogicalRectVecDestructorType
146);
147impl_vec_clone!(LogicalRect, LogicalRectVec, LogicalRectVecDestructor);
148impl_vec_debug!(LogicalRect, LogicalRectVec);
149impl_vec_partialeq!(LogicalRect, LogicalRectVec);
150impl_vec_partialord!(LogicalRect, LogicalRectVec);
151impl_vec_ord!(LogicalRect, LogicalRectVec);
152impl_vec_hash!(LogicalRect, LogicalRectVec);
153impl_vec_eq!(LogicalRect, LogicalRectVec);
154
155use core::{
156 cmp::Ordering,
157 hash::{Hash, Hasher},
158 ops::{self, AddAssign, SubAssign},
159};
160
161use azul_css::props::{
162 basic::{LayoutPoint, LayoutRect, LayoutSize},
163 layout::LayoutWritingMode,
164};
165
166#[derive(Default, Copy, Clone, PartialEq, PartialOrd)]
167#[repr(C)]
168pub struct LogicalPosition {
169 pub x: f32,
170 pub y: f32,
171}
172
173impl LogicalPosition {
174 pub fn scale_for_dpi(&mut self, scale_factor: f32) {
175 self.x *= scale_factor;
176 self.y *= scale_factor;
177 }
178}
179
180impl SubAssign<LogicalPosition> for LogicalPosition {
181 fn sub_assign(&mut self, other: LogicalPosition) {
182 self.x -= other.x;
183 self.y -= other.y;
184 }
185}
186
187impl AddAssign<LogicalPosition> for LogicalPosition {
188 fn add_assign(&mut self, other: LogicalPosition) {
189 self.x += other.x;
190 self.y += other.y;
191 }
192}
193
194impl core::fmt::Debug for LogicalPosition {
195 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
196 write!(f, "({}, {})", self.x, self.y)
197 }
198}
199
200impl core::fmt::Display for LogicalPosition {
201 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
202 write!(f, "({}, {})", self.x, self.y)
203 }
204}
205
206impl ops::Add for LogicalPosition {
207 type Output = Self;
208
209 #[inline]
210 fn add(self, other: Self) -> Self {
211 Self {
212 x: self.x + other.x,
213 y: self.y + other.y,
214 }
215 }
216}
217
218impl ops::Sub for LogicalPosition {
219 type Output = Self;
220
221 #[inline]
222 fn sub(self, other: Self) -> Self {
223 Self {
224 x: self.x - other.x,
225 y: self.y - other.y,
226 }
227 }
228}
229
230const DECIMAL_MULTIPLIER: f32 = 1000.0;
231
232impl_option!(
233 LogicalPosition,
234 OptionLogicalPosition,
235 [Debug, Copy, Clone, PartialEq, PartialOrd]
236);
237
238impl Ord for LogicalPosition {
239 fn cmp(&self, other: &LogicalPosition) -> Ordering {
240 let self_x = (self.x * DECIMAL_MULTIPLIER) as usize;
241 let self_y = (self.y * DECIMAL_MULTIPLIER) as usize;
242 let other_x = (other.x * DECIMAL_MULTIPLIER) as usize;
243 let other_y = (other.y * DECIMAL_MULTIPLIER) as usize;
244 self_x.cmp(&other_x).then(self_y.cmp(&other_y))
245 }
246}
247
248impl Eq for LogicalPosition {}
249
250impl Hash for LogicalPosition {
251 fn hash<H>(&self, state: &mut H)
252 where
253 H: Hasher,
254 {
255 let self_x = (self.x * DECIMAL_MULTIPLIER) as usize;
256 let self_y = (self.y * DECIMAL_MULTIPLIER) as usize;
257 self_x.hash(state);
258 self_y.hash(state);
259 }
260}
261
262impl LogicalPosition {
263 pub fn main(&self, wm: LayoutWritingMode) -> f32 {
264 match wm {
265 LayoutWritingMode::HorizontalTb => self.y,
266 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.x,
267 }
268 }
269
270 pub fn cross(&self, wm: LayoutWritingMode) -> f32 {
271 match wm {
272 LayoutWritingMode::HorizontalTb => self.x,
273 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.y,
274 }
275 }
276
277 pub fn from_main_cross(main: f32, cross: f32, wm: LayoutWritingMode) -> Self {
279 match wm {
280 LayoutWritingMode::HorizontalTb => Self::new(cross, main),
281 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self::new(main, cross),
282 }
283 }
284}
285
286#[derive(Default, Copy, Clone, PartialEq, PartialOrd)]
287#[repr(C)]
288pub struct LogicalSize {
289 pub width: f32,
290 pub height: f32,
291}
292
293impl LogicalSize {
294 pub fn scale_for_dpi(&mut self, scale_factor: f32) -> Self {
295 self.width *= scale_factor;
296 self.height *= scale_factor;
297 *self
298 }
299
300 pub fn from_main_cross(main: f32, cross: f32, wm: LayoutWritingMode) -> Self {
302 match wm {
303 LayoutWritingMode::HorizontalTb => Self::new(cross, main),
304 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self::new(main, cross),
305 }
306 }
307}
308
309impl core::fmt::Debug for LogicalSize {
310 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
311 write!(f, "{}x{}", self.width, self.height)
312 }
313}
314
315impl core::fmt::Display for LogicalSize {
316 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
317 write!(f, "{}x{}", self.width, self.height)
318 }
319}
320
321impl_option!(
322 LogicalSize,
323 OptionLogicalSize,
324 [Debug, Copy, Clone, PartialEq, PartialOrd]
325);
326
327impl_option!(
328 LogicalRect,
329 OptionLogicalRect,
330 [Debug, Copy, Clone, PartialEq, PartialOrd]
331);
332
333impl Ord for LogicalSize {
334 fn cmp(&self, other: &LogicalSize) -> Ordering {
335 let self_width = (self.width * DECIMAL_MULTIPLIER) as usize;
336 let self_height = (self.height * DECIMAL_MULTIPLIER) as usize;
337 let other_width = (other.width * DECIMAL_MULTIPLIER) as usize;
338 let other_height = (other.height * DECIMAL_MULTIPLIER) as usize;
339 self_width
340 .cmp(&other_width)
341 .then(self_height.cmp(&other_height))
342 }
343}
344
345impl Eq for LogicalSize {}
346
347impl Hash for LogicalSize {
348 fn hash<H>(&self, state: &mut H)
349 where
350 H: Hasher,
351 {
352 let self_width = (self.width * DECIMAL_MULTIPLIER) as usize;
353 let self_height = (self.height * DECIMAL_MULTIPLIER) as usize;
354 self_width.hash(state);
355 self_height.hash(state);
356 }
357}
358
359impl LogicalSize {
360 pub fn main(&self, wm: LayoutWritingMode) -> f32 {
361 match wm {
362 LayoutWritingMode::HorizontalTb => self.height,
363 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.width,
364 }
365 }
366
367 pub fn cross(&self, wm: LayoutWritingMode) -> f32 {
368 match wm {
369 LayoutWritingMode::HorizontalTb => self.width,
370 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => self.height,
371 }
372 }
373
374 pub fn with_main(self, wm: LayoutWritingMode, value: f32) -> Self {
376 match wm {
377 LayoutWritingMode::HorizontalTb => Self {
378 height: value,
379 ..self
380 },
381 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self {
382 width: value,
383 ..self
384 },
385 }
386 }
387
388 pub fn with_cross(self, wm: LayoutWritingMode, value: f32) -> Self {
389 match wm {
390 LayoutWritingMode::HorizontalTb => Self {
391 width: value,
392 ..self
393 },
394 LayoutWritingMode::VerticalRl | LayoutWritingMode::VerticalLr => Self {
395 height: value,
396 ..self
397 },
398 }
399 }
400}
401
402#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
403#[repr(C)]
404pub struct PhysicalPosition<T> {
405 pub x: T,
406 pub y: T,
407}
408
409impl<T: ::core::fmt::Display> ::core::fmt::Debug for PhysicalPosition<T> {
410 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
411 write!(f, "({}, {})", self.x, self.y)
412 }
413}
414
415pub type PhysicalPositionI32 = PhysicalPosition<i32>;
416impl_option!(
417 PhysicalPositionI32,
418 OptionPhysicalPositionI32,
419 [Debug, Copy, Clone, PartialEq, PartialOrd]
420);
421
422#[derive(Ord, Hash, Eq, Copy, Clone, PartialEq, PartialOrd)]
423#[repr(C)]
424pub struct PhysicalSize<T> {
425 pub width: T,
426 pub height: T,
427}
428
429impl<T: ::core::fmt::Display> ::core::fmt::Debug for PhysicalSize<T> {
430 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
431 write!(f, "{}x{}", self.width, self.height)
432 }
433}
434
435pub type PhysicalSizeU32 = PhysicalSize<u32>;
436impl_option!(
437 PhysicalSizeU32,
438 OptionPhysicalSizeU32,
439 [Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash]
440);
441pub type PhysicalSizeF32 = PhysicalSize<f32>;
442impl_option!(
443 PhysicalSizeF32,
444 OptionPhysicalSizeF32,
445 [Debug, Copy, Clone, PartialEq, PartialOrd]
446);
447
448impl LogicalPosition {
449 #[inline(always)]
450 pub const fn new(x: f32, y: f32) -> Self {
451 Self { x, y }
452 }
453 #[inline(always)]
454 pub const fn zero() -> Self {
455 Self::new(0.0, 0.0)
456 }
457 #[inline(always)]
458 pub fn to_physical(self, hidpi_factor: f32) -> PhysicalPosition<u32> {
459 PhysicalPosition {
460 x: (self.x * hidpi_factor) as u32,
461 y: (self.y * hidpi_factor) as u32,
462 }
463 }
464}
465
466impl<T> PhysicalPosition<T> {
467 #[inline(always)]
468 pub const fn new(x: T, y: T) -> Self {
469 Self { x, y }
470 }
471}
472
473impl PhysicalPosition<i32> {
474 #[inline(always)]
475 pub const fn zero() -> Self {
476 Self::new(0, 0)
477 }
478 #[inline(always)]
479 pub fn to_logical(self, hidpi_factor: f32) -> LogicalPosition {
480 LogicalPosition {
481 x: self.x as f32 / hidpi_factor,
482 y: self.y as f32 / hidpi_factor,
483 }
484 }
485}
486
487impl PhysicalPosition<f64> {
488 #[inline(always)]
489 pub const fn zero() -> Self {
490 Self::new(0.0, 0.0)
491 }
492 #[inline(always)]
493 pub fn to_logical(self, hidpi_factor: f32) -> LogicalPosition {
494 LogicalPosition {
495 x: self.x as f32 / hidpi_factor,
496 y: self.y as f32 / hidpi_factor,
497 }
498 }
499}
500
501impl LogicalSize {
502 #[inline(always)]
503 pub const fn new(width: f32, height: f32) -> Self {
504 Self { width, height }
505 }
506 #[inline(always)]
507 pub const fn zero() -> Self {
508 Self::new(0.0, 0.0)
509 }
510 #[inline(always)]
511 pub fn to_physical(self, hidpi_factor: f32) -> PhysicalSize<u32> {
512 PhysicalSize {
513 width: (self.width * hidpi_factor) as u32,
514 height: (self.height * hidpi_factor) as u32,
515 }
516 }
517}
518
519impl<T> PhysicalSize<T> {
520 #[inline(always)]
521 pub const fn new(width: T, height: T) -> Self {
522 Self { width, height }
523 }
524}
525
526impl PhysicalSize<u32> {
527 #[inline(always)]
528 pub const fn zero() -> Self {
529 Self::new(0, 0)
530 }
531 #[inline(always)]
532 pub fn to_logical(self, hidpi_factor: f32) -> LogicalSize {
533 LogicalSize {
534 width: self.width as f32 / hidpi_factor,
535 height: self.height as f32 / hidpi_factor,
536 }
537 }
538}
539
540#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
586#[repr(C)]
587pub enum CoordinateSpace {
588 Window,
591
592 ScrollFrame,
595
596 Parent,
598
599 ReferenceFrame,
601}
602
603impl CoordinateSpace {
604 pub const fn description(&self) -> &'static str {
606 match self {
607 CoordinateSpace::Window => "Absolute window coordinates (layout engine output)",
608 CoordinateSpace::ScrollFrame => "Relative to scroll frame origin (for WebRender scroll nodes)",
609 CoordinateSpace::Parent => "Relative to parent node origin",
610 CoordinateSpace::ReferenceFrame => "Relative to CSS transform origin",
611 }
612 }
613}