Skip to content

Commit c408286

Browse files
committed
Handle logical sizes
1 parent f7d3ea8 commit c408286

File tree

7 files changed

+315
-124
lines changed

7 files changed

+315
-124
lines changed

build-prefixes.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,10 @@ let mdnFeatures = {
198198
mediaIntervalSyntax: {}, // currently no browsers
199199
logicalBorders: mdn.css.properties['border-inline-start'].__compat.support,
200200
logicalBorderRadius: mdn.css.properties['border-start-start-radius'].__compat.support,
201-
logicalMargin: mdn.css.properties['margin-inline-start'].__compat.support
201+
logicalMargin: mdn.css.properties['margin-inline-start'].__compat.support,
202+
logicalPadding: mdn.css.properties['padding-inline-start'].__compat.support,
203+
logicalInset: mdn.css.properties['inset-inline-start'].__compat.support,
204+
logicalSize: mdn.css.properties['inline-size'].__compat.support
202205
};
203206

204207
for (let feature in mdnFeatures) {

src/compat.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub enum Feature {
3737
LogicalInset,
3838
LogicalMargin,
3939
LogicalPadding,
40+
LogicalSize,
4041
MediaIntervalSyntax,
4142
MediaRangeSyntax,
4243
OverflowShorthand,
@@ -1420,6 +1421,48 @@ impl Feature {
14201421
}
14211422
}
14221423
}
1424+
Feature::LogicalSize => {
1425+
if let Some(version) = browsers.chrome {
1426+
if version >= 3735552 {
1427+
return true
1428+
}
1429+
}
1430+
if let Some(version) = browsers.edge {
1431+
if version >= 5177344 {
1432+
return true
1433+
}
1434+
}
1435+
if let Some(version) = browsers.firefox {
1436+
if version >= 2686976 {
1437+
return true
1438+
}
1439+
}
1440+
if let Some(version) = browsers.opera {
1441+
if version >= 2818048 {
1442+
return true
1443+
}
1444+
}
1445+
if let Some(version) = browsers.safari {
1446+
if version >= 786688 {
1447+
return true
1448+
}
1449+
}
1450+
if let Some(version) = browsers.ios_saf {
1451+
if version >= 786944 {
1452+
return true
1453+
}
1454+
}
1455+
if let Some(version) = browsers.samsung {
1456+
if version >= 327680 {
1457+
return true
1458+
}
1459+
}
1460+
if let Some(version) = browsers.android {
1461+
if version >= 3735552 {
1462+
return true
1463+
}
1464+
}
1465+
}
14231466
}
14241467
false
14251468
}

src/declaration.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::properties::{
2020
overflow::OverflowHandler,
2121
list::ListStyleHandler,
2222
grid::GridHandler,
23+
size::SizeHandler,
2324
};
2425
use crate::targets::Browsers;
2526
use crate::parser::ParserOptions;
@@ -170,6 +171,7 @@ pub(crate) struct DeclarationHandler {
170171
flex: FlexHandler,
171172
grid: GridHandler,
172173
align: AlignHandler,
174+
size: SizeHandler,
173175
margin: MarginHandler,
174176
padding: PaddingHandler,
175177
scroll_margin: ScrollMarginHandler,
@@ -197,6 +199,7 @@ impl DeclarationHandler {
197199
flex: FlexHandler::new(targets),
198200
grid: GridHandler::default(),
199201
align: AlignHandler::new(targets),
202+
size: SizeHandler::default(),
200203
margin: MarginHandler::default(),
201204
padding: PaddingHandler::default(),
202205
scroll_margin: ScrollMarginHandler::default(),
@@ -223,6 +226,7 @@ impl DeclarationHandler {
223226
self.flex.handle_property(property, &mut self.decls, logical_properties) ||
224227
self.grid.handle_property(property, &mut self.decls, logical_properties) ||
225228
self.align.handle_property(property, &mut self.decls, logical_properties) ||
229+
self.size.handle_property(property, &mut self.decls, logical_properties) ||
226230
self.margin.handle_property(property, &mut self.decls, logical_properties) ||
227231
self.padding.handle_property(property, &mut self.decls, logical_properties) ||
228232
self.scroll_margin.handle_property(property, &mut self.decls, logical_properties) ||
@@ -247,6 +251,7 @@ impl DeclarationHandler {
247251
self.flex.finalize(&mut self.decls, logical_properties);
248252
self.grid.finalize(&mut self.decls, logical_properties);
249253
self.align.finalize(&mut self.decls, logical_properties);
254+
self.size.finalize(&mut self.decls, logical_properties);
250255
self.margin.finalize(&mut self.decls, logical_properties);
251256
self.padding.finalize(&mut self.decls, logical_properties);
252257
self.scroll_margin.finalize(&mut self.decls, logical_properties);

src/lib.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,6 +1581,66 @@ mod tests {
15811581
});
15821582
}
15831583

1584+
#[test]
1585+
fn test_size() {
1586+
prefix_test(r#"
1587+
.foo {
1588+
block-size: 25px;
1589+
inline-size: 25px;
1590+
min-block-size: 25px;
1591+
min-inline-size: 25px;
1592+
}
1593+
"#, indoc! {r#"
1594+
.foo {
1595+
height: 25px;
1596+
width: 25px;
1597+
min-height: 25px;
1598+
min-width: 25px;
1599+
}
1600+
"#}, Browsers {
1601+
safari: Some(8 << 16),
1602+
..Browsers::default()
1603+
});
1604+
1605+
prefix_test(r#"
1606+
.foo {
1607+
block-size: 25px;
1608+
inline-size: 25px;
1609+
min-block-size: 25px;
1610+
min-inline-size: 25px;
1611+
}
1612+
"#, indoc! {r#"
1613+
.foo {
1614+
block-size: 25px;
1615+
inline-size: 25px;
1616+
min-block-size: 25px;
1617+
min-inline-size: 25px;
1618+
}
1619+
"#}, Browsers {
1620+
safari: Some(14 << 16),
1621+
..Browsers::default()
1622+
});
1623+
1624+
prefix_test(r#"
1625+
.foo {
1626+
block-size: var(--size);
1627+
inline-size: var(--size);
1628+
min-block-size: var(--size);
1629+
min-inline-size: var(--size);
1630+
}
1631+
"#, indoc! {r#"
1632+
.foo {
1633+
height: var(--size);
1634+
width: var(--size);
1635+
min-height: var(--size);
1636+
min-width: var(--size);
1637+
}
1638+
"#}, Browsers {
1639+
safari: Some(8 << 16),
1640+
..Browsers::default()
1641+
});
1642+
}
1643+
15841644
#[test]
15851645
pub fn test_background() {
15861646
test(r#"

src/properties/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub mod list;
2222
#[cfg(feature = "grid")]
2323
pub mod grid;
2424
pub mod css_modules;
25+
pub mod size;
2526

2627
use cssparser::*;
2728
use custom::*;
@@ -45,7 +46,8 @@ use list::*;
4546
#[cfg(feature = "grid")]
4647
use grid::*;
4748
use css_modules::*;
48-
use crate::values::{image::*, length::*, position::*, alpha::*, size::*, rect::*, color::*, time::Time, easing::EasingFunction};
49+
use size::*;
50+
use crate::values::{image::*, length::*, position::*, alpha::*, size::Size2D, rect::*, color::*, time::Time, easing::EasingFunction};
4951
use crate::traits::{Parse, ToCss};
5052
use crate::printer::Printer;
5153
use smallvec::{SmallVec, smallvec};

src/properties/size.rs

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
use cssparser::*;
2+
use crate::traits::{Parse, ToCss, PropertyHandler};
3+
use crate::printer::Printer;
4+
use crate::values::length::LengthPercentage;
5+
use crate::macros::enum_property;
6+
use crate::error::{ParserError, PrinterError};
7+
use crate::properties::{Property, PropertyId};
8+
use crate::declaration::DeclarationList;
9+
use crate::logical::LogicalProperties;
10+
use crate::compat::Feature;
11+
12+
/// https://drafts.csswg.org/css-sizing-3/#specifying-sizes
13+
14+
/// https://drafts.csswg.org/css-sizing-3/#preferred-size-properties
15+
#[derive(Debug, Clone, PartialEq)]
16+
pub enum Size {
17+
Auto,
18+
LengthPercentage(LengthPercentage),
19+
MinContent,
20+
MaxContent,
21+
FitContent(LengthPercentage)
22+
}
23+
24+
impl Parse for Size {
25+
fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
26+
if input.try_parse(|i| i.expect_ident_matching("auto")).is_ok() {
27+
return Ok(Size::Auto);
28+
}
29+
30+
if input.try_parse(|i| i.expect_ident_matching("min-content")).is_ok() {
31+
return Ok(Size::MinContent);
32+
}
33+
34+
if input.try_parse(|i| i.expect_ident_matching("max-content")).is_ok() {
35+
return Ok(Size::MaxContent);
36+
}
37+
38+
if let Ok(l) = input.try_parse(|input| LengthPercentage::parse(input)) {
39+
return Ok(Size::LengthPercentage(l))
40+
}
41+
42+
if let Ok(l) = parse_fit_content(input) {
43+
return Ok(Size::FitContent(l))
44+
}
45+
46+
Err(input.new_error_for_next_token())
47+
}
48+
}
49+
50+
impl ToCss for Size {
51+
fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError> where W: std::fmt::Write {
52+
use Size::*;
53+
match self {
54+
Auto => dest.write_str("auto"),
55+
MinContent => dest.write_str("min-content"),
56+
MaxContent => dest.write_str("max-content"),
57+
FitContent(l) => {
58+
dest.write_str("fit-content(")?;
59+
l.to_css(dest)?;
60+
dest.write_str(")")
61+
}
62+
LengthPercentage(l) => l.to_css(dest)
63+
}
64+
}
65+
}
66+
67+
/// https://drafts.csswg.org/css-sizing-3/#min-size-properties
68+
/// https://drafts.csswg.org/css-sizing-3/#max-size-properties
69+
#[derive(Debug, Clone, PartialEq)]
70+
pub enum MinMaxSize {
71+
None,
72+
LengthPercentage(LengthPercentage),
73+
MinContent,
74+
MaxContent,
75+
FitContent(LengthPercentage)
76+
}
77+
78+
impl Parse for MinMaxSize {
79+
fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i, ParserError<'i>>> {
80+
if input.try_parse(|i| i.expect_ident_matching("none")).is_ok() {
81+
return Ok(MinMaxSize::None);
82+
}
83+
84+
if input.try_parse(|i| i.expect_ident_matching("min-content")).is_ok() {
85+
return Ok(MinMaxSize::MinContent);
86+
}
87+
88+
if input.try_parse(|i| i.expect_ident_matching("max-content")).is_ok() {
89+
return Ok(MinMaxSize::MaxContent);
90+
}
91+
92+
if let Ok(percent) = input.try_parse(|input| LengthPercentage::parse(input)) {
93+
return Ok(MinMaxSize::LengthPercentage(percent))
94+
}
95+
96+
if let Ok(l) = parse_fit_content(input) {
97+
return Ok(MinMaxSize::FitContent(l))
98+
}
99+
100+
Err(input.new_error_for_next_token())
101+
}
102+
}
103+
104+
impl ToCss for MinMaxSize {
105+
fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError> where W: std::fmt::Write {
106+
use MinMaxSize::*;
107+
match self {
108+
None => dest.write_str("none"),
109+
MinContent => dest.write_str("min-content"),
110+
MaxContent => dest.write_str("max-content"),
111+
FitContent(l) => {
112+
dest.write_str("fit-content(")?;
113+
l.to_css(dest)?;
114+
dest.write_str(")")
115+
}
116+
LengthPercentage(l) => l.to_css(dest)
117+
}
118+
}
119+
}
120+
121+
fn parse_fit_content<'i, 't>(input: &mut Parser<'i, 't>) -> Result<LengthPercentage, ParseError<'i, ParserError<'i>>> {
122+
input.expect_function_matching("fit-content")?;
123+
input.parse_nested_block(|input| LengthPercentage::parse(input))
124+
}
125+
126+
// https://drafts.csswg.org/css-sizing-3/#box-sizing
127+
enum_property!(BoxSizing,
128+
("content-box", ContentBox),
129+
("border-box", BorderBox)
130+
);
131+
132+
#[derive(Default)]
133+
pub(crate) struct SizeHandler;
134+
135+
impl PropertyHandler for SizeHandler {
136+
fn handle_property(&mut self, property: &Property, dest: &mut DeclarationList, logical: &mut LogicalProperties) -> bool {
137+
let logical_supported = logical.is_supported(Feature::LogicalSize);
138+
139+
macro_rules! logical {
140+
($prop: ident, $val: ident, $physical: ident) => {
141+
if logical_supported {
142+
dest.push(Property::$prop($val.clone()));
143+
} else {
144+
dest.push(Property::$physical($val.clone()));
145+
}
146+
};
147+
}
148+
149+
match property {
150+
Property::Width(_) |
151+
Property::Height(_) |
152+
Property::MinWidth(_) |
153+
Property::MaxWidth(_) |
154+
Property::MinHeight(_) |
155+
Property::MaxHeight(_) => {
156+
dest.push(property.clone());
157+
}
158+
Property::BlockSize(size) => logical!(BlockSize, size, Height),
159+
Property::MinBlockSize(size) => logical!(MinBlockSize, size, MinHeight),
160+
Property::MaxBlockSize(size) => logical!(MaxBlockSize, size, MaxHeight),
161+
Property::InlineSize(size) => logical!(InlineSize, size, Width),
162+
Property::MinInlineSize(size) => logical!(MinInlineSize, size, MinWidth),
163+
Property::MaxInlineSize(size) => logical!(MaxInlineSize, size, MaxWidth),
164+
Property::Unparsed(unparsed) => {
165+
macro_rules! logical_unparsed {
166+
($physical: ident) => {
167+
if logical_supported {
168+
dest.push(property.clone());
169+
} else {
170+
dest.push(Property::Unparsed(unparsed.with_property_id(PropertyId::$physical)));
171+
}
172+
};
173+
}
174+
175+
match &unparsed.property_id {
176+
PropertyId::Width |
177+
PropertyId::Height |
178+
PropertyId::MinWidth |
179+
PropertyId::MaxWidth |
180+
PropertyId::MinHeight |
181+
PropertyId::MaxHeight => {
182+
dest.push(property.clone());
183+
}
184+
PropertyId::BlockSize => logical_unparsed!(Height),
185+
PropertyId::MinBlockSize => logical_unparsed!(MinHeight),
186+
PropertyId::MaxBlockSize => logical_unparsed!(MaxHeight),
187+
PropertyId::InlineSize => logical_unparsed!(Width),
188+
PropertyId::MinInlineSize => logical_unparsed!(MinWidth),
189+
PropertyId::MaxInlineSize => logical_unparsed!(MaxWidth),
190+
_ => return false
191+
}
192+
}
193+
_ => return false
194+
}
195+
196+
true
197+
}
198+
199+
fn finalize(&mut self, _: &mut DeclarationList, _: &mut LogicalProperties) {}
200+
}

0 commit comments

Comments
 (0)