/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! Computed values for font properties
usecrate::parser::{Parse, ParserContext}; usecrate::values::animated::ToAnimatedValue; usecrate::values::computed::{
Angle, Context, Integer, Length, NonNegativeLength, NonNegativeNumber, Number, Percentage,
ToComputedValue, Zoom,
}; usecrate::values::generics::font::{
FeatureTagValue, FontSettings, TaggedFontValue, VariationValue,
}; usecrate::values::generics::{font as generics, NonNegative}; usecrate::values::resolved::{Context as ResolvedContext, ToResolvedValue}; usecrate::values::specified::font::{ selfas specified, KeywordInfo, MAX_FONT_WEIGHT, MIN_FONT_WEIGHT,
}; usecrate::values::specified::length::{FontBaseSize, LineHeightBase, NoCalcLength}; usecrate::Atom; use cssparser::{serialize_identifier, CssStringWriter, Parser}; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use num_traits::abs; use num_traits::cast::AsPrimitive; use std::fmt::{self, Write}; use style_traits::{CssWriter, ParseError, ToCss};
pubusecrate::values::computed::Length as MozScriptMinSize; pubusecrate::values::specified::font::MozScriptSizeMultiplier; pubusecrate::values::specified::font::{FontPalette, FontSynthesis}; pubusecrate::values::specified::font::{
FontVariantAlternates, FontVariantEastAsian, FontVariantLigatures, FontVariantNumeric, XLang,
XTextScale,
}; pubusecrate::values::specified::Integer as SpecifiedInteger; pubusecrate::values::specified::Number as SpecifiedNumber;
/// Generic template for font property type classes that use a fixed-point /// internal representation with `FRACTION_BITS` for the fractional part. /// /// Values are constructed from and exposed as floating-point, but stored /// internally as fixed point, so there will be a quantization effect on /// fractional values, depending on the number of fractional bits used. /// /// Using (16-bit) fixed-point types rather than floats for these style /// attributes reduces the memory footprint of gfxFontEntry and gfxFontStyle; it /// will also tend to reduce the number of distinct font instances that get /// created, particularly when styles are animated or set to arbitrary values /// (e.g. by sliders in the UI), which should reduce pressure on graphics /// resources and improve cache hit rates. /// /// cbindgen:derive-lt /// cbindgen:derive-lte /// cbindgen:derive-gt /// cbindgen:derive-gte #[repr(C)] #[derive(
Clone,
ComputeSquaredDistance,
Copy,
Debug,
Eq,
Hash,
MallocSizeOf,
PartialEq,
PartialOrd,
ToResolvedValue,
)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] pubstruct FixedPoint<T, const FRACTION_BITS: u16> { /// The actual representation. pub value: T,
}
/// Returns a fixed-point bit from a floating-point context. pubfn from_float(v: f32) -> Self { Self {
value: (v * Self::SCALE as f32).round().as_(),
}
}
// We implement this and mul below only for u16 types, because u32 types might need more care about // overflow. But it's not hard to implement in either case. impl<const FRACTION_BITS: u16> std::ops::Div for FixedPoint<u16, FRACTION_BITS> { type Output = Self; fn div(self, rhs: Self) -> Self { Self {
value: (((self.value as u32) << (FRACTION_BITS as u32)) / (rhs.value as u32)) as u16,
}
}
} impl<const FRACTION_BITS: u16> std::ops::Mul for FixedPoint<u16, FRACTION_BITS> { type Output = Self; fn mul(self, rhs: Self) -> Self { Self {
value: (((self.value as u32) * (rhs.value as u32)) >> (FRACTION_BITS as u32)) as u16,
}
}
}
/// font-weight: range 1..1000, fractional values permitted; keywords /// 'normal', 'bold' aliased to 400, 700 respectively. /// /// We use an unsigned 10.6 fixed-point value (range 0.0 - 1023.984375) pubconst FONT_WEIGHT_FRACTION_BITS: u16 = 6;
/// This is an alias which is useful mostly as a cbindgen / C++ inference /// workaround. pubtype FontWeightFixedPoint = FixedPoint<u16, FONT_WEIGHT_FRACTION_BITS>;
/// A value for the font-weight property per: /// /// https://drafts.csswg.org/css-fonts-4/#propdef-font-weight /// /// cbindgen:derive-lt /// cbindgen:derive-lte /// cbindgen:derive-gt /// cbindgen:derive-gte #[derive(
Clone,
ComputeSquaredDistance,
Copy,
Debug,
Hash,
MallocSizeOf,
PartialEq,
PartialOrd,
ToResolvedValue,
)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[repr(C)] pubstruct FontWeight(FontWeightFixedPoint); impl ToAnimatedValue for FontWeight { type AnimatedValue = Number;
/// The threshold from which we consider a font bold. pubconst BOLD_THRESHOLD: FontWeight = FontWeight(FontWeightFixedPoint {
value: 600 << FONT_WEIGHT_FRACTION_BITS,
});
/// Weither this weight is bold pubfn is_bold(&self) -> bool {
*self >= Self::BOLD_THRESHOLD
}
/// Returns the value as a float. pubfn value(&self) -> f32 { self.0.to_float()
}
/// Construct a valid weight from a float value. pubfn from_float(v: f32) -> Self { Self(FixedPoint::from_float(
v.max(MIN_FONT_WEIGHT).min(MAX_FONT_WEIGHT),
))
}
/// Return the bolder weight. /// /// See the table in: /// https://drafts.csswg.org/css-fonts-4/#font-weight-numeric-values pubfn bolder(self) -> Self { let value = self.value(); if value < 350. { returnSelf::NORMAL;
} if value < 550. { returnSelf::BOLD;
} Self::from_float(value.max(900.))
}
/// Return the lighter weight. /// /// See the table in: /// https://drafts.csswg.org/css-fonts-4/#font-weight-numeric-values pubfn lighter(self) -> Self { let value = self.value(); if value < 550. { returnSelf::from_float(value.min(100.));
} if value < 750. { returnSelf::NORMAL;
} Self::BOLD
}
}
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
MallocSizeOf,
PartialEq,
ToAnimatedZero,
ToCss,
)] #[cfg_attr(feature = "servo", derive(Serialize, Deserialize))] /// The computed value of font-size pubstruct FontSize { /// The computed size, that we use to compute ems etc. This accounts for /// e.g., text-zoom. pub computed_size: NonNegativeLength, /// The actual used size. This is the computed font size, potentially /// constrained by other factors like minimum font-size settings and so on. #[css(skip)] pub used_size: NonNegativeLength, /// If derived from a keyword, the keyword and additional transformations applied to it #[css(skip)] pub keyword_info: KeywordInfo,
}
impl FontSize { /// The actual computed font size. #[inline] pubfn computed_size(&self) -> Length { self.computed_size.0
}
/// The actual used font size. #[inline] pubfn used_size(&self) -> Length { self.used_size.0
}
/// Apply zoom to the font-size. This is usually done by ToComputedValue. #[inline] pubfn zoom(&self, zoom: Zoom) -> Self { Self {
computed_size: NonNegative(Length::new(zoom.zoom(self.computed_size.0.px()))),
used_size: NonNegative(Length::new(zoom.zoom(self.used_size.0.px()))),
keyword_info: self.keyword_info,
}
}
#[inline] /// Get default value of font size. pubfn medium() -> Self { Self {
computed_size: NonNegative(Length::new(specified::FONT_MEDIUM_PX)),
used_size: NonNegative(Length::new(specified::FONT_MEDIUM_PX)),
keyword_info: KeywordInfo::medium(),
}
}
}
impl ToAnimatedValue for FontSize { type AnimatedValue = Length;
#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToResolvedValue)] #[cfg_attr(feature = "servo", derive(Hash, Serialize, Deserialize))] /// Specifies a prioritized list of font family names or generic family names. #[repr(C)] pubstruct FontFamily { /// The actual list of family names. pub families: FontFamilyList, /// Whether this font-family came from a specified system-font. pub is_system_font: bool, /// Whether this is the initial font-family that might react to language /// changes. pub is_initial: bool,
}
impl FontFamily { #[inline] /// Get default font family as `serif` which is a generic font-family pubfn serif() -> Self { Self::generic(GenericFontFamily::Serif).clone()
}
/// Returns the font family for `-moz-bullet-font`. #[cfg(feature = "gecko")] pub(crate) fn moz_bullet() -> &'static Self {
static_font_family!(
MOZ_BULLET,
SingleFontFamily::FamilyName(FamilyName {
name: atom!("-moz-bullet-font"),
syntax: FontFamilyNameSyntax::Identifiers,
})
);
&*MOZ_BULLET
}
/// Returns a font family for a single system font. #[cfg(feature = "gecko")] pubfn for_system_font(name: &str) -> Self { Self {
families: FontFamilyList {
list: crate::ArcSlice::from_iter(std::iter::once(SingleFontFamily::FamilyName(
FamilyName {
name: Atom::from(name),
syntax: FontFamilyNameSyntax::Identifiers,
},
))),
},
is_system_font: true,
is_initial: false,
}
}
impl MallocSizeOf for FontFamily { fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize { use malloc_size_of::MallocUnconditionalSizeOf; // SharedFontList objects are generally measured from the pointer stored // in the specified value. So only count this if the SharedFontList is // unshared. let shared_font_list = &self.families.list; if shared_font_list.is_unique() {
shared_font_list.unconditional_size_of(ops)
} else { 0
}
}
}
impl ToCss for FontFamily { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where
W: fmt::Write,
{ letmut iter = self.families.iter(); match iter.next() {
Some(f) => f.to_css(dest)?,
None => return Ok(()),
} for family in iter {
dest.write_str(", ")?;
family.to_css(dest)?;
}
Ok(())
}
}
/// The name of a font family of choice. #[derive(
Clone, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem,
)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[repr(C)] pubstruct FamilyName { /// Name of the font family. pub name: Atom, /// Syntax of the font family. pub syntax: FontFamilyNameSyntax,
}
impl ToCss for FamilyName { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where
W: fmt::Write,
{ matchself.syntax {
FontFamilyNameSyntax::Quoted => {
dest.write_char('"')?;
write!(CssStringWriter::new(dest), "{}", self.name)?;
dest.write_char('"')
},
FontFamilyNameSyntax::Identifiers => { letmut first = true; for ident inself.name.to_string().split(' ') { if first {
first = false;
} else {
dest.write_char(' ')?;
}
debug_assert!(
!ident.is_empty(), "Family name with leading, \
trailing, or consecutive white spaces should \
have been marked quoted by the parser"
);
serialize_identifier(ident, dest)?;
}
Ok(())
},
}
}
}
#[derive(
Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem,
)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] /// Font family names must either be given quoted as strings, /// or unquoted as a sequence of one or more identifiers. #[repr(u8)] pubenum FontFamilyNameSyntax { /// The family name was specified in a quoted form, e.g. "Font Name" /// or 'Font Name'.
Quoted,
/// The family name was specified in an unquoted form as a sequence of /// identifiers.
Identifiers,
}
/// A set of faces that vary in weight, width or slope. /// cbindgen:derive-mut-casts=true #[derive(
Clone, Debug, Eq, MallocSizeOf, PartialEq, ToCss, ToComputedValue, ToResolvedValue, ToShmem,
)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize, Hash))] #[repr(u8)] pubenum SingleFontFamily { /// The name of a font family of choice.
FamilyName(FamilyName), /// Generic family name.
Generic(GenericFontFamily),
}
/// A generic font-family name. /// /// The order here is important, if you change it make sure that /// `gfxPlatformFontList.h`s ranged array and `gfxFontFamilyList`'s /// sSingleGenerics are updated as well. /// /// NOTE(emilio): Should be u8, but it's a u32 because of ABI issues between GCC /// and LLVM see https://bugs.llvm.org/show_bug.cgi?id=44228 / bug 1600735 / /// bug 1726515. #[derive(
Clone,
Copy,
Debug,
Eq,
Hash,
MallocSizeOf,
PartialEq,
Parse,
ToCss,
ToComputedValue,
ToResolvedValue,
ToShmem,
)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[repr(u32)] #[allow(missing_docs)] pubenum GenericFontFamily { /// No generic family specified, only for internal usage. /// /// NOTE(emilio): Gecko code relies on this variant being zero. #[css(skip)]
None = 0,
Serif,
SansSerif, #[parse(aliases = "-moz-fixed")]
Monospace,
Cursive,
Fantasy, #[parse(condition = "system_ui_enabled")]
SystemUi, /// An internal value for emoji font selection. #[css(skip)] #[cfg(feature = "gecko")]
MozEmoji,
}
impl GenericFontFamily { /// When we disallow websites to override fonts, we ignore some generic /// families that the website might specify, since they're not configured by /// the user. See bug 789788 and bug 1730098. pub(crate) fn valid_for_user_font_prioritization(self) -> bool { matchself { Self::None | Self::Fantasy | Self::Cursive | Self::SystemUi => false, #[cfg(feature = "gecko")] Self::MozEmoji => false, Self::Serif | Self::SansSerif | Self::Monospace => true,
}
}
}
let first_ident = input.expect_ident_cloned()?; let reserved = match_ignore_ascii_case! { &first_ident, // https://drafts.csswg.org/css-fonts/#propdef-font-family // "Font family names that happen to be the same as a keyword value // (`inherit`, `serif`, `sans-serif`, `monospace`, `fantasy`, and `cursive`) // must be quoted to prevent confusion with the keywords with the same names. // The keywords ‘initial’ and ‘default’ are reserved for future use // and must also be quoted when used as font names. // UAs must not consider these keywords as matching the <family-name> type." "inherit" | "initial" | "unset" | "revert" | "default" => true,
_ => false,
};
letmut value = first_ident.as_ref().to_owned(); letmut serialize_quoted = value.contains(' ');
// These keywords are not allowed by themselves. // The only way this value can be valid with with another keyword. if reserved { let ident = input.expect_ident()?;
serialize_quoted = serialize_quoted || ident.contains(' ');
value.push(' ');
value.push_str(&ident);
} whilelet Ok(ident) = input.try_parse(|i| i.expect_ident_cloned()) {
serialize_quoted = serialize_quoted || ident.contains(' ');
value.push(' ');
value.push_str(&ident);
} let syntax = if serialize_quoted { // For font family names which contains special white spaces, e.g. // `font-family: \ a\ \ b\ \ c\ ;`, it is tricky to serialize them // as identifiers correctly. Just mark them quoted so we don't need // to worry about them in serialization code.
FontFamilyNameSyntax::Quoted
} else {
FontFamilyNameSyntax::Identifiers
};
Ok(SingleFontFamily::FamilyName(FamilyName {
name: Atom::from(value),
syntax,
}))
}
}
/// A list of font families. #[derive(Clone, Debug, ToComputedValue, ToResolvedValue, ToShmem, PartialEq, Eq)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize, Hash))] #[repr(C)] pubstruct FontFamilyList { /// The actual list of font families specified. pub list: crate::ArcSlice<SingleFontFamily>,
}
/// If there's a generic font family on the list which is suitable for user /// font prioritization, then move it ahead of the other families in the list, /// except for any families known to be ligature-based icon fonts, where using a /// generic instead of the site's specified font may cause substantial breakage. /// If no suitable generic is found in the list, insert the default generic ahead /// of all the listed families except for known ligature-based icon fonts. #[cfg_attr(feature = "servo", allow(unused))] pub(crate) fn prioritize_first_generic_or_prepend(&mutself, generic: GenericFontFamily) { letmut index_of_first_generic = None; letmut target_index = None;
for (i, f) inself.iter().enumerate() { match &*f {
SingleFontFamily::Generic(f) => { if index_of_first_generic.is_none() && f.valid_for_user_font_prioritization() { // If we haven't found a target position, there's nothing to do; // this entry is already ahead of everything except any whitelisted // icon fonts. if target_index.is_none() { return;
}
index_of_first_generic = Some(i); break;
} // A non-prioritized generic (e.g. cursive, fantasy) becomes the target // position for prioritization, just like arbitrary named families. if target_index.is_none() {
target_index = Some(i);
}
},
SingleFontFamily::FamilyName(fam) => { // Target position for the first generic is in front of the first // non-whitelisted icon font family we find. if target_index.is_none() && !fam.is_known_icon_font_family() {
target_index = Some(i);
}
},
}
}
letmut new_list = self.list.iter().cloned().collect::<Vec<_>>(); let first_generic = match index_of_first_generic {
Some(i) => new_list.remove(i),
None => SingleFontFamily::Generic(generic),
};
/// Returns whether we need to prioritize user fonts. #[cfg_attr(feature = "servo", allow(unused))] pub(crate) fn needs_user_font_prioritization(&self) -> bool { self.iter().next().map_or(true, |f| match f {
SingleFontFamily::Generic(f) => !f.valid_for_user_font_prioritization(),
_ => true,
})
}
/// Return the generic ID if it is a single generic font pubfn single_generic(&self) -> Option<GenericFontFamily> { letmut iter = self.iter(); iflet Some(SingleFontFamily::Generic(f)) = iter.next() { if iter.next().is_none() { return Some(*f);
}
}
None
}
}
/// Preserve the readability of text when font fallback occurs. pubtype FontSizeAdjust = generics::GenericFontSizeAdjust<NonNegativeNumber>;
impl FontSizeAdjust { #[inline] /// Default value of font-size-adjust pubfn none() -> Self {
FontSizeAdjust::None
}
}
impl ToComputedValue for specified::FontSizeAdjust { type ComputedValue = FontSizeAdjust;
let font_metrics = |vertical| { let orient = if vertical {
FontMetricsOrientation::MatchContextPreferVertical
} else {
FontMetricsOrientation::Horizontal
}; let metrics = context.query_font_metrics(FontBaseSize::CurrentStyle, orient, false); let font_size = context.style().get_font().clone_font_size().used_size.0;
(metrics, font_size)
};
// Macro to resolve a from-font value using the given metric field. If not present, // returns the fallback value, or if that is negative, resolves using ascent instead // of the missing field (this is the fallback for cap-height).
macro_rules! resolve {
($basis:ident, $value:expr, $vertical:expr, $field:ident, $fallback:expr) => {{ match $value {
specified::FontSizeAdjustFactor::Number(f) => {
FontSizeAdjust::$basis(f.to_computed_value(context))
},
specified::FontSizeAdjustFactor::FromFont => { let (metrics, font_size) = font_metrics($vertical); let ratio = iflet Some(metric) = metrics.$field {
metric / font_size
} elseif $fallback >= 0.0 {
$fallback
} else {
metrics.ascent / font_size
}; if ratio.is_nan() {
FontSizeAdjust::$basis(NonNegative(abs($fallback)))
} else {
FontSizeAdjust::$basis(NonNegative(ratio))
}
},
}
}};
}
/// Use FontSettings as computed type of FontFeatureSettings. pubtype FontFeatureSettings = FontSettings<FeatureTagValue<Integer>>;
/// The computed value for font-variation-settings. pubtype FontVariationSettings = FontSettings<VariationValue<Number>>;
// The computed value of font-{feature,variation}-settings discards values // with duplicate tags, keeping only the last occurrence of each tag. fn dedup_font_settings<T>(settings_list: &mut Vec<T>) where
T: TaggedFontValue,
{ if settings_list.len() > 1 {
settings_list.sort_by_key(|k| k.tag().0); // dedup() keeps the first of any duplicates, but we want the last, // so we implement it manually here. letmut prev_tag = settings_list.last().unwrap().tag(); for i in (0..settings_list.len() - 1).rev() { let cur_tag = settings_list[i].tag(); if cur_tag == prev_tag {
settings_list.remove(i);
}
prev_tag = cur_tag;
}
}
}
impl<T> ToComputedValue for FontSettings<T> where
T: ToComputedValue,
<T as ToComputedValue>::ComputedValue: TaggedFontValue,
{ type ComputedValue = FontSettings<T::ComputedValue>;
/// font-language-override can only have a single 1-4 ASCII character /// OpenType "language system" tag, so we should be able to compute /// it and store it as a 32-bit integer /// (see http://www.microsoft.com/typography/otspec/languagetags.htm). #[derive(
Clone,
Copy,
Debug,
Eq,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
ToResolvedValue,
ToShmem,
)] #[repr(C)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[value_info(other_values = "normal")] pubstruct FontLanguageOverride(pub u32);
impl FontLanguageOverride { #[inline] /// Get computed default value of `font-language-override` with 0 pubfn normal() -> FontLanguageOverride {
FontLanguageOverride(0)
}
/// Returns this value as a `&str`, backed by `storage`. #[inline] pub(crate) fn to_str(self, storage: &mut [u8; 4]) -> &str {
*storage = u32::to_be_bytes(self.0); // Safe because we ensure it's ASCII during parsing let slice = if cfg!(debug_assertions) {
std::str::from_utf8(&storage[..]).unwrap()
} else { unsafe { std::str::from_utf8_unchecked(&storage[..]) }
};
slice.trim_end()
}
/// Unsafe because `Self::to_str` requires the value to represent a UTF-8 /// string. #[inline] pubunsafefn from_u32(value: u32) -> Self { Self(value)
}
}
impl ToComputedValue for specified::MozScriptMinSize { type ComputedValue = MozScriptMinSize;
fn to_computed_value(&self, cx: &Context) -> MozScriptMinSize { // this value is used in the computation of font-size, so // we use the parent size let base_size = FontBaseSize::InheritedStyle; let line_height_base = LineHeightBase::InheritedStyle; matchself.0 {
NoCalcLength::FontRelative(value) => {
value.to_computed_value(cx, base_size, line_height_base)
},
NoCalcLength::ServoCharacterWidth(value) => {
value.to_computed_value(base_size.resolve(cx).computed_size())
}, ref l => l.to_computed_value(cx),
}
}
/// The computed value of the math-depth property. pubtype MathDepth = i8;
#[cfg(feature = "gecko")] impl ToComputedValue for specified::MathDepth { type ComputedValue = MathDepth;
fn to_computed_value(&self, cx: &Context) -> i8 { usecrate::properties::longhands::math_style::SpecifiedValue as MathStyleValue; use std::{cmp, i8};
let int = match *self {
specified::MathDepth::AutoAdd => { let parent = cx.builder.get_parent_font().clone_math_depth() as i32; let style = cx.builder.get_parent_font().clone_math_style(); if style == MathStyleValue::Compact {
parent.saturating_add(1)
} else {
parent
}
},
specified::MathDepth::Add(rel) => { let parent = cx.builder.get_parent_font().clone_math_depth();
(parent as i32).saturating_add(rel.to_computed_value(cx))
},
specified::MathDepth::Absolute(abs) => abs.to_computed_value(cx),
};
cmp::min(int, i8::MAX as i32) as i8
}
fn from_computed_value(other: &i8) -> Self { let computed_value = *other as i32;
specified::MathDepth::Absolute(SpecifiedInteger::from_computed_value(&computed_value))
}
}
/// - Use a signed 8.8 fixed-point value (representable range -128.0..128) /// /// Values of <angle> below -90 or above 90 not permitted, so we use out of /// range values to represent normal | oblique pubconst FONT_STYLE_FRACTION_BITS: u16 = 8;
/// This is an alias which is useful mostly as a cbindgen / C++ inference /// workaround. pubtype FontStyleFixedPoint = FixedPoint<i16, FONT_STYLE_FRACTION_BITS>;
/// The computed value of `font-style`. /// /// - Define out of range values min value (-128.0) as meaning 'normal' /// - Define max value (127.99609375) as 'italic' /// - Other values represent 'oblique <angle>' /// - Note that 'oblique 0deg' is distinct from 'normal' (should it be?) /// /// cbindgen:derive-lt /// cbindgen:derive-lte /// cbindgen:derive-gt /// cbindgen:derive-gte #[derive(
Clone,
ComputeSquaredDistance,
Copy,
Debug,
Eq,
Hash,
MallocSizeOf,
PartialEq,
PartialOrd,
ToResolvedValue,
)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[repr(C)] pubstruct FontStyle(FontStyleFixedPoint);
/// font-stretch is a percentage relative to normal. /// /// We use an unsigned 10.6 fixed-point value (range 0.0 - 1023.984375) /// /// We arbitrarily limit here to 1000%. (If that becomes a problem, we could /// reduce the number of fractional bits and increase the limit.) pubconst FONT_STRETCH_FRACTION_BITS: u16 = 6;
/// This is an alias which is useful mostly as a cbindgen / C++ inference /// workaround. pubtype FontStretchFixedPoint = FixedPoint<u16, FONT_STRETCH_FRACTION_BITS>;
/// A value for the font-stretch property per: /// /// https://drafts.csswg.org/css-fonts-4/#propdef-font-stretch /// /// cbindgen:derive-lt /// cbindgen:derive-lte /// cbindgen:derive-gt /// cbindgen:derive-gte #[derive(
Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd, ToResolvedValue,
)] #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] #[repr(C)] pubstruct FontStretch(pub FontStretchFixedPoint);
impl FontStretch { /// The fraction bits, as an easy-to-access-constant. pubconst FRACTION_BITS: u16 = FONT_STRETCH_FRACTION_BITS; /// 0.5 in our floating point representation. pubconst HALF: u16 = 1 << (Self::FRACTION_BITS - 1);
/// Converts to a computed percentage. #[inline] pubfn to_percentage(&self) -> Percentage {
Percentage(self.0.to_float() / 100.0)
}
/// Converts from a computed percentage value. pubfn from_percentage(p: f32) -> Self { Self(FixedPoint::from_float((p * 100.).max(0.0).min(1000.0)))
}
/// Returns a relevant stretch value from a keyword. /// https://drafts.csswg.org/css-fonts-4/#font-stretch-prop pubfn from_keyword(kw: specified::FontStretchKeyword) -> Self { use specified::FontStretchKeyword::*; match kw {
UltraCondensed => Self::ULTRA_CONDENSED,
ExtraCondensed => Self::EXTRA_CONDENSED,
Condensed => Self::CONDENSED,
SemiCondensed => Self::SEMI_CONDENSED,
Normal => Self::NORMAL,
SemiExpanded => Self::SEMI_EXPANDED,
Expanded => Self::EXPANDED,
ExtraExpanded => Self::EXTRA_EXPANDED,
UltraExpanded => Self::ULTRA_EXPANDED,
}
}
/// Returns the stretch keyword if we map to one of the relevant values. pubfn as_keyword(&self) -> Option<specified::FontStretchKeyword> { use specified::FontStretchKeyword::*; // TODO: Can we use match here? if *self == Self::ULTRA_CONDENSED { return Some(UltraCondensed);
} if *self == Self::EXTRA_CONDENSED { return Some(ExtraCondensed);
} if *self == Self::CONDENSED { return Some(Condensed);
} if *self == Self::SEMI_CONDENSED { return Some(SemiCondensed);
} if *self == Self::NORMAL { return Some(Normal);
} if *self == Self::SEMI_EXPANDED { return Some(SemiExpanded);
} if *self == Self::EXPANDED { return Some(Expanded);
} if *self == Self::EXTRA_EXPANDED { return Some(ExtraExpanded);
} if *self == Self::ULTRA_EXPANDED { return Some(UltraExpanded);
}
None
}
}
impl ToCss for FontStretch { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where
W: fmt::Write,
{ self.to_percentage().to_css(dest)
}
}
impl ToAnimatedValue for FontStretch { type AnimatedValue = Percentage;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.