use std::sync::Arc;
use super::length::parse_length_token;
use super::length::{FontContext, Viewport};
use indexmap::IndexMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum BoxSizing {
#[default]
BorderBox,
ContentBox,
}
#[doc(hidden)]
pub fn parse_box_sizing(s: &str) -> Option<BoxSizing> {
match s.trim().to_ascii_lowercase().as_str() {
"content-box" => Some(BoxSizing::ContentBox),
"border-box" => Some(BoxSizing::BorderBox),
_ => None,
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum Position {
#[default]
Static,
Relative,
Absolute,
Fixed,
Sticky,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum Visibility {
#[default]
Visible,
Hidden,
}
#[doc(hidden)]
pub fn parse_visibility(s: &str) -> Option<Visibility> {
match s.trim().to_ascii_lowercase().as_str() {
"visible" => Some(Visibility::Visible),
"hidden" | "collapse" => Some(Visibility::Hidden),
_ => None,
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum TableLayout {
#[default]
Auto,
Fixed,
}
pub fn parse_table_layout(s: &str) -> Option<TableLayout> {
match s.trim().to_ascii_lowercase().as_str() {
"auto" => Some(TableLayout::Auto),
"fixed" => Some(TableLayout::Fixed),
_ => None,
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum CaptionSide {
#[default]
Top,
Bottom,
}
pub fn parse_caption_side(s: &str) -> Option<CaptionSide> {
match s.trim().to_ascii_lowercase().as_str() {
"top" => Some(CaptionSide::Top),
"bottom" => Some(CaptionSide::Bottom),
_ => None,
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum EmptyCells {
#[default]
Show,
Hide,
}
pub fn parse_empty_cells(s: &str) -> Option<EmptyCells> {
match s.trim().to_ascii_lowercase().as_str() {
"show" => Some(EmptyCells::Show),
"hide" => Some(EmptyCells::Hide),
_ => None,
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub enum Overflow {
#[default]
Visible,
Clip,
}
#[doc(hidden)]
pub fn parse_overflow(s: &str) -> Option<Overflow> {
match s.trim().to_ascii_lowercase().as_str() {
"visible" => Some(Overflow::Visible),
"hidden" | "auto" | "scroll" | "clip" => Some(Overflow::Clip),
_ => None,
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct InsetSides {
pub top: Option<isize>,
pub right: Option<isize>,
pub bottom: Option<isize>,
pub left: Option<isize>,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Positioning {
pub position: Position,
pub inset: InsetSides,
pub z_index: Option<i32>,
}
#[doc(hidden)]
pub fn parse_position(s: &str) -> Option<Position> {
match s.trim().to_ascii_lowercase().as_str() {
"relative" => Some(Position::Relative),
"absolute" => Some(Position::Absolute),
"fixed" => Some(Position::Fixed),
"sticky" => Some(Position::Sticky),
"static" => Some(Position::Static),
_ => None,
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct CornerRadii {
pub top_left: usize,
pub top_right: usize,
pub bottom_right: usize,
pub bottom_left: usize,
}
impl CornerRadii {
pub const fn is_rounded(&self) -> bool {
self.top_left > 0 || self.top_right > 0 || self.bottom_right > 0 || self.bottom_left > 0
}
}
pub(in crate::html::css_parse) fn parse_border_radius(
decls: &IndexMap<Arc<str>, Arc<str>>,
containing_width: usize,
font_ctx: FontContext,
viewport: Viewport,
) -> CornerRadii {
let mut radii: CornerRadii = decls
.get("border-radius")
.map(|value| {
let parsed: Vec<usize> = value
.split_whitespace()
.filter_map(|t| parse_length_token(Some(t), containing_width, font_ctx, viewport))
.collect();
match parsed.len() {
0 => CornerRadii::default(),
1 => CornerRadii {
top_left: parsed[0],
top_right: parsed[0],
bottom_right: parsed[0],
bottom_left: parsed[0],
},
2 => CornerRadii {
top_left: parsed[0],
top_right: parsed[1],
bottom_right: parsed[0],
bottom_left: parsed[1],
},
3 => CornerRadii {
top_left: parsed[0],
top_right: parsed[1],
bottom_right: parsed[2],
bottom_left: parsed[1],
},
_ => CornerRadii {
top_left: parsed[0],
top_right: parsed[1],
bottom_right: parsed[2],
bottom_left: parsed[3],
},
}
})
.unwrap_or_default();
for (name, slot) in [
("border-top-left-radius", &mut radii.top_left),
("border-top-right-radius", &mut radii.top_right),
("border-bottom-right-radius", &mut radii.bottom_right),
("border-bottom-left-radius", &mut radii.bottom_left),
] {
if let Some(raw) = decls.get(name)
&& let Some(len) =
parse_length_token(Some(raw.as_ref()), containing_width, font_ctx, viewport)
{
*slot = len;
}
}
radii
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CssDisplay {
Block,
Flow,
FlowRoot,
Inline,
InlineBlock,
ListItem,
Flex,
InlineFlex,
Grid,
InlineGrid,
Table,
InlineTable,
TableRowGroup,
TableHeaderGroup,
TableFooterGroup,
TableRow,
TableCell,
TableColumnGroup,
TableColumn,
TableCaption,
None,
Contents,
}
impl CssDisplay {
pub fn parse(value: &str) -> Option<Self> {
match value.trim().to_ascii_lowercase().as_str() {
"block" => Some(CssDisplay::Block),
"flow" => Some(CssDisplay::Flow),
"flow-root" => Some(CssDisplay::FlowRoot),
"inline" => Some(CssDisplay::Inline),
"inline-block" => Some(CssDisplay::InlineBlock),
"list-item" => Some(CssDisplay::ListItem),
"flex" => Some(CssDisplay::Flex),
"inline-flex" => Some(CssDisplay::InlineFlex),
"grid" => Some(CssDisplay::Grid),
"inline-grid" => Some(CssDisplay::InlineGrid),
"table" => Some(CssDisplay::Table),
"inline-table" => Some(CssDisplay::InlineTable),
"table-row-group" => Some(CssDisplay::TableRowGroup),
"table-header-group" => Some(CssDisplay::TableHeaderGroup),
"table-footer-group" => Some(CssDisplay::TableFooterGroup),
"table-row" => Some(CssDisplay::TableRow),
"table-cell" => Some(CssDisplay::TableCell),
"table-column-group" => Some(CssDisplay::TableColumnGroup),
"table-column" => Some(CssDisplay::TableColumn),
"table-caption" => Some(CssDisplay::TableCaption),
"none" => Some(CssDisplay::None),
"contents" => Some(CssDisplay::Contents),
_ => None,
}
}
pub fn is_dropped(self) -> bool {
matches!(self, CssDisplay::None)
}
pub fn is_transparent(self) -> bool {
matches!(self, CssDisplay::Contents)
}
pub fn is_block_level(self) -> bool {
matches!(
self,
CssDisplay::Block
| CssDisplay::Flow
| CssDisplay::FlowRoot
| CssDisplay::ListItem
| CssDisplay::Flex
| CssDisplay::Grid
| CssDisplay::Table
| CssDisplay::TableRowGroup
| CssDisplay::TableHeaderGroup
| CssDisplay::TableFooterGroup
| CssDisplay::TableRow
| CssDisplay::TableCell
| CssDisplay::TableColumnGroup
| CssDisplay::TableColumn
| CssDisplay::TableCaption
)
}
pub fn is_inline_level(self) -> bool {
matches!(
self,
CssDisplay::Inline
| CssDisplay::InlineBlock
| CssDisplay::InlineFlex
| CssDisplay::InlineGrid
| CssDisplay::InlineTable
)
}
pub fn is_flex(self) -> bool {
matches!(self, CssDisplay::Flex | CssDisplay::InlineFlex)
}
pub fn is_grid(self) -> bool {
matches!(self, CssDisplay::Grid | CssDisplay::InlineGrid)
}
pub fn is_table_family(self) -> bool {
matches!(
self,
CssDisplay::Table
| CssDisplay::InlineTable
| CssDisplay::TableRowGroup
| CssDisplay::TableHeaderGroup
| CssDisplay::TableFooterGroup
| CssDisplay::TableRow
| CssDisplay::TableCell
| CssDisplay::TableColumnGroup
| CssDisplay::TableColumn
| CssDisplay::TableCaption
)
}
}
impl Default for CssDisplay {
fn default() -> Self {
CssDisplay::Flow
}
}