mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
style: Refactor and add infrastructure for font metrics in style.
This commit itself only moves things around and adds an extra parameter to the `apply_declarations` function to eventually handle #14079 correctly. Probably needs a more granular API to query fonts, á la nsFontMetrics, but that's trivial to do once this is landed. Then we should make the font provider mandatory, and implement the missing stylo bits.
This commit is contained in:
parent
9fd6f0acd5
commit
6c3458767b
15 changed files with 196 additions and 94 deletions
|
@ -403,6 +403,7 @@ fn compute_style_for_animation_step(context: &SharedStyleContext,
|
||||||
previous_style,
|
previous_style,
|
||||||
/* cascade_info = */ None,
|
/* cascade_info = */ None,
|
||||||
context.error_reporter.clone(),
|
context.error_reporter.clone(),
|
||||||
|
/* Metrics provider */ None,
|
||||||
CascadeFlags::empty());
|
CascadeFlags::empty());
|
||||||
computed
|
computed
|
||||||
}
|
}
|
||||||
|
|
35
components/style/font_metrics.rs
Normal file
35
components/style/font_metrics.rs
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use Atom;
|
||||||
|
use app_units::Au;
|
||||||
|
use euclid::Size2D;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
/// Represents the font metrics that style needs from a font to compute the
|
||||||
|
/// value of certain CSS units like `ex`.
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub struct FontMetrics {
|
||||||
|
pub x_height: Au,
|
||||||
|
pub zero_advance_measure: Size2D<Au>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub enum FontMetricsQueryResult {
|
||||||
|
Available(Option<FontMetrics>),
|
||||||
|
NotAvailable,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait used to represent something capable of providing us font metrics.
|
||||||
|
pub trait FontMetricsProvider: Send + Sync + fmt::Debug {
|
||||||
|
/// Obtain the metrics for given font family.
|
||||||
|
///
|
||||||
|
/// TODO: We could make this take the full list, I guess, and save a few
|
||||||
|
/// virtual calls.
|
||||||
|
///
|
||||||
|
/// This is not too common in practice though.
|
||||||
|
fn query(&self, _font_name: &Atom) -> FontMetricsQueryResult {
|
||||||
|
FontMetricsQueryResult::NotAvailable
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,7 +38,7 @@ impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
|
||||||
fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
|
fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
|
||||||
let has_percentage = other.percentage.is_some();
|
let has_percentage = other.percentage.is_some();
|
||||||
nsStyleCoord_CalcValue {
|
nsStyleCoord_CalcValue {
|
||||||
mLength: other.length.map_or(0, |l| l.0),
|
mLength: other.length.0,
|
||||||
mPercent: other.percentage.unwrap_or(0.0),
|
mPercent: other.percentage.unwrap_or(0.0),
|
||||||
mHasPercent: has_percentage,
|
mHasPercent: has_percentage,
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ impl From<nsStyleCoord_CalcValue> for CalcLengthOrPercentage {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
CalcLengthOrPercentage {
|
CalcLengthOrPercentage {
|
||||||
length: Some(Au(other.mLength)),
|
length: Au(other.mLength),
|
||||||
percentage: percentage,
|
percentage: percentage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,7 @@ pub mod dom;
|
||||||
pub mod element_state;
|
pub mod element_state;
|
||||||
pub mod error_reporting;
|
pub mod error_reporting;
|
||||||
pub mod font_face;
|
pub mod font_face;
|
||||||
|
pub mod font_metrics;
|
||||||
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko;
|
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko;
|
||||||
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko_bindings;
|
#[cfg(feature = "gecko")] #[allow(unsafe_code)] pub mod gecko_bindings;
|
||||||
pub mod keyframes;
|
pub mod keyframes;
|
||||||
|
|
|
@ -10,10 +10,10 @@ use Atom;
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use cssparser::{Delimiter, Parser, Token};
|
use cssparser::{Delimiter, Parser, Token};
|
||||||
use euclid::size::{Size2D, TypedSize2D};
|
use euclid::size::{Size2D, TypedSize2D};
|
||||||
use properties::longhands;
|
|
||||||
use serialize_comma_separated_list;
|
use serialize_comma_separated_list;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use style_traits::{ToCss, ViewportPx};
|
use style_traits::{ToCss, ViewportPx};
|
||||||
|
use values::computed::{self, ToComputedValue};
|
||||||
use values::specified;
|
use values::specified;
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,28 +49,11 @@ impl Range<specified::Length> {
|
||||||
fn to_computed_range(&self, viewport_size: Size2D<Au>) -> Range<Au> {
|
fn to_computed_range(&self, viewport_size: Size2D<Au>) -> Range<Au> {
|
||||||
// http://dev.w3.org/csswg/mediaqueries3/#units
|
// http://dev.w3.org/csswg/mediaqueries3/#units
|
||||||
// em units are relative to the initial font-size.
|
// em units are relative to the initial font-size.
|
||||||
let initial_font_size = longhands::font_size::get_initial_value();
|
let context = computed::Context::initial(viewport_size, false);
|
||||||
let compute_width = |&width| {
|
|
||||||
match width {
|
|
||||||
specified::Length::Absolute(value) => value,
|
|
||||||
specified::Length::FontRelative(value)
|
|
||||||
=> value.to_computed_value(initial_font_size, initial_font_size),
|
|
||||||
specified::Length::ViewportPercentage(value)
|
|
||||||
=> value.to_computed_value(viewport_size),
|
|
||||||
specified::Length::Calc(val, range)
|
|
||||||
=> range.clamp(
|
|
||||||
val.compute_from_viewport_and_font_size(viewport_size,
|
|
||||||
initial_font_size,
|
|
||||||
initial_font_size)
|
|
||||||
.length()),
|
|
||||||
specified::Length::ServoCharacterWidth(..)
|
|
||||||
=> unreachable!(),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Range::Min(ref width) => Range::Min(compute_width(width)),
|
Range::Min(ref width) => Range::Min(width.to_computed_value(&context)),
|
||||||
Range::Max(ref width) => Range::Max(compute_width(width)),
|
Range::Max(ref width) => Range::Max(width.to_computed_value(&context)),
|
||||||
//Range::Eq(ref width) => Range::Eq(compute_width(width))
|
//Range::Eq(ref width) => Range::Eq(compute_width(width))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -916,6 +916,14 @@ fn static_assert() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn font_family_count(&self) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn font_family_at(&self, _: usize) -> longhands::font_family::computed_value::FontFamily {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn copy_font_family_from(&mut self, other: &Self) {
|
pub fn copy_font_family_from(&mut self, other: &Self) {
|
||||||
unsafe { Gecko_CopyFontFamilyFrom(&mut self.gecko.mFont, &other.gecko.mFont); }
|
unsafe { Gecko_CopyFontFamilyFrom(&mut self.gecko.mFont, &other.gecko.mFont); }
|
||||||
}
|
}
|
||||||
|
|
|
@ -418,7 +418,7 @@ impl Interpolate for CalcLengthOrPercentage {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(CalcLengthOrPercentage {
|
Ok(CalcLengthOrPercentage {
|
||||||
length: try!(interpolate_half(self.length, other.length, progress)),
|
length: try!(self.length.interpolate(&other.length, progress)),
|
||||||
percentage: try!(interpolate_half(self.percentage, other.percentage, progress)),
|
percentage: try!(interpolate_half(self.percentage, other.percentage, progress)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<% data.new_style_struct("Font",
|
<% data.new_style_struct("Font",
|
||||||
inherited=True,
|
inherited=True,
|
||||||
additional_methods=[Method("compute_font_hash", is_mut=True)]) %>
|
additional_methods=[Method("compute_font_hash", is_mut=True)]) %>
|
||||||
<%helpers:longhand name="font-family" animatable="False">
|
<%helpers:longhand name="font-family" animatable="False" need_index="True">
|
||||||
use self::computed_value::FontFamily;
|
use self::computed_value::FontFamily;
|
||||||
use values::NoViewportPercentage;
|
use values::NoViewportPercentage;
|
||||||
use values::computed::ComputedValueAsSpecified;
|
use values::computed::ComputedValueAsSpecified;
|
||||||
|
@ -21,6 +21,7 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use Atom;
|
use Atom;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
pub use self::FontFamily as SingleComputedValue;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf, Deserialize, Serialize))]
|
||||||
|
@ -28,8 +29,8 @@
|
||||||
FamilyName(Atom),
|
FamilyName(Atom),
|
||||||
Generic(Atom),
|
Generic(Atom),
|
||||||
}
|
}
|
||||||
impl FontFamily {
|
|
||||||
|
|
||||||
|
impl FontFamily {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn atom(&self) -> &Atom {
|
pub fn atom(&self) -> &Atom {
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -67,11 +68,13 @@
|
||||||
FontFamily::FamilyName(input)
|
FontFamily::FamilyName(input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for FontFamily {
|
impl ToCss for FontFamily {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
self.atom().with_str(|s| dest.write_str(s))
|
self.atom().with_str(|s| dest.write_str(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for T {
|
impl ToCss for T {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
let mut iter = self.0.iter();
|
let mut iter = self.0.iter();
|
||||||
|
@ -83,6 +86,7 @@
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub struct T(pub Vec<FontFamily>);
|
pub struct T(pub Vec<FontFamily>);
|
||||||
|
@ -307,8 +311,7 @@ ${helpers.single_keyword("font-variant",
|
||||||
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
LengthOrPercentage::Length(Length::FontRelative(value)) => {
|
LengthOrPercentage::Length(Length::FontRelative(value)) => {
|
||||||
value.to_computed_value(context.inherited_style().get_font().clone_font_size(),
|
value.to_computed_value(context, /* use inherited */ true)
|
||||||
context.style().root_font_size())
|
|
||||||
}
|
}
|
||||||
LengthOrPercentage::Length(Length::ServoCharacterWidth(value)) => {
|
LengthOrPercentage::Length(Length::ServoCharacterWidth(value)) => {
|
||||||
value.to_computed_value(context.inherited_style().get_font().clone_font_size())
|
value.to_computed_value(context.inherited_style().get_font().clone_font_size())
|
||||||
|
|
|
@ -25,6 +25,7 @@ use url::Url;
|
||||||
#[cfg(feature = "servo")] use euclid::side_offsets::SideOffsets2D;
|
#[cfg(feature = "servo")] use euclid::side_offsets::SideOffsets2D;
|
||||||
use euclid::size::Size2D;
|
use euclid::size::Size2D;
|
||||||
use computed_values;
|
use computed_values;
|
||||||
|
use font_metrics::FontMetricsProvider;
|
||||||
#[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
|
#[cfg(feature = "servo")] use logical_geometry::{LogicalMargin, PhysicalSide};
|
||||||
use logical_geometry::WritingMode;
|
use logical_geometry::WritingMode;
|
||||||
use parser::{Parse, ParserContext, ParserContextExtraData};
|
use parser::{Parse, ParserContext, ParserContextExtraData};
|
||||||
|
@ -1464,6 +1465,7 @@ pub fn cascade(viewport_size: Size2D<Au>,
|
||||||
inherited_style,
|
inherited_style,
|
||||||
cascade_info,
|
cascade_info,
|
||||||
error_reporter,
|
error_reporter,
|
||||||
|
None,
|
||||||
flags)
|
flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1475,6 +1477,7 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
|
||||||
inherited_style: &ComputedValues,
|
inherited_style: &ComputedValues,
|
||||||
mut cascade_info: Option<<&mut CascadeInfo>,
|
mut cascade_info: Option<<&mut CascadeInfo>,
|
||||||
mut error_reporter: StdBox<ParseErrorReporter + Send>,
|
mut error_reporter: StdBox<ParseErrorReporter + Send>,
|
||||||
|
font_metrics_provider: Option<<&FontMetricsProvider>,
|
||||||
flags: CascadeFlags)
|
flags: CascadeFlags)
|
||||||
-> ComputedValues
|
-> ComputedValues
|
||||||
where F: Fn() -> I, I: Iterator<Item = &'a PropertyDeclaration>
|
where F: Fn() -> I, I: Iterator<Item = &'a PropertyDeclaration>
|
||||||
|
@ -1528,6 +1531,7 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
|
||||||
viewport_size: viewport_size,
|
viewport_size: viewport_size,
|
||||||
inherited_style: inherited_style,
|
inherited_style: inherited_style,
|
||||||
style: starting_style,
|
style: starting_style,
|
||||||
|
font_metrics_provider: font_metrics_provider,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set computed values, overwriting earlier declarations for the same
|
// Set computed values, overwriting earlier declarations for the same
|
||||||
|
@ -1562,6 +1566,7 @@ pub fn apply_declarations<'a, F, I>(viewport_size: Size2D<Au>,
|
||||||
// classification is correct.
|
// classification is correct.
|
||||||
let is_early_property = matches!(*declaration,
|
let is_early_property = matches!(*declaration,
|
||||||
PropertyDeclaration::FontSize(_) |
|
PropertyDeclaration::FontSize(_) |
|
||||||
|
PropertyDeclaration::FontFamily(_) |
|
||||||
PropertyDeclaration::Color(_) |
|
PropertyDeclaration::Color(_) |
|
||||||
PropertyDeclaration::Position(_) |
|
PropertyDeclaration::Position(_) |
|
||||||
PropertyDeclaration::Float(_) |
|
PropertyDeclaration::Float(_) |
|
||||||
|
|
|
@ -17,14 +17,14 @@ pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
|
||||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub struct CalcLengthOrPercentage {
|
pub struct CalcLengthOrPercentage {
|
||||||
pub length: Option<Au>,
|
pub length: Au,
|
||||||
pub percentage: Option<CSSFloat>,
|
pub percentage: Option<CSSFloat>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CalcLengthOrPercentage {
|
impl CalcLengthOrPercentage {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn length(&self) -> Au {
|
pub fn length(&self) -> Au {
|
||||||
self.length.unwrap_or(Au(0))
|
self.length
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -38,13 +38,13 @@ impl From<LengthOrPercentage> for CalcLengthOrPercentage {
|
||||||
match len {
|
match len {
|
||||||
LengthOrPercentage::Percentage(this) => {
|
LengthOrPercentage::Percentage(this) => {
|
||||||
CalcLengthOrPercentage {
|
CalcLengthOrPercentage {
|
||||||
length: None,
|
length: Au(0),
|
||||||
percentage: Some(this),
|
percentage: Some(this),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LengthOrPercentage::Length(this) => {
|
LengthOrPercentage::Length(this) => {
|
||||||
CalcLengthOrPercentage {
|
CalcLengthOrPercentage {
|
||||||
length: Some(this),
|
length: this,
|
||||||
percentage: None,
|
percentage: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,13 +60,13 @@ impl From<LengthOrPercentageOrAuto> for Option<CalcLengthOrPercentage> {
|
||||||
match len {
|
match len {
|
||||||
LengthOrPercentageOrAuto::Percentage(this) => {
|
LengthOrPercentageOrAuto::Percentage(this) => {
|
||||||
Some(CalcLengthOrPercentage {
|
Some(CalcLengthOrPercentage {
|
||||||
length: None,
|
length: Au(0),
|
||||||
percentage: Some(this),
|
percentage: Some(this),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
LengthOrPercentageOrAuto::Length(this) => {
|
LengthOrPercentageOrAuto::Length(this) => {
|
||||||
Some(CalcLengthOrPercentage {
|
Some(CalcLengthOrPercentage {
|
||||||
length: Some(this),
|
length: this,
|
||||||
percentage: None,
|
percentage: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -83,10 +83,9 @@ impl From<LengthOrPercentageOrAuto> for Option<CalcLengthOrPercentage> {
|
||||||
impl ToCss for CalcLengthOrPercentage {
|
impl ToCss for CalcLengthOrPercentage {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
match (self.length, self.percentage) {
|
match (self.length, self.percentage) {
|
||||||
(None, Some(p)) => write!(dest, "{}%", p * 100.),
|
(l, Some(p)) if l == Au(0) => write!(dest, "{}%", p * 100.),
|
||||||
(Some(l), None) => write!(dest, "{}px", Au::to_px(l)),
|
(l, Some(p)) => write!(dest, "calc({}px + {}%)", Au::to_px(l), p * 100.),
|
||||||
(Some(l), Some(p)) => write!(dest, "calc({}px + {}%)", Au::to_px(l), p * 100.),
|
(l, None) => write!(dest, "{}px", Au::to_px(l)),
|
||||||
_ => unreachable!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,16 +94,34 @@ impl ToComputedValue for specified::CalcLengthOrPercentage {
|
||||||
type ComputedValue = CalcLengthOrPercentage;
|
type ComputedValue = CalcLengthOrPercentage;
|
||||||
|
|
||||||
fn to_computed_value(&self, context: &Context) -> CalcLengthOrPercentage {
|
fn to_computed_value(&self, context: &Context) -> CalcLengthOrPercentage {
|
||||||
self.compute_from_viewport_and_font_size(context.viewport_size(),
|
let mut length = Au(0);
|
||||||
context.style().get_font().clone_font_size(),
|
|
||||||
context.style().root_font_size())
|
|
||||||
|
|
||||||
|
if let Some(absolute) = self.absolute {
|
||||||
|
length += absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
for val in &[self.vw, self.vh, self.vmin, self.vmax] {
|
||||||
|
if let Some(val) = *val {
|
||||||
|
length += val.to_computed_value(context.viewport_size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for val in &[self.ch, self.em, self.ex, self.rem] {
|
||||||
|
if let Some(val) = *val {
|
||||||
|
length += val.to_computed_value(context, /* use inherited */ false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CalcLengthOrPercentage {
|
||||||
|
length: length,
|
||||||
|
percentage: self.percentage.map(|p| p.0),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_computed_value(computed: &CalcLengthOrPercentage) -> Self {
|
fn from_computed_value(computed: &CalcLengthOrPercentage) -> Self {
|
||||||
specified::CalcLengthOrPercentage {
|
specified::CalcLengthOrPercentage {
|
||||||
absolute: computed.length,
|
absolute: Some(computed.length),
|
||||||
percentage: computed.percentage.map(specified::Percentage),
|
percentage: computed.percentage.map(specified::Percentage),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use euclid::size::Size2D;
|
use euclid::size::Size2D;
|
||||||
|
use font_metrics::FontMetricsProvider;
|
||||||
use properties::ComputedValues;
|
use properties::ComputedValues;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
@ -28,9 +29,11 @@ pub struct Context<'a> {
|
||||||
pub viewport_size: Size2D<Au>,
|
pub viewport_size: Size2D<Au>,
|
||||||
pub inherited_style: &'a ComputedValues,
|
pub inherited_style: &'a ComputedValues,
|
||||||
|
|
||||||
/// Values access through this need to be in the properties "computed early":
|
/// Values access through this need to be in the properties "computed
|
||||||
/// color, text-decoration, font-size, display, position, float, border-*-style, outline-style
|
/// early": color, text-decoration, font-size, display, position, float,
|
||||||
|
/// border-*-style, outline-style, font-family, writing-mode...
|
||||||
pub style: ComputedValues,
|
pub style: ComputedValues,
|
||||||
|
pub font_metrics_provider: Option<&'a FontMetricsProvider>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Context<'a> {
|
impl<'a> Context<'a> {
|
||||||
|
@ -39,6 +42,20 @@ impl<'a> Context<'a> {
|
||||||
pub fn inherited_style(&self) -> &ComputedValues { &self.inherited_style }
|
pub fn inherited_style(&self) -> &ComputedValues { &self.inherited_style }
|
||||||
pub fn style(&self) -> &ComputedValues { &self.style }
|
pub fn style(&self) -> &ComputedValues { &self.style }
|
||||||
pub fn mutate_style(&mut self) -> &mut ComputedValues { &mut self.style }
|
pub fn mutate_style(&mut self) -> &mut ComputedValues { &mut self.style }
|
||||||
|
|
||||||
|
/// Creates a dummy computed context for use in multiple places, like
|
||||||
|
/// evaluating media queries.
|
||||||
|
pub fn initial(viewport_size: Size2D<Au>, is_root_element: bool) -> Self {
|
||||||
|
let initial_style = ComputedValues::initial_values();
|
||||||
|
// FIXME: Enforce a font metrics provider.
|
||||||
|
Context {
|
||||||
|
is_root_element: is_root_element,
|
||||||
|
viewport_size: viewport_size,
|
||||||
|
inherited_style: initial_style,
|
||||||
|
style: initial_style.clone(),
|
||||||
|
font_metrics_provider: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToComputedValue {
|
pub trait ToComputedValue {
|
||||||
|
@ -99,8 +116,7 @@ impl ToComputedValue for specified::Length {
|
||||||
specified::Length::Absolute(length) => length,
|
specified::Length::Absolute(length) => length,
|
||||||
specified::Length::Calc(calc, range) => range.clamp(calc.to_computed_value(context).length()),
|
specified::Length::Calc(calc, range) => range.clamp(calc.to_computed_value(context).length()),
|
||||||
specified::Length::FontRelative(length) =>
|
specified::Length::FontRelative(length) =>
|
||||||
length.to_computed_value(context.style().get_font().clone_font_size(),
|
length.to_computed_value(context, /* use inherited */ false),
|
||||||
context.style().root_font_size()),
|
|
||||||
specified::Length::ViewportPercentage(length) =>
|
specified::Length::ViewportPercentage(length) =>
|
||||||
length.to_computed_value(context.viewport_size()),
|
length.to_computed_value(context.viewport_size()),
|
||||||
specified::Length::ServoCharacterWidth(length) =>
|
specified::Length::ServoCharacterWidth(length) =>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use cssparser::{Parser, Token};
|
use cssparser::{Parser, Token};
|
||||||
use euclid::size::Size2D;
|
use euclid::size::Size2D;
|
||||||
|
use font_metrics::FontMetrics;
|
||||||
use parser::Parse;
|
use parser::Parse;
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
@ -13,7 +14,8 @@ use std::ops::Mul;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use style_traits::values::specified::AllowedNumericType;
|
use style_traits::values::specified::AllowedNumericType;
|
||||||
use super::{Angle, Number, SimplifiedValueNode, SimplifiedSumNode, Time};
|
use super::{Angle, Number, SimplifiedValueNode, SimplifiedSumNode, Time};
|
||||||
use values::{CSSFloat, Either, FONT_MEDIUM_PX, HasViewportPercentage, None_, computed};
|
use values::{CSSFloat, Either, FONT_MEDIUM_PX, HasViewportPercentage, None_};
|
||||||
|
use values::computed::Context;
|
||||||
|
|
||||||
pub use super::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient};
|
pub use super::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient};
|
||||||
pub use super::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, LengthOrPercentageOrKeyword};
|
pub use super::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, LengthOrPercentageOrKeyword};
|
||||||
|
@ -40,18 +42,78 @@ impl ToCss for FontRelativeLength {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontRelativeLength {
|
impl FontRelativeLength {
|
||||||
pub fn to_computed_value(&self,
|
pub fn find_first_available_font_metrics(context: &Context) -> Option<FontMetrics> {
|
||||||
reference_font_size: Au,
|
use font_metrics::FontMetricsQueryResult::*;
|
||||||
root_font_size: Au)
|
if let Some(ref metrics_provider) = context.font_metrics_provider {
|
||||||
-> Au
|
for family in context.style().get_font().font_family_iter() {
|
||||||
{
|
if let Available(metrics) = metrics_provider.query(family.atom()) {
|
||||||
|
return metrics;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// NB: The use_inherited flag is used to special-case the computation of
|
||||||
|
// font-family.
|
||||||
|
pub fn to_computed_value(&self, context: &Context, use_inherited: bool) -> Au {
|
||||||
|
let reference_font_size = if use_inherited {
|
||||||
|
context.inherited_style().get_font().clone_font_size()
|
||||||
|
} else {
|
||||||
|
context.style().get_font().clone_font_size()
|
||||||
|
};
|
||||||
|
|
||||||
|
let root_font_size = context.style().root_font_size;
|
||||||
match *self {
|
match *self {
|
||||||
FontRelativeLength::Em(length) => reference_font_size.scale_by(length),
|
FontRelativeLength::Em(length) => reference_font_size.scale_by(length),
|
||||||
FontRelativeLength::Ex(length) | FontRelativeLength::Ch(length) => {
|
FontRelativeLength::Ex(length) => {
|
||||||
// https://github.com/servo/servo/issues/7462
|
match Self::find_first_available_font_metrics(context) {
|
||||||
let em_factor = 0.5;
|
Some(metrics) => metrics.x_height,
|
||||||
reference_font_size.scale_by(length * em_factor)
|
// 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.
|
||||||
|
//
|
||||||
|
None => reference_font_size.scale_by(0.5 * length),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
FontRelativeLength::Ch(length) => {
|
||||||
|
let wm = context.style().writing_mode;
|
||||||
|
|
||||||
|
// TODO(emilio, #14144): Compute this properly once we support
|
||||||
|
// all the relevant writing-mode related properties, this should
|
||||||
|
// be equivalent to "is the text in the block direction?".
|
||||||
|
let vertical = wm.is_vertical();
|
||||||
|
|
||||||
|
match Self::find_first_available_font_metrics(context) {
|
||||||
|
Some(metrics) => {
|
||||||
|
if vertical {
|
||||||
|
metrics.zero_advance_measure.height
|
||||||
|
} else {
|
||||||
|
metrics.zero_advance_measure.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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).
|
||||||
|
//
|
||||||
|
None => {
|
||||||
|
if vertical {
|
||||||
|
reference_font_size.scale_by(length)
|
||||||
|
} else {
|
||||||
|
reference_font_size.scale_by(0.5 * length)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
FontRelativeLength::Rem(length) => root_font_size.scale_by(length)
|
FontRelativeLength::Rem(length) => root_font_size.scale_by(length)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -612,38 +674,6 @@ impl CalcLengthOrPercentage {
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compute_from_viewport_and_font_size(&self,
|
|
||||||
viewport_size: Size2D<Au>,
|
|
||||||
font_size: Au,
|
|
||||||
root_font_size: Au)
|
|
||||||
-> computed::CalcLengthOrPercentage
|
|
||||||
{
|
|
||||||
let mut length = None;
|
|
||||||
|
|
||||||
if let Some(absolute) = self.absolute {
|
|
||||||
length = Some(length.unwrap_or(Au(0)) + absolute);
|
|
||||||
}
|
|
||||||
|
|
||||||
for val in &[self.vw, self.vh, self.vmin, self.vmax] {
|
|
||||||
if let Some(val) = *val {
|
|
||||||
length = Some(length.unwrap_or(Au(0)) +
|
|
||||||
val.to_computed_value(viewport_size));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for val in &[self.ch, self.em, self.ex, self.rem] {
|
|
||||||
if let Some(val) = *val {
|
|
||||||
length = Some(length.unwrap_or(Au(0)) + val.to_computed_value(
|
|
||||||
font_size, root_font_size));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
computed::CalcLengthOrPercentage {
|
|
||||||
length: length,
|
|
||||||
percentage: self.percentage.map(|p| p.0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasViewportPercentage for CalcLengthOrPercentage {
|
impl HasViewportPercentage for CalcLengthOrPercentage {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
//!
|
//!
|
||||||
//! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
|
//! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
|
||||||
|
|
||||||
|
use app_units::Au;
|
||||||
use cssparser::{Parser, Token};
|
use cssparser::{Parser, Token};
|
||||||
use parser::Parse;
|
use parser::Parse;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -290,9 +291,9 @@ impl ToComputedValue for Position {
|
||||||
Keyword::Right => {
|
Keyword::Right => {
|
||||||
if let Some(x) = self.horiz_position {
|
if let Some(x) = self.horiz_position {
|
||||||
let (length, percentage) = match x {
|
let (length, percentage) = match x {
|
||||||
LengthOrPercentage::Percentage(Percentage(y)) => (None, Some(1.0 - y)),
|
LengthOrPercentage::Percentage(Percentage(y)) => (Au(0), Some(1.0 - y)),
|
||||||
LengthOrPercentage::Length(y) => (Some(-y.to_computed_value(context)), Some(1.0)),
|
LengthOrPercentage::Length(y) => (-y.to_computed_value(context), Some(1.0)),
|
||||||
_ => (None, None),
|
_ => (Au(0), None),
|
||||||
};
|
};
|
||||||
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
|
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
|
||||||
length: length,
|
length: length,
|
||||||
|
@ -316,9 +317,9 @@ impl ToComputedValue for Position {
|
||||||
Keyword::Bottom => {
|
Keyword::Bottom => {
|
||||||
if let Some(x) = self.vert_position {
|
if let Some(x) = self.vert_position {
|
||||||
let (length, percentage) = match x {
|
let (length, percentage) = match x {
|
||||||
LengthOrPercentage::Percentage(Percentage(y)) => (None, Some(1.0 - y)),
|
LengthOrPercentage::Percentage(Percentage(y)) => (Au(0), Some(1.0 - y)),
|
||||||
LengthOrPercentage::Length(y) => (Some(-y.to_computed_value(context)), Some(1.0)),
|
LengthOrPercentage::Length(y) => (-y.to_computed_value(context), Some(1.0)),
|
||||||
_ => (None, None),
|
_ => (Au(0), None),
|
||||||
};
|
};
|
||||||
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
|
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
|
||||||
length: length,
|
length: length,
|
||||||
|
|
|
@ -633,6 +633,7 @@ impl MaybeNew for ViewportConstraints {
|
||||||
viewport_size: initial_viewport,
|
viewport_size: initial_viewport,
|
||||||
inherited_style: ComputedValues::initial_values(),
|
inherited_style: ComputedValues::initial_values(),
|
||||||
style: ComputedValues::initial_values().clone(),
|
style: ComputedValues::initial_values().clone(),
|
||||||
|
font_metrics_provider: None, // TODO: Should have!
|
||||||
};
|
};
|
||||||
|
|
||||||
// DEVICE-ADAPT § 9.3 Resolving 'extend-to-zoom'
|
// DEVICE-ADAPT § 9.3 Resolving 'extend-to-zoom'
|
||||||
|
|
|
@ -148,6 +148,7 @@ pub extern "C" fn Servo_RestyleWithAddedDeclaration(declarations: RawServoDeclar
|
||||||
previous_style,
|
previous_style,
|
||||||
None,
|
None,
|
||||||
Box::new(StdoutErrorReporter),
|
Box::new(StdoutErrorReporter),
|
||||||
|
None,
|
||||||
CascadeFlags::empty());
|
CascadeFlags::empty());
|
||||||
Arc::new(computed).into_strong()
|
Arc::new(computed).into_strong()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue