style: Expose line-height resolution to style, and use it from ToResolvedValue

For ToResolvedValue implementation purposes we wouldn't need to split
out the vertical / font / line-height arguments and we could just pass
around the ComputedStyle, but the lh unit would need that distinction,
(because computing lh on font properties should use the parent style).

Differential Revision: https://phabricator.services.mozilla.com/D168705
This commit is contained in:
Emilio Cobos Álvarez 2023-02-14 22:36:31 +00:00 committed by Martin Robinson
parent aa810f77ec
commit 8997888c6f
4 changed files with 62 additions and 28 deletions

View file

@ -14,7 +14,7 @@ use crate::media_queries::MediaType;
use crate::properties::ComputedValues; use crate::properties::ComputedValues;
use crate::string_cache::Atom; use crate::string_cache::Atom;
use crate::values::computed::font::GenericFontFamily; use crate::values::computed::font::GenericFontFamily;
use crate::values::computed::{ColorScheme, Length}; use crate::values::computed::{ColorScheme, Length, NonNegativeLength};
use crate::values::specified::color::SystemColor; use crate::values::specified::color::SystemColor;
use crate::values::specified::font::FONT_MEDIUM_PX; use crate::values::specified::font::FONT_MEDIUM_PX;
use crate::values::specified::ViewportVariant; use crate::values::specified::ViewportVariant;
@ -115,6 +115,30 @@ impl Device {
&self.environment &self.environment
} }
/// Returns the computed line-height for the font in a given computed values instance.
///
/// If you pass down an element, then the used line-height is returned.
pub fn calc_line_height(
&self,
line_height: &crate::values::computed::LineHeight,
vertical: bool,
font: &crate::properties::style_structs::Font,
element: Option<super::wrapper::GeckoElement>,
) -> NonNegativeLength {
let pres_context = self.pres_context();
let au = Au(unsafe {
bindings::Gecko_CalcLineHeight(
line_height,
pres_context.map_or(std::ptr::null(), |pc| pc),
vertical,
font.gecko(),
element.map_or(std::ptr::null(), |e| e.0)
)
});
NonNegativeLength::new(au.to_f32_px())
}
/// Tells the device that a new viewport rule has been found, and stores the /// Tells the device that a new viewport rule has been found, and stores the
/// relevant viewport constraints. /// relevant viewport constraints.
pub fn account_for_viewport_rule(&mut self, _constraints: &ViewportConstraints) { pub fn account_for_viewport_rule(&mut self, _constraints: &ViewportConstraints) {

View file

@ -3145,24 +3145,18 @@ impl ComputedValues {
} }
% endfor % endfor
/// Writes the value of the given longhand as a string in `dest`. /// Writes the (resolved or computed) value of the given longhand as a string in `dest`.
///
/// Note that the value will usually be the computed value, except for
/// colors, where it's resolved.
/// ///
/// TODO(emilio): We should move all the special resolution from /// TODO(emilio): We should move all the special resolution from
/// nsComputedDOMStyle to ToResolvedValue instead. /// nsComputedDOMStyle to ToResolvedValue instead.
pub fn get_resolved_value( pub fn computed_or_resolved_value(
&self, &self,
property_id: LonghandId, property_id: LonghandId,
context: Option<<&resolved::Context>,
dest: &mut CssStringWriter, dest: &mut CssStringWriter,
) -> fmt::Result { ) -> fmt::Result {
use crate::values::resolved::ToResolvedValue; use crate::values::resolved::ToResolvedValue;
let mut dest = CssWriter::new(dest); let mut dest = CssWriter::new(dest);
let context = resolved::Context {
style: self,
};
match property_id { match property_id {
% for specified_type, props in groupby(data.longhands, key=lambda x: x.specified_type()): % for specified_type, props in groupby(data.longhands, key=lambda x: x.specified_type()):
<% props = list(props) %> <% props = list(props) %>
@ -3173,34 +3167,39 @@ impl ComputedValues {
% endfor % endfor
_ => unsafe { debug_unreachable!() }, _ => unsafe { debug_unreachable!() },
}; };
value.to_resolved_value(&context).to_css(&mut dest) if let Some(c) = context {
value.to_resolved_value(c).to_css(&mut dest)
} else {
value.to_css(&mut dest)
}
} }
% endfor % endfor
} }
} }
/// Returns the given longhand's resolved value as a property declaration. /// Returns the given longhand's resolved value as a property declaration.
pub fn resolved_declaration(&self, property_id: LonghandId) -> PropertyDeclaration { pub fn computed_or_resolved_declaration(
&self,
property_id: LonghandId,
context: Option<<&resolved::Context>,
) -> PropertyDeclaration {
use crate::values::resolved::ToResolvedValue; use crate::values::resolved::ToResolvedValue;
use crate::values::computed::ToComputedValue; use crate::values::computed::ToComputedValue;
let context = resolved::Context {
style: self,
};
match property_id { match property_id {
% for specified_type, props in groupby(data.longhands, key=lambda x: x.specified_type()): % for specified_type, props in groupby(data.longhands, key=lambda x: x.specified_type()):
<% props = list(props) %> <% props = list(props) %>
${" |\n".join("LonghandId::{}".format(p.camel_case) for p in props)} => { ${" |\n".join("LonghandId::{}".format(p.camel_case) for p in props)} => {
let value = match property_id { let mut computed_value = match property_id {
% for prop in props: % for prop in props:
LonghandId::${prop.camel_case} => self.clone_${prop.ident}(), LonghandId::${prop.camel_case} => self.clone_${prop.ident}(),
% endfor % endfor
_ => unsafe { debug_unreachable!() }, _ => unsafe { debug_unreachable!() },
}; };
let resolved = value.to_resolved_value(&context); if let Some(c) = context {
let computed = ToResolvedValue::from_resolved_value(resolved); let resolved = computed_value.to_resolved_value(c);
let specified = ToComputedValue::from_computed_value(&computed); computed_value = ToResolvedValue::from_resolved_value(resolved);
}
let specified = ToComputedValue::from_computed_value(&computed_value);
% if props[0].boxed: % if props[0].boxed:
let specified = Box::new(specified); let specified = Box::new(specified);
% endif % endif

View file

@ -119,12 +119,12 @@ impl ToResolvedValue for LineHeight {
fn to_resolved_value(self, context: &ResolvedContext) -> Self::ResolvedValue { fn to_resolved_value(self, context: &ResolvedContext) -> Self::ResolvedValue {
// Resolve <number> to an absolute <length> based on font size. // Resolve <number> to an absolute <length> based on font size.
if let LineHeight::Number(num) = &self { if matches!(self, Self::Normal | Self::MozBlockHeight) {
let size = context.style.get_font().clone_font_size().computed_size(); return self;
LineHeight::Length(NonNegativeLength::new(size.px() * num.0))
} else {
self
} }
let wm = context.style.writing_mode;
let vertical = wm.is_vertical() && !wm.is_sideways();
Self::Length(context.device.calc_line_height(&self, vertical, context.style.get_font(), Some(context.element_info.element)))
} }
#[inline] #[inline]

View file

@ -5,6 +5,7 @@
//! Resolved values. These are almost always computed values, but in some cases //! Resolved values. These are almost always computed values, but in some cases
//! there are used values. //! there are used values.
use crate::media_queries::Device;
use crate::properties::ComputedValues; use crate::properties::ComputedValues;
use crate::ArcSlice; use crate::ArcSlice;
use cssparser; use cssparser;
@ -16,12 +17,22 @@ mod counters;
use crate::values::computed; use crate::values::computed;
/// Element-specific information needed to resolve property values.
pub struct ResolvedElementInfo<'a> {
/// Element we're resolving line-height against.
#[cfg(feature = "gecko")]
pub element: crate::gecko::wrapper::GeckoElement<'a>,
}
/// Information needed to resolve a given value. /// Information needed to resolve a given value.
pub struct Context<'a> { pub struct Context<'a> {
/// The style we're resolving for. This is useful to resolve currentColor. /// The style we're resolving for. This is useful to resolve currentColor.
pub style: &'a ComputedValues, pub style: &'a ComputedValues,
// TODO(emilio): Add layout box information, and maybe property-specific /// The device / document we're resolving style for. Useful to do font metrics stuff needed for
// information? /// line-height.
pub device: &'a Device,
/// The element-specific information to resolve the value.
pub element_info: ResolvedElementInfo<'a>,
} }
/// A trait to represent the conversion between resolved and resolved values. /// A trait to represent the conversion between resolved and resolved values.