mirror of
https://github.com/servo/servo.git
synced 2025-07-22 14:53:49 +01:00
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:
parent
ee3fb92e53
commit
02deb99a05
8 changed files with 184 additions and 273 deletions
|
@ -4,7 +4,7 @@
|
|||
|
||||
use crate::context::LayoutContext;
|
||||
use crate::fragments::{BoxFragment, Fragment};
|
||||
use crate::geom::physical::{Rect, Vec2};
|
||||
use crate::geom::{PhysicalPoint, PhysicalRect, ToWebRender};
|
||||
use crate::replaced::IntrinsicSizes;
|
||||
use embedder_traits::Cursor;
|
||||
use euclid::{Point2D, SideOffsets2D, Size2D, Vector2D};
|
||||
|
@ -74,7 +74,7 @@ impl Fragment {
|
|||
pub(crate) fn build_display_list(
|
||||
&self,
|
||||
builder: &mut DisplayListBuilder,
|
||||
containing_block: &Rect<Length>,
|
||||
containing_block: &PhysicalRect<Length>,
|
||||
) {
|
||||
match self {
|
||||
Fragment::Box(b) => BuilderForBoxFragment::new(b, containing_block).build(builder),
|
||||
|
@ -82,7 +82,7 @@ impl Fragment {
|
|||
let rect = a
|
||||
.rect
|
||||
.to_physical(a.mode, containing_block)
|
||||
.translate(&containing_block.top_left);
|
||||
.translate(containing_block.origin.to_vector());
|
||||
for child in &a.children {
|
||||
child.build_display_list(builder, &rect)
|
||||
}
|
||||
|
@ -92,30 +92,35 @@ impl Fragment {
|
|||
let rect = t
|
||||
.rect
|
||||
.to_physical(t.parent_style.writing_mode, containing_block)
|
||||
.translate(&containing_block.top_left);
|
||||
let mut baseline_origin = rect.top_left.clone();
|
||||
.translate(containing_block.origin.to_vector());
|
||||
let mut baseline_origin = rect.origin.clone();
|
||||
baseline_origin.y += t.ascent;
|
||||
let glyphs = glyphs(&t.glyphs, baseline_origin);
|
||||
if glyphs.is_empty() {
|
||||
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);
|
||||
let color = t.parent_style.clone_color();
|
||||
builder
|
||||
.wr
|
||||
.push_text(&common, rect.into(), &glyphs, t.font_key, rgba(color), None);
|
||||
builder.wr.push_text(
|
||||
&common,
|
||||
rect.to_webrender(),
|
||||
&glyphs,
|
||||
t.font_key,
|
||||
rgba(color),
|
||||
None,
|
||||
);
|
||||
},
|
||||
Fragment::Image(i) => {
|
||||
builder.is_contentful = true;
|
||||
let rect = i
|
||||
.rect
|
||||
.to_physical(i.style.writing_mode, containing_block)
|
||||
.translate(&containing_block.top_left);
|
||||
let common = builder.common_properties(rect.clone().into());
|
||||
.translate(containing_block.origin.to_vector());
|
||||
let common = builder.common_properties(rect.clone().to_webrender());
|
||||
builder.wr.push_image(
|
||||
&common,
|
||||
rect.into(),
|
||||
rect.to_webrender(),
|
||||
image_rendering(i.style.get_inherited_box().image_rendering),
|
||||
wr::AlphaType::PremultipliedAlpha,
|
||||
i.image_key,
|
||||
|
@ -128,7 +133,7 @@ impl Fragment {
|
|||
|
||||
struct BuilderForBoxFragment<'a> {
|
||||
fragment: &'a BoxFragment,
|
||||
containing_block: &'a Rect<Length>,
|
||||
containing_block: &'a PhysicalRect<Length>,
|
||||
border_rect: units::LayoutRect,
|
||||
padding_rect: OnceCell<units::LayoutRect>,
|
||||
content_rect: OnceCell<units::LayoutRect>,
|
||||
|
@ -137,12 +142,12 @@ struct 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
|
||||
.border_rect()
|
||||
.to_physical(fragment.style.writing_mode, containing_block)
|
||||
.translate(&containing_block.top_left)
|
||||
.into();
|
||||
.translate(containing_block.origin.to_vector())
|
||||
.to_webrender();
|
||||
|
||||
let border_radius = {
|
||||
let resolve = |radius: &LengthPercentage, box_size: f32| {
|
||||
|
@ -179,8 +184,8 @@ impl<'a> BuilderForBoxFragment<'a> {
|
|||
self.fragment
|
||||
.content_rect
|
||||
.to_physical(self.fragment.style.writing_mode, self.containing_block)
|
||||
.translate(&self.containing_block.top_left)
|
||||
.into()
|
||||
.translate(self.containing_block.origin.to_vector())
|
||||
.to_webrender()
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -189,8 +194,8 @@ impl<'a> BuilderForBoxFragment<'a> {
|
|||
self.fragment
|
||||
.padding_rect()
|
||||
.to_physical(self.fragment.style.writing_mode, self.containing_block)
|
||||
.translate(&self.containing_block.top_left)
|
||||
.into()
|
||||
.translate(self.containing_block.origin.to_vector())
|
||||
.to_webrender()
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -235,7 +240,7 @@ impl<'a> BuilderForBoxFragment<'a> {
|
|||
.fragment
|
||||
.content_rect
|
||||
.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 {
|
||||
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 range::Range;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use crate::context::LayoutContext;
|
||||
use crate::element_data::{LayoutBox, LayoutDataForElement};
|
||||
use crate::geom::physical::Vec2;
|
||||
use crate::geom::PhysicalSize;
|
||||
use crate::replaced::ReplacedContent;
|
||||
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside, DisplayOutside};
|
||||
use crate::wrapper::GetRawData;
|
||||
|
@ -307,7 +307,7 @@ pub(crate) trait NodeExt<'dom>: 'dom + Copy + LayoutNode + Send + Sync {
|
|||
|
||||
/// Returns the image if it’s loaded, and its size in image pixels
|
||||
/// 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 next_sibling(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 (resource, metadata) = node.image_data()?;
|
||||
let (width, height) = resource
|
||||
|
@ -350,11 +350,7 @@ where
|
|||
width = width / density;
|
||||
height = height / density;
|
||||
}
|
||||
let size = Vec2 {
|
||||
x: width,
|
||||
y: height,
|
||||
};
|
||||
Some((resource, size))
|
||||
Some((resource, PhysicalSize::new(width, height)))
|
||||
}
|
||||
|
||||
fn first_child(self) -> Option<Self> {
|
||||
|
|
|
@ -9,9 +9,8 @@ use crate::flow::float::FloatBox;
|
|||
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
|
||||
use crate::formatting_contexts::IndependentFormattingContext;
|
||||
use crate::fragments::Fragment;
|
||||
use crate::geom;
|
||||
use crate::geom::flow_relative::Vec2;
|
||||
use crate::geom::physical;
|
||||
use crate::geom::PhysicalRect;
|
||||
use crate::positioned::AbsolutelyPositionedBox;
|
||||
use crate::positioned::PositioningContext;
|
||||
use crate::replaced::ReplacedContent;
|
||||
|
@ -25,7 +24,6 @@ use script_layout_interface::wrapper_traits::LayoutNode;
|
|||
use servo_arc::Arc;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::Length;
|
||||
use style::Zero;
|
||||
use style_traits::CSSPixel;
|
||||
|
||||
pub struct BoxTreeRoot(BlockFormattingContext);
|
||||
|
@ -35,10 +33,10 @@ pub struct FragmentTreeRoot {
|
|||
children: Vec<Fragment>,
|
||||
|
||||
/// 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
|
||||
bounding_box_of_border_boxes: physical::Rect<Length>,
|
||||
bounding_box_of_border_boxes: PhysicalRect<Length>,
|
||||
}
|
||||
|
||||
impl BoxTreeRoot {
|
||||
|
@ -116,7 +114,7 @@ impl BoxTreeRoot {
|
|||
pub fn layout(
|
||||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
viewport: geom::Size<CSSPixel>,
|
||||
viewport: euclid::Size2D<f32, CSSPixel>,
|
||||
) -> FragmentTreeRoot {
|
||||
let style = ComputedValues::initial_values();
|
||||
let initial_containing_block = DefiniteContainingBlock {
|
||||
|
@ -150,7 +148,7 @@ impl BoxTreeRoot {
|
|||
independent_layout
|
||||
.fragments
|
||||
.iter()
|
||||
.fold(physical::Rect::zero(), |acc, child| {
|
||||
.fold(PhysicalRect::zero(), |acc, child| {
|
||||
let child_overflow = child.scrollable_overflow();
|
||||
|
||||
// https://drafts.csswg.org/css-overflow/#scrolling-direction
|
||||
|
@ -159,23 +157,23 @@ impl BoxTreeRoot {
|
|||
//
|
||||
// FIXME(mrobinson, bug 25564): This should take into account writing
|
||||
// mode.
|
||||
let child_overflow = physical::Rect {
|
||||
top_left: physical::Vec2::zero(),
|
||||
size: physical::Vec2 {
|
||||
x: child_overflow.size.x + child_overflow.top_left.x,
|
||||
y: child_overflow.size.y + child_overflow.top_left.y,
|
||||
},
|
||||
};
|
||||
acc.axis_aligned_bounding_box(&child_overflow)
|
||||
let child_overflow = PhysicalRect::new(
|
||||
euclid::Point2D::zero(),
|
||||
euclid::Size2D::new(
|
||||
child_overflow.size.width + child_overflow.origin.x,
|
||||
child_overflow.size.height + child_overflow.origin.y,
|
||||
),
|
||||
);
|
||||
acc.union(&child_overflow)
|
||||
});
|
||||
|
||||
let containing_block = physical::Rect::zero();
|
||||
let containing_block = PhysicalRect::zero();
|
||||
let bounding_box_of_border_boxes =
|
||||
independent_layout
|
||||
.fragments
|
||||
.iter()
|
||||
.fold(physical::Rect::zero(), |acc, child| {
|
||||
acc.axis_aligned_bounding_box(&match child {
|
||||
.fold(PhysicalRect::zero(), |acc, child| {
|
||||
acc.union(&match child {
|
||||
Fragment::Box(fragment) => fragment
|
||||
.border_rect()
|
||||
.to_physical(fragment.style.writing_mode, &containing_block),
|
||||
|
@ -205,16 +203,13 @@ impl FragmentTreeRoot {
|
|||
builder: &mut crate::display_list::DisplayListBuilder,
|
||||
viewport_size: webrender_api::units::LayoutSize,
|
||||
) {
|
||||
let containing_block = geom::physical::Rect {
|
||||
top_left: geom::physical::Vec2 {
|
||||
x: Length::zero(),
|
||||
y: Length::zero(),
|
||||
},
|
||||
size: geom::physical::Vec2 {
|
||||
x: Length::new(viewport_size.width),
|
||||
y: Length::new(viewport_size.height),
|
||||
},
|
||||
};
|
||||
let containing_block = PhysicalRect::new(
|
||||
euclid::Point2D::zero(),
|
||||
euclid::Size2D::new(
|
||||
Length::new(viewport_size.width),
|
||||
Length::new(viewport_size.height),
|
||||
),
|
||||
);
|
||||
for fragment in &self.children {
|
||||
fragment.build_display_list(builder, &containing_block)
|
||||
}
|
||||
|
@ -229,19 +224,19 @@ impl FragmentTreeRoot {
|
|||
|
||||
pub fn scrollable_overflow(&self) -> webrender_api::units::LayoutSize {
|
||||
webrender_api::units::LayoutSize::from_untyped(Size2D::new(
|
||||
self.scrollable_overflow.size.x.px(),
|
||||
self.scrollable_overflow.size.y.px(),
|
||||
self.scrollable_overflow.size.width.px(),
|
||||
self.scrollable_overflow.size.height.px(),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn bounding_box_of_border_boxes(&self) -> Rect<Au> {
|
||||
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.top_left.y.px()),
|
||||
Au::from_f32_px(self.bounding_box_of_border_boxes.origin.x.px()),
|
||||
Au::from_f32_px(self.bounding_box_of_border_boxes.origin.y.px()),
|
||||
);
|
||||
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.y.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.height.px()),
|
||||
);
|
||||
Rect::new(origin, size)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
||||
use crate::geom::physical;
|
||||
use crate::geom::PhysicalRect;
|
||||
use gfx::text::glyph::GlyphStore;
|
||||
use gfx_traits::print_tree::PrintTree;
|
||||
use servo_arc::Arc as ServoArc;
|
||||
|
@ -39,7 +39,7 @@ pub(crate) struct BoxFragment {
|
|||
pub block_margins_collapsed_with_children: CollapsedBlockMargins,
|
||||
|
||||
/// The scrollable overflow of this box fragment.
|
||||
pub scrollable_overflow: physical::Rect<Length>,
|
||||
pub scrollable_overflow: PhysicalRect<Length>,
|
||||
}
|
||||
|
||||
pub(crate) struct CollapsedBlockMargins {
|
||||
|
@ -61,7 +61,7 @@ pub(crate) struct AnonymousFragment {
|
|||
pub mode: WritingMode,
|
||||
|
||||
/// The scrollable overflow of this anonymous fragment's children.
|
||||
pub scrollable_overflow: physical::Rect<Length>,
|
||||
pub scrollable_overflow: PhysicalRect<Length>,
|
||||
}
|
||||
|
||||
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
|
||||
// here to properly convert scrollable overflow to physical geometry.
|
||||
match self {
|
||||
|
@ -106,10 +106,10 @@ impl Fragment {
|
|||
Fragment::Anonymous(fragment) => fragment.scrollable_overflow.clone(),
|
||||
Fragment::Text(fragment) => fragment
|
||||
.rect
|
||||
.to_physical(fragment.parent_style.writing_mode, &physical::Rect::zero()),
|
||||
.to_physical(fragment.parent_style.writing_mode, &PhysicalRect::zero()),
|
||||
Fragment::Image(fragment) => fragment
|
||||
.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![],
|
||||
rect: Rect::zero(),
|
||||
mode,
|
||||
scrollable_overflow: physical::Rect::zero(),
|
||||
scrollable_overflow: PhysicalRect::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(rect: Rect<Length>, children: Vec<Fragment>, mode: WritingMode) -> Self {
|
||||
// FIXME(mrobinson, bug 25564): We should be using the containing block
|
||||
// here to properly convert scrollable overflow to physical geometry.
|
||||
let scrollable_overflow = children.iter().fold(physical::Rect::zero(), |acc, child| {
|
||||
acc.axis_aligned_bounding_box(&child.scrollable_overflow())
|
||||
let scrollable_overflow = children.iter().fold(PhysicalRect::zero(), |acc, child| {
|
||||
acc.union(&child.scrollable_overflow())
|
||||
});
|
||||
AnonymousFragment {
|
||||
rect,
|
||||
|
@ -168,8 +168,8 @@ impl BoxFragment {
|
|||
let scrollable_overflow = children.iter().fold(
|
||||
content_rect
|
||||
.inflate(&border)
|
||||
.to_physical(style.writing_mode, &physical::Rect::zero()),
|
||||
|acc, child| acc.axis_aligned_bounding_box(&child.scrollable_overflow()),
|
||||
.to_physical(style.writing_mode, &PhysicalRect::zero()),
|
||||
|acc, child| acc.union(&child.scrollable_overflow()),
|
||||
);
|
||||
BoxFragment {
|
||||
tag,
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<physical::Vec2<Length>> for Point<CSSPixel> {
|
||||
fn from(v: physical::Vec2<Length>) -> Self {
|
||||
Point::from_lengths(v.x.into(), v.y.into())
|
||||
PhysicalSize::new(x.clone(), y.clone())
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 }
|
||||
PhysicalRect::new(
|
||||
PhysicalPoint::new(tl_x.clone(), tl_y.clone()),
|
||||
self.size.to_physical(mode),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Zero> physical::Rect<T> {
|
||||
pub fn zero() -> Self {
|
||||
Self {
|
||||
top_left: physical::Vec2::zero(),
|
||||
size: physical::Vec2::zero(),
|
||||
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 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 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 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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
use crate::dom_traversal::NodeExt;
|
||||
use crate::fragments::{Fragment, ImageFragment};
|
||||
use crate::geom::flow_relative::{Rect, Vec2};
|
||||
use crate::geom::physical;
|
||||
use crate::geom::PhysicalSize;
|
||||
use crate::sizing::ContentSizes;
|
||||
use crate::style_ext::ComputedValuesExt;
|
||||
use crate::ContainingBlock;
|
||||
|
@ -55,8 +55,8 @@ impl ReplacedContent {
|
|||
// https://drafts.csswg.org/css-images-4/#the-image-resolution
|
||||
let dppx = 1.0;
|
||||
|
||||
let width = (intrinsic_size_in_dots.x as CSSFloat) / dppx;
|
||||
let height = (intrinsic_size_in_dots.y as CSSFloat) / dppx;
|
||||
let width = (intrinsic_size_in_dots.width as CSSFloat) / dppx;
|
||||
let height = (intrinsic_size_in_dots.height as CSSFloat) / dppx;
|
||||
return Some(Self {
|
||||
kind: ReplacedContentKind::Image(image),
|
||||
intrinsic: IntrinsicSizes {
|
||||
|
@ -71,11 +71,8 @@ impl ReplacedContent {
|
|||
}
|
||||
|
||||
fn flow_relative_intrinsic_size(&self, style: &ComputedValues) -> Vec2<Option<Length>> {
|
||||
let intrinsic_size = physical::Vec2 {
|
||||
x: self.intrinsic.width,
|
||||
y: self.intrinsic.height,
|
||||
};
|
||||
intrinsic_size.size_to_flow_relative(style.writing_mode)
|
||||
let intrinsic_size = PhysicalSize::new(self.intrinsic.width, self.intrinsic.height);
|
||||
Vec2::from_physical_size(&intrinsic_size, style.writing_mode)
|
||||
}
|
||||
|
||||
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.”
|
||||
// “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.”
|
||||
physical::Vec2 {
|
||||
x: Length::new(300.),
|
||||
y: Length::new(150.),
|
||||
}
|
||||
.size_to_flow_relative(mode)
|
||||
Vec2::from_physical_size(
|
||||
&PhysicalSize::new(Length::new(300.), Length::new(150.)),
|
||||
mode,
|
||||
)
|
||||
};
|
||||
let clamp = |inline_size: Length, block_size: Length| Vec2 {
|
||||
inline: inline_size.clamp_between_extremums(min_box_size.inline, max_box_size.inline),
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
use crate::geom::{flow_relative, physical};
|
||||
use crate::geom::{flow_relative, PhysicalSides, PhysicalSize};
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::{Length, LengthPercentage, LengthPercentageOrAuto};
|
||||
use style::values::computed::{NonNegativeLengthPercentage, Size};
|
||||
|
@ -75,33 +75,39 @@ impl ComputedValuesExt for ComputedValues {
|
|||
#[inline]
|
||||
fn box_offsets(&self) -> flow_relative::Sides<LengthPercentageOrAuto> {
|
||||
let position = self.get_position();
|
||||
physical::Sides {
|
||||
top: position.top.clone(),
|
||||
left: position.left.clone(),
|
||||
bottom: position.bottom.clone(),
|
||||
right: position.right.clone(),
|
||||
}
|
||||
.to_flow_relative(self.writing_mode)
|
||||
flow_relative::Sides::from_physical(
|
||||
&PhysicalSides::new(
|
||||
position.top.clone(),
|
||||
position.right.clone(),
|
||||
position.bottom.clone(),
|
||||
position.left.clone(),
|
||||
),
|
||||
self.writing_mode,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn box_size(&self) -> flow_relative::Vec2<LengthPercentageOrAuto> {
|
||||
let position = self.get_position();
|
||||
physical::Vec2 {
|
||||
x: size_to_length(position.width.clone()),
|
||||
y: size_to_length(position.height.clone()),
|
||||
}
|
||||
.size_to_flow_relative(self.writing_mode)
|
||||
flow_relative::Vec2::from_physical_size(
|
||||
&PhysicalSize::new(
|
||||
size_to_length(position.width.clone()),
|
||||
size_to_length(position.height.clone()),
|
||||
),
|
||||
self.writing_mode,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn min_box_size(&self) -> flow_relative::Vec2<LengthPercentageOrAuto> {
|
||||
let position = self.get_position();
|
||||
physical::Vec2 {
|
||||
x: size_to_length(position.min_width.clone()),
|
||||
y: size_to_length(position.min_height.clone()),
|
||||
}
|
||||
.size_to_flow_relative(self.writing_mode)
|
||||
flow_relative::Vec2::from_physical_size(
|
||||
&PhysicalSize::new(
|
||||
size_to_length(position.min_width.clone()),
|
||||
size_to_length(position.min_height.clone()),
|
||||
),
|
||||
self.writing_mode,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -111,45 +117,53 @@ impl ComputedValuesExt for ComputedValues {
|
|||
MaxSize::None => MaxSize::None,
|
||||
};
|
||||
let position = self.get_position();
|
||||
physical::Vec2 {
|
||||
x: unwrap(position.max_width.clone()),
|
||||
y: unwrap(position.max_height.clone()),
|
||||
}
|
||||
.size_to_flow_relative(self.writing_mode)
|
||||
flow_relative::Vec2::from_physical_size(
|
||||
&PhysicalSize::new(
|
||||
unwrap(position.max_width.clone()),
|
||||
unwrap(position.max_height.clone()),
|
||||
),
|
||||
self.writing_mode,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn padding(&self) -> flow_relative::Sides<LengthPercentage> {
|
||||
let padding = self.get_padding();
|
||||
physical::Sides {
|
||||
top: padding.padding_top.0.clone(),
|
||||
left: padding.padding_left.0.clone(),
|
||||
bottom: padding.padding_bottom.0.clone(),
|
||||
right: padding.padding_right.0.clone(),
|
||||
}
|
||||
.to_flow_relative(self.writing_mode)
|
||||
flow_relative::Sides::from_physical(
|
||||
&PhysicalSides::new(
|
||||
padding.padding_top.0.clone(),
|
||||
padding.padding_right.0.clone(),
|
||||
padding.padding_bottom.0.clone(),
|
||||
padding.padding_left.0.clone(),
|
||||
),
|
||||
self.writing_mode,
|
||||
)
|
||||
}
|
||||
|
||||
fn border_width(&self) -> flow_relative::Sides<Length> {
|
||||
let border = self.get_border();
|
||||
physical::Sides {
|
||||
top: border.border_top_width.0,
|
||||
left: border.border_left_width.0,
|
||||
bottom: border.border_bottom_width.0,
|
||||
right: border.border_right_width.0,
|
||||
}
|
||||
.to_flow_relative(self.writing_mode)
|
||||
flow_relative::Sides::from_physical(
|
||||
&PhysicalSides::new(
|
||||
border.border_top_width.0,
|
||||
border.border_right_width.0,
|
||||
border.border_bottom_width.0,
|
||||
border.border_left_width.0,
|
||||
),
|
||||
self.writing_mode,
|
||||
)
|
||||
}
|
||||
|
||||
fn margin(&self) -> flow_relative::Sides<LengthPercentageOrAuto> {
|
||||
let margin = self.get_margin();
|
||||
physical::Sides {
|
||||
top: margin.margin_top.clone(),
|
||||
left: margin.margin_left.clone(),
|
||||
bottom: margin.margin_bottom.clone(),
|
||||
right: margin.margin_right.clone(),
|
||||
}
|
||||
.to_flow_relative(self.writing_mode)
|
||||
flow_relative::Sides::from_physical(
|
||||
&PhysicalSides::new(
|
||||
margin.margin_top.clone(),
|
||||
margin.margin_right.clone(),
|
||||
margin.margin_bottom.clone(),
|
||||
margin.margin_left.clone(),
|
||||
),
|
||||
self.writing_mode,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -715,7 +715,7 @@ impl CSSPixelLength {
|
|||
}
|
||||
}
|
||||
|
||||
impl Zero for CSSPixelLength {
|
||||
impl num_traits::Zero for CSSPixelLength {
|
||||
fn zero() -> Self {
|
||||
CSSPixelLength::new(0.)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue