aboutsummaryrefslogtreecommitdiffstats
path: root/components/style/logical_geometry.rs
diff options
context:
space:
mode:
authorDelan Azabani <dazabani@igalia.com>2024-02-27 23:39:06 +0800
committerGitHub <noreply@github.com>2024-02-27 15:39:06 +0000
commitfaf754dfa655f0b9a28f62bc47a78fbf78ebcaf4 (patch)
tree4725e1446680d036797b1fc258733ae6b2c9f354 /components/style/logical_geometry.rs
parentb07505417e629bbb081be9683630f2d7a5f50544 (diff)
downloadservo-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.rs1522
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,
-}