diff options
author | Delan Azabani <dazabani@igalia.com> | 2024-02-27 23:39:06 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-27 15:39:06 +0000 |
commit | faf754dfa655f0b9a28f62bc47a78fbf78ebcaf4 (patch) | |
tree | 4725e1446680d036797b1fc258733ae6b2c9f354 /components/style/logical_geometry.rs | |
parent | b07505417e629bbb081be9683630f2d7a5f50544 (diff) | |
download | servo-faf754dfa655f0b9a28f62bc47a78fbf78ebcaf4.tar.gz servo-faf754dfa655f0b9a28f62bc47a78fbf78ebcaf4.zip |
Move Stylo to its own repo (#31350)
* Remove packages that were moved to external repo
* Add workspace dependencies pointing to 2023-06-14 branch
* Fix servo-tidy.toml errors
* Update commit to include #31346
* Update commit to include servo/stylo#2
* Move css-properties.json lookup to target/doc/stylo
* Remove dependency on vendored mako in favour of pypi dependency
This also removes etc/ci/generate_workflow.py, which has been unused
since at least 9e71bd6a7010d6e5723831696ae0ebe26b47682f.
* Add temporary code to debug Windows test failures
* Fix failures on Windows due to custom target dir
* Update commit to include servo/stylo#3
* Fix license in tests/unit/style/build.rs
* Document how to build with local Stylo in Cargo.toml
Diffstat (limited to 'components/style/logical_geometry.rs')
-rw-r--r-- | components/style/logical_geometry.rs | 1522 |
1 files changed, 0 insertions, 1522 deletions
diff --git a/components/style/logical_geometry.rs b/components/style/logical_geometry.rs deleted file mode 100644 index 9a823a5a24a..00000000000 --- a/components/style/logical_geometry.rs +++ /dev/null @@ -1,1522 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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/. */ - -//! Geometry in flow-relative space. - -use crate::properties::style_structs; -use euclid::default::{Point2D, Rect, SideOffsets2D, Size2D}; -use euclid::num::Zero; -use std::cmp::{max, min}; -use std::fmt::{self, Debug, Error, Formatter}; -use std::ops::{Add, Sub}; -use unicode_bidi as bidi; - -pub enum BlockFlowDirection { - TopToBottom, - RightToLeft, - LeftToRight, -} - -pub enum InlineBaseDirection { - LeftToRight, - RightToLeft, -} - -// TODO: improve the readability of the WritingMode serialization, refer to the Debug:fmt() -bitflags!( - #[cfg_attr(feature = "servo", derive(MallocSizeOf, Serialize))] - #[repr(C)] - pub struct WritingMode: u8 { - /// A vertical writing mode; writing-mode is vertical-rl, - /// vertical-lr, sideways-lr, or sideways-rl. - const VERTICAL = 1 << 0; - /// The inline flow direction is reversed against the physical - /// direction (i.e. right-to-left or bottom-to-top); writing-mode is - /// sideways-lr or direction is rtl (but not both). - /// - /// (This bit can be derived from the others, but we store it for - /// convenience.) - const INLINE_REVERSED = 1 << 1; - /// A vertical writing mode whose block progression direction is left- - /// to-right; writing-mode is vertical-lr or sideways-lr. - /// - /// Never set without VERTICAL. - const VERTICAL_LR = 1 << 2; - /// The line-over/line-under sides are inverted with respect to the - /// block-start/block-end edge; writing-mode is vertical-lr. - /// - /// Never set without VERTICAL and VERTICAL_LR. - const LINE_INVERTED = 1 << 3; - /// direction is rtl. - const RTL = 1 << 4; - /// All text within a vertical writing mode is displayed sideways - /// and runs top-to-bottom or bottom-to-top; set in these cases: - /// - /// * writing-mode: sideways-rl; - /// * writing-mode: sideways-lr; - /// - /// Never set without VERTICAL. - const VERTICAL_SIDEWAYS = 1 << 5; - /// Similar to VERTICAL_SIDEWAYS, but is set via text-orientation; - /// set in these cases: - /// - /// * writing-mode: vertical-rl; text-orientation: sideways; - /// * writing-mode: vertical-lr; text-orientation: sideways; - /// - /// Never set without VERTICAL. - const TEXT_SIDEWAYS = 1 << 6; - /// Horizontal text within a vertical writing mode is displayed with each - /// glyph upright; set in these cases: - /// - /// * writing-mode: vertical-rl; text-orientation: upright; - /// * writing-mode: vertical-lr: text-orientation: upright; - /// - /// Never set without VERTICAL. - const UPRIGHT = 1 << 7; - } -); - -impl WritingMode { - /// Return a WritingMode bitflags from the relevant CSS properties. - pub fn new(inheritedbox_style: &style_structs::InheritedBox) -> Self { - use crate::properties::longhands::direction::computed_value::T as Direction; - use crate::properties::longhands::writing_mode::computed_value::T as SpecifiedWritingMode; - - let mut flags = WritingMode::empty(); - - let direction = inheritedbox_style.clone_direction(); - let writing_mode = inheritedbox_style.clone_writing_mode(); - - match direction { - Direction::Ltr => {}, - Direction::Rtl => { - flags.insert(WritingMode::RTL); - }, - } - - match writing_mode { - SpecifiedWritingMode::HorizontalTb => { - if direction == Direction::Rtl { - flags.insert(WritingMode::INLINE_REVERSED); - } - }, - SpecifiedWritingMode::VerticalRl => { - flags.insert(WritingMode::VERTICAL); - if direction == Direction::Rtl { - flags.insert(WritingMode::INLINE_REVERSED); - } - }, - SpecifiedWritingMode::VerticalLr => { - flags.insert(WritingMode::VERTICAL); - flags.insert(WritingMode::VERTICAL_LR); - flags.insert(WritingMode::LINE_INVERTED); - if direction == Direction::Rtl { - flags.insert(WritingMode::INLINE_REVERSED); - } - }, - #[cfg(feature = "gecko")] - SpecifiedWritingMode::SidewaysRl => { - flags.insert(WritingMode::VERTICAL); - flags.insert(WritingMode::VERTICAL_SIDEWAYS); - if direction == Direction::Rtl { - flags.insert(WritingMode::INLINE_REVERSED); - } - }, - #[cfg(feature = "gecko")] - SpecifiedWritingMode::SidewaysLr => { - flags.insert(WritingMode::VERTICAL); - flags.insert(WritingMode::VERTICAL_LR); - flags.insert(WritingMode::VERTICAL_SIDEWAYS); - if direction == Direction::Ltr { - flags.insert(WritingMode::INLINE_REVERSED); - } - }, - } - - #[cfg(feature = "gecko")] - { - use crate::properties::longhands::text_orientation::computed_value::T as TextOrientation; - - // text-orientation only has an effect for vertical-rl and - // vertical-lr values of writing-mode. - match writing_mode { - SpecifiedWritingMode::VerticalRl | SpecifiedWritingMode::VerticalLr => { - match inheritedbox_style.clone_text_orientation() { - TextOrientation::Mixed => {}, - TextOrientation::Upright => { - flags.insert(WritingMode::UPRIGHT); - - // https://drafts.csswg.org/css-writing-modes-3/#valdef-text-orientation-upright: - // - // > This value causes the used value of direction - // > to be ltr, and for the purposes of bidi - // > reordering, causes all characters to be treated - // > as strong LTR. - flags.remove(WritingMode::RTL); - flags.remove(WritingMode::INLINE_REVERSED); - }, - TextOrientation::Sideways => { - flags.insert(WritingMode::TEXT_SIDEWAYS); - }, - } - }, - _ => {}, - } - } - - flags - } - - /// Returns the `horizontal-tb` value. - pub fn horizontal_tb() -> Self { - Self::from_bits_truncate(0) - } - - #[inline] - pub fn is_vertical(&self) -> bool { - self.intersects(WritingMode::VERTICAL) - } - - #[inline] - pub fn is_horizontal(&self) -> bool { - !self.is_vertical() - } - - /// Assuming .is_vertical(), does the block direction go left to right? - #[inline] - pub fn is_vertical_lr(&self) -> bool { - self.intersects(WritingMode::VERTICAL_LR) - } - - /// Assuming .is_vertical(), does the inline direction go top to bottom? - #[inline] - pub fn is_inline_tb(&self) -> bool { - // https://drafts.csswg.org/css-writing-modes-3/#logical-to-physical - !self.intersects(WritingMode::INLINE_REVERSED) - } - - #[inline] - pub fn is_bidi_ltr(&self) -> bool { - !self.intersects(WritingMode::RTL) - } - - #[inline] - pub fn is_sideways(&self) -> bool { - self.intersects(WritingMode::VERTICAL_SIDEWAYS | WritingMode::TEXT_SIDEWAYS) - } - - #[inline] - pub fn is_upright(&self) -> bool { - self.intersects(WritingMode::UPRIGHT) - } - - /// https://drafts.csswg.org/css-writing-modes/#logical-to-physical - /// - /// | Return | line-left is… | line-right is… | - /// |---------|---------------|----------------| - /// | `true` | inline-start | inline-end | - /// | `false` | inline-end | inline-start | - #[inline] - pub fn line_left_is_inline_start(&self) -> bool { - // https://drafts.csswg.org/css-writing-modes/#inline-start - // “For boxes with a used direction value of ltr, this means the line-left side. - // For boxes with a used direction value of rtl, this means the line-right side.” - self.is_bidi_ltr() - } - - #[inline] - pub fn inline_start_physical_side(&self) -> PhysicalSide { - match (self.is_vertical(), self.is_inline_tb(), self.is_bidi_ltr()) { - (false, _, true) => PhysicalSide::Left, - (false, _, false) => PhysicalSide::Right, - (true, true, _) => PhysicalSide::Top, - (true, false, _) => PhysicalSide::Bottom, - } - } - - #[inline] - pub fn inline_end_physical_side(&self) -> PhysicalSide { - match (self.is_vertical(), self.is_inline_tb(), self.is_bidi_ltr()) { - (false, _, true) => PhysicalSide::Right, - (false, _, false) => PhysicalSide::Left, - (true, true, _) => PhysicalSide::Bottom, - (true, false, _) => PhysicalSide::Top, - } - } - - #[inline] - pub fn block_start_physical_side(&self) -> PhysicalSide { - match (self.is_vertical(), self.is_vertical_lr()) { - (false, _) => PhysicalSide::Top, - (true, true) => PhysicalSide::Left, - (true, false) => PhysicalSide::Right, - } - } - - #[inline] - pub fn block_end_physical_side(&self) -> PhysicalSide { - match (self.is_vertical(), self.is_vertical_lr()) { - (false, _) => PhysicalSide::Bottom, - (true, true) => PhysicalSide::Right, - (true, false) => PhysicalSide::Left, - } - } - - #[inline] - fn physical_sides_to_corner( - block_side: PhysicalSide, - inline_side: PhysicalSide, - ) -> PhysicalCorner { - match (block_side, inline_side) { - (PhysicalSide::Top, PhysicalSide::Left) | (PhysicalSide::Left, PhysicalSide::Top) => { - PhysicalCorner::TopLeft - }, - (PhysicalSide::Top, PhysicalSide::Right) | (PhysicalSide::Right, PhysicalSide::Top) => { - PhysicalCorner::TopRight - }, - (PhysicalSide::Bottom, PhysicalSide::Right) | - (PhysicalSide::Right, PhysicalSide::Bottom) => PhysicalCorner::BottomRight, - (PhysicalSide::Bottom, PhysicalSide::Left) | - (PhysicalSide::Left, PhysicalSide::Bottom) => PhysicalCorner::BottomLeft, - _ => unreachable!("block and inline sides must be orthogonal"), - } - } - - #[inline] - pub fn start_start_physical_corner(&self) -> PhysicalCorner { - WritingMode::physical_sides_to_corner( - self.block_start_physical_side(), - self.inline_start_physical_side(), - ) - } - - #[inline] - pub fn start_end_physical_corner(&self) -> PhysicalCorner { - WritingMode::physical_sides_to_corner( - self.block_start_physical_side(), - self.inline_end_physical_side(), - ) - } - - #[inline] - pub fn end_start_physical_corner(&self) -> PhysicalCorner { - WritingMode::physical_sides_to_corner( - self.block_end_physical_side(), - self.inline_start_physical_side(), - ) - } - - #[inline] - pub fn end_end_physical_corner(&self) -> PhysicalCorner { - WritingMode::physical_sides_to_corner( - self.block_end_physical_side(), - self.inline_end_physical_side(), - ) - } - - #[inline] - pub fn block_flow_direction(&self) -> BlockFlowDirection { - match (self.is_vertical(), self.is_vertical_lr()) { - (false, _) => BlockFlowDirection::TopToBottom, - (true, true) => BlockFlowDirection::LeftToRight, - (true, false) => BlockFlowDirection::RightToLeft, - } - } - - #[inline] - pub fn inline_base_direction(&self) -> InlineBaseDirection { - if self.intersects(WritingMode::RTL) { - InlineBaseDirection::RightToLeft - } else { - InlineBaseDirection::LeftToRight - } - } - - #[inline] - /// The default bidirectional embedding level for this writing mode. - /// - /// Returns bidi level 0 if the mode is LTR, or 1 otherwise. - pub fn to_bidi_level(&self) -> bidi::Level { - if self.is_bidi_ltr() { - bidi::Level::ltr() - } else { - bidi::Level::rtl() - } - } -} - -impl fmt::Display for WritingMode { - fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> { - if self.is_vertical() { - write!(formatter, "V")?; - if self.is_vertical_lr() { - write!(formatter, " LR")?; - } else { - write!(formatter, " RL")?; - } - if self.is_sideways() { - write!(formatter, " Sideways")?; - } - if self.intersects(WritingMode::LINE_INVERTED) { - write!(formatter, " Inverted")?; - } - } else { - write!(formatter, "H")?; - } - if self.is_bidi_ltr() { - write!(formatter, " LTR") - } else { - write!(formatter, " RTL") - } - } -} - -/// Wherever logical geometry is used, the writing mode is known based on context: -/// every method takes a `mode` parameter. -/// However, this context is easy to get wrong. -/// In debug builds only, logical geometry objects store their writing mode -/// (in addition to taking it as a parameter to methods) and check it. -/// In non-debug builds, make this storage zero-size and the checks no-ops. -#[cfg(not(debug_assertions))] -#[derive(Clone, Copy, Eq, PartialEq)] -#[cfg_attr(feature = "servo", derive(Serialize))] -struct DebugWritingMode; - -#[cfg(debug_assertions)] -#[derive(Clone, Copy, Eq, PartialEq)] -#[cfg_attr(feature = "servo", derive(Serialize))] -struct DebugWritingMode { - mode: WritingMode, -} - -#[cfg(not(debug_assertions))] -impl DebugWritingMode { - #[inline] - fn check(&self, _other: WritingMode) {} - - #[inline] - fn check_debug(&self, _other: DebugWritingMode) {} - - #[inline] - fn new(_mode: WritingMode) -> DebugWritingMode { - DebugWritingMode - } -} - -#[cfg(debug_assertions)] -impl DebugWritingMode { - #[inline] - fn check(&self, other: WritingMode) { - assert_eq!(self.mode, other) - } - - #[inline] - fn check_debug(&self, other: DebugWritingMode) { - assert_eq!(self.mode, other.mode) - } - - #[inline] - fn new(mode: WritingMode) -> DebugWritingMode { - DebugWritingMode { mode: mode } - } -} - -impl Debug for DebugWritingMode { - #[cfg(not(debug_assertions))] - fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> { - write!(formatter, "?") - } - - #[cfg(debug_assertions)] - fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> { - write!(formatter, "{}", self.mode) - } -} - -// Used to specify the logical direction. -#[derive(Clone, Copy, Debug, PartialEq)] -#[cfg_attr(feature = "servo", derive(Serialize))] -pub enum Direction { - Inline, - Block, -} - -/// A 2D size in flow-relative dimensions -#[derive(Clone, Copy, Eq, PartialEq)] -#[cfg_attr(feature = "servo", derive(Serialize))] -pub struct LogicalSize<T> { - pub inline: T, // inline-size, a.k.a. logical width, a.k.a. measure - pub block: T, // block-size, a.k.a. logical height, a.k.a. extent - debug_writing_mode: DebugWritingMode, -} - -impl<T: Debug> Debug for LogicalSize<T> { - fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> { - write!( - formatter, - "LogicalSize({:?}, i{:?}×b{:?})", - self.debug_writing_mode, self.inline, self.block - ) - } -} - -// Can not implement the Zero trait: its zero() method does not have the `mode` parameter. -impl<T: Zero> LogicalSize<T> { - #[inline] - pub fn zero(mode: WritingMode) -> LogicalSize<T> { - LogicalSize { - inline: Zero::zero(), - block: Zero::zero(), - debug_writing_mode: DebugWritingMode::new(mode), - } - } -} - -impl<T> LogicalSize<T> { - #[inline] - pub fn new(mode: WritingMode, inline: T, block: T) -> LogicalSize<T> { - LogicalSize { - inline: inline, - block: block, - debug_writing_mode: DebugWritingMode::new(mode), - } - } - - #[inline] - pub fn from_physical(mode: WritingMode, size: Size2D<T>) -> LogicalSize<T> { - if mode.is_vertical() { - LogicalSize::new(mode, size.height, size.width) - } else { - LogicalSize::new(mode, size.width, size.height) - } - } -} - -impl<T: Copy> LogicalSize<T> { - #[inline] - pub fn width(&self, mode: WritingMode) -> T { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - self.block - } else { - self.inline - } - } - - #[inline] - pub fn set_width(&mut self, mode: WritingMode, width: T) { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - self.block = width - } else { - self.inline = width - } - } - - #[inline] - pub fn height(&self, mode: WritingMode) -> T { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - self.inline - } else { - self.block - } - } - - #[inline] - pub fn set_height(&mut self, mode: WritingMode, height: T) { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - self.inline = height - } else { - self.block = height - } - } - - #[inline] - pub fn to_physical(&self, mode: WritingMode) -> Size2D<T> { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - Size2D::new(self.block, self.inline) - } else { - Size2D::new(self.inline, self.block) - } - } - - #[inline] - pub fn convert(&self, mode_from: WritingMode, mode_to: WritingMode) -> LogicalSize<T> { - if mode_from == mode_to { - self.debug_writing_mode.check(mode_from); - *self - } else { - LogicalSize::from_physical(mode_to, self.to_physical(mode_from)) - } - } -} - -impl<T: Add<T, Output = T>> Add for LogicalSize<T> { - type Output = LogicalSize<T>; - - #[inline] - fn add(self, other: LogicalSize<T>) -> LogicalSize<T> { - self.debug_writing_mode - .check_debug(other.debug_writing_mode); - LogicalSize { - debug_writing_mode: self.debug_writing_mode, - inline: self.inline + other.inline, - block: self.block + other.block, - } - } -} - -// TODO(servo#30577) remove this once underlying bugs are fixed -impl<T: Add<T, Output = T>> LogicalSize<T> { - #[inline] - pub fn add_or_warn(self, other: LogicalSize<T>) -> LogicalSize<T> { - #[cfg(debug_assertions)] - if !(self.debug_writing_mode.mode == other.debug_writing_mode.mode) { - log::warn!("debug assertion failed! self.debug_writing_mode.mode == other.debug_writing_mode.mode"); - } - LogicalSize { - debug_writing_mode: self.debug_writing_mode, - inline: self.inline + other.inline, - block: self.block + other.block, - } - } -} - -impl<T: Sub<T, Output = T>> Sub for LogicalSize<T> { - type Output = LogicalSize<T>; - - #[inline] - fn sub(self, other: LogicalSize<T>) -> LogicalSize<T> { - self.debug_writing_mode - .check_debug(other.debug_writing_mode); - LogicalSize { - debug_writing_mode: self.debug_writing_mode, - inline: self.inline - other.inline, - block: self.block - other.block, - } - } -} - -/// A 2D point in flow-relative dimensions -#[derive(Clone, Copy, Eq, PartialEq)] -#[cfg_attr(feature = "servo", derive(Serialize))] -pub struct LogicalPoint<T> { - /// inline-axis coordinate - pub i: T, - /// block-axis coordinate - pub b: T, - debug_writing_mode: DebugWritingMode, -} - -impl<T: Debug> Debug for LogicalPoint<T> { - fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> { - write!( - formatter, - "LogicalPoint({:?} (i{:?}, b{:?}))", - self.debug_writing_mode, self.i, self.b - ) - } -} - -// Can not implement the Zero trait: its zero() method does not have the `mode` parameter. -impl<T: Zero> LogicalPoint<T> { - #[inline] - pub fn zero(mode: WritingMode) -> LogicalPoint<T> { - LogicalPoint { - i: Zero::zero(), - b: Zero::zero(), - debug_writing_mode: DebugWritingMode::new(mode), - } - } -} - -impl<T: Copy> LogicalPoint<T> { - #[inline] - pub fn new(mode: WritingMode, i: T, b: T) -> LogicalPoint<T> { - LogicalPoint { - i: i, - b: b, - debug_writing_mode: DebugWritingMode::new(mode), - } - } -} - -impl<T: Copy + Sub<T, Output = T>> LogicalPoint<T> { - #[inline] - pub fn from_physical( - mode: WritingMode, - point: Point2D<T>, - container_size: Size2D<T>, - ) -> LogicalPoint<T> { - if mode.is_vertical() { - LogicalPoint { - i: if mode.is_inline_tb() { - point.y - } else { - container_size.height - point.y - }, - b: if mode.is_vertical_lr() { - point.x - } else { - container_size.width - point.x - }, - debug_writing_mode: DebugWritingMode::new(mode), - } - } else { - LogicalPoint { - i: if mode.is_bidi_ltr() { - point.x - } else { - container_size.width - point.x - }, - b: point.y, - debug_writing_mode: DebugWritingMode::new(mode), - } - } - } - - #[inline] - pub fn x(&self, mode: WritingMode, container_size: Size2D<T>) -> T { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - if mode.is_vertical_lr() { - self.b - } else { - container_size.width - self.b - } - } else { - if mode.is_bidi_ltr() { - self.i - } else { - container_size.width - self.i - } - } - } - - #[inline] - pub fn set_x(&mut self, mode: WritingMode, x: T, container_size: Size2D<T>) { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - self.b = if mode.is_vertical_lr() { - x - } else { - container_size.width - x - } - } else { - self.i = if mode.is_bidi_ltr() { - x - } else { - container_size.width - x - } - } - } - - #[inline] - pub fn y(&self, mode: WritingMode, container_size: Size2D<T>) -> T { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - if mode.is_inline_tb() { - self.i - } else { - container_size.height - self.i - } - } else { - self.b - } - } - - #[inline] - pub fn set_y(&mut self, mode: WritingMode, y: T, container_size: Size2D<T>) { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - self.i = if mode.is_inline_tb() { - y - } else { - container_size.height - y - } - } else { - self.b = y - } - } - - #[inline] - pub fn to_physical(&self, mode: WritingMode, container_size: Size2D<T>) -> Point2D<T> { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - Point2D::new( - if mode.is_vertical_lr() { - self.b - } else { - container_size.width - self.b - }, - if mode.is_inline_tb() { - self.i - } else { - container_size.height - self.i - }, - ) - } else { - Point2D::new( - if mode.is_bidi_ltr() { - self.i - } else { - container_size.width - self.i - }, - self.b, - ) - } - } - - // TODO(servo#30577) remove this once underlying bugs are fixed - #[inline] - pub fn to_physical_or_warn(&self, mode: WritingMode, container_size: Size2D<T>) -> Point2D<T> { - #[cfg(debug_assertions)] - if !(self.debug_writing_mode.mode == mode) { - log::warn!("debug assertion failed! self.debug_writing_mode.mode == mode"); - } - if mode.is_vertical() { - Point2D::new( - if mode.is_vertical_lr() { - self.b - } else { - container_size.width - self.b - }, - if mode.is_inline_tb() { - self.i - } else { - container_size.height - self.i - }, - ) - } else { - Point2D::new( - if mode.is_bidi_ltr() { - self.i - } else { - container_size.width - self.i - }, - self.b, - ) - } - } - - #[inline] - pub fn convert( - &self, - mode_from: WritingMode, - mode_to: WritingMode, - container_size: Size2D<T>, - ) -> LogicalPoint<T> { - if mode_from == mode_to { - self.debug_writing_mode.check(mode_from); - *self - } else { - LogicalPoint::from_physical( - mode_to, - self.to_physical(mode_from, container_size), - container_size, - ) - } - } -} - -impl<T: Copy + Add<T, Output = T>> LogicalPoint<T> { - /// This doesn’t really makes sense, - /// but happens when dealing with multiple origins. - #[inline] - pub fn add_point(&self, other: &LogicalPoint<T>) -> LogicalPoint<T> { - self.debug_writing_mode - .check_debug(other.debug_writing_mode); - LogicalPoint { - debug_writing_mode: self.debug_writing_mode, - i: self.i + other.i, - b: self.b + other.b, - } - } -} - -impl<T: Copy + Add<T, Output = T>> Add<LogicalSize<T>> for LogicalPoint<T> { - type Output = LogicalPoint<T>; - - #[inline] - fn add(self, other: LogicalSize<T>) -> LogicalPoint<T> { - self.debug_writing_mode - .check_debug(other.debug_writing_mode); - LogicalPoint { - debug_writing_mode: self.debug_writing_mode, - i: self.i + other.inline, - b: self.b + other.block, - } - } -} - -impl<T: Copy + Sub<T, Output = T>> Sub<LogicalSize<T>> for LogicalPoint<T> { - type Output = LogicalPoint<T>; - - #[inline] - fn sub(self, other: LogicalSize<T>) -> LogicalPoint<T> { - self.debug_writing_mode - .check_debug(other.debug_writing_mode); - LogicalPoint { - debug_writing_mode: self.debug_writing_mode, - i: self.i - other.inline, - b: self.b - other.block, - } - } -} - -/// A "margin" in flow-relative dimensions -/// Represents the four sides of the margins, borders, or padding of a CSS box, -/// or a combination of those. -/// A positive "margin" can be added to a rectangle to obtain a bigger rectangle. -#[derive(Clone, Copy, Eq, PartialEq)] -#[cfg_attr(feature = "servo", derive(Serialize))] -pub struct LogicalMargin<T> { - pub block_start: T, - pub inline_end: T, - pub block_end: T, - pub inline_start: T, - debug_writing_mode: DebugWritingMode, -} - -impl<T: Debug> Debug for LogicalMargin<T> { - fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> { - let writing_mode_string = if cfg!(debug_assertions) { - format!("{:?}, ", self.debug_writing_mode) - } else { - "".to_owned() - }; - - write!( - formatter, - "LogicalMargin({}i:{:?}..{:?} b:{:?}..{:?})", - writing_mode_string, - self.inline_start, - self.inline_end, - self.block_start, - self.block_end - ) - } -} - -impl<T: Zero> LogicalMargin<T> { - #[inline] - pub fn zero(mode: WritingMode) -> LogicalMargin<T> { - LogicalMargin { - block_start: Zero::zero(), - inline_end: Zero::zero(), - block_end: Zero::zero(), - inline_start: Zero::zero(), - debug_writing_mode: DebugWritingMode::new(mode), - } - } -} - -impl<T> LogicalMargin<T> { - #[inline] - pub fn new( - mode: WritingMode, - block_start: T, - inline_end: T, - block_end: T, - inline_start: T, - ) -> LogicalMargin<T> { - LogicalMargin { - block_start, - inline_end, - block_end, - inline_start, - debug_writing_mode: DebugWritingMode::new(mode), - } - } - - #[inline] - pub fn from_physical(mode: WritingMode, offsets: SideOffsets2D<T>) -> LogicalMargin<T> { - let block_start; - let inline_end; - let block_end; - let inline_start; - if mode.is_vertical() { - if mode.is_vertical_lr() { - block_start = offsets.left; - block_end = offsets.right; - } else { - block_start = offsets.right; - block_end = offsets.left; - } - if mode.is_inline_tb() { - inline_start = offsets.top; - inline_end = offsets.bottom; - } else { - inline_start = offsets.bottom; - inline_end = offsets.top; - } - } else { - block_start = offsets.top; - block_end = offsets.bottom; - if mode.is_bidi_ltr() { - inline_start = offsets.left; - inline_end = offsets.right; - } else { - inline_start = offsets.right; - inline_end = offsets.left; - } - } - LogicalMargin::new(mode, block_start, inline_end, block_end, inline_start) - } -} - -impl<T: Copy> LogicalMargin<T> { - #[inline] - pub fn new_all_same(mode: WritingMode, value: T) -> LogicalMargin<T> { - LogicalMargin::new(mode, value, value, value, value) - } - - #[inline] - pub fn top(&self, mode: WritingMode) -> T { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - if mode.is_inline_tb() { - self.inline_start - } else { - self.inline_end - } - } else { - self.block_start - } - } - - #[inline] - pub fn set_top(&mut self, mode: WritingMode, top: T) { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - if mode.is_inline_tb() { - self.inline_start = top - } else { - self.inline_end = top - } - } else { - self.block_start = top - } - } - - #[inline] - pub fn right(&self, mode: WritingMode) -> T { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - if mode.is_vertical_lr() { - self.block_end - } else { - self.block_start - } - } else { - if mode.is_bidi_ltr() { - self.inline_end - } else { - self.inline_start - } - } - } - - #[inline] - pub fn set_right(&mut self, mode: WritingMode, right: T) { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - if mode.is_vertical_lr() { - self.block_end = right - } else { - self.block_start = right - } - } else { - if mode.is_bidi_ltr() { - self.inline_end = right - } else { - self.inline_start = right - } - } - } - - #[inline] - pub fn bottom(&self, mode: WritingMode) -> T { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - if mode.is_inline_tb() { - self.inline_end - } else { - self.inline_start - } - } else { - self.block_end - } - } - - #[inline] - pub fn set_bottom(&mut self, mode: WritingMode, bottom: T) { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - if mode.is_inline_tb() { - self.inline_end = bottom - } else { - self.inline_start = bottom - } - } else { - self.block_end = bottom - } - } - - #[inline] - pub fn left(&self, mode: WritingMode) -> T { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - if mode.is_vertical_lr() { - self.block_start - } else { - self.block_end - } - } else { - if mode.is_bidi_ltr() { - self.inline_start - } else { - self.inline_end - } - } - } - - #[inline] - pub fn set_left(&mut self, mode: WritingMode, left: T) { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - if mode.is_vertical_lr() { - self.block_start = left - } else { - self.block_end = left - } - } else { - if mode.is_bidi_ltr() { - self.inline_start = left - } else { - self.inline_end = left - } - } - } - - #[inline] - pub fn convert(&self, mode_from: WritingMode, mode_to: WritingMode) -> LogicalMargin<T> { - if mode_from == mode_to { - self.debug_writing_mode.check(mode_from); - *self - } else { - LogicalMargin::from_physical(mode_to, self.to_physical(mode_from)) - } - } -} - -impl<T: Clone> LogicalMargin<T> { - #[inline] - pub fn to_physical(&self, mode: WritingMode) -> SideOffsets2D<T> { - self.debug_writing_mode.check(mode); - let top; - let right; - let bottom; - let left; - if mode.is_vertical() { - if mode.is_vertical_lr() { - left = self.block_start.clone(); - right = self.block_end.clone(); - } else { - right = self.block_start.clone(); - left = self.block_end.clone(); - } - if mode.is_inline_tb() { - top = self.inline_start.clone(); - bottom = self.inline_end.clone(); - } else { - bottom = self.inline_start.clone(); - top = self.inline_end.clone(); - } - } else { - top = self.block_start.clone(); - bottom = self.block_end.clone(); - if mode.is_bidi_ltr() { - left = self.inline_start.clone(); - right = self.inline_end.clone(); - } else { - right = self.inline_start.clone(); - left = self.inline_end.clone(); - } - } - SideOffsets2D::new(top, right, bottom, left) - } -} - -impl<T: PartialEq + Zero> LogicalMargin<T> { - #[inline] - pub fn is_zero(&self) -> bool { - self.block_start == Zero::zero() && - self.inline_end == Zero::zero() && - self.block_end == Zero::zero() && - self.inline_start == Zero::zero() - } -} - -impl<T: Copy + Add<T, Output = T>> LogicalMargin<T> { - #[inline] - pub fn inline_start_end(&self) -> T { - self.inline_start + self.inline_end - } - - #[inline] - pub fn block_start_end(&self) -> T { - self.block_start + self.block_end - } - - #[inline] - pub fn start_end(&self, direction: Direction) -> T { - match direction { - Direction::Inline => self.inline_start + self.inline_end, - Direction::Block => self.block_start + self.block_end, - } - } - - #[inline] - pub fn top_bottom(&self, mode: WritingMode) -> T { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - self.inline_start_end() - } else { - self.block_start_end() - } - } - - #[inline] - pub fn left_right(&self, mode: WritingMode) -> T { - self.debug_writing_mode.check(mode); - if mode.is_vertical() { - self.block_start_end() - } else { - self.inline_start_end() - } - } -} - -impl<T: Add<T, Output = T>> Add for LogicalMargin<T> { - type Output = LogicalMargin<T>; - - #[inline] - fn add(self, other: LogicalMargin<T>) -> LogicalMargin<T> { - self.debug_writing_mode - .check_debug(other.debug_writing_mode); - LogicalMargin { - debug_writing_mode: self.debug_writing_mode, - block_start: self.block_start + other.block_start, - inline_end: self.inline_end + other.inline_end, - block_end: self.block_end + other.block_end, - inline_start: self.inline_start + other.inline_start, - } - } -} - -impl<T: Sub<T, Output = T>> Sub for LogicalMargin<T> { - type Output = LogicalMargin<T>; - - #[inline] - fn sub(self, other: LogicalMargin<T>) -> LogicalMargin<T> { - self.debug_writing_mode - .check_debug(other.debug_writing_mode); - LogicalMargin { - debug_writing_mode: self.debug_writing_mode, - block_start: self.block_start - other.block_start, - inline_end: self.inline_end - other.inline_end, - block_end: self.block_end - other.block_end, - inline_start: self.inline_start - other.inline_start, - } - } -} - -/// A rectangle in flow-relative dimensions -#[derive(Clone, Copy, Eq, PartialEq)] -#[cfg_attr(feature = "servo", derive(Serialize))] -pub struct LogicalRect<T> { - pub start: LogicalPoint<T>, - pub size: LogicalSize<T>, - debug_writing_mode: DebugWritingMode, -} - -impl<T: Debug> Debug for LogicalRect<T> { - fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> { - let writing_mode_string = if cfg!(debug_assertions) { - format!("{:?}, ", self.debug_writing_mode) - } else { - "".to_owned() - }; - - write!( - formatter, - "LogicalRect({}i{:?}×b{:?}, @ (i{:?},b{:?}))", - writing_mode_string, self.size.inline, self.size.block, self.start.i, self.start.b - ) - } -} - -impl<T: Zero> LogicalRect<T> { - #[inline] - pub fn zero(mode: WritingMode) -> LogicalRect<T> { - LogicalRect { - start: LogicalPoint::zero(mode), - size: LogicalSize::zero(mode), - debug_writing_mode: DebugWritingMode::new(mode), - } - } -} - -impl<T: Copy> LogicalRect<T> { - #[inline] - pub fn new( - mode: WritingMode, - inline_start: T, - block_start: T, - inline: T, - block: T, - ) -> LogicalRect<T> { - LogicalRect { - start: LogicalPoint::new(mode, inline_start, block_start), - size: LogicalSize::new(mode, inline, block), - debug_writing_mode: DebugWritingMode::new(mode), - } - } - - #[inline] - pub fn from_point_size( - mode: WritingMode, - start: LogicalPoint<T>, - size: LogicalSize<T>, - ) -> LogicalRect<T> { - start.debug_writing_mode.check(mode); - size.debug_writing_mode.check(mode); - LogicalRect { - start: start, - size: size, - debug_writing_mode: DebugWritingMode::new(mode), - } - } -} - -impl<T: Copy + Add<T, Output = T> + Sub<T, Output = T>> LogicalRect<T> { - #[inline] - pub fn from_physical( - mode: WritingMode, - rect: Rect<T>, - container_size: Size2D<T>, - ) -> LogicalRect<T> { - let inline_start; - let block_start; - let inline; - let block; - if mode.is_vertical() { - inline = rect.size.height; - block = rect.size.width; - if mode.is_vertical_lr() { - block_start = rect.origin.x; - } else { - block_start = container_size.width - (rect.origin.x + rect.size.width); - } - if mode.is_inline_tb() { - inline_start = rect.origin.y; - } else { - inline_start = container_size.height - (rect.origin.y + rect.size.height); - } - } else { - inline = rect.size.width; - block = rect.size.height; - block_start = rect.origin.y; - if mode.is_bidi_ltr() { - inline_start = rect.origin.x; - } else { - inline_start = container_size.width - (rect.origin.x + rect.size.width); - } - } - LogicalRect { - start: LogicalPoint::new(mode, inline_start, block_start), - size: LogicalSize::new(mode, inline, block), - debug_writing_mode: DebugWritingMode::new(mode), - } - } - - #[inline] - pub fn inline_end(&self) -> T { - self.start.i + self.size.inline - } - - #[inline] - pub fn block_end(&self) -> T { - self.start.b + self.size.block - } - - #[inline] - pub fn to_physical(&self, mode: WritingMode, container_size: Size2D<T>) -> Rect<T> { - self.debug_writing_mode.check(mode); - let x; - let y; - let width; - let height; - if mode.is_vertical() { - width = self.size.block; - height = self.size.inline; - if mode.is_vertical_lr() { - x = self.start.b; - } else { - x = container_size.width - self.block_end(); - } - if mode.is_inline_tb() { - y = self.start.i; - } else { - y = container_size.height - self.inline_end(); - } - } else { - width = self.size.inline; - height = self.size.block; - y = self.start.b; - if mode.is_bidi_ltr() { - x = self.start.i; - } else { - x = container_size.width - self.inline_end(); - } - } - Rect { - origin: Point2D::new(x, y), - size: Size2D::new(width, height), - } - } - - #[inline] - pub fn convert( - &self, - mode_from: WritingMode, - mode_to: WritingMode, - container_size: Size2D<T>, - ) -> LogicalRect<T> { - if mode_from == mode_to { - self.debug_writing_mode.check(mode_from); - *self - } else { - LogicalRect::from_physical( - mode_to, - self.to_physical(mode_from, container_size), - container_size, - ) - } - } - - pub fn translate_by_size(&self, offset: LogicalSize<T>) -> LogicalRect<T> { - LogicalRect { - start: self.start + offset, - ..*self - } - } - - pub fn translate(&self, offset: &LogicalPoint<T>) -> LogicalRect<T> { - LogicalRect { - start: self.start + - LogicalSize { - inline: offset.i, - block: offset.b, - debug_writing_mode: offset.debug_writing_mode, - }, - size: self.size, - debug_writing_mode: self.debug_writing_mode, - } - } -} - -impl<T: Copy + Ord + Add<T, Output = T> + Sub<T, Output = T>> LogicalRect<T> { - #[inline] - pub fn union(&self, other: &LogicalRect<T>) -> LogicalRect<T> { - self.debug_writing_mode - .check_debug(other.debug_writing_mode); - - let inline_start = min(self.start.i, other.start.i); - let block_start = min(self.start.b, other.start.b); - LogicalRect { - start: LogicalPoint { - i: inline_start, - b: block_start, - debug_writing_mode: self.debug_writing_mode, - }, - size: LogicalSize { - inline: max(self.inline_end(), other.inline_end()) - inline_start, - block: max(self.block_end(), other.block_end()) - block_start, - debug_writing_mode: self.debug_writing_mode, - }, - debug_writing_mode: self.debug_writing_mode, - } - } -} - -impl<T: Copy + Add<T, Output = T> + Sub<T, Output = T>> Add<LogicalMargin<T>> for LogicalRect<T> { - type Output = LogicalRect<T>; - - #[inline] - fn add(self, other: LogicalMargin<T>) -> LogicalRect<T> { - self.debug_writing_mode - .check_debug(other.debug_writing_mode); - LogicalRect { - start: LogicalPoint { - // Growing a rectangle on the start side means pushing its - // start point on the negative direction. - i: self.start.i - other.inline_start, - b: self.start.b - other.block_start, - debug_writing_mode: self.debug_writing_mode, - }, - size: LogicalSize { - inline: self.size.inline + other.inline_start_end(), - block: self.size.block + other.block_start_end(), - debug_writing_mode: self.debug_writing_mode, - }, - debug_writing_mode: self.debug_writing_mode, - } - } -} - -impl<T: Copy + Add<T, Output = T> + Sub<T, Output = T>> Sub<LogicalMargin<T>> for LogicalRect<T> { - type Output = LogicalRect<T>; - - #[inline] - fn sub(self, other: LogicalMargin<T>) -> LogicalRect<T> { - self.debug_writing_mode - .check_debug(other.debug_writing_mode); - LogicalRect { - start: LogicalPoint { - // Shrinking a rectangle on the start side means pushing its - // start point on the positive direction. - i: self.start.i + other.inline_start, - b: self.start.b + other.block_start, - debug_writing_mode: self.debug_writing_mode, - }, - size: LogicalSize { - inline: self.size.inline - other.inline_start_end(), - block: self.size.block - other.block_start_end(), - debug_writing_mode: self.debug_writing_mode, - }, - debug_writing_mode: self.debug_writing_mode, - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum PhysicalSide { - Top, - Right, - Bottom, - Left, -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum PhysicalCorner { - TopLeft, - TopRight, - BottomRight, - BottomLeft, -} |