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

@ -4,7 +4,7 @@
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::fragments::{BoxFragment, Fragment}; use crate::fragments::{BoxFragment, Fragment};
use crate::geom::physical::{Rect, Vec2}; use crate::geom::{PhysicalPoint, PhysicalRect, ToWebRender};
use crate::replaced::IntrinsicSizes; use crate::replaced::IntrinsicSizes;
use embedder_traits::Cursor; use embedder_traits::Cursor;
use euclid::{Point2D, SideOffsets2D, Size2D, Vector2D}; use euclid::{Point2D, SideOffsets2D, Size2D, Vector2D};
@ -74,7 +74,7 @@ impl Fragment {
pub(crate) fn build_display_list( pub(crate) fn build_display_list(
&self, &self,
builder: &mut DisplayListBuilder, builder: &mut DisplayListBuilder,
containing_block: &Rect<Length>, containing_block: &PhysicalRect<Length>,
) { ) {
match self { match self {
Fragment::Box(b) => BuilderForBoxFragment::new(b, containing_block).build(builder), Fragment::Box(b) => BuilderForBoxFragment::new(b, containing_block).build(builder),
@ -82,7 +82,7 @@ impl Fragment {
let rect = a let rect = a
.rect .rect
.to_physical(a.mode, containing_block) .to_physical(a.mode, containing_block)
.translate(&containing_block.top_left); .translate(containing_block.origin.to_vector());
for child in &a.children { for child in &a.children {
child.build_display_list(builder, &rect) child.build_display_list(builder, &rect)
} }
@ -92,30 +92,35 @@ impl Fragment {
let rect = t let rect = t
.rect .rect
.to_physical(t.parent_style.writing_mode, containing_block) .to_physical(t.parent_style.writing_mode, containing_block)
.translate(&containing_block.top_left); .translate(containing_block.origin.to_vector());
let mut baseline_origin = rect.top_left.clone(); let mut baseline_origin = rect.origin.clone();
baseline_origin.y += t.ascent; baseline_origin.y += t.ascent;
let glyphs = glyphs(&t.glyphs, baseline_origin); let glyphs = glyphs(&t.glyphs, baseline_origin);
if glyphs.is_empty() { if glyphs.is_empty() {
return; return;
} }
let mut common = builder.common_properties(rect.clone().into()); let mut common = builder.common_properties(rect.clone().to_webrender());
common.hit_info = hit_info(&t.parent_style, t.tag, Cursor::Text); common.hit_info = hit_info(&t.parent_style, t.tag, Cursor::Text);
let color = t.parent_style.clone_color(); let color = t.parent_style.clone_color();
builder builder.wr.push_text(
.wr &common,
.push_text(&common, rect.into(), &glyphs, t.font_key, rgba(color), None); rect.to_webrender(),
&glyphs,
t.font_key,
rgba(color),
None,
);
}, },
Fragment::Image(i) => { Fragment::Image(i) => {
builder.is_contentful = true; builder.is_contentful = true;
let rect = i let rect = i
.rect .rect
.to_physical(i.style.writing_mode, containing_block) .to_physical(i.style.writing_mode, containing_block)
.translate(&containing_block.top_left); .translate(containing_block.origin.to_vector());
let common = builder.common_properties(rect.clone().into()); let common = builder.common_properties(rect.clone().to_webrender());
builder.wr.push_image( builder.wr.push_image(
&common, &common,
rect.into(), rect.to_webrender(),
image_rendering(i.style.get_inherited_box().image_rendering), image_rendering(i.style.get_inherited_box().image_rendering),
wr::AlphaType::PremultipliedAlpha, wr::AlphaType::PremultipliedAlpha,
i.image_key, i.image_key,
@ -128,7 +133,7 @@ impl Fragment {
struct BuilderForBoxFragment<'a> { struct BuilderForBoxFragment<'a> {
fragment: &'a BoxFragment, fragment: &'a BoxFragment,
containing_block: &'a Rect<Length>, containing_block: &'a PhysicalRect<Length>,
border_rect: units::LayoutRect, border_rect: units::LayoutRect,
padding_rect: OnceCell<units::LayoutRect>, padding_rect: OnceCell<units::LayoutRect>,
content_rect: OnceCell<units::LayoutRect>, content_rect: OnceCell<units::LayoutRect>,
@ -137,12 +142,12 @@ struct BuilderForBoxFragment<'a> {
} }
impl<'a> BuilderForBoxFragment<'a> { impl<'a> BuilderForBoxFragment<'a> {
fn new(fragment: &'a BoxFragment, containing_block: &'a Rect<Length>) -> Self { fn new(fragment: &'a BoxFragment, containing_block: &'a PhysicalRect<Length>) -> Self {
let border_rect: units::LayoutRect = fragment let border_rect: units::LayoutRect = fragment
.border_rect() .border_rect()
.to_physical(fragment.style.writing_mode, containing_block) .to_physical(fragment.style.writing_mode, containing_block)
.translate(&containing_block.top_left) .translate(containing_block.origin.to_vector())
.into(); .to_webrender();
let border_radius = { let border_radius = {
let resolve = |radius: &LengthPercentage, box_size: f32| { let resolve = |radius: &LengthPercentage, box_size: f32| {
@ -179,8 +184,8 @@ impl<'a> BuilderForBoxFragment<'a> {
self.fragment self.fragment
.content_rect .content_rect
.to_physical(self.fragment.style.writing_mode, self.containing_block) .to_physical(self.fragment.style.writing_mode, self.containing_block)
.translate(&self.containing_block.top_left) .translate(self.containing_block.origin.to_vector())
.into() .to_webrender()
}) })
} }
@ -189,8 +194,8 @@ impl<'a> BuilderForBoxFragment<'a> {
self.fragment self.fragment
.padding_rect() .padding_rect()
.to_physical(self.fragment.style.writing_mode, self.containing_block) .to_physical(self.fragment.style.writing_mode, self.containing_block)
.translate(&self.containing_block.top_left) .translate(self.containing_block.origin.to_vector())
.into() .to_webrender()
}) })
} }
@ -235,7 +240,7 @@ impl<'a> BuilderForBoxFragment<'a> {
.fragment .fragment
.content_rect .content_rect
.to_physical(self.fragment.style.writing_mode, self.containing_block) .to_physical(self.fragment.style.writing_mode, self.containing_block)
.translate(&self.containing_block.top_left); .translate(self.containing_block.origin.to_vector());
for child in &self.fragment.children { for child in &self.fragment.children {
child.build_display_list(builder, &content_rect) child.build_display_list(builder, &content_rect)
} }
@ -580,7 +585,10 @@ fn rgba(rgba: cssparser::RGBA) -> wr::ColorF {
) )
} }
fn glyphs(glyph_runs: &[Arc<GlyphStore>], mut origin: Vec2<Length>) -> Vec<wr::GlyphInstance> { fn glyphs(
glyph_runs: &[Arc<GlyphStore>],
mut origin: PhysicalPoint<Length>,
) -> Vec<wr::GlyphInstance> {
use gfx_traits::ByteIndex; use gfx_traits::ByteIndex;
use range::Range; use range::Range;

View file

@ -4,7 +4,7 @@
use crate::context::LayoutContext; use crate::context::LayoutContext;
use crate::element_data::{LayoutBox, LayoutDataForElement}; use crate::element_data::{LayoutBox, LayoutDataForElement};
use crate::geom::physical::Vec2; use crate::geom::PhysicalSize;
use crate::replaced::ReplacedContent; use crate::replaced::ReplacedContent;
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside, DisplayOutside}; use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside, DisplayOutside};
use crate::wrapper::GetRawData; use crate::wrapper::GetRawData;
@ -307,7 +307,7 @@ pub(crate) trait NodeExt<'dom>: 'dom + Copy + LayoutNode + Send + Sync {
/// Returns the image if its loaded, and its size in image pixels /// Returns the image if its loaded, and its size in image pixels
/// adjusted for `image_density`. /// adjusted for `image_density`.
fn as_image(self) -> Option<(Option<Arc<NetImage>>, Vec2<f64>)>; fn as_image(self) -> Option<(Option<Arc<NetImage>>, PhysicalSize<f64>)>;
fn first_child(self) -> Option<Self>; fn first_child(self) -> Option<Self>;
fn next_sibling(self) -> Option<Self>; fn next_sibling(self) -> Option<Self>;
fn parent_node(self) -> Option<Self>; fn parent_node(self) -> Option<Self>;
@ -337,7 +337,7 @@ where
} }
} }
fn as_image(self) -> Option<(Option<Arc<NetImage>>, Vec2<f64>)> { fn as_image(self) -> Option<(Option<Arc<NetImage>>, PhysicalSize<f64>)> {
let node = self.to_threadsafe(); let node = self.to_threadsafe();
let (resource, metadata) = node.image_data()?; let (resource, metadata) = node.image_data()?;
let (width, height) = resource let (width, height) = resource
@ -350,11 +350,7 @@ where
width = width / density; width = width / density;
height = height / density; height = height / density;
} }
let size = Vec2 { Some((resource, PhysicalSize::new(width, height)))
x: width,
y: height,
};
Some((resource, size))
} }
fn first_child(self) -> Option<Self> { fn first_child(self) -> Option<Self> {

View file

@ -9,9 +9,8 @@ use crate::flow::float::FloatBox;
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox}; use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext; use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Fragment; use crate::fragments::Fragment;
use crate::geom;
use crate::geom::flow_relative::Vec2; use crate::geom::flow_relative::Vec2;
use crate::geom::physical; use crate::geom::PhysicalRect;
use crate::positioned::AbsolutelyPositionedBox; use crate::positioned::AbsolutelyPositionedBox;
use crate::positioned::PositioningContext; use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent; use crate::replaced::ReplacedContent;
@ -25,7 +24,6 @@ use script_layout_interface::wrapper_traits::LayoutNode;
use servo_arc::Arc; use servo_arc::Arc;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::Length; use style::values::computed::Length;
use style::Zero;
use style_traits::CSSPixel; use style_traits::CSSPixel;
pub struct BoxTreeRoot(BlockFormattingContext); pub struct BoxTreeRoot(BlockFormattingContext);
@ -35,10 +33,10 @@ pub struct FragmentTreeRoot {
children: Vec<Fragment>, children: Vec<Fragment>,
/// The scrollable overflow of the root of the fragment tree. /// The scrollable overflow of the root of the fragment tree.
scrollable_overflow: physical::Rect<Length>, scrollable_overflow: PhysicalRect<Length>,
/// The axis-aligned bounding box of the border box of all child fragments /// The axis-aligned bounding box of the border box of all child fragments
bounding_box_of_border_boxes: physical::Rect<Length>, bounding_box_of_border_boxes: PhysicalRect<Length>,
} }
impl BoxTreeRoot { impl BoxTreeRoot {
@ -116,7 +114,7 @@ impl BoxTreeRoot {
pub fn layout( pub fn layout(
&self, &self,
layout_context: &LayoutContext, layout_context: &LayoutContext,
viewport: geom::Size<CSSPixel>, viewport: euclid::Size2D<f32, CSSPixel>,
) -> FragmentTreeRoot { ) -> FragmentTreeRoot {
let style = ComputedValues::initial_values(); let style = ComputedValues::initial_values();
let initial_containing_block = DefiniteContainingBlock { let initial_containing_block = DefiniteContainingBlock {
@ -150,7 +148,7 @@ impl BoxTreeRoot {
independent_layout independent_layout
.fragments .fragments
.iter() .iter()
.fold(physical::Rect::zero(), |acc, child| { .fold(PhysicalRect::zero(), |acc, child| {
let child_overflow = child.scrollable_overflow(); let child_overflow = child.scrollable_overflow();
// https://drafts.csswg.org/css-overflow/#scrolling-direction // https://drafts.csswg.org/css-overflow/#scrolling-direction
@ -159,23 +157,23 @@ impl BoxTreeRoot {
// //
// FIXME(mrobinson, bug 25564): This should take into account writing // FIXME(mrobinson, bug 25564): This should take into account writing
// mode. // mode.
let child_overflow = physical::Rect { let child_overflow = PhysicalRect::new(
top_left: physical::Vec2::zero(), euclid::Point2D::zero(),
size: physical::Vec2 { euclid::Size2D::new(
x: child_overflow.size.x + child_overflow.top_left.x, child_overflow.size.width + child_overflow.origin.x,
y: child_overflow.size.y + child_overflow.top_left.y, child_overflow.size.height + child_overflow.origin.y,
}, ),
}; );
acc.axis_aligned_bounding_box(&child_overflow) acc.union(&child_overflow)
}); });
let containing_block = physical::Rect::zero(); let containing_block = PhysicalRect::zero();
let bounding_box_of_border_boxes = let bounding_box_of_border_boxes =
independent_layout independent_layout
.fragments .fragments
.iter() .iter()
.fold(physical::Rect::zero(), |acc, child| { .fold(PhysicalRect::zero(), |acc, child| {
acc.axis_aligned_bounding_box(&match child { acc.union(&match child {
Fragment::Box(fragment) => fragment Fragment::Box(fragment) => fragment
.border_rect() .border_rect()
.to_physical(fragment.style.writing_mode, &containing_block), .to_physical(fragment.style.writing_mode, &containing_block),
@ -205,16 +203,13 @@ impl FragmentTreeRoot {
builder: &mut crate::display_list::DisplayListBuilder, builder: &mut crate::display_list::DisplayListBuilder,
viewport_size: webrender_api::units::LayoutSize, viewport_size: webrender_api::units::LayoutSize,
) { ) {
let containing_block = geom::physical::Rect { let containing_block = PhysicalRect::new(
top_left: geom::physical::Vec2 { euclid::Point2D::zero(),
x: Length::zero(), euclid::Size2D::new(
y: Length::zero(), Length::new(viewport_size.width),
}, Length::new(viewport_size.height),
size: geom::physical::Vec2 { ),
x: Length::new(viewport_size.width), );
y: Length::new(viewport_size.height),
},
};
for fragment in &self.children { for fragment in &self.children {
fragment.build_display_list(builder, &containing_block) fragment.build_display_list(builder, &containing_block)
} }
@ -229,19 +224,19 @@ impl FragmentTreeRoot {
pub fn scrollable_overflow(&self) -> webrender_api::units::LayoutSize { pub fn scrollable_overflow(&self) -> webrender_api::units::LayoutSize {
webrender_api::units::LayoutSize::from_untyped(Size2D::new( webrender_api::units::LayoutSize::from_untyped(Size2D::new(
self.scrollable_overflow.size.x.px(), self.scrollable_overflow.size.width.px(),
self.scrollable_overflow.size.y.px(), self.scrollable_overflow.size.height.px(),
)) ))
} }
pub fn bounding_box_of_border_boxes(&self) -> Rect<Au> { pub fn bounding_box_of_border_boxes(&self) -> Rect<Au> {
let origin = Point2D::new( let origin = Point2D::new(
Au::from_f32_px(self.bounding_box_of_border_boxes.top_left.x.px()), Au::from_f32_px(self.bounding_box_of_border_boxes.origin.x.px()),
Au::from_f32_px(self.bounding_box_of_border_boxes.top_left.y.px()), Au::from_f32_px(self.bounding_box_of_border_boxes.origin.y.px()),
); );
let size = Size2D::new( let size = Size2D::new(
Au::from_f32_px(self.bounding_box_of_border_boxes.size.x.px()), Au::from_f32_px(self.bounding_box_of_border_boxes.size.width.px()),
Au::from_f32_px(self.bounding_box_of_border_boxes.size.y.px()), Au::from_f32_px(self.bounding_box_of_border_boxes.size.height.px()),
); );
Rect::new(origin, size) Rect::new(origin, size)
} }

View file

@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::geom::flow_relative::{Rect, Sides, Vec2}; use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::geom::physical; use crate::geom::PhysicalRect;
use gfx::text::glyph::GlyphStore; use gfx::text::glyph::GlyphStore;
use gfx_traits::print_tree::PrintTree; use gfx_traits::print_tree::PrintTree;
use servo_arc::Arc as ServoArc; use servo_arc::Arc as ServoArc;
@ -39,7 +39,7 @@ pub(crate) struct BoxFragment {
pub block_margins_collapsed_with_children: CollapsedBlockMargins, pub block_margins_collapsed_with_children: CollapsedBlockMargins,
/// The scrollable overflow of this box fragment. /// The scrollable overflow of this box fragment.
pub scrollable_overflow: physical::Rect<Length>, pub scrollable_overflow: PhysicalRect<Length>,
} }
pub(crate) struct CollapsedBlockMargins { pub(crate) struct CollapsedBlockMargins {
@ -61,7 +61,7 @@ pub(crate) struct AnonymousFragment {
pub mode: WritingMode, pub mode: WritingMode,
/// The scrollable overflow of this anonymous fragment's children. /// The scrollable overflow of this anonymous fragment's children.
pub scrollable_overflow: physical::Rect<Length>, pub scrollable_overflow: PhysicalRect<Length>,
} }
pub(crate) struct TextFragment { pub(crate) struct TextFragment {
@ -98,7 +98,7 @@ impl Fragment {
} }
} }
pub fn scrollable_overflow(&self) -> physical::Rect<Length> { pub fn scrollable_overflow(&self) -> PhysicalRect<Length> {
// FIXME(mrobinson, bug 25564): We should be using the containing block // FIXME(mrobinson, bug 25564): We should be using the containing block
// here to properly convert scrollable overflow to physical geometry. // here to properly convert scrollable overflow to physical geometry.
match self { match self {
@ -106,10 +106,10 @@ impl Fragment {
Fragment::Anonymous(fragment) => fragment.scrollable_overflow.clone(), Fragment::Anonymous(fragment) => fragment.scrollable_overflow.clone(),
Fragment::Text(fragment) => fragment Fragment::Text(fragment) => fragment
.rect .rect
.to_physical(fragment.parent_style.writing_mode, &physical::Rect::zero()), .to_physical(fragment.parent_style.writing_mode, &PhysicalRect::zero()),
Fragment::Image(fragment) => fragment Fragment::Image(fragment) => fragment
.rect .rect
.to_physical(fragment.style.writing_mode, &physical::Rect::zero()), .to_physical(fragment.style.writing_mode, &PhysicalRect::zero()),
} }
} }
} }
@ -120,15 +120,15 @@ impl AnonymousFragment {
children: vec![], children: vec![],
rect: Rect::zero(), rect: Rect::zero(),
mode, mode,
scrollable_overflow: physical::Rect::zero(), scrollable_overflow: PhysicalRect::zero(),
} }
} }
pub fn new(rect: Rect<Length>, children: Vec<Fragment>, mode: WritingMode) -> Self { pub fn new(rect: Rect<Length>, children: Vec<Fragment>, mode: WritingMode) -> Self {
// FIXME(mrobinson, bug 25564): We should be using the containing block // FIXME(mrobinson, bug 25564): We should be using the containing block
// here to properly convert scrollable overflow to physical geometry. // here to properly convert scrollable overflow to physical geometry.
let scrollable_overflow = children.iter().fold(physical::Rect::zero(), |acc, child| { let scrollable_overflow = children.iter().fold(PhysicalRect::zero(), |acc, child| {
acc.axis_aligned_bounding_box(&child.scrollable_overflow()) acc.union(&child.scrollable_overflow())
}); });
AnonymousFragment { AnonymousFragment {
rect, rect,
@ -168,8 +168,8 @@ impl BoxFragment {
let scrollable_overflow = children.iter().fold( let scrollable_overflow = children.iter().fold(
content_rect content_rect
.inflate(&border) .inflate(&border)
.to_physical(style.writing_mode, &physical::Rect::zero()), .to_physical(style.writing_mode, &PhysicalRect::zero()),
|acc, child| acc.axis_aligned_bounding_box(&child.scrollable_overflow()), |acc, child| acc.union(&child.scrollable_overflow()),
); );
BoxFragment { BoxFragment {
tag, tag,

View file

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

View file

@ -5,7 +5,7 @@
use crate::dom_traversal::NodeExt; use crate::dom_traversal::NodeExt;
use crate::fragments::{Fragment, ImageFragment}; use crate::fragments::{Fragment, ImageFragment};
use crate::geom::flow_relative::{Rect, Vec2}; use crate::geom::flow_relative::{Rect, Vec2};
use crate::geom::physical; use crate::geom::PhysicalSize;
use crate::sizing::ContentSizes; use crate::sizing::ContentSizes;
use crate::style_ext::ComputedValuesExt; use crate::style_ext::ComputedValuesExt;
use crate::ContainingBlock; use crate::ContainingBlock;
@ -55,8 +55,8 @@ impl ReplacedContent {
// https://drafts.csswg.org/css-images-4/#the-image-resolution // https://drafts.csswg.org/css-images-4/#the-image-resolution
let dppx = 1.0; let dppx = 1.0;
let width = (intrinsic_size_in_dots.x as CSSFloat) / dppx; let width = (intrinsic_size_in_dots.width as CSSFloat) / dppx;
let height = (intrinsic_size_in_dots.y as CSSFloat) / dppx; let height = (intrinsic_size_in_dots.height as CSSFloat) / dppx;
return Some(Self { return Some(Self {
kind: ReplacedContentKind::Image(image), kind: ReplacedContentKind::Image(image),
intrinsic: IntrinsicSizes { intrinsic: IntrinsicSizes {
@ -71,11 +71,8 @@ impl ReplacedContent {
} }
fn flow_relative_intrinsic_size(&self, style: &ComputedValues) -> Vec2<Option<Length>> { fn flow_relative_intrinsic_size(&self, style: &ComputedValues) -> Vec2<Option<Length>> {
let intrinsic_size = physical::Vec2 { let intrinsic_size = PhysicalSize::new(self.intrinsic.width, self.intrinsic.height);
x: self.intrinsic.width, Vec2::from_physical_size(&intrinsic_size, style.writing_mode)
y: self.intrinsic.height,
};
intrinsic_size.size_to_flow_relative(style.writing_mode)
} }
fn inline_size_over_block_size_intrinsic_ratio( fn inline_size_over_block_size_intrinsic_ratio(
@ -158,11 +155,10 @@ impl ReplacedContent {
// the largest rectangle that has a 2:1 ratio and fits the device instead.” // the largest rectangle that has a 2:1 ratio and fits the device instead.”
// “height of the largest rectangle that has a 2:1 ratio, has a height not greater // “height of the largest rectangle that has a 2:1 ratio, has a height not greater
// than 150px, and has a width not greater than the device width.” // than 150px, and has a width not greater than the device width.”
physical::Vec2 { Vec2::from_physical_size(
x: Length::new(300.), &PhysicalSize::new(Length::new(300.), Length::new(150.)),
y: Length::new(150.), mode,
} )
.size_to_flow_relative(mode)
}; };
let clamp = |inline_size: Length, block_size: Length| Vec2 { let clamp = |inline_size: Length, block_size: Length| Vec2 {
inline: inline_size.clamp_between_extremums(min_box_size.inline, max_box_size.inline), inline: inline_size.clamp_between_extremums(min_box_size.inline, max_box_size.inline),

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::geom::{flow_relative, physical}; use crate::geom::{flow_relative, PhysicalSides, PhysicalSize};
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::{Length, LengthPercentage, LengthPercentageOrAuto}; use style::values::computed::{Length, LengthPercentage, LengthPercentageOrAuto};
use style::values::computed::{NonNegativeLengthPercentage, Size}; use style::values::computed::{NonNegativeLengthPercentage, Size};
@ -75,33 +75,39 @@ impl ComputedValuesExt for ComputedValues {
#[inline] #[inline]
fn box_offsets(&self) -> flow_relative::Sides<LengthPercentageOrAuto> { fn box_offsets(&self) -> flow_relative::Sides<LengthPercentageOrAuto> {
let position = self.get_position(); let position = self.get_position();
physical::Sides { flow_relative::Sides::from_physical(
top: position.top.clone(), &PhysicalSides::new(
left: position.left.clone(), position.top.clone(),
bottom: position.bottom.clone(), position.right.clone(),
right: position.right.clone(), position.bottom.clone(),
} position.left.clone(),
.to_flow_relative(self.writing_mode) ),
self.writing_mode,
)
} }
#[inline] #[inline]
fn box_size(&self) -> flow_relative::Vec2<LengthPercentageOrAuto> { fn box_size(&self) -> flow_relative::Vec2<LengthPercentageOrAuto> {
let position = self.get_position(); let position = self.get_position();
physical::Vec2 { flow_relative::Vec2::from_physical_size(
x: size_to_length(position.width.clone()), &PhysicalSize::new(
y: size_to_length(position.height.clone()), size_to_length(position.width.clone()),
} size_to_length(position.height.clone()),
.size_to_flow_relative(self.writing_mode) ),
self.writing_mode,
)
} }
#[inline] #[inline]
fn min_box_size(&self) -> flow_relative::Vec2<LengthPercentageOrAuto> { fn min_box_size(&self) -> flow_relative::Vec2<LengthPercentageOrAuto> {
let position = self.get_position(); let position = self.get_position();
physical::Vec2 { flow_relative::Vec2::from_physical_size(
x: size_to_length(position.min_width.clone()), &PhysicalSize::new(
y: size_to_length(position.min_height.clone()), size_to_length(position.min_width.clone()),
} size_to_length(position.min_height.clone()),
.size_to_flow_relative(self.writing_mode) ),
self.writing_mode,
)
} }
#[inline] #[inline]
@ -111,45 +117,53 @@ impl ComputedValuesExt for ComputedValues {
MaxSize::None => MaxSize::None, MaxSize::None => MaxSize::None,
}; };
let position = self.get_position(); let position = self.get_position();
physical::Vec2 { flow_relative::Vec2::from_physical_size(
x: unwrap(position.max_width.clone()), &PhysicalSize::new(
y: unwrap(position.max_height.clone()), unwrap(position.max_width.clone()),
} unwrap(position.max_height.clone()),
.size_to_flow_relative(self.writing_mode) ),
self.writing_mode,
)
} }
#[inline] #[inline]
fn padding(&self) -> flow_relative::Sides<LengthPercentage> { fn padding(&self) -> flow_relative::Sides<LengthPercentage> {
let padding = self.get_padding(); let padding = self.get_padding();
physical::Sides { flow_relative::Sides::from_physical(
top: padding.padding_top.0.clone(), &PhysicalSides::new(
left: padding.padding_left.0.clone(), padding.padding_top.0.clone(),
bottom: padding.padding_bottom.0.clone(), padding.padding_right.0.clone(),
right: padding.padding_right.0.clone(), padding.padding_bottom.0.clone(),
} padding.padding_left.0.clone(),
.to_flow_relative(self.writing_mode) ),
self.writing_mode,
)
} }
fn border_width(&self) -> flow_relative::Sides<Length> { fn border_width(&self) -> flow_relative::Sides<Length> {
let border = self.get_border(); let border = self.get_border();
physical::Sides { flow_relative::Sides::from_physical(
top: border.border_top_width.0, &PhysicalSides::new(
left: border.border_left_width.0, border.border_top_width.0,
bottom: border.border_bottom_width.0, border.border_right_width.0,
right: border.border_right_width.0, border.border_bottom_width.0,
} border.border_left_width.0,
.to_flow_relative(self.writing_mode) ),
self.writing_mode,
)
} }
fn margin(&self) -> flow_relative::Sides<LengthPercentageOrAuto> { fn margin(&self) -> flow_relative::Sides<LengthPercentageOrAuto> {
let margin = self.get_margin(); let margin = self.get_margin();
physical::Sides { flow_relative::Sides::from_physical(
top: margin.margin_top.clone(), &PhysicalSides::new(
left: margin.margin_left.clone(), margin.margin_top.clone(),
bottom: margin.margin_bottom.clone(), margin.margin_right.clone(),
right: margin.margin_right.clone(), margin.margin_bottom.clone(),
} margin.margin_left.clone(),
.to_flow_relative(self.writing_mode) ),
self.writing_mode,
)
} }
} }

View file

@ -715,7 +715,7 @@ impl CSSPixelLength {
} }
} }
impl Zero for CSSPixelLength { impl num_traits::Zero for CSSPixelLength {
fn zero() -> Self { fn zero() -> Self {
CSSPixelLength::new(0.) CSSPixelLength::new(0.)
} }