2014-07-09 21:04:59 +00:00
|
|
|
|
/* 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 http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
2014-11-10 12:33:35 +00:00
|
|
|
|
//! Geometry in flow-relative space.
|
2014-07-09 21:04:59 +00:00
|
|
|
|
|
2017-06-14 14:25:05 +00:00
|
|
|
|
use euclid::{Point2D, Rect, Size2D, SideOffsets2D};
|
2015-06-19 02:50:22 +00:00
|
|
|
|
use euclid::num::Zero;
|
2015-09-23 21:02:56 +00:00
|
|
|
|
use std::cmp::{max, min};
|
|
|
|
|
use std::fmt::{self, Debug, Error, Formatter};
|
2015-01-28 01:15:50 +00:00
|
|
|
|
use std::ops::{Add, Sub};
|
2017-05-23 04:06:07 +00:00
|
|
|
|
use unicode_bidi as bidi;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
|
2016-03-11 18:49:24 +00:00
|
|
|
|
pub enum BlockFlowDirection {
|
|
|
|
|
TopToBottom,
|
|
|
|
|
RightToLeft,
|
|
|
|
|
LeftToRight
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub enum InlineBaseDirection {
|
|
|
|
|
LeftToRight,
|
|
|
|
|
RightToLeft
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-07 08:15:03 +00:00
|
|
|
|
// TODO: improve the readability of the WritingMode serialization, refer to the Debug:fmt()
|
2014-07-09 21:04:59 +00:00
|
|
|
|
bitflags!(
|
servo: Merge #18938 - Replace all uses of the `heapsize` crate with `malloc_size_of` (from nnethercote:bug-1409255); r=SimonSapin
Servo currently uses `heapsize`, but Stylo/Gecko use `malloc_size_of`.
`malloc_size_of` is better -- it handles various cases that `heapsize` does not
-- so this patch changes Servo to use `malloc_size_of`.
This patch makes the following changes to the `malloc_size_of` crate.
- Adds `MallocSizeOf` trait implementations for numerous types, some built-in
(e.g. `VecDeque`), some external and Servo-only (e.g. `string_cache`).
- Makes `enclosing_size_of_op` optional, because vanilla jemalloc doesn't
support that operation.
- For `HashSet`/`HashMap`, falls back to a computed estimate when
`enclosing_size_of_op` isn't available.
- Adds an extern "C" `malloc_size_of` function that does the actual heap
measurement; this is based on the same functions from the `heapsize` crate.
This patch makes the following changes elsewhere.
- Converts all the uses of `heapsize` to instead use `malloc_size_of`.
- Disables the "heapsize"/"heap_size" feature for the external crates that
provide it.
- Removes the `HeapSizeOf` implementation from `hashglobe`.
- Adds `ignore` annotations to a few `Rc`/`Arc`, because `malloc_size_of`
doesn't derive those types, unlike `heapsize`.
<!-- Please describe your changes on the following line: -->
---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [ ] These changes fix https://bugzilla.mozilla.org/show_bug.cgi?id=1409255
<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because testing is on the Gecko side.
<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->
<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
Source-Repo: https://github.com/servo/servo
Source-Revision: 4c538b642e4bdfbf42c522c5a59c258a6d14546e
--HG--
extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear
extra : subtree_revision : f9a6feed1088d0b0be2b55d7f0c2ec9c594ac33b
2017-10-18 18:56:05 +00:00
|
|
|
|
#[cfg_attr(feature = "servo", derive(MallocSizeOf, Serialize))]
|
2017-10-19 21:23:30 +00:00
|
|
|
|
pub flags WritingMode: u8 {
|
|
|
|
|
const FLAG_RTL = 1 << 0,
|
|
|
|
|
const FLAG_VERTICAL = 1 << 1,
|
|
|
|
|
const FLAG_VERTICAL_LR = 1 << 2,
|
2017-04-17 01:26:18 +00:00
|
|
|
|
/// For vertical writing modes only. When set, line-over/line-under
|
|
|
|
|
/// sides are inverted from block-start/block-end. This flag is
|
|
|
|
|
/// set when sideways-lr is used.
|
2017-10-19 21:23:30 +00:00
|
|
|
|
const FLAG_LINE_INVERTED = 1 << 3,
|
|
|
|
|
const FLAG_SIDEWAYS = 1 << 4,
|
|
|
|
|
const FLAG_UPRIGHT = 1 << 5,
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
2015-01-28 01:15:50 +00:00
|
|
|
|
);
|
2014-07-09 21:04:59 +00:00
|
|
|
|
|
|
|
|
|
impl WritingMode {
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn is_vertical(&self) -> bool {
|
2017-10-19 21:23:30 +00:00
|
|
|
|
self.intersects(FLAG_VERTICAL)
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-12 09:12:51 +00:00
|
|
|
|
/// Assuming .is_vertical(), does the block direction go left to right?
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn is_vertical_lr(&self) -> bool {
|
2017-10-19 21:23:30 +00:00
|
|
|
|
self.intersects(FLAG_VERTICAL_LR)
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-12 09:12:51 +00:00
|
|
|
|
/// Assuming .is_vertical(), does the inline direction go top to bottom?
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn is_inline_tb(&self) -> bool {
|
2017-01-29 01:24:47 +00:00
|
|
|
|
// https://drafts.csswg.org/css-writing-modes-3/#logical-to-physical
|
2017-10-19 21:23:30 +00:00
|
|
|
|
self.intersects(FLAG_RTL) == self.intersects(FLAG_LINE_INVERTED)
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn is_bidi_ltr(&self) -> bool {
|
2017-10-19 21:23:30 +00:00
|
|
|
|
!self.intersects(FLAG_RTL)
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
2014-08-29 16:51:26 +00:00
|
|
|
|
|
|
|
|
|
#[inline]
|
2017-01-29 01:24:47 +00:00
|
|
|
|
pub fn is_sideways(&self) -> bool {
|
2017-10-19 21:23:30 +00:00
|
|
|
|
self.intersects(FLAG_SIDEWAYS)
|
2017-01-29 01:24:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn is_upright(&self) -> bool {
|
2017-10-19 21:23:30 +00:00
|
|
|
|
self.intersects(FLAG_UPRIGHT)
|
2014-08-29 16:51:26 +00:00
|
|
|
|
}
|
2015-04-27 17:29:15 +00:00
|
|
|
|
|
|
|
|
|
#[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,
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-07-24 03:20:49 +00:00
|
|
|
|
|
2016-03-11 18:49:24 +00:00
|
|
|
|
#[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 {
|
2017-10-19 21:23:30 +00:00
|
|
|
|
if self.intersects(FLAG_RTL) {
|
2016-03-11 18:49:24 +00:00
|
|
|
|
InlineBaseDirection::RightToLeft
|
|
|
|
|
} else {
|
|
|
|
|
InlineBaseDirection::LeftToRight
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-24 03:20:49 +00:00
|
|
|
|
#[inline]
|
|
|
|
|
/// The default bidirectional embedding level for this writing mode.
|
|
|
|
|
///
|
2017-05-23 04:06:07 +00:00
|
|
|
|
/// 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()
|
|
|
|
|
}
|
2015-07-24 03:20:49 +00:00
|
|
|
|
}
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-06-02 17:53:37 +00:00
|
|
|
|
impl fmt::Display for WritingMode {
|
2015-01-08 15:00:57 +00:00
|
|
|
|
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
if self.is_vertical() {
|
2017-06-18 12:55:11 +00:00
|
|
|
|
write!(formatter, "V")?;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
if self.is_vertical_lr() {
|
2017-06-18 12:55:11 +00:00
|
|
|
|
write!(formatter, " LR")?;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2017-06-18 12:55:11 +00:00
|
|
|
|
write!(formatter, " RL")?;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
2017-10-19 21:23:30 +00:00
|
|
|
|
if self.intersects(FLAG_SIDEWAYS) {
|
2017-06-18 12:55:11 +00:00
|
|
|
|
write!(formatter, " Sideways")?;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
2017-10-19 21:23:30 +00:00
|
|
|
|
if self.intersects(FLAG_LINE_INVERTED) {
|
2017-06-18 12:55:11 +00:00
|
|
|
|
write!(formatter, " Inverted")?;
|
2017-04-17 01:26:18 +00:00
|
|
|
|
}
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2017-06-18 12:55:11 +00:00
|
|
|
|
write!(formatter, "H")?;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
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.
|
2015-06-01 20:53:02 +00:00
|
|
|
|
#[cfg(not(debug_assertions))]
|
2017-08-23 22:18:31 +00:00
|
|
|
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
2016-11-07 08:15:03 +00:00
|
|
|
|
#[cfg_attr(feature = "servo", derive(Serialize))]
|
2014-07-09 21:04:59 +00:00
|
|
|
|
struct DebugWritingMode;
|
|
|
|
|
|
2015-06-01 20:53:02 +00:00
|
|
|
|
#[cfg(debug_assertions)]
|
2017-08-23 22:18:31 +00:00
|
|
|
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
2016-11-07 08:15:03 +00:00
|
|
|
|
#[cfg_attr(feature = "servo", derive(Serialize))]
|
2014-07-09 21:04:59 +00:00
|
|
|
|
struct DebugWritingMode {
|
|
|
|
|
mode: WritingMode
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-01 20:53:02 +00:00
|
|
|
|
#[cfg(not(debug_assertions))]
|
2014-07-09 21:04:59 +00:00
|
|
|
|
impl DebugWritingMode {
|
|
|
|
|
#[inline]
|
|
|
|
|
fn check(&self, _other: WritingMode) {}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn check_debug(&self, _other: DebugWritingMode) {}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn new(_mode: WritingMode) -> DebugWritingMode {
|
|
|
|
|
DebugWritingMode
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-01 20:53:02 +00:00
|
|
|
|
#[cfg(debug_assertions)]
|
2014-07-09 21:04:59 +00:00
|
|
|
|
impl DebugWritingMode {
|
|
|
|
|
#[inline]
|
|
|
|
|
fn check(&self, other: WritingMode) {
|
|
|
|
|
assert!(self.mode == other)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn check_debug(&self, other: DebugWritingMode) {
|
|
|
|
|
assert!(self.mode == other.mode)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
fn new(mode: WritingMode) -> DebugWritingMode {
|
|
|
|
|
DebugWritingMode { mode: mode }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 00:24:45 +00:00
|
|
|
|
impl Debug for DebugWritingMode {
|
2015-06-01 20:53:02 +00:00
|
|
|
|
#[cfg(not(debug_assertions))]
|
2015-01-08 15:00:57 +00:00
|
|
|
|
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
write!(formatter, "?")
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-01 20:53:02 +00:00
|
|
|
|
#[cfg(debug_assertions)]
|
2015-01-08 15:00:57 +00:00
|
|
|
|
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
|
2015-11-24 02:19:07 +00:00
|
|
|
|
write!(formatter, "{}", self.mode)
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-11-10 17:53:05 +00:00
|
|
|
|
// Used to specify the logical direction.
|
2017-08-23 22:18:31 +00:00
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
2016-12-28 08:33:31 +00:00
|
|
|
|
#[cfg_attr(feature = "servo", derive(Serialize))]
|
2016-11-10 17:53:05 +00:00
|
|
|
|
pub enum Direction {
|
|
|
|
|
Inline,
|
|
|
|
|
Block
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-09 21:04:59 +00:00
|
|
|
|
/// A 2D size in flow-relative dimensions
|
2017-08-23 22:18:31 +00:00
|
|
|
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
2016-11-07 08:15:03 +00:00
|
|
|
|
#[cfg_attr(feature = "servo", derive(Serialize))]
|
2014-07-09 21:04:59 +00:00
|
|
|
|
pub struct LogicalSize<T> {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
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
|
2014-07-09 21:04:59 +00:00
|
|
|
|
debug_writing_mode: DebugWritingMode,
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 00:24:45 +00:00
|
|
|
|
impl<T: Debug> Debug for LogicalSize<T> {
|
2015-01-08 15:00:57 +00:00
|
|
|
|
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
|
2015-01-28 01:15:50 +00:00
|
|
|
|
write!(formatter, "LogicalSize({:?}, i{:?}×b{:?})",
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.debug_writing_mode, self.inline, self.block)
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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 {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline: Zero::zero(),
|
|
|
|
|
block: Zero::zero(),
|
2014-07-09 21:04:59 +00:00
|
|
|
|
debug_writing_mode: DebugWritingMode::new(mode),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: Copy> LogicalSize<T> {
|
|
|
|
|
#[inline]
|
2014-07-18 20:27:23 +00:00
|
|
|
|
pub fn new(mode: WritingMode, inline: T, block: T) -> LogicalSize<T> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
LogicalSize {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline: inline,
|
|
|
|
|
block: block,
|
2014-07-09 21:04:59 +00:00
|
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn width(&self, mode: WritingMode) -> T {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.block
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.inline
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_width(&mut self, mode: WritingMode, width: T) {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.block = width
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.inline = width
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn height(&self, mode: WritingMode) -> T {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.inline
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.block
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_height(&mut self, mode: WritingMode, height: T) {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.inline = height
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.block = height
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn to_physical(&self, mode: WritingMode) -> Size2D<T> {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2016-08-12 01:12:29 +00:00
|
|
|
|
Size2D::new(self.block, self.inline)
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2016-08-12 01:12:29 +00:00
|
|
|
|
Size2D::new(self.inline, self.block)
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[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))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 01:15:50 +00:00
|
|
|
|
impl<T: Add<T, Output=T>> Add for LogicalSize<T> {
|
|
|
|
|
type Output = LogicalSize<T>;
|
|
|
|
|
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[inline]
|
2015-01-28 01:15:50 +00:00
|
|
|
|
fn add(self, other: LogicalSize<T>) -> LogicalSize<T> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
self.debug_writing_mode.check_debug(other.debug_writing_mode);
|
|
|
|
|
LogicalSize {
|
|
|
|
|
debug_writing_mode: self.debug_writing_mode,
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline: self.inline + other.inline,
|
|
|
|
|
block: self.block + other.block,
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 01:15:50 +00:00
|
|
|
|
impl<T: Sub<T, Output=T>> Sub for LogicalSize<T> {
|
|
|
|
|
type Output = LogicalSize<T>;
|
|
|
|
|
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[inline]
|
2015-01-28 01:15:50 +00:00
|
|
|
|
fn sub(self, other: LogicalSize<T>) -> LogicalSize<T> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
self.debug_writing_mode.check_debug(other.debug_writing_mode);
|
|
|
|
|
LogicalSize {
|
|
|
|
|
debug_writing_mode: self.debug_writing_mode,
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline: self.inline - other.inline,
|
|
|
|
|
block: self.block - other.block,
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// A 2D point in flow-relative dimensions
|
2017-08-23 22:18:31 +00:00
|
|
|
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
2016-11-07 08:15:03 +00:00
|
|
|
|
#[cfg_attr(feature = "servo", derive(Serialize))]
|
2014-07-09 21:04:59 +00:00
|
|
|
|
pub struct LogicalPoint<T> {
|
2015-10-23 13:00:09 +00:00
|
|
|
|
/// inline-axis coordinate
|
|
|
|
|
pub i: T,
|
|
|
|
|
/// block-axis coordinate
|
|
|
|
|
pub b: T,
|
2014-07-09 21:04:59 +00:00
|
|
|
|
debug_writing_mode: DebugWritingMode,
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 00:24:45 +00:00
|
|
|
|
impl<T: Debug> Debug for LogicalPoint<T> {
|
2015-01-08 15:00:57 +00:00
|
|
|
|
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
|
2015-01-28 01:15:50 +00:00
|
|
|
|
write!(formatter, "LogicalPoint({:?} (i{:?}, b{:?}))",
|
2014-07-09 21:04:59 +00:00
|
|
|
|
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),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 01:15:50 +00:00
|
|
|
|
impl<T: Copy + Sub<T, Output=T>> LogicalPoint<T> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[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() {
|
2016-08-12 01:12:29 +00:00
|
|
|
|
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 })
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2016-08-12 01:12:29 +00:00
|
|
|
|
Point2D::new(
|
|
|
|
|
if mode.is_bidi_ltr() { self.i } else { container_size.width - self.i },
|
|
|
|
|
self.b)
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 01:15:50 +00:00
|
|
|
|
impl<T: Copy + Add<T, Output=T>> LogicalPoint<T> {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
/// This doesn’t really makes sense,
|
2014-12-12 09:12:51 +00:00
|
|
|
|
/// but happens when dealing with multiple origins.
|
2014-07-18 20:27:23 +00:00
|
|
|
|
#[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,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-16 14:37:40 +00:00
|
|
|
|
impl<T: Copy + Add<T, Output=T>> Add<LogicalSize<T>> for LogicalPoint<T> {
|
2015-01-28 01:15:50 +00:00
|
|
|
|
type Output = LogicalPoint<T>;
|
|
|
|
|
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[inline]
|
2015-01-28 01:15:50 +00:00
|
|
|
|
fn add(self, other: LogicalSize<T>) -> LogicalPoint<T> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
self.debug_writing_mode.check_debug(other.debug_writing_mode);
|
|
|
|
|
LogicalPoint {
|
|
|
|
|
debug_writing_mode: self.debug_writing_mode,
|
2014-07-18 20:27:23 +00:00
|
|
|
|
i: self.i + other.inline,
|
|
|
|
|
b: self.b + other.block,
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-16 14:37:40 +00:00
|
|
|
|
impl<T: Copy + Sub<T, Output=T>> Sub<LogicalSize<T>> for LogicalPoint<T> {
|
2015-01-28 01:15:50 +00:00
|
|
|
|
type Output = LogicalPoint<T>;
|
|
|
|
|
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[inline]
|
2015-01-28 01:15:50 +00:00
|
|
|
|
fn sub(self, other: LogicalSize<T>) -> LogicalPoint<T> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
self.debug_writing_mode.check_debug(other.debug_writing_mode);
|
|
|
|
|
LogicalPoint {
|
|
|
|
|
debug_writing_mode: self.debug_writing_mode,
|
2014-07-18 20:27:23 +00:00
|
|
|
|
i: self.i - other.inline,
|
|
|
|
|
b: self.b - other.block,
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// 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.
|
2017-08-23 22:18:31 +00:00
|
|
|
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
2016-11-07 08:15:03 +00:00
|
|
|
|
#[cfg_attr(feature = "servo", derive(Serialize))]
|
2014-07-09 21:04:59 +00:00
|
|
|
|
pub struct LogicalMargin<T> {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
pub block_start: T,
|
|
|
|
|
pub inline_end: T,
|
|
|
|
|
pub block_end: T,
|
|
|
|
|
pub inline_start: T,
|
2014-07-09 21:04:59 +00:00
|
|
|
|
debug_writing_mode: DebugWritingMode,
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 00:24:45 +00:00
|
|
|
|
impl<T: Debug> Debug for LogicalMargin<T> {
|
2015-01-08 15:00:57 +00:00
|
|
|
|
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
|
2015-11-24 02:19:07 +00:00
|
|
|
|
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)
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: Zero> LogicalMargin<T> {
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn zero(mode: WritingMode) -> LogicalMargin<T> {
|
|
|
|
|
LogicalMargin {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
block_start: Zero::zero(),
|
|
|
|
|
inline_end: Zero::zero(),
|
|
|
|
|
block_end: Zero::zero(),
|
|
|
|
|
inline_start: Zero::zero(),
|
2014-07-09 21:04:59 +00:00
|
|
|
|
debug_writing_mode: DebugWritingMode::new(mode),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T: Copy> LogicalMargin<T> {
|
|
|
|
|
#[inline]
|
2014-07-18 20:27:23 +00:00
|
|
|
|
pub fn new(mode: WritingMode, block_start: T, inline_end: T, block_end: T, inline_start: T)
|
|
|
|
|
-> LogicalMargin<T> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
LogicalMargin {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
block_start: block_start,
|
|
|
|
|
inline_end: inline_end,
|
|
|
|
|
block_end: block_end,
|
|
|
|
|
inline_start: inline_start,
|
2014-07-09 21:04:59 +00:00
|
|
|
|
debug_writing_mode: DebugWritingMode::new(mode),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-18 20:27:23 +00:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn new_all_same(mode: WritingMode, value: T) -> LogicalMargin<T> {
|
|
|
|
|
LogicalMargin::new(mode, value, value, value, value)
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn from_physical(mode: WritingMode, offsets: SideOffsets2D<T>) -> LogicalMargin<T> {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
let block_start;
|
|
|
|
|
let inline_end;
|
|
|
|
|
let block_end;
|
|
|
|
|
let inline_start;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
if mode.is_vertical() {
|
|
|
|
|
if mode.is_vertical_lr() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
block_start = offsets.left;
|
|
|
|
|
block_end = offsets.right;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
block_start = offsets.right;
|
|
|
|
|
block_end = offsets.left;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
if mode.is_inline_tb() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline_start = offsets.top;
|
|
|
|
|
inline_end = offsets.bottom;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline_start = offsets.bottom;
|
|
|
|
|
inline_end = offsets.top;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
block_start = offsets.top;
|
|
|
|
|
block_end = offsets.bottom;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
if mode.is_bidi_ltr() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline_start = offsets.left;
|
|
|
|
|
inline_end = offsets.right;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline_start = offsets.right;
|
|
|
|
|
inline_end = offsets.left;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-07-18 20:27:23 +00:00
|
|
|
|
LogicalMargin::new(mode, block_start, inline_end, block_end, inline_start)
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn top(&self, mode: WritingMode) -> T {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
if mode.is_inline_tb() { self.inline_start } else { self.inline_end }
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.block_start
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_top(&mut self, mode: WritingMode, top: T) {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
if mode.is_inline_tb() { self.inline_start = top } else { self.inline_end = top }
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.block_start = top
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn right(&self, mode: WritingMode) -> T {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
if mode.is_vertical_lr() { self.block_end } else { self.block_start }
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
if mode.is_bidi_ltr() { self.inline_end } else { self.inline_start }
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_right(&mut self, mode: WritingMode, right: T) {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
if mode.is_vertical_lr() { self.block_end = right } else { self.block_start = right }
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
if mode.is_bidi_ltr() { self.inline_end = right } else { self.inline_start = right }
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn bottom(&self, mode: WritingMode) -> T {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
if mode.is_inline_tb() { self.inline_end } else { self.inline_start }
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.block_end
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_bottom(&mut self, mode: WritingMode, bottom: T) {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
if mode.is_inline_tb() { self.inline_end = bottom } else { self.inline_start = bottom }
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.block_end = bottom
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn left(&self, mode: WritingMode) -> T {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
if mode.is_vertical_lr() { self.block_start } else { self.block_end }
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
if mode.is_bidi_ltr() { self.inline_start } else { self.inline_end }
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_left(&mut self, mode: WritingMode, left: T) {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
if mode.is_vertical_lr() { self.block_start = left } else { self.block_end = left }
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
if mode.is_bidi_ltr() { self.inline_start = left } else { self.inline_end = left }
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[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() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
left = self.block_start;
|
|
|
|
|
right = self.block_end;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
right = self.block_start;
|
|
|
|
|
left = self.block_end;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
if mode.is_inline_tb() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
top = self.inline_start;
|
|
|
|
|
bottom = self.inline_end;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
bottom = self.inline_start;
|
|
|
|
|
top = self.inline_end;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
top = self.block_start;
|
|
|
|
|
bottom = self.block_end;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
if mode.is_bidi_ltr() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
left = self.inline_start;
|
|
|
|
|
right = self.inline_end;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
right = self.inline_start;
|
|
|
|
|
left = self.inline_end;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SideOffsets2D::new(top, right, bottom, 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))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-18 11:42:50 +00:00
|
|
|
|
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()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 01:15:50 +00:00
|
|
|
|
impl<T: Copy + Add<T, Output=T>> LogicalMargin<T> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[inline]
|
2014-07-18 20:27:23 +00:00
|
|
|
|
pub fn inline_start_end(&self) -> T {
|
|
|
|
|
self.inline_start + self.inline_end
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2014-07-18 20:27:23 +00:00
|
|
|
|
pub fn block_start_end(&self) -> T {
|
|
|
|
|
self.block_start + self.block_end
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-10 17:53:05 +00:00
|
|
|
|
#[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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn top_bottom(&self, mode: WritingMode) -> T {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.inline_start_end()
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.block_start_end()
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn left_right(&self, mode: WritingMode) -> T {
|
|
|
|
|
self.debug_writing_mode.check(mode);
|
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.block_start_end()
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
self.inline_start_end()
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 01:15:50 +00:00
|
|
|
|
impl<T: Add<T, Output=T>> Add for LogicalMargin<T> {
|
|
|
|
|
type Output = LogicalMargin<T>;
|
|
|
|
|
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[inline]
|
2015-01-28 01:15:50 +00:00
|
|
|
|
fn add(self, other: LogicalMargin<T>) -> LogicalMargin<T> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
self.debug_writing_mode.check_debug(other.debug_writing_mode);
|
|
|
|
|
LogicalMargin {
|
|
|
|
|
debug_writing_mode: self.debug_writing_mode,
|
2014-07-18 20:27:23 +00:00
|
|
|
|
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,
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 01:15:50 +00:00
|
|
|
|
impl<T: Sub<T, Output=T>> Sub for LogicalMargin<T> {
|
|
|
|
|
type Output = LogicalMargin<T>;
|
|
|
|
|
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[inline]
|
2015-01-28 01:15:50 +00:00
|
|
|
|
fn sub(self, other: LogicalMargin<T>) -> LogicalMargin<T> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
self.debug_writing_mode.check_debug(other.debug_writing_mode);
|
|
|
|
|
LogicalMargin {
|
|
|
|
|
debug_writing_mode: self.debug_writing_mode,
|
2014-07-18 20:27:23 +00:00
|
|
|
|
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,
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// A rectangle in flow-relative dimensions
|
2017-08-23 22:18:31 +00:00
|
|
|
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
2016-11-07 08:15:03 +00:00
|
|
|
|
#[cfg_attr(feature = "servo", derive(Serialize))]
|
2014-07-09 21:04:59 +00:00
|
|
|
|
pub struct LogicalRect<T> {
|
|
|
|
|
pub start: LogicalPoint<T>,
|
|
|
|
|
pub size: LogicalSize<T>,
|
|
|
|
|
debug_writing_mode: DebugWritingMode,
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-12 00:24:45 +00:00
|
|
|
|
impl<T: Debug> Debug for LogicalRect<T> {
|
2015-01-08 15:00:57 +00:00
|
|
|
|
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> {
|
2015-11-24 02:19:07 +00:00
|
|
|
|
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,
|
2014-10-22 01:00:37 +00:00
|
|
|
|
self.size.inline,
|
|
|
|
|
self.size.block,
|
|
|
|
|
self.start.i,
|
|
|
|
|
self.start.b)
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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]
|
2014-07-18 20:27:23 +00:00
|
|
|
|
pub fn new(mode: WritingMode, inline_start: T, block_start: T, inline: T, block: T)
|
|
|
|
|
-> LogicalRect<T> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
LogicalRect {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
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,
|
2014-07-09 21:04:59 +00:00
|
|
|
|
debug_writing_mode: DebugWritingMode::new(mode),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 01:15:50 +00:00
|
|
|
|
impl<T: Copy + Add<T, Output=T> + Sub<T, Output=T>> LogicalRect<T> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[inline]
|
|
|
|
|
pub fn from_physical(mode: WritingMode, rect: Rect<T>, container_size: Size2D<T>)
|
|
|
|
|
-> LogicalRect<T> {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
let inline_start;
|
|
|
|
|
let block_start;
|
|
|
|
|
let inline;
|
|
|
|
|
let block;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
if mode.is_vertical() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline = rect.size.height;
|
|
|
|
|
block = rect.size.width;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
if mode.is_vertical_lr() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
block_start = rect.origin.x;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
block_start = container_size.width - (rect.origin.x + rect.size.width);
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
if mode.is_inline_tb() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline_start = rect.origin.y;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline_start = container_size.height - (rect.origin.y + rect.size.height);
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline = rect.size.width;
|
|
|
|
|
block = rect.size.height;
|
|
|
|
|
block_start = rect.origin.y;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
if mode.is_bidi_ltr() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline_start = rect.origin.x;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline_start = container_size.width - (rect.origin.x + rect.size.width);
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
LogicalRect {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
start: LogicalPoint::new(mode, inline_start, block_start),
|
|
|
|
|
size: LogicalSize::new(mode, inline, block),
|
2014-07-09 21:04:59 +00:00
|
|
|
|
debug_writing_mode: DebugWritingMode::new(mode),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2014-07-18 20:27:23 +00:00
|
|
|
|
pub fn inline_end(&self) -> T {
|
|
|
|
|
self.start.i + self.size.inline
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2014-07-18 20:27:23 +00:00
|
|
|
|
pub fn block_end(&self) -> T {
|
|
|
|
|
self.start.b + self.size.block
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[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() {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
width = self.size.block;
|
|
|
|
|
height = self.size.inline;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
if mode.is_vertical_lr() {
|
|
|
|
|
x = self.start.b;
|
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
x = container_size.width - self.block_end();
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
if mode.is_inline_tb() {
|
|
|
|
|
y = self.start.i;
|
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
y = container_size.height - self.inline_end();
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
width = self.size.inline;
|
|
|
|
|
height = self.size.block;
|
2014-07-09 21:04:59 +00:00
|
|
|
|
y = self.start.b;
|
|
|
|
|
if mode.is_bidi_ltr() {
|
|
|
|
|
x = self.start.i;
|
|
|
|
|
} else {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
x = container_size.width - self.inline_end();
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Rect {
|
2016-08-12 01:12:29 +00:00
|
|
|
|
origin: Point2D::new(x, y),
|
|
|
|
|
size: Size2D::new(width, height),
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[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)
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-07-18 20:27:23 +00:00
|
|
|
|
|
2015-05-19 16:29:34 +00:00
|
|
|
|
pub fn translate_by_size(&self, offset: LogicalSize<T>) -> LogicalRect<T> {
|
|
|
|
|
LogicalRect {
|
|
|
|
|
start: self.start + offset,
|
|
|
|
|
..*self
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-18 20:27:23 +00:00
|
|
|
|
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,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 01:15:50 +00:00
|
|
|
|
impl<T: Copy + Ord + Add<T, Output=T> + Sub<T, Output=T>> LogicalRect<T> {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
#[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,
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-07-09 21:04:59 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 01:15:50 +00:00
|
|
|
|
impl<T: Copy + Add<T, Output=T> + Sub<T, Output=T>> Add<LogicalMargin<T>> for LogicalRect<T> {
|
|
|
|
|
type Output = LogicalRect<T>;
|
|
|
|
|
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[inline]
|
2015-01-28 01:15:50 +00:00
|
|
|
|
fn add(self, other: LogicalMargin<T>) -> LogicalRect<T> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
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.
|
2014-07-18 20:27:23 +00:00
|
|
|
|
i: self.start.i - other.inline_start,
|
|
|
|
|
b: self.start.b - other.block_start,
|
2014-07-09 21:04:59 +00:00
|
|
|
|
debug_writing_mode: self.debug_writing_mode,
|
|
|
|
|
},
|
|
|
|
|
size: LogicalSize {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline: self.size.inline + other.inline_start_end(),
|
|
|
|
|
block: self.size.block + other.block_start_end(),
|
2014-07-09 21:04:59 +00:00
|
|
|
|
debug_writing_mode: self.debug_writing_mode,
|
|
|
|
|
},
|
|
|
|
|
debug_writing_mode: self.debug_writing_mode,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-01-28 01:15:50 +00:00
|
|
|
|
impl<T: Copy + Add<T, Output=T> + Sub<T, Output=T>> Sub<LogicalMargin<T>> for LogicalRect<T> {
|
|
|
|
|
type Output = LogicalRect<T>;
|
|
|
|
|
|
2014-07-09 21:04:59 +00:00
|
|
|
|
#[inline]
|
2015-01-28 01:15:50 +00:00
|
|
|
|
fn sub(self, other: LogicalMargin<T>) -> LogicalRect<T> {
|
2014-07-09 21:04:59 +00:00
|
|
|
|
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.
|
2014-07-18 20:27:23 +00:00
|
|
|
|
i: self.start.i + other.inline_start,
|
|
|
|
|
b: self.start.b + other.block_start,
|
2014-07-09 21:04:59 +00:00
|
|
|
|
debug_writing_mode: self.debug_writing_mode,
|
|
|
|
|
},
|
|
|
|
|
size: LogicalSize {
|
2014-07-18 20:27:23 +00:00
|
|
|
|
inline: self.size.inline - other.inline_start_end(),
|
|
|
|
|
block: self.size.block - other.block_start_end(),
|
2014-07-09 21:04:59 +00:00
|
|
|
|
debug_writing_mode: self.debug_writing_mode,
|
|
|
|
|
},
|
|
|
|
|
debug_writing_mode: self.debug_writing_mode,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-04-27 17:29:15 +00:00
|
|
|
|
|
2017-08-23 22:18:31 +00:00
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
2015-04-27 17:29:15 +00:00
|
|
|
|
pub enum PhysicalSide {
|
|
|
|
|
Top,
|
|
|
|
|
Right,
|
|
|
|
|
Bottom,
|
|
|
|
|
Left,
|
|
|
|
|
}
|