use crate::parser::{Parse, ParserContext};
use crate::values::animated::ToAnimatedZero;
use crate::One;
use byteorder::{BigEndian, ReadBytesExt};
use cssparser::Parser;
use std::fmt::{self, Write};
use std::io::Cursor;
use style_traits::{CssWriter, ParseError};
use style_traits::{StyleParseErrorKind, ToCss};
pub trait TaggedFontValue {
fn tag(&self) -> FontTag;
}
#[derive(
Clone,
Debug,
Eq,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToResolvedValue,
ToShmem,
)]
pub struct FeatureTagValue<Integer> {
pub tag: FontTag,
pub value: Integer,
}
impl<T> TaggedFontValue for FeatureTagValue<T> {
fn tag(&self) -> FontTag {
self.tag
}
}
impl<Integer> ToCss for FeatureTagValue<Integer>
where
Integer: One + ToCss + PartialEq,
{
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
self.tag.to_css(dest)?;
if !self.value.is_one() {
dest.write_char(' ')?;
self.value.to_css(dest)?;
}
Ok(())
}
}
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Debug,
Eq,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
pub struct VariationValue<Number> {
#[animation(constant)]
pub tag: FontTag,
pub value: Number,
}
impl<T> TaggedFontValue for VariationValue<T> {
fn tag(&self) -> FontTag {
self.tag
}
}
#[derive(
Clone, Debug, Eq, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToAnimatedValue, ToCss, ToResolvedValue, ToShmem,
)]
#[css(comma)]
pub struct FontSettings<T>(#[css(if_empty = "normal", iterable)] pub Box<[T]>);
impl<T> FontSettings<T> {
#[inline]
pub fn normal() -> Self {
FontSettings(vec![].into_boxed_slice())
}
}
impl<T: Parse> Parse for FontSettings<T> {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if input
.try_parse(|i| i.expect_ident_matching("normal"))
.is_ok()
{
return Ok(Self::normal());
}
Ok(FontSettings(
input
.parse_comma_separated(|i| T::parse(context, i))?
.into_boxed_slice(),
))
}
}
#[derive(
Clone,
Copy,
Debug,
Eq,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToResolvedValue,
ToShmem,
)]
pub struct FontTag(pub u32);
impl ToCss for FontTag {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
use byteorder::ByteOrder;
use std::str;
let mut raw = [0u8; 4];
BigEndian::write_u32(&mut raw, self.0);
str::from_utf8(&raw).unwrap_or_default().to_css(dest)
}
}
impl Parse for FontTag {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let location = input.current_source_location();
let tag = input.expect_string()?;
if tag.len() != 4 || tag.as_bytes().iter().any(|c| *c < b' ' || *c > b'~') {
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
let mut raw = Cursor::new(tag.as_bytes());
Ok(FontTag(raw.read_u32::<BigEndian>().unwrap()))
}
}
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
Hash,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToResolvedValue,
ToShmem,
)]
pub enum FontStyle<Angle> {
#[animation(error)]
Normal,
#[animation(error)]
Italic,
#[value_info(starts_with_keyword)]
Oblique(Angle),
}
#[allow(missing_docs)]
#[repr(u8)]
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
Hash,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToAnimatedZero,
ToComputedValue,
ToResolvedValue,
ToShmem,
)]
pub enum GenericFontSizeAdjust<Factor> {
#[animation(error)]
None,
#[value_info(starts_with_keyword)]
ExHeight(Factor),
#[value_info(starts_with_keyword)]
CapHeight(Factor),
#[value_info(starts_with_keyword)]
ChWidth(Factor),
#[value_info(starts_with_keyword)]
IcWidth(Factor),
#[value_info(starts_with_keyword)]
IcHeight(Factor),
}
impl<Factor: ToCss> ToCss for GenericFontSizeAdjust<Factor> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
let (prefix, value) = match self {
Self::None => return dest.write_str("none"),
Self::ExHeight(v) => ("", v),
Self::CapHeight(v) => ("cap-height ", v),
Self::ChWidth(v) => ("ch-width ", v),
Self::IcWidth(v) => ("ic-width ", v),
Self::IcHeight(v) => ("ic-height ", v),
};
dest.write_str(prefix)?;
value.to_css(dest)
}
}
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToAnimatedValue,
ToCss,
ToShmem,
Parse,
)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[repr(C, u8)]
pub enum GenericLineHeight<N, L> {
Normal,
#[cfg(feature = "gecko")]
#[parse(condition = "ParserContext::in_ua_sheet")]
MozBlockHeight,
Number(N),
Length(L),
}
pub use self::GenericLineHeight as LineHeight;
impl<N, L> ToAnimatedZero for LineHeight<N, L> {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
Err(())
}
}
impl<N, L> LineHeight<N, L> {
#[inline]
pub fn normal() -> Self {
LineHeight::Normal
}
}