1use std::convert::From;
6use std::fmt;
7use std::ops::{Add, AddAssign, Neg, Sub, SubAssign};
8use std::sync::atomic::{AtomicI32, Ordering};
9
10use app_units::Au;
11use euclid::{Point2D, Size2D};
12use malloc_size_of_derive::MallocSizeOf;
13use style::Zero;
14use style::logical_geometry::{BlockFlowDirection, InlineBaseDirection, WritingMode};
15use style::values::computed::{CSSPixelLength, LengthPercentage};
16use style::values::generics::length::GenericLengthPercentageOrAuto as AutoOr;
17use style_traits::CSSPixel;
18
19use crate::ContainingBlock;
20use crate::sizing::Size;
21
22pub type PhysicalPoint<U> = euclid::Point2D<U, CSSPixel>;
23pub type PhysicalSize<U> = euclid::Size2D<U, CSSPixel>;
24pub type PhysicalVec<U> = euclid::Vector2D<U, CSSPixel>;
25pub type PhysicalRect<U> = euclid::Rect<U, CSSPixel>;
26pub type PhysicalSides<U> = euclid::SideOffsets2D<U, CSSPixel>;
27pub type AuOrAuto = AutoOr<Au>;
28pub type LengthPercentageOrAuto<'a> = AutoOr<&'a LengthPercentage>;
29
30#[derive(Clone, Copy, MallocSizeOf, PartialEq)]
31pub struct LogicalVec2<T> {
32 pub inline: T,
33 pub block: T,
34}
35
36#[derive(Clone, Copy, MallocSizeOf)]
37pub struct LogicalRect<T> {
38 pub start_corner: LogicalVec2<T>,
39 pub size: LogicalVec2<T>,
40}
41
42#[derive(Clone, Copy, Debug, Default)]
43pub struct LogicalSides<T> {
44 pub inline_start: T,
45 pub inline_end: T,
46 pub block_start: T,
47 pub block_end: T,
48}
49
50#[derive(Clone, Copy, Debug, Default, MallocSizeOf, PartialEq)]
51pub(crate) struct LogicalSides1D<T> {
52 pub start: T,
53 pub end: T,
54}
55
56impl<T> LogicalSides1D<T> {
57 pub(crate) fn map<U>(&self, f: impl Fn(&T) -> U) -> LogicalSides1D<U> {
58 LogicalSides1D {
59 start: f(&self.start),
60 end: f(&self.end),
61 }
62 }
63}
64
65impl LogicalSides1D<AutoOr<&LengthPercentage>> {
66 pub(crate) fn percentages_relative_to(&self, basis: Au) -> LogicalSides1D<AutoOr<Au>> {
67 self.map(|value| value.map(|length_percentage| length_percentage.to_used_value(basis)))
68 }
69}
70
71impl<T: fmt::Debug> fmt::Debug for LogicalVec2<T> {
72 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73 f.write_str("Vec2 { i: ")?;
75 self.inline.fmt(f)?;
76 f.write_str(", b: ")?;
77 self.block.fmt(f)?;
78 f.write_str(" }")
79 }
80}
81
82impl<T: Default> Default for LogicalVec2<T> {
83 fn default() -> Self {
84 Self {
85 inline: T::default(),
86 block: T::default(),
87 }
88 }
89}
90
91impl<T: Copy> From<T> for LogicalVec2<T> {
92 fn from(value: T) -> Self {
93 Self {
94 inline: value,
95 block: value,
96 }
97 }
98}
99
100impl<T> LogicalVec2<T> {
101 pub fn map_inline_and_block_axes<U>(
102 &self,
103 inline_f: impl FnOnce(&T) -> U,
104 block_f: impl FnOnce(&T) -> U,
105 ) -> LogicalVec2<U> {
106 LogicalVec2 {
107 inline: inline_f(&self.inline),
108 block: block_f(&self.block),
109 }
110 }
111}
112
113impl<T: Clone> LogicalVec2<Size<T>> {
114 pub fn map_inline_and_block_sizes<U>(
115 &self,
116 inline_f: impl FnOnce(T) -> U,
117 block_f: impl FnOnce(T) -> U,
118 ) -> LogicalVec2<Size<U>> {
119 self.map_inline_and_block_axes(|size| size.map(inline_f), |size| size.map(block_f))
120 }
121}
122
123impl<T: Clone> LogicalVec2<T> {
124 pub fn from_physical_size(physical_size: &PhysicalSize<T>, mode: WritingMode) -> Self {
125 let (i, b) = if mode.is_horizontal() {
127 (&physical_size.width, &physical_size.height)
128 } else {
129 (&physical_size.height, &physical_size.width)
130 };
131 LogicalVec2 {
132 inline: i.clone(),
133 block: b.clone(),
134 }
135 }
136
137 pub fn map<U>(&self, f: impl Fn(&T) -> U) -> LogicalVec2<U> {
138 LogicalVec2 {
139 inline: f(&self.inline),
140 block: f(&self.block),
141 }
142 }
143
144 pub(crate) fn map_with<U, V>(
145 &self,
146 other: &LogicalVec2<U>,
147 f: impl Fn(&T, &U) -> V,
148 ) -> LogicalVec2<V> {
149 LogicalVec2 {
150 inline: f(&self.inline, &other.inline),
151 block: f(&self.block, &other.block),
152 }
153 }
154}
155
156impl<T: Add<Output = T> + Copy> Add<LogicalVec2<T>> for LogicalVec2<T> {
157 type Output = LogicalVec2<T>;
158 fn add(self, other: Self) -> Self::Output {
159 LogicalVec2 {
160 inline: self.inline + other.inline,
161 block: self.block + other.block,
162 }
163 }
164}
165
166impl<T: Sub<Output = T> + Copy> Sub<LogicalVec2<T>> for LogicalVec2<T> {
167 type Output = LogicalVec2<T>;
168 fn sub(self, other: Self) -> Self::Output {
169 LogicalVec2 {
170 inline: self.inline - other.inline,
171 block: self.block - other.block,
172 }
173 }
174}
175
176impl<T: AddAssign<T> + Copy> AddAssign<LogicalVec2<T>> for LogicalVec2<T> {
177 fn add_assign(&mut self, other: LogicalVec2<T>) {
178 self.inline += other.inline;
179 self.block += other.block;
180 }
181}
182
183impl<T: SubAssign<T> + Copy> SubAssign<LogicalVec2<T>> for LogicalVec2<T> {
184 fn sub_assign(&mut self, other: LogicalVec2<T>) {
185 self.inline -= other.inline;
186 self.block -= other.block;
187 }
188}
189
190impl<T: Neg<Output = T> + Copy> Neg for LogicalVec2<T> {
191 type Output = LogicalVec2<T>;
192 fn neg(self) -> Self::Output {
193 Self {
194 inline: -self.inline,
195 block: -self.block,
196 }
197 }
198}
199
200impl<T: Zero> LogicalVec2<T> {
201 pub fn zero() -> Self {
202 Self {
203 inline: T::zero(),
204 block: T::zero(),
205 }
206 }
207}
208
209impl<T: Clone> LogicalVec2<AutoOr<T>> {
210 pub fn auto_is(&self, f: impl Fn() -> T) -> LogicalVec2<T> {
211 self.map(|t| t.auto_is(&f))
212 }
213}
214
215impl<T: Zero> LogicalRect<T> {
216 pub fn zero() -> Self {
217 Self {
218 start_corner: LogicalVec2::zero(),
219 size: LogicalVec2::zero(),
220 }
221 }
222}
223
224impl fmt::Debug for LogicalRect<Au> {
225 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
226 write!(
227 f,
228 "Rect(i{}×b{} @ (i{},b{}))",
229 self.size.inline.to_f32_px(),
230 self.size.block.to_f32_px(),
231 self.start_corner.inline.to_f32_px(),
232 self.start_corner.block.to_f32_px(),
233 )
234 }
235}
236
237impl<T: Clone> LogicalVec2<T> {
238 pub fn to_physical_size(&self, mode: WritingMode) -> PhysicalSize<T> {
239 let (x, y) = if mode.is_horizontal() {
241 (&self.inline, &self.block)
242 } else {
243 (&self.block, &self.inline)
244 };
245 PhysicalSize::new(x.clone(), y.clone())
246 }
247}
248
249impl<T: Copy + Neg<Output = T>> LogicalVec2<T> {
250 pub fn to_physical_vector(&self, mode: WritingMode) -> PhysicalVec<T> {
251 if mode.is_horizontal() {
252 if mode.is_bidi_ltr() {
253 PhysicalVec::new(self.inline, self.block)
254 } else {
255 PhysicalVec::new(-self.inline, self.block)
256 }
257 } else if mode.is_inline_tb() {
258 PhysicalVec::new(self.block, self.inline)
259 } else {
260 PhysicalVec::new(-self.block, self.inline)
261 }
262 }
263}
264
265impl<T: Clone> LogicalSides<T> {
266 pub fn from_physical(sides: &PhysicalSides<T>, mode: WritingMode) -> Self {
267 let block_flow = mode.block_flow_direction();
269 let (bs, be) = match mode.block_flow_direction() {
270 BlockFlowDirection::TopToBottom => (&sides.top, &sides.bottom),
271 BlockFlowDirection::RightToLeft => (&sides.right, &sides.left),
272 BlockFlowDirection::LeftToRight => (&sides.left, &sides.right),
273 };
274 use BlockFlowDirection::TopToBottom;
275 let (is, ie) = match (block_flow, mode.inline_base_direction()) {
276 (TopToBottom, InlineBaseDirection::LeftToRight) => (&sides.left, &sides.right),
277 (TopToBottom, InlineBaseDirection::RightToLeft) => (&sides.right, &sides.left),
278 (_, InlineBaseDirection::LeftToRight) => (&sides.top, &sides.bottom),
279 (_, InlineBaseDirection::RightToLeft) => (&sides.bottom, &sides.top),
280 };
281 LogicalSides {
282 inline_start: is.clone(),
283 inline_end: ie.clone(),
284 block_start: bs.clone(),
285 block_end: be.clone(),
286 }
287 }
288}
289
290impl<T> LogicalSides<T> {
291 pub fn map<U>(&self, f: impl Fn(&T) -> U) -> LogicalSides<U> {
292 LogicalSides {
293 inline_start: f(&self.inline_start),
294 inline_end: f(&self.inline_end),
295 block_start: f(&self.block_start),
296 block_end: f(&self.block_end),
297 }
298 }
299
300 pub fn map_inline_and_block_axes<U>(
301 &self,
302 inline_f: impl Fn(&T) -> U,
303 block_f: impl Fn(&T) -> U,
304 ) -> LogicalSides<U> {
305 LogicalSides {
306 inline_start: inline_f(&self.inline_start),
307 inline_end: inline_f(&self.inline_end),
308 block_start: block_f(&self.block_start),
309 block_end: block_f(&self.block_end),
310 }
311 }
312
313 pub fn inline_sum(&self) -> T::Output
314 where
315 T: Add + Copy,
316 {
317 self.inline_start + self.inline_end
318 }
319
320 pub fn block_sum(&self) -> T::Output
321 where
322 T: Add + Copy,
323 {
324 self.block_start + self.block_end
325 }
326
327 pub fn sum(&self) -> LogicalVec2<T::Output>
328 where
329 T: Add + Copy,
330 {
331 LogicalVec2 {
332 inline: self.inline_sum(),
333 block: self.block_sum(),
334 }
335 }
336
337 pub fn to_physical(&self, mode: WritingMode) -> PhysicalSides<T>
338 where
339 T: Clone,
340 {
341 let top;
342 let right;
343 let bottom;
344 let left;
345 if mode.is_vertical() {
346 if mode.is_vertical_lr() {
347 left = self.block_start.clone();
348 right = self.block_end.clone();
349 } else {
350 right = self.block_start.clone();
351 left = self.block_end.clone();
352 }
353
354 if mode.is_inline_tb() {
355 top = self.inline_start.clone();
356 bottom = self.inline_end.clone();
357 } else {
358 bottom = self.inline_start.clone();
359 top = self.inline_end.clone();
360 }
361 } else {
362 top = self.block_start.clone();
363 bottom = self.block_end.clone();
364 if mode.is_bidi_ltr() {
365 left = self.inline_start.clone();
366 right = self.inline_end.clone();
367 } else {
368 right = self.inline_start.clone();
369 left = self.inline_end.clone();
370 }
371 }
372 PhysicalSides::new(top, right, bottom, left)
373 }
374}
375
376impl<T: Copy> LogicalSides<T> {
377 pub fn start_offset(&self) -> LogicalVec2<T> {
378 LogicalVec2 {
379 inline: self.inline_start,
380 block: self.block_start,
381 }
382 }
383
384 #[inline]
385 pub(crate) fn inline_sides(&self) -> LogicalSides1D<T> {
386 LogicalSides1D::new(self.inline_start, self.inline_end)
387 }
388
389 #[inline]
390 pub(crate) fn block_sides(&self) -> LogicalSides1D<T> {
391 LogicalSides1D::new(self.block_start, self.block_end)
392 }
393}
394
395impl LogicalSides<LengthPercentage> {
396 pub fn percentages_relative_to(&self, basis: Au) -> LogicalSides<Au> {
397 self.map(|value| value.to_used_value(basis))
398 }
399}
400
401impl LogicalSides<LengthPercentageOrAuto<'_>> {
402 pub fn percentages_relative_to(&self, basis: Au) -> LogicalSides<AuOrAuto> {
403 self.map(|value| value.map(|value| value.to_used_value(basis)))
404 }
405}
406
407impl<T: Clone> LogicalSides<AutoOr<T>> {
408 pub fn auto_is(&self, f: impl Fn() -> T) -> LogicalSides<T> {
409 self.map(|s| s.auto_is(&f))
410 }
411}
412
413impl<T: Add<Output = T> + Copy> Add<LogicalSides<T>> for LogicalSides<T> {
414 type Output = LogicalSides<T>;
415
416 fn add(self, other: Self) -> Self::Output {
417 LogicalSides {
418 inline_start: self.inline_start + other.inline_start,
419 inline_end: self.inline_end + other.inline_end,
420 block_start: self.block_start + other.block_start,
421 block_end: self.block_end + other.block_end,
422 }
423 }
424}
425
426impl<T: Sub<Output = T> + Copy> Sub<LogicalSides<T>> for LogicalSides<T> {
427 type Output = LogicalSides<T>;
428
429 fn sub(self, other: Self) -> Self::Output {
430 LogicalSides {
431 inline_start: self.inline_start - other.inline_start,
432 inline_end: self.inline_end - other.inline_end,
433 block_start: self.block_start - other.block_start,
434 block_end: self.block_end - other.block_end,
435 }
436 }
437}
438
439impl<T: Neg<Output = T> + Copy> Neg for LogicalSides<T> {
440 type Output = LogicalSides<T>;
441 fn neg(self) -> Self::Output {
442 Self {
443 inline_start: -self.inline_start,
444 inline_end: -self.inline_end,
445 block_start: -self.block_start,
446 block_end: -self.block_end,
447 }
448 }
449}
450
451impl<T: Zero> LogicalSides<T> {
452 pub(crate) fn zero() -> LogicalSides<T> {
453 Self {
454 inline_start: T::zero(),
455 inline_end: T::zero(),
456 block_start: T::zero(),
457 block_end: T::zero(),
458 }
459 }
460}
461
462impl From<LogicalSides<CSSPixelLength>> for LogicalSides<Au> {
463 fn from(value: LogicalSides<CSSPixelLength>) -> Self {
464 Self {
465 inline_start: value.inline_start.into(),
466 inline_end: value.inline_end.into(),
467 block_start: value.block_start.into(),
468 block_end: value.block_end.into(),
469 }
470 }
471}
472
473impl From<LogicalSides<Au>> for LogicalSides<CSSPixelLength> {
474 fn from(value: LogicalSides<Au>) -> Self {
475 Self {
476 inline_start: value.inline_start.into(),
477 inline_end: value.inline_end.into(),
478 block_start: value.block_start.into(),
479 block_end: value.block_end.into(),
480 }
481 }
482}
483
484impl<T> LogicalSides1D<T> {
485 #[inline]
486 pub(crate) fn new(start: T, end: T) -> Self {
487 Self { start, end }
488 }
489}
490
491impl<T> LogicalSides1D<AutoOr<T>> {
492 #[inline]
493 pub(crate) fn either_specified(&self) -> bool {
494 !self.start.is_auto() || !self.end.is_auto()
495 }
496
497 #[inline]
498 pub(crate) fn either_auto(&self) -> bool {
499 self.start.is_auto() || self.end.is_auto()
500 }
501}
502
503impl<T> LogicalRect<T> {
504 pub fn max_inline_position(&self) -> T
505 where
506 T: Add<Output = T> + Copy,
507 {
508 self.start_corner.inline + self.size.inline
509 }
510
511 pub fn max_block_position(&self) -> T
512 where
513 T: Add<Output = T> + Copy,
514 {
515 self.start_corner.block + self.size.block
516 }
517
518 pub fn inflate(&self, sides: &LogicalSides<T>) -> Self
519 where
520 T: Add<Output = T> + Copy,
521 T: Sub<Output = T> + Copy,
522 {
523 Self {
524 start_corner: LogicalVec2 {
525 inline: self.start_corner.inline - sides.inline_start,
526 block: self.start_corner.block - sides.block_start,
527 },
528 size: LogicalVec2 {
529 inline: self.size.inline + sides.inline_sum(),
530 block: self.size.block + sides.block_sum(),
531 },
532 }
533 }
534
535 pub fn deflate(&self, sides: &LogicalSides<T>) -> Self
536 where
537 T: Add<Output = T> + Copy,
538 T: Sub<Output = T> + Copy,
539 {
540 LogicalRect {
541 start_corner: LogicalVec2 {
542 inline: self.start_corner.inline + sides.inline_start,
543 block: self.start_corner.block + sides.block_start,
544 },
545 size: LogicalVec2 {
546 inline: self.size.inline - sides.inline_sum(),
547 block: self.size.block - sides.block_sum(),
548 },
549 }
550 }
551}
552
553impl LogicalRect<Au> {
554 pub(crate) fn as_physical(
555 &self,
556 containing_block: Option<&ContainingBlock<'_>>,
557 ) -> PhysicalRect<Au> {
558 let mode = containing_block.map_or_else(WritingMode::horizontal_tb, |containing_block| {
559 containing_block.style.writing_mode
560 });
561 let (x, y, width, height) = if mode.is_vertical() {
562 (
564 self.start_corner.block,
565 self.start_corner.inline,
566 self.size.block,
567 self.size.inline,
568 )
569 } else {
570 let y = self.start_corner.block;
571 let x = match containing_block {
572 Some(containing_block) if !mode.is_bidi_ltr() => {
573 containing_block.size.inline - self.max_inline_position()
574 },
575 _ => self.start_corner.inline,
576 };
577 (x, y, self.size.inline, self.size.block)
578 };
579
580 PhysicalRect::new(PhysicalPoint::new(x, y), PhysicalSize::new(width, height))
581 }
582}
583
584impl From<LogicalVec2<CSSPixelLength>> for LogicalVec2<Au> {
585 fn from(value: LogicalVec2<CSSPixelLength>) -> Self {
586 LogicalVec2 {
587 inline: value.inline.into(),
588 block: value.block.into(),
589 }
590 }
591}
592
593impl From<LogicalVec2<Au>> for LogicalVec2<CSSPixelLength> {
594 fn from(value: LogicalVec2<Au>) -> Self {
595 LogicalVec2 {
596 inline: value.inline.into(),
597 block: value.block.into(),
598 }
599 }
600}
601
602impl From<LogicalRect<Au>> for LogicalRect<CSSPixelLength> {
603 fn from(value: LogicalRect<Au>) -> Self {
604 LogicalRect {
605 start_corner: value.start_corner.into(),
606 size: value.size.into(),
607 }
608 }
609}
610
611impl From<LogicalRect<CSSPixelLength>> for LogicalRect<Au> {
612 fn from(value: LogicalRect<CSSPixelLength>) -> Self {
613 LogicalRect {
614 start_corner: value.start_corner.into(),
615 size: value.size.into(),
616 }
617 }
618}
619
620pub(crate) trait ToLogical<Unit, LogicalType> {
621 fn to_logical(&self, writing_mode: WritingMode) -> LogicalType;
622}
623
624impl<Unit: Copy> ToLogical<Unit, LogicalVec2<Unit>> for PhysicalSize<Unit> {
625 fn to_logical(&self, writing_mode: WritingMode) -> LogicalVec2<Unit> {
626 LogicalVec2::from_physical_size(self, writing_mode)
627 }
628}
629
630impl<Unit: Copy> ToLogical<Unit, LogicalSides<Unit>> for PhysicalSides<Unit> {
631 fn to_logical(&self, writing_mode: WritingMode) -> LogicalSides<Unit> {
632 LogicalSides::from_physical(self, writing_mode)
633 }
634}
635
636pub(crate) trait ToLogicalWithContainingBlock<LogicalType> {
637 fn to_logical(&self, containing_block: &ContainingBlock) -> LogicalType;
638}
639
640impl ToLogicalWithContainingBlock<LogicalVec2<Au>> for PhysicalPoint<Au> {
641 fn to_logical(&self, containing_block: &ContainingBlock) -> LogicalVec2<Au> {
642 let writing_mode = containing_block.style.writing_mode;
643 if writing_mode.is_vertical() {
645 LogicalVec2 {
646 inline: self.y,
647 block: self.x,
648 }
649 } else {
650 LogicalVec2 {
651 inline: if writing_mode.is_bidi_ltr() {
652 self.x
653 } else {
654 containing_block.size.inline - self.x
655 },
656 block: self.y,
657 }
658 }
659 }
660}
661
662impl ToLogicalWithContainingBlock<LogicalRect<Au>> for PhysicalRect<Au> {
663 fn to_logical(&self, containing_block: &ContainingBlock) -> LogicalRect<Au> {
664 let inline_start;
665 let block_start;
666 let inline;
667 let block;
668
669 let writing_mode = containing_block.style.writing_mode;
670 if writing_mode.is_vertical() {
671 inline = self.size.height;
673 block = self.size.width;
674 block_start = self.origin.x;
675 inline_start = self.origin.y;
676 } else {
677 inline = self.size.width;
678 block = self.size.height;
679 block_start = self.origin.y;
680 if writing_mode.is_bidi_ltr() {
681 inline_start = self.origin.x;
682 } else {
683 inline_start = containing_block.size.inline - (self.origin.x + self.size.width);
684 }
685 }
686 LogicalRect {
687 start_corner: LogicalVec2 {
688 inline: inline_start,
689 block: block_start,
690 },
691 size: LogicalVec2 { inline, block },
692 }
693 }
694}
695
696#[derive(MallocSizeOf, Default)]
710pub(crate) struct SyncPhysicalRectAu(PhysicalRect<AtomicI32>);
711
712impl SyncPhysicalRectAu {
713 #[inline]
714 pub(crate) fn new(rect: PhysicalRect<Au>) -> Self {
715 Self(PhysicalRect::new(
716 PhysicalPoint::new(rect.origin.x.0.into(), rect.origin.y.0.into()),
717 PhysicalSize::new(rect.size.width.0.into(), rect.size.height.0.into()),
718 ))
719 }
720
721 pub(crate) fn get(&self) -> PhysicalRect<Au> {
722 PhysicalRect::new(self.origin(), self.size())
723 }
724
725 pub(crate) fn set(&self, new_rect: PhysicalRect<Au>) {
726 self.set_origin(new_rect.origin);
727 self.set_size(new_rect.size);
728 }
729
730 #[inline]
731 pub(crate) fn origin(&self) -> PhysicalPoint<Au> {
732 Point2D::new(
733 Au(self.0.origin.x.load(Ordering::Relaxed)),
736 Au(self.0.origin.y.load(Ordering::Relaxed)),
737 )
738 }
739
740 #[inline]
741 pub(crate) fn size(&self) -> PhysicalSize<Au> {
742 Size2D::new(
743 Au(self.0.size.width.load(Ordering::Relaxed)),
746 Au(self.0.size.height.load(Ordering::Relaxed)),
747 )
748 }
749
750 #[inline]
751 pub(crate) fn set_origin(&self, new_origin: PhysicalPoint<Au>) {
752 let origin = &self.0.origin;
753 origin.x.store(new_origin.x.0, Ordering::Relaxed);
754 origin.y.store(new_origin.y.0, Ordering::Relaxed);
755 }
756
757 #[inline]
758 pub(crate) fn set_size(&self, new_size: PhysicalSize<Au>) {
759 let size = &self.0.size;
760 size.width.store(new_size.width.0, Ordering::Relaxed);
761 size.height.store(new_size.height.0, Ordering::Relaxed);
762 }
763
764 #[inline]
765 pub(crate) fn translate(&self, offset: PhysicalSize<Au>) {
766 let new_origin = self.origin() + offset;
769 self.set_origin(new_origin);
770 }
771}
772
773impl fmt::Debug for SyncPhysicalRectAu {
774 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
775 self.get().fmt(f)
776 }
777}