/* 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/. */
usesuper::{AllowQuirks, Number, Percentage, ToComputedValue}; usecrate::computed_value_flags::ComputedValueFlags; usecrate::font_metrics::{FontMetrics, FontMetricsOrientation}; #[cfg(feature = "gecko")] usecrate::gecko_bindings::structs::GeckoFontMetrics; usecrate::parser::{Parse, ParserContext}; usecrate::values::computed::{self, CSSPixelLength, Context}; usecrate::values::generics::length as generics; usecrate::values::generics::length::{
GenericAnchorSizeFunction, GenericLengthOrNumber, GenericLengthPercentageOrNormal,
GenericMargin, GenericMaxSize, GenericSize,
}; usecrate::values::generics::NonNegative; usecrate::values::specified::calc::{self, AllowAnchorPositioningFunctions, CalcNode}; usecrate::values::specified::NonNegativeNumber; usecrate::values::CSSFloat; usecrate::{Zero, ZeroNoPercent}; use app_units::AU_PER_PX; use cssparser::{Parser, Token}; use std::cmp; use std::fmt::{self, Write}; use style_traits::values::specified::AllowedNumericType; use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss};
pubusesuper::image::Image; pubusesuper::image::{EndingShape as GradientEndingShape, Gradient}; pubusecrate::values::specified::calc::CalcLengthPercentage;
/// Number of pixels per inch pubconst PX_PER_IN: CSSFloat = 96.; /// Number of pixels per centimeter pubconst PX_PER_CM: CSSFloat = PX_PER_IN / 2.54; /// Number of pixels per millimeter pubconst PX_PER_MM: CSSFloat = PX_PER_IN / 25.4; /// Number of pixels per quarter pubconst PX_PER_Q: CSSFloat = PX_PER_MM / 4.; /// Number of pixels per point pubconst PX_PER_PT: CSSFloat = PX_PER_IN / 72.; /// Number of pixels per pica pubconst PX_PER_PC: CSSFloat = PX_PER_PT * 12.;
/// A source to resolve font-relative units against #[derive(Clone, Copy, Debug, PartialEq)] pubenum FontBaseSize { /// Use the font-size of the current element.
CurrentStyle, /// Use the inherited font-size.
InheritedStyle,
}
/// A source to resolve font-relative line-height units against. #[derive(Clone, Copy, Debug, PartialEq)] pubenum LineHeightBase { /// Use the line-height of the current element.
CurrentStyle, /// Use the inherited line-height.
InheritedStyle,
}
impl FontBaseSize { /// Calculate the actual size for a given context pubfn resolve(&self, context: &Context) -> computed::FontSize { let style = context.style(); match *self { Self::CurrentStyle => style.get_font().clone_font_size(), Self::InheritedStyle => { // If we're using the size from our inherited style, we still need to apply our // own zoom. let zoom = style.resolved_specified_zoom();
style.get_parent_font().clone_font_size().zoom(zoom)
},
}
}
}
impl FontRelativeLength { /// Unit identifier for `em`. pubconst EM: &'static str = "em"; /// Unit identifier for `ex`. pubconst EX: &'static str = "ex"; /// Unit identifier for `ch`. pubconst CH: &'static str = "ch"; /// Unit identifier for `cap`. pubconst CAP: &'static str = "cap"; /// Unit identifier for `ic`. pubconst IC: &'static str = "ic"; /// Unit identifier for `rem`. pubconst REM: &'static str = "rem"; /// Unit identifier for `lh`. pubconst LH: &'static str = "lh"; /// Unit identifier for `rlh`. pubconst RLH: &'static str = "rlh";
/// Computes the length, given a GeckoFontMetrics getter to resolve font-relative units. #[cfg(feature = "gecko")] pubfn to_computed_pixel_length_with_font_metrics(
&self,
get_font_metrics: implFn() -> GeckoFontMetrics,
) -> Result<CSSFloat, ()> { let metrics = get_font_metrics();
Ok(match *self { Self::Em(v) => v * metrics.mComputedEmSize.px(), Self::Ex(v) => v * metrics.mXSize.px(), Self::Ch(v) => v * metrics.mChSize.px(), Self::Cap(v) => v * metrics.mCapHeight.px(), Self::Ic(v) => v * metrics.mIcWidth.px(), // `lh`, `rlh` & `rem` are unsupported as we have no context for it. Self::Rem(_) | Self::Lh(_) | Self::Rlh(_) => return Err(()),
})
}
/// Return reference font size. /// /// We use the base_size flag to pass a different size for computing /// font-size and unconstrained font-size. /// /// This returns a pair, the first one is the reference font size, and the /// second one is the unpacked relative length. fn reference_font_size_and_length(
&self,
context: &Context,
base_size: FontBaseSize,
line_height_base: LineHeightBase,
) -> (computed::Length, CSSFloat) { fn query_font_metrics(
context: &Context,
base_size: FontBaseSize,
orientation: FontMetricsOrientation,
) -> FontMetrics { let retrieve_math_scales = false;
context.query_font_metrics(base_size, orientation, retrieve_math_scales)
}
let reference_font_size = base_size.resolve(context); match *self { Self::Em(length) => { if context.for_non_inherited_property && base_size == FontBaseSize::CurrentStyle {
context
.rule_cache_conditions
.borrow_mut()
.set_font_size_dependency(reference_font_size.computed_size);
}
(reference_font_size.computed_size(), length)
}, Self::Ex(length) => { // The x-height is an intrinsically horizontal metric. let metrics =
query_font_metrics(context, base_size, FontMetricsOrientation::Horizontal); let reference_size = metrics.x_height.unwrap_or_else(|| { // https://drafts.csswg.org/css-values/#ex // // In the cases where it is impossible or impractical to // determine the x-height, a value of 0.5em must be // assumed. // // (But note we use 0.5em of the used, not computed // font-size)
reference_font_size.used_size() * 0.5
});
(reference_size, length)
}, Self::Ch(length) => { // https://drafts.csswg.org/css-values/#ch: // // Equal to the used advance measure of the “0” (ZERO, // U+0030) glyph in the font used to render it. (The advance // measure of a glyph is its advance width or height, // whichever is in the inline axis of the element.) // let metrics = query_font_metrics(
context,
base_size,
FontMetricsOrientation::MatchContextPreferHorizontal,
); let reference_size = metrics.zero_advance_measure.unwrap_or_else(|| { // https://drafts.csswg.org/css-values/#ch // // In the cases where it is impossible or impractical to // determine the measure of the “0” glyph, it must be // assumed to be 0.5em wide by 1em tall. Thus, the ch // unit falls back to 0.5em in the general case, and to // 1em when it would be typeset upright (i.e. // writing-mode is vertical-rl or vertical-lr and // text-orientation is upright). // // Same caveat about computed vs. used font-size applies // above. let wm = context.style().writing_mode; if wm.is_vertical() && wm.is_upright() {
reference_font_size.used_size()
} else {
reference_font_size.used_size() * 0.5
}
});
(reference_size, length)
}, Self::Cap(length) => { let metrics =
query_font_metrics(context, base_size, FontMetricsOrientation::Horizontal); let reference_size = metrics.cap_height.unwrap_or_else(|| { // https://drafts.csswg.org/css-values/#cap // // In the cases where it is impossible or impractical to // determine the cap-height, the font’s ascent must be // used. //
metrics.ascent
});
(reference_size, length)
}, Self::Ic(length) => { let metrics = query_font_metrics(
context,
base_size,
FontMetricsOrientation::MatchContextPreferVertical,
); let reference_size = metrics.ic_width.unwrap_or_else(|| { // https://drafts.csswg.org/css-values/#ic // // In the cases where it is impossible or impractical to // determine the ideographic advance measure, it must be // assumed to be 1em. // // Same caveat about computed vs. used as for other // metric-dependent units.
reference_font_size.used_size()
});
(reference_size, length)
}, Self::Rem(length) => { // https://drafts.csswg.org/css-values/#rem: // // When specified on the font-size property of the root // element, the rem units refer to the property's initial // value. // let reference_size = if context.builder.is_root_element || context.in_media_query {
reference_font_size.computed_size()
} else {
context
.device()
.root_font_size()
.zoom(context.builder.effective_zoom)
};
(reference_size, length)
}, Self::Lh(length) => { // https://drafts.csswg.org/css-values-4/#lh // // When specified in media-query, the lh units refer to the // initial values of font and line-height properties. // let reference_size = if context.in_media_query {
context
.device()
.calc_line_height(
&context.default_style().get_font(),
context.style().writing_mode,
None,
)
.0
} else { let line_height = context.builder.calc_line_height(
context.device(),
line_height_base,
context.style().writing_mode,
); if context.for_non_inherited_property &&
line_height_base == LineHeightBase::CurrentStyle
{
context
.rule_cache_conditions
.borrow_mut()
.set_line_height_dependency(line_height)
}
line_height.0
};
(reference_size, length)
}, Self::Rlh(length) => { // https://drafts.csswg.org/css-values-4/#rlh // // When specified on the root element, the rlh units refer // to the initial values of font and line-height properties. // let reference_size = if context.builder.is_root_element || context.in_media_query {
context
.device()
.calc_line_height(
&context.default_style().get_font(),
context.style().writing_mode,
None,
)
.0
} else {
context.device().root_line_height()
}; let reference_size = reference_size.zoom(context.builder.effective_zoom);
(reference_size, length)
},
}
}
}
/// Computes the given viewport-relative length for the given viewport size. pubfn to_computed_value(&self, context: &Context) -> CSSPixelLength { let (variant, unit, factor) = self.unpack(); let size = context.viewport_size_for_viewport_unit_resolution(variant); let length: app_units::Au = match unit {
ViewportUnit::Vw => size.width,
ViewportUnit::Vh => size.height,
ViewportUnit::Vmin => cmp::min(size.width, size.height),
ViewportUnit::Vmax => cmp::max(size.width, size.height),
ViewportUnit::Vi | ViewportUnit::Vb => {
context
.rule_cache_conditions
.borrow_mut()
.set_writing_mode_dependency(context.builder.writing_mode); if (unit == ViewportUnit::Vb) == context.style().writing_mode.is_vertical() {
size.width
} else {
size.height
}
},
};
// NOTE: This is in app units! let length = context.builder.effective_zoom.zoom(length.0as f32);
// FIXME: Bug 1396535, we need to fix the extremely small viewport length for transform. // See bug 989802. We truncate so that adding multiple viewport units that add up to 100 // does not overflow due to rounding differences. We convert appUnits to CSS px manually // here to avoid premature clamping by going through the Au type. let trunc_scaled =
((length as f64 * factor as f64 / 100.).trunc() / AU_PER_PX as f64) as f32;
CSSPixelLength::new(crate::values::normalize(trunc_scaled))
}
}
/// HTML5 "character width", as defined in HTML5 § 14.5.4. #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)] #[repr(C)] pubstruct CharacterWidth(pub i32);
impl CharacterWidth { /// Computes the given character width. pubfn to_computed_value(&self, reference_font_size: computed::Length) -> computed::Length { // This applies the *converting a character width to pixels* algorithm // as specified in HTML5 § 14.5.4. // // TODO(pcwalton): Find these from the font. let average_advance = reference_font_size * 0.5; let max_advance = reference_font_size;
(average_advance * (self.0as CSSFloat - 1.0) + max_advance).finite()
}
}
/// Represents an absolute length with its unit #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)] #[repr(u8)] pubenum AbsoluteLength { /// An absolute length in pixels (px) #[css(dimension)]
Px(CSSFloat), /// An absolute length in inches (in) #[css(dimension)] In(CSSFloat), /// An absolute length in centimeters (cm) #[css(dimension)]
Cm(CSSFloat), /// An absolute length in millimeters (mm) #[css(dimension)]
Mm(CSSFloat), /// An absolute length in quarter-millimeters (q) #[css(dimension)]
Q(CSSFloat), /// An absolute length in points (pt) #[css(dimension)]
Pt(CSSFloat), /// An absolute length in pica (pc) #[css(dimension)]
Pc(CSSFloat),
}
/// A container query length. /// /// <https://drafts.csswg.org/css-contain-3/#container-lengths>
ContainerRelative(ContainerRelativeLength), /// HTML5 "character width", as defined in HTML5 § 14.5.4. /// /// This cannot be specified by the user directly and is only generated by /// `Stylist::synthesize_rules_for_legacy_attributes()`.
ServoCharacterWidth(CharacterWidth),
}
// Return the unit, as a string. fn unit(&self) -> &'static str { match *self { Self::Absolute(v) => v.unit(), Self::FontRelative(v) => v.unit(), Self::ViewportPercentage(v) => v.unit(), Self::ContainerRelative(v) => v.unit(), Self::ServoCharacterWidth(_) => "",
}
}
/// Returns whether the value of this length without unit is less than zero. pubfn is_negative(&self) -> bool { self.unitless_value().is_sign_negative()
}
/// Returns whether the value of this length without unit is equal to zero. pubfn is_zero(&self) -> bool { self.unitless_value() == 0.0
}
/// Returns whether the value of this length without unit is infinite. pubfn is_infinite(&self) -> bool { self.unitless_value().is_infinite()
}
/// Returns whether the value of this length without unit is NaN. pubfn is_nan(&self) -> bool { self.unitless_value().is_nan()
}
/// Whether text-only zoom should be applied to this length. /// /// Generally, font-dependent/relative units don't get text-only-zoomed, /// because the font they're relative to should be zoomed already. pubfn should_zoom_text(&self) -> bool { match *self { Self::Absolute(..) | Self::ViewportPercentage(..) | Self::ContainerRelative(..) => true, Self::ServoCharacterWidth(..) | Self::FontRelative(..) => false,
}
}
/// Get a px value without context (so only absolute units can be handled). #[inline] pubfn to_computed_pixel_length_without_context(&self) -> Result<CSSFloat, ()> { match *self { Self::Absolute(len) => Ok(CSSPixelLength::new(len.to_px()).finite().px()),
_ => Err(()),
}
}
/// Get a px value without a full style context; this can handle either /// absolute or (if a font metrics getter is provided) font-relative units. #[cfg(feature = "gecko")] #[inline] pubfn to_computed_pixel_length_with_font_metrics(
&self,
get_font_metrics: Option<implFn() -> GeckoFontMetrics>,
) -> Result<CSSFloat, ()> { match *self { Self::Absolute(len) => Ok(CSSPixelLength::new(len.to_px()).finite().px()), Self::FontRelative(fr) => { iflet Some(getter) = get_font_metrics {
fr.to_computed_pixel_length_with_font_metrics(getter)
} else {
Err(())
}
},
_ => Err(()),
}
}
/// Get an absolute length from a px value. #[inline] pubfn from_px(px_value: CSSFloat) -> NoCalcLength {
NoCalcLength::Absolute(AbsoluteLength::Px(px_value))
}
}
/// An extension to `NoCalcLength` to parse `calc` expressions. /// This is commonly used for the `<length>` values. /// /// <https://drafts.csswg.org/css-values/#lengths> #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] pubenum Length { /// The internal length type that cannot parse `calc`
NoCalc(NoCalcLength), /// A calc expression. /// /// <https://drafts.csswg.org/css-values/#calc-notation>
Calc(Box<CalcLengthPercentage>),
}
/// A `<length-percentage>` value. This can be either a `<length>`, a /// `<percentage>`, or a combination of both via `calc()`. /// /// https://drafts.csswg.org/css-values-4/#typedef-length-percentage #[allow(missing_docs)] #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] pubenum LengthPercentage {
Length(NoCalcLength),
Percentage(computed::Percentage),
Calc(Box<CalcLengthPercentage>),
}
impl From<Length> for LengthPercentage { fn from(len: Length) -> LengthPercentage { match len {
Length::NoCalc(l) => LengthPercentage::Length(l),
Length::Calc(l) => LengthPercentage::Calc(l),
}
}
}
/// Parses allowing the unitless length quirk, as well as allowing /// anchor-positioning related functions, `anchor()` and `anchor-size()`. #[inline] pubfn parse_quirky_with_anchor_functions<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> { Self::parse_internal(
context,
input,
AllowedNumericType::All,
allow_quirks,
AllowAnchorPositioningFunctions::AllowAnchorAndAnchorSize,
)
}
/// Parses non-negative length, allowing the unitless length quirk, /// as well as allowing `anchor-size()`. pubfn parse_non_negative_with_anchor_size<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> { Self::parse_internal(
context,
input,
AllowedNumericType::NonNegative,
allow_quirks,
AllowAnchorPositioningFunctions::AllowAnchorSize,
)
}
/// Parse a non-negative length. /// /// FIXME(emilio): This should be not public and we should use /// NonNegativeLengthPercentage instead. #[inline] pubfn parse_non_negative<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
}
/// Returns self as specified::calc::CalcNode. /// Note that this expect the clamping_mode is AllowedNumericType::All for Calc. The caller /// should take care about it when using this function. fn to_calc_node(self) -> (CalcNode, bool) { matchself {
LengthPercentage::Length(l) => (CalcNode::Leaf(calc::Leaf::Length(l)), false),
LengthPercentage::Percentage(p) => (CalcNode::Leaf(calc::Leaf::Percentage(p.0)), false),
LengthPercentage::Calc(p) => (p.node, p.has_anchor_function),
}
}
/// Construct the value representing `calc(100% - self)`. pubfn hundred_percent_minus(self, clamping_mode: AllowedNumericType) -> Self { letmut sum = smallvec::SmallVec::<[CalcNode; 2]>::new();
sum.push(CalcNode::Leaf(calc::Leaf::Percentage(1.0)));
let (mut node, has_anchor_function) = self.to_calc_node();
node.negate();
sum.push(node);
/// A wrapper of LengthPercentageOrAuto, whose value must be >= 0. pubtype NonNegativeLengthPercentageOrAuto =
generics::LengthPercentageOrAuto<NonNegativeLengthPercentage>;
impl NonNegativeLengthPercentageOrAuto { /// Returns a value representing `0%`. #[inline] pubfn zero_percent() -> Self {
generics::LengthPercentageOrAuto::LengthPercentage(
NonNegativeLengthPercentage::zero_percent(),
)
}
/// A wrapper of LengthPercentage, whose value must be >= 0. pubtype NonNegativeLengthPercentage = NonNegative<LengthPercentage>;
/// Either a NonNegativeLengthPercentage or the `normal` keyword. pubtype NonNegativeLengthPercentageOrNormal =
GenericLengthPercentageOrNormal<NonNegativeLengthPercentage>;
/// Parses a length or a percentage, allowing the unitless length quirk. /// <https://quirks.spec.whatwg.org/#the-unitless-length-quirk> #[inline] pubfn parse_quirky<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> {
LengthPercentage::parse_non_negative_quirky(context, input, allow_quirks).map(NonNegative)
}
/// Parses a length or a percentage, allowing the unitless length quirk, /// as well as allowing `anchor-size()`. #[inline] pubfn parse_non_negative_with_anchor_size<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
allow_quirks: AllowQuirks,
) -> Result<Self, ParseError<'i>> {
LengthPercentage::parse_non_negative_with_anchor_size(context, input, allow_quirks).map(NonNegative)
}
}
/// Either a `<length>` or the `auto` keyword. /// /// Note that we use LengthPercentage just for convenience, since it pretty much /// is everything we care about, but we could just add a similar LengthOrAuto /// instead if we think getting rid of this weirdness is worth it. pubtype LengthOrAuto = generics::LengthPercentageOrAuto<Length>;
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.