mirror of
https://github.com/servo/servo.git
synced 2025-08-08 15:05:35 +01:00
style: Make word-spacing, letter-spacing, and line-height use Rust lengths.
This also adopts the resolution from [1] while at it, making letter-spacing compute to a length, serializing 0 to normal rather than keeping normal in the computed value, which matches every other engine. This removes the SMIL tests for percentages from letter-spacing since letter-spacing does in fact not support percentages, so they were passing just by chance. [1]: https://github.com/w3c/csswg-drafts/issues/1484 Differential Revision: https://phabricator.services.mozilla.com/D21850
This commit is contained in:
parent
c16e88d229
commit
b96981f88e
5 changed files with 94 additions and 171 deletions
|
@ -7,13 +7,14 @@
|
|||
#[cfg(feature = "servo")]
|
||||
use crate::properties::StyleBuilder;
|
||||
use crate::values::computed::length::{Length, LengthPercentage};
|
||||
use crate::values::computed::{NonNegativeLength, NonNegativeNumber};
|
||||
use crate::values::computed::{Context, NonNegativeLength, NonNegativeNumber, ToComputedValue};
|
||||
use crate::values::generics::text::InitialLetter as GenericInitialLetter;
|
||||
use crate::values::generics::text::LineHeight as GenericLineHeight;
|
||||
use crate::values::generics::text::Spacing;
|
||||
use crate::values::specified::text::TextOverflowSide;
|
||||
use crate::values::specified::text::{self as specified, TextOverflowSide};
|
||||
use crate::values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword};
|
||||
use crate::values::{CSSFloat, CSSInteger};
|
||||
use crate::Zero;
|
||||
use std::fmt::{self, Write};
|
||||
use style_traits::{CssWriter, ToCss};
|
||||
|
||||
|
@ -25,10 +26,78 @@ pub use crate::values::specified::TextEmphasisPosition;
|
|||
pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
|
||||
|
||||
/// A computed value for the `letter-spacing` property.
|
||||
pub type LetterSpacing = Spacing<Length>;
|
||||
#[repr(transparent)]
|
||||
#[derive(
|
||||
Animate,
|
||||
Clone,
|
||||
ComputeSquaredDistance,
|
||||
Copy,
|
||||
Debug,
|
||||
MallocSizeOf,
|
||||
PartialEq,
|
||||
ToAnimatedValue,
|
||||
ToAnimatedZero,
|
||||
)]
|
||||
pub struct LetterSpacing(Length);
|
||||
|
||||
impl LetterSpacing {
|
||||
/// Return the `normal` computed value, which is just zero.
|
||||
#[inline]
|
||||
pub fn normal() -> Self {
|
||||
LetterSpacing(Length::zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToCss for LetterSpacing {
|
||||
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
|
||||
where
|
||||
W: Write,
|
||||
{
|
||||
// https://drafts.csswg.org/css-text/#propdef-letter-spacing
|
||||
//
|
||||
// For legacy reasons, a computed letter-spacing of zero yields a
|
||||
// resolved value (getComputedStyle() return value) of normal.
|
||||
if self.0.is_zero() {
|
||||
return dest.write_str("normal");
|
||||
}
|
||||
self.0.to_css(dest)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToComputedValue for specified::LetterSpacing {
|
||||
type ComputedValue = LetterSpacing;
|
||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
match *self {
|
||||
Spacing::Normal => LetterSpacing(Length::zero()),
|
||||
Spacing::Value(ref v) => LetterSpacing(v.to_computed_value(context)),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||
if computed.0.is_zero() {
|
||||
return Spacing::Normal;
|
||||
}
|
||||
Spacing::Value(ToComputedValue::from_computed_value(&computed.0))
|
||||
}
|
||||
}
|
||||
|
||||
/// A computed value for the `word-spacing` property.
|
||||
pub type WordSpacing = Spacing<LengthPercentage>;
|
||||
pub type WordSpacing = LengthPercentage;
|
||||
|
||||
impl ToComputedValue for specified::WordSpacing {
|
||||
type ComputedValue = WordSpacing;
|
||||
|
||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
match *self {
|
||||
Spacing::Normal => LengthPercentage::zero(),
|
||||
Spacing::Value(ref v) => v.to_computed_value(context),
|
||||
}
|
||||
}
|
||||
|
||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||
Spacing::Value(ToComputedValue::from_computed_value(computed))
|
||||
}
|
||||
}
|
||||
|
||||
/// A computed value for the `line-height` property.
|
||||
pub type LineHeight = GenericLineHeight<NonNegativeNumber, NonNegativeLength>;
|
||||
|
|
|
@ -5,9 +5,7 @@
|
|||
//! Generic types for text properties.
|
||||
|
||||
use crate::parser::ParserContext;
|
||||
use crate::values::animated::{Animate, Procedure, ToAnimatedZero};
|
||||
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
|
||||
use app_units::Au;
|
||||
use crate::values::animated::ToAnimatedZero;
|
||||
use cssparser::Parser;
|
||||
use style_traits::ParseError;
|
||||
|
||||
|
@ -32,7 +30,7 @@ impl<N, I> InitialLetter<N, I> {
|
|||
|
||||
/// A generic spacing value for the `letter-spacing` and `word-spacing` properties.
|
||||
#[derive(
|
||||
Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss,
|
||||
Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss,
|
||||
)]
|
||||
pub enum Spacing<Value> {
|
||||
/// `normal`
|
||||
|
@ -63,51 +61,6 @@ impl<Value> Spacing<Value> {
|
|||
}
|
||||
parse(context, input).map(Spacing::Value)
|
||||
}
|
||||
|
||||
/// Returns the spacing value, if not `normal`.
|
||||
#[inline]
|
||||
pub fn value(&self) -> Option<&Value> {
|
||||
match *self {
|
||||
Spacing::Normal => None,
|
||||
Spacing::Value(ref value) => Some(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Value> Animate for Spacing<Value>
|
||||
where
|
||||
Value: Animate + From<Au>,
|
||||
{
|
||||
#[inline]
|
||||
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
|
||||
if let (&Spacing::Normal, &Spacing::Normal) = (self, other) {
|
||||
return Ok(Spacing::Normal);
|
||||
}
|
||||
let zero = Value::from(Au(0));
|
||||
let this = self.value().unwrap_or(&zero);
|
||||
let other = other.value().unwrap_or(&zero);
|
||||
Ok(Spacing::Value(this.animate(other, procedure)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> ComputeSquaredDistance for Spacing<V>
|
||||
where
|
||||
V: ComputeSquaredDistance + From<Au>,
|
||||
{
|
||||
#[inline]
|
||||
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
|
||||
let zero = V::from(Au(0));
|
||||
let this = self.value().unwrap_or(&zero);
|
||||
let other = other.value().unwrap_or(&zero);
|
||||
this.compute_squared_distance(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> ToAnimatedZero for Spacing<V> {
|
||||
#[inline]
|
||||
fn to_animated_zero(&self) -> Result<Self, ()> {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A generic value for the `line-height` property.
|
||||
|
@ -123,18 +76,21 @@ impl<V> ToAnimatedZero for Spacing<V> {
|
|||
ToAnimatedValue,
|
||||
ToCss,
|
||||
)]
|
||||
pub enum LineHeight<Number, LengthPercentage> {
|
||||
#[repr(C, u8)]
|
||||
pub enum GenericLineHeight<N, L> {
|
||||
/// `normal`
|
||||
Normal,
|
||||
/// `-moz-block-height`
|
||||
#[cfg(feature = "gecko")]
|
||||
MozBlockHeight,
|
||||
/// `<number>`
|
||||
Number(Number),
|
||||
/// `<length-or-percentage>`
|
||||
Length(LengthPercentage),
|
||||
Number(N),
|
||||
/// `<length-percentage>`
|
||||
Length(L),
|
||||
}
|
||||
|
||||
pub use self::GenericLineHeight as LineHeight;
|
||||
|
||||
impl<N, L> ToAnimatedZero for LineHeight<N, L> {
|
||||
#[inline]
|
||||
fn to_animated_zero(&self) -> Result<Self, ()> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue