1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 //! A collection of coordinate spaces and their corresponding Point, Size and Rect types.
6 //!
7 //! Physical pixels take into account the device pixel ratio and their dimensions tend
8 //! to correspond to the allocated size of resources in memory, while logical pixels
9 //! don't have the device pixel ratio applied which means they are agnostic to the usage
10 //! of hidpi screens and the like.
11 //!
12 //! The terms "layer" and "stacking context" can be used interchangeably
13 //! in the context of coordinate systems.
14 
15 pub use app_units::Au;
16 use euclid::{Length, Rect, Scale, Size2D, Transform3D, Translation2D};
17 use euclid::{Point2D, Point3D, Vector2D, Vector3D, SideOffsets2D, Box2D};
18 use euclid::HomogeneousVector;
19 use peek_poke::PeekPoke;
20 // local imports
21 use crate::image::DirtyRect;
22 
23 /// Geometry in the coordinate system of the render target (screen or intermediate
24 /// surface) in physical pixels.
25 #[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
26 pub struct DevicePixel;
27 
28 pub type DeviceIntRect = Rect<i32, DevicePixel>;
29 pub type DeviceIntPoint = Point2D<i32, DevicePixel>;
30 pub type DeviceIntSize = Size2D<i32, DevicePixel>;
31 pub type DeviceIntLength = Length<i32, DevicePixel>;
32 pub type DeviceIntSideOffsets = SideOffsets2D<i32, DevicePixel>;
33 
34 pub type DeviceRect = Rect<f32, DevicePixel>;
35 pub type DevicePoint = Point2D<f32, DevicePixel>;
36 pub type DeviceVector2D = Vector2D<f32, DevicePixel>;
37 pub type DeviceSize = Size2D<f32, DevicePixel>;
38 pub type DeviceHomogeneousVector = HomogeneousVector<f32, DevicePixel>;
39 
40 /// Geometry in the coordinate system of the framebuffer in physical pixels.
41 /// It's Y-flipped comparing to DevicePixel.
42 #[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
43 pub struct FramebufferPixel;
44 
45 pub type FramebufferIntPoint = Point2D<i32, FramebufferPixel>;
46 pub type FramebufferIntSize = Size2D<i32, FramebufferPixel>;
47 pub type FramebufferIntRect = Rect<i32, FramebufferPixel>;
48 
49 /// Geometry in the coordinate system of a Picture (intermediate
50 /// surface) in physical pixels.
51 #[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
52 pub struct PicturePixel;
53 
54 pub type PictureIntRect = Rect<i32, PicturePixel>;
55 pub type PictureIntPoint = Point2D<i32, PicturePixel>;
56 pub type PictureIntSize = Size2D<i32, PicturePixel>;
57 pub type PictureRect = Rect<f32, PicturePixel>;
58 pub type PicturePoint = Point2D<f32, PicturePixel>;
59 pub type PictureSize = Size2D<f32, PicturePixel>;
60 pub type PicturePoint3D = Point3D<f32, PicturePixel>;
61 pub type PictureVector2D = Vector2D<f32, PicturePixel>;
62 pub type PictureVector3D = Vector3D<f32, PicturePixel>;
63 pub type PictureBox2D = Box2D<f32, PicturePixel>;
64 
65 /// Geometry gets rasterized in a given root coordinate space. This
66 /// is often the root spatial node (world space), but may be a local
67 /// space for a variety of reasons (e.g. perspective).
68 #[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
69 pub struct RasterPixel;
70 
71 pub type RasterIntRect = Rect<i32, RasterPixel>;
72 pub type RasterIntPoint = Point2D<i32, RasterPixel>;
73 pub type RasterIntSize = Size2D<i32, RasterPixel>;
74 pub type RasterRect = Rect<f32, RasterPixel>;
75 pub type RasterPoint = Point2D<f32, RasterPixel>;
76 pub type RasterSize = Size2D<f32, RasterPixel>;
77 pub type RasterPoint3D = Point3D<f32, RasterPixel>;
78 pub type RasterVector2D = Vector2D<f32, RasterPixel>;
79 pub type RasterVector3D = Vector3D<f32, RasterPixel>;
80 
81 /// Geometry in a stacking context's local coordinate space (logical pixels).
82 #[derive(Hash, Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Ord, PartialOrd, Deserialize, Serialize, PeekPoke)]
83 pub struct LayoutPixel;
84 
85 pub type LayoutRect = Rect<f32, LayoutPixel>;
86 pub type LayoutPoint = Point2D<f32, LayoutPixel>;
87 pub type LayoutPoint3D = Point3D<f32, LayoutPixel>;
88 pub type LayoutVector2D = Vector2D<f32, LayoutPixel>;
89 pub type LayoutVector3D = Vector3D<f32, LayoutPixel>;
90 pub type LayoutSize = Size2D<f32, LayoutPixel>;
91 pub type LayoutSideOffsets = SideOffsets2D<f32, LayoutPixel>;
92 
93 pub type LayoutIntRect = Rect<i32, LayoutPixel>;
94 pub type LayoutIntPoint = Point2D<i32, LayoutPixel>;
95 pub type LayoutIntSize = Size2D<i32, LayoutPixel>;
96 
97 /// Geometry in the document's coordinate space (logical pixels).
98 #[derive(Hash, Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, Ord, PartialOrd)]
99 pub struct WorldPixel;
100 
101 pub type WorldRect = Rect<f32, WorldPixel>;
102 pub type WorldPoint = Point2D<f32, WorldPixel>;
103 pub type WorldSize = Size2D<f32, WorldPixel>;
104 pub type WorldPoint3D = Point3D<f32, WorldPixel>;
105 pub type WorldVector2D = Vector2D<f32, WorldPixel>;
106 pub type WorldVector3D = Vector3D<f32, WorldPixel>;
107 
108 /// Offset in number of tiles.
109 #[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
110 pub struct Tiles;
111 pub type TileOffset = Point2D<i32, Tiles>;
112 pub type TileRange = Rect<i32, Tiles>;
113 
114 /// Scaling ratio from world pixels to device pixels.
115 pub type DevicePixelScale = Scale<f32, WorldPixel, DevicePixel>;
116 /// Scaling ratio from layout to world. Used for cases where we know the layout
117 /// is in world space, or specifically want to treat it this way.
118 pub type LayoutToWorldScale = Scale<f32, LayoutPixel, WorldPixel>;
119 /// A complete scaling ratio from layout space to device pixel space.
120 pub type LayoutToDeviceScale = Scale<f32, LayoutPixel, DevicePixel>;
121 
122 pub type LayoutTransform = Transform3D<f32, LayoutPixel, LayoutPixel>;
123 pub type LayoutToWorldTransform = Transform3D<f32, LayoutPixel, WorldPixel>;
124 pub type WorldToLayoutTransform = Transform3D<f32, WorldPixel, LayoutPixel>;
125 
126 pub type LayoutToPictureTransform = Transform3D<f32, LayoutPixel, PicturePixel>;
127 pub type PictureToLayoutTransform = Transform3D<f32, PicturePixel, LayoutPixel>;
128 
129 pub type LayoutToRasterTransform = Transform3D<f32, LayoutPixel, RasterPixel>;
130 pub type RasterToLayoutTransform = Transform3D<f32, RasterPixel, LayoutPixel>;
131 
132 pub type PictureToRasterTransform = Transform3D<f32, PicturePixel, RasterPixel>;
133 pub type RasterToPictureTransform = Transform3D<f32, RasterPixel, PicturePixel>;
134 
135 // Fixed position coordinates, to avoid float precision errors.
136 pub type LayoutPointAu = Point2D<Au, LayoutPixel>;
137 pub type LayoutRectAu = Rect<Au, LayoutPixel>;
138 pub type LayoutSizeAu = Size2D<Au, LayoutPixel>;
139 pub type LayoutVector2DAu = Vector2D<Au, LayoutPixel>;
140 pub type LayoutSideOffsetsAu = SideOffsets2D<Au, LayoutPixel>;
141 
142 pub type ImageDirtyRect = DirtyRect<i32, DevicePixel>;
143 pub type BlobDirtyRect = DirtyRect<i32, LayoutPixel>;
144 
145 pub type BlobToDeviceTranslation = Translation2D<i32, LayoutPixel, DevicePixel>;
146 
147 /// Stores two coordinates in texel space. The coordinates
148 /// are stored in texel coordinates because the texture atlas
149 /// may grow. Storing them as texel coords and normalizing
150 /// the UVs in the vertex shader means nothing needs to be
151 /// updated on the CPU when the texture size changes.
152 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
153 pub struct TexelRect {
154     pub uv0: DevicePoint,
155     pub uv1: DevicePoint,
156 }
157 
158 impl TexelRect {
new(u0: f32, v0: f32, u1: f32, v1: f32) -> Self159     pub fn new(u0: f32, v0: f32, u1: f32, v1: f32) -> Self {
160         TexelRect {
161             uv0: DevicePoint::new(u0, v0),
162             uv1: DevicePoint::new(u1, v1),
163         }
164     }
165 
invalid() -> Self166     pub fn invalid() -> Self {
167         TexelRect {
168             uv0: DevicePoint::new(-1.0, -1.0),
169             uv1: DevicePoint::new(-1.0, -1.0),
170         }
171     }
172 }
173 
174 impl Into<TexelRect> for DeviceIntRect {
into(self) -> TexelRect175     fn into(self) -> TexelRect {
176         TexelRect {
177             uv0: self.min().to_f32(),
178             uv1: self.max().to_f32(),
179         }
180     }
181 }
182 
183 const MAX_AU_FLOAT: f32 = 1.0e6;
184 
185 pub trait AuHelpers<T> {
from_au(data: T) -> Self186     fn from_au(data: T) -> Self;
to_au(&self) -> T187     fn to_au(&self) -> T;
188 }
189 
190 impl AuHelpers<LayoutSizeAu> for LayoutSize {
from_au(size: LayoutSizeAu) -> Self191     fn from_au(size: LayoutSizeAu) -> Self {
192         LayoutSize::new(
193             size.width.to_f32_px(),
194             size.height.to_f32_px(),
195         )
196     }
197 
to_au(&self) -> LayoutSizeAu198     fn to_au(&self) -> LayoutSizeAu {
199         let width = self.width.min(2.0 * MAX_AU_FLOAT);
200         let height = self.height.min(2.0 * MAX_AU_FLOAT);
201 
202         LayoutSizeAu::new(
203             Au::from_f32_px(width),
204             Au::from_f32_px(height),
205         )
206     }
207 }
208 
209 impl AuHelpers<LayoutVector2DAu> for LayoutVector2D {
from_au(size: LayoutVector2DAu) -> Self210     fn from_au(size: LayoutVector2DAu) -> Self {
211         LayoutVector2D::new(
212             size.x.to_f32_px(),
213             size.y.to_f32_px(),
214         )
215     }
216 
to_au(&self) -> LayoutVector2DAu217     fn to_au(&self) -> LayoutVector2DAu {
218         LayoutVector2DAu::new(
219             Au::from_f32_px(self.x),
220             Au::from_f32_px(self.y),
221         )
222     }
223 }
224 
225 impl AuHelpers<LayoutPointAu> for LayoutPoint {
from_au(point: LayoutPointAu) -> Self226     fn from_au(point: LayoutPointAu) -> Self {
227         LayoutPoint::new(
228             point.x.to_f32_px(),
229             point.y.to_f32_px(),
230         )
231     }
232 
to_au(&self) -> LayoutPointAu233     fn to_au(&self) -> LayoutPointAu {
234         let x = self.x.min(MAX_AU_FLOAT).max(-MAX_AU_FLOAT);
235         let y = self.y.min(MAX_AU_FLOAT).max(-MAX_AU_FLOAT);
236 
237         LayoutPointAu::new(
238             Au::from_f32_px(x),
239             Au::from_f32_px(y),
240         )
241     }
242 }
243 
244 impl AuHelpers<LayoutRectAu> for LayoutRect {
from_au(rect: LayoutRectAu) -> Self245     fn from_au(rect: LayoutRectAu) -> Self {
246         LayoutRect::new(
247             LayoutPoint::from_au(rect.origin),
248             LayoutSize::from_au(rect.size),
249         )
250     }
251 
to_au(&self) -> LayoutRectAu252     fn to_au(&self) -> LayoutRectAu {
253         LayoutRectAu::new(
254             self.origin.to_au(),
255             self.size.to_au(),
256         )
257     }
258 }
259 
260 impl AuHelpers<LayoutSideOffsetsAu> for LayoutSideOffsets {
from_au(offsets: LayoutSideOffsetsAu) -> Self261     fn from_au(offsets: LayoutSideOffsetsAu) -> Self {
262         LayoutSideOffsets::new(
263             offsets.top.to_f32_px(),
264             offsets.right.to_f32_px(),
265             offsets.bottom.to_f32_px(),
266             offsets.left.to_f32_px(),
267         )
268     }
269 
to_au(&self) -> LayoutSideOffsetsAu270     fn to_au(&self) -> LayoutSideOffsetsAu {
271         LayoutSideOffsetsAu::new(
272             Au::from_f32_px(self.top),
273             Au::from_f32_px(self.right),
274             Au::from_f32_px(self.bottom),
275             Au::from_f32_px(self.left),
276         )
277     }
278 }
279 
280 pub trait RectExt {
281     type Point;
top_left(&self) -> Self::Point282     fn top_left(&self) -> Self::Point;
top_right(&self) -> Self::Point283     fn top_right(&self) -> Self::Point;
bottom_left(&self) -> Self::Point284     fn bottom_left(&self) -> Self::Point;
bottom_right(&self) -> Self::Point285     fn bottom_right(&self) -> Self::Point;
286 }
287 
288 impl<U> RectExt for Rect<f32, U> {
289     type Point = Point2D<f32, U>;
top_left(&self) -> Self::Point290     fn top_left(&self) -> Self::Point {
291         self.min()
292     }
top_right(&self) -> Self::Point293     fn top_right(&self) -> Self::Point {
294         Point2D::new(self.max_x(), self.min_y())
295     }
bottom_left(&self) -> Self::Point296     fn bottom_left(&self) -> Self::Point {
297         Point2D::new(self.min_x(), self.max_y())
298     }
bottom_right(&self) -> Self::Point299     fn bottom_right(&self) -> Self::Point {
300         self.max()
301     }
302 }
303 
304 // A few helpers to convert to cast between coordinate spaces that are often equivalent.
305 
306 #[inline]
layout_rect_as_picture_rect(layout_rect: &LayoutRect) -> PictureRect307 pub fn layout_rect_as_picture_rect(layout_rect: &LayoutRect) -> PictureRect {
308     layout_rect.cast_unit()
309 }
310 
311 #[inline]
layout_vector_as_picture_vector(layout_vector: LayoutVector2D) -> PictureVector2D312 pub fn layout_vector_as_picture_vector(layout_vector: LayoutVector2D) -> PictureVector2D {
313     layout_vector.cast_unit()
314 }
315 
316 #[inline]
device_size_as_framebuffer_size(framebuffer_size: DeviceIntSize) -> FramebufferIntSize317 pub fn device_size_as_framebuffer_size(framebuffer_size: DeviceIntSize) -> FramebufferIntSize {
318     framebuffer_size.cast_unit()
319 }
320 
321 #[inline]
device_rect_as_framebuffer_rect(framebuffer_rect: &DeviceIntRect) -> FramebufferIntRect322 pub fn device_rect_as_framebuffer_rect(framebuffer_rect: &DeviceIntRect) -> FramebufferIntRect {
323     framebuffer_rect.cast_unit()
324 }
325