mirror of
https://github.com/servo/servo.git
synced 2025-10-17 00:39:15 +01:00
style: Add resolution support to calc()
Differential Revision: https://phabricator.services.mozilla.com/D172338
This commit is contained in:
parent
76e8eeda72
commit
2c986f0005
6 changed files with 171 additions and 47 deletions
|
@ -7,67 +7,135 @@
|
|||
//! https://drafts.csswg.org/css-values/#resolution
|
||||
|
||||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::values::specified::CalcNode;
|
||||
use crate::values::CSSFloat;
|
||||
use cssparser::{Parser, Token};
|
||||
use style_traits::{ParseError, StyleParseErrorKind};
|
||||
use std::fmt::{self, Write};
|
||||
use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
|
||||
|
||||
/// A specified resolution.
|
||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
||||
pub enum Resolution {
|
||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToShmem)]
|
||||
pub struct Resolution {
|
||||
value: CSSFloat,
|
||||
unit: ResolutionUnit,
|
||||
was_calc: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
||||
enum ResolutionUnit {
|
||||
/// Dots per inch.
|
||||
#[css(dimension)]
|
||||
Dpi(CSSFloat),
|
||||
Dpi,
|
||||
/// An alias unit for dots per pixel.
|
||||
#[css(dimension)]
|
||||
X(CSSFloat),
|
||||
X,
|
||||
/// Dots per pixel.
|
||||
#[css(dimension)]
|
||||
Dppx(CSSFloat),
|
||||
Dppx,
|
||||
/// Dots per centimeter.
|
||||
#[css(dimension)]
|
||||
Dpcm(CSSFloat),
|
||||
Dpcm,
|
||||
}
|
||||
|
||||
impl ResolutionUnit {
|
||||
fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Dpi => "dpi",
|
||||
Self::X => "x",
|
||||
Self::Dppx => "dppx",
|
||||
Self::Dpcm => "dpcm",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Resolution {
|
||||
/// Returns a resolution value from dppx units.
|
||||
pub fn from_dppx(value: CSSFloat) -> Self {
|
||||
Self {
|
||||
value,
|
||||
unit: ResolutionUnit::Dppx,
|
||||
was_calc: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a resolution value from dppx units.
|
||||
pub fn from_x(value: CSSFloat) -> Self {
|
||||
Self {
|
||||
value,
|
||||
unit: ResolutionUnit::X,
|
||||
was_calc: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a resolution value from dppx units.
|
||||
pub fn from_dppx_calc(value: CSSFloat) -> Self {
|
||||
Self {
|
||||
value,
|
||||
unit: ResolutionUnit::Dppx,
|
||||
was_calc: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert this resolution value to dppx units.
|
||||
pub fn to_dppx(&self) -> CSSFloat {
|
||||
match *self {
|
||||
Resolution::X(f) | Resolution::Dppx(f) => f,
|
||||
_ => self.to_dpi() / 96.0,
|
||||
pub fn dppx(&self) -> CSSFloat {
|
||||
match self.unit {
|
||||
ResolutionUnit::X | ResolutionUnit::Dppx => self.value,
|
||||
_ => self.dpi() / 96.0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert this resolution value to dpi units.
|
||||
pub fn to_dpi(&self) -> CSSFloat {
|
||||
match *self {
|
||||
Resolution::Dpi(f) => f,
|
||||
Resolution::X(f) | Resolution::Dppx(f) => f * 96.0,
|
||||
Resolution::Dpcm(f) => f * 2.54,
|
||||
pub fn dpi(&self) -> CSSFloat {
|
||||
match self.unit {
|
||||
ResolutionUnit::Dpi => self.value,
|
||||
ResolutionUnit::X | ResolutionUnit::Dppx => self.value * 96.0,
|
||||
ResolutionUnit::Dpcm => self.value * 2.54,
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a resolution given a value and unit.
|
||||
pub fn parse_dimension<'i, 't>(value: CSSFloat, unit: &str) -> Result<Self, ()> {
|
||||
let unit = match_ignore_ascii_case! { &unit,
|
||||
"dpi" => ResolutionUnit::Dpi,
|
||||
"dppx" => ResolutionUnit::Dppx,
|
||||
"dpcm" => ResolutionUnit::Dpcm,
|
||||
"x" => ResolutionUnit::X,
|
||||
_ => return Err(())
|
||||
};
|
||||
Ok(Self {
|
||||
value,
|
||||
unit,
|
||||
was_calc: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for Resolution {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
crate::values::serialize_specified_dimension(
|
||||
self.value,
|
||||
self.unit.as_str(),
|
||||
self.was_calc,
|
||||
dest,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Resolution {
|
||||
fn parse<'i, 't>(
|
||||
_: &ParserContext,
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let location = input.current_source_location();
|
||||
let (value, unit) = match *input.next()? {
|
||||
match *input.next()? {
|
||||
Token::Dimension {
|
||||
value, ref unit, ..
|
||||
} => (value, unit),
|
||||
} => Self::parse_dimension(value, unit)
|
||||
.map_err(|()| location.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
|
||||
Token::Function(ref name) => {
|
||||
let function = CalcNode::math_function(name, location)?;
|
||||
CalcNode::parse_resolution(context, input, function)
|
||||
},
|
||||
ref t => return Err(location.new_unexpected_token_error(t.clone())),
|
||||
};
|
||||
|
||||
match_ignore_ascii_case! { &unit,
|
||||
"dpi" => Ok(Resolution::Dpi(value)),
|
||||
"dppx" => Ok(Resolution::Dppx(value)),
|
||||
"dpcm" => Ok(Resolution::Dpcm(value)),
|
||||
"x" => Ok(Resolution::X(value)),
|
||||
_ => Err(location.new_custom_error(
|
||||
StyleParseErrorKind::UnexpectedDimension(unit.clone())
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue