Use euclid data types for physical structs in layout_2020

This removes a bit of duplication and allows layout_2020 to benefit from
a much richer set of utilities.
This commit is contained in:
Martin Robinson 2020-01-22 12:13:28 +01:00
parent ee3fb92e53
commit 02deb99a05
8 changed files with 184 additions and 273 deletions

View file

@ -12,31 +12,10 @@ use style::values::generics::length::MaxSize;
use style::Zero;
use style_traits::CSSPixel;
pub type Point<U> = euclid::Point2D<f32, U>;
pub type Size<U> = euclid::Size2D<f32, U>;
pub type Rect<U> = euclid::Rect<f32, U>;
pub(crate) mod physical {
#[derive(Clone)]
pub(crate) struct Vec2<T> {
pub x: T,
pub y: T,
}
#[derive(Clone, Debug)]
pub(crate) struct Rect<T> {
pub top_left: Vec2<T>,
pub size: Vec2<T>,
}
#[derive(Clone, Debug)]
pub(crate) struct Sides<T> {
pub top: T,
pub left: T,
pub bottom: T,
pub right: T,
}
}
pub type PhysicalPoint<U> = euclid::Point2D<U, CSSPixel>;
pub type PhysicalSize<U> = euclid::Size2D<U, CSSPixel>;
pub type PhysicalRect<U> = euclid::Rect<U, CSSPixel>;
pub type PhysicalSides<U> = euclid::SideOffsets2D<U, CSSPixel>;
pub(crate) mod flow_relative {
#[derive(Clone)]
@ -60,26 +39,6 @@ pub(crate) mod flow_relative {
}
}
impl<T: Zero> physical::Vec2<T> {
pub fn zero() -> Self {
Self {
x: T::zero(),
y: T::zero(),
}
}
}
impl<T: fmt::Debug> fmt::Debug for physical::Vec2<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Not using f.debug_struct on purpose here, to keep {:?} output somewhat compact
f.write_str("Vec2 { x: ")?;
self.x.fmt(f)?;
f.write_str(", y: ")?;
self.y.fmt(f)?;
f.write_str(" }")
}
}
impl<T: fmt::Debug> fmt::Debug for flow_relative::Vec2<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Not using f.debug_struct on purpose here, to keep {:?} output somewhat compact
@ -91,27 +50,13 @@ impl<T: fmt::Debug> fmt::Debug for flow_relative::Vec2<T> {
}
}
impl<T> Add<&'_ physical::Vec2<T>> for &'_ physical::Vec2<T>
where
T: Add<Output = T> + Copy,
{
type Output = physical::Vec2<T>;
fn add(self, other: &'_ physical::Vec2<T>) -> Self::Output {
physical::Vec2 {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
impl<T: Clone> physical::Vec2<T> {
pub fn size_to_flow_relative(&self, mode: WritingMode) -> flow_relative::Vec2<T> {
impl<T: Clone> flow_relative::Vec2<T> {
pub fn from_physical_size(physical_size: &PhysicalSize<T>, mode: WritingMode) -> Self {
// https://drafts.csswg.org/css-writing-modes/#logical-to-physical
let (i, b) = if mode.is_horizontal() {
(&self.x, &self.y)
(&physical_size.width, &physical_size.height)
} else {
(&self.y, &self.x)
(&physical_size.height, &physical_size.width)
};
flow_relative::Vec2 {
inline: i.clone(),
@ -223,41 +168,32 @@ impl fmt::Debug for flow_relative::Rect<Length> {
}
impl<T: Clone> flow_relative::Vec2<T> {
pub fn size_to_physical(&self, mode: WritingMode) -> physical::Vec2<T> {
pub fn to_physical(&self, mode: WritingMode) -> PhysicalSize<T> {
// https://drafts.csswg.org/css-writing-modes/#logical-to-physical
let (x, y) = if mode.is_horizontal() {
(&self.inline, &self.block)
} else {
(&self.block, &self.inline)
};
physical::Vec2 {
x: x.clone(),
y: y.clone(),
}
PhysicalSize::new(x.clone(), y.clone())
}
}
impl From<physical::Vec2<Length>> for Point<CSSPixel> {
fn from(v: physical::Vec2<Length>) -> Self {
Point::from_lengths(v.x.into(), v.y.into())
}
}
impl<T: Clone> physical::Sides<T> {
pub fn to_flow_relative(&self, mode: WritingMode) -> flow_relative::Sides<T> {
impl<T: Clone> flow_relative::Sides<T> {
pub fn from_physical(sides: &PhysicalSides<T>, mode: WritingMode) -> Self {
// https://drafts.csswg.org/css-writing-modes/#logical-to-physical
let block_flow = mode.block_flow_direction();
let (bs, be) = match mode.block_flow_direction() {
BlockFlowDirection::TopToBottom => (&self.top, &self.bottom),
BlockFlowDirection::RightToLeft => (&self.right, &self.left),
BlockFlowDirection::LeftToRight => (&self.left, &self.right),
BlockFlowDirection::TopToBottom => (&sides.top, &sides.bottom),
BlockFlowDirection::RightToLeft => (&sides.right, &sides.left),
BlockFlowDirection::LeftToRight => (&sides.left, &sides.right),
};
use BlockFlowDirection::TopToBottom;
let (is, ie) = match (block_flow, mode.inline_base_direction()) {
(TopToBottom, InlineBaseDirection::LeftToRight) => (&self.left, &self.right),
(TopToBottom, InlineBaseDirection::RightToLeft) => (&self.right, &self.left),
(_, InlineBaseDirection::LeftToRight) => (&self.top, &self.bottom),
(_, InlineBaseDirection::RightToLeft) => (&self.bottom, &self.top),
(TopToBottom, InlineBaseDirection::LeftToRight) => (&sides.left, &sides.right),
(TopToBottom, InlineBaseDirection::RightToLeft) => (&sides.right, &sides.left),
(_, InlineBaseDirection::LeftToRight) => (&sides.top, &sides.bottom),
(_, InlineBaseDirection::RightToLeft) => (&sides.bottom, &sides.top),
};
flow_relative::Sides {
inline_start: is.clone(),
@ -364,8 +300,8 @@ impl<T> flow_relative::Rect<T> {
// Will be needed for other writing modes
// FIXME: what if the containing block has a different mode?
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
_containing_block: &physical::Rect<T>,
) -> physical::Rect<T>
_containing_block: &PhysicalRect<T>,
) -> PhysicalRect<T>
where
T: Clone,
{
@ -374,69 +310,35 @@ impl<T> flow_relative::Rect<T> {
PhysicalCorner::TopLeft => (&self.start_corner.inline, &self.start_corner.block),
_ => unimplemented!(),
};
physical::Rect {
top_left: physical::Vec2 {
x: tl_x.clone(),
y: tl_y.clone(),
},
size: self.size.size_to_physical(mode),
}
PhysicalRect::new(
PhysicalPoint::new(tl_x.clone(), tl_y.clone()),
self.size.to_physical(mode),
)
}
}
impl<T> physical::Rect<T> {
pub fn translate(&self, by: &physical::Vec2<T>) -> Self
where
T: Add<Output = T> + Copy,
{
physical::Rect {
top_left: &self.top_left + by,
size: self.size.clone(),
}
pub trait ToWebRender {
type Type;
fn to_webrender(&self) -> Self::Type;
}
impl ToWebRender for PhysicalPoint<Length> {
type Type = webrender_api::units::LayoutPoint;
fn to_webrender(&self) -> Self::Type {
webrender_api::units::LayoutPoint::new(self.x.px(), self.y.px())
}
}
impl physical::Rect<Length> {
pub fn axis_aligned_bounding_box(&self, other: &Self) -> Self {
let top_left = physical::Vec2 {
x: self.top_left.x.min(other.top_left.x),
y: self.top_left.y.min(other.top_left.y),
};
let bottom_corner_x = (self.top_left.x + self.size.x).max(other.top_left.x + other.size.x);
let bottom_corner_y = (self.top_left.y + self.size.y).max(other.top_left.y + other.size.y);
let size = physical::Vec2 {
x: bottom_corner_x - top_left.x,
y: bottom_corner_y - top_left.y,
};
Self { top_left, size }
impl ToWebRender for PhysicalSize<Length> {
type Type = webrender_api::units::LayoutSize;
fn to_webrender(&self) -> Self::Type {
webrender_api::units::LayoutSize::new(self.width.px(), self.height.px())
}
}
impl<T: Zero> physical::Rect<T> {
pub fn zero() -> Self {
Self {
top_left: physical::Vec2::zero(),
size: physical::Vec2::zero(),
}
}
}
impl From<physical::Rect<Length>> for Rect<CSSPixel> {
fn from(r: physical::Rect<Length>) -> Self {
Rect {
origin: Point::new(r.top_left.x.px(), r.top_left.y.px()),
size: Size::new(r.size.x.px(), r.size.y.px()),
}
}
}
impl From<physical::Rect<Length>> for webrender_api::units::LayoutRect {
fn from(r: physical::Rect<Length>) -> Self {
Rect {
origin: Point::new(r.top_left.x.px(), r.top_left.y.px()),
size: Size::new(r.size.x.px(), r.size.y.px()),
}
impl ToWebRender for PhysicalRect<Length> {
type Type = webrender_api::units::LayoutRect;
fn to_webrender(&self) -> Self::Type {
webrender_api::units::LayoutRect::new(self.origin.to_webrender(), self.size.to_webrender())
}
}