Skip to content

Commit f6de533

Browse files
emilioaditj
authored andcommitted
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]: w3c/csswg-drafts#1484 Differential Revision: https://phabricator.services.mozilla.com/D21850
1 parent 7dc4f23 commit f6de533

File tree

5 files changed

+94
-171
lines changed

5 files changed

+94
-171
lines changed

components/style/cbindgen.toml

+4
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,10 @@ include = [
7878
"Resize",
7979
"Overflow",
8080
"LengthPercentage",
81+
"LetterSpacing",
8182
"NonNegativeLengthPercentage",
8283
"LengthPercentageOrAuto",
84+
"LineHeight",
8385
"NonNegativeLengthPercentageOrAuto",
8486
"Rect",
8587
"IntersectionObserverRootMargin",
@@ -102,6 +104,7 @@ item_types = ["enums", "structs", "typedefs"]
102104
[export.body]
103105
"CSSPixelLength" = """
104106
inline nscoord ToAppUnits() const;
107+
inline bool IsZero() const;
105108
"""
106109

107110
"LengthPercentage" = """
@@ -118,6 +121,7 @@ item_types = ["enums", "structs", "typedefs"]
118121
inline bool ConvertsToPercentage() const;
119122
inline bool HasLengthAndPercentage() const;
120123
inline float ToPercentage() const;
124+
inline bool IsDefinitelyZero() const;
121125
inline CSSCoord ResolveToCSSPixels(CSSCoord aPercentageBasisInCSSPixels) const;
122126
template<typename T> inline CSSCoord ResolveToCSSPixelsWith(T aPercentageGetter) const;
123127
template<typename T, typename U>

components/style/properties/gecko.mako.rs

+7-113
Original file line numberDiff line numberDiff line change
@@ -1227,56 +1227,23 @@ impl Clone for ${style_struct.gecko_struct_name} {
12271227

12281228
# Types used with predefined_type()-defined properties that we can auto-generate.
12291229
predefined_types = {
1230-
"Appearance": impl_simple,
1231-
"OverscrollBehavior": impl_simple,
1232-
"OverflowClipBox": impl_simple,
1233-
"ScrollSnapAlign": impl_simple,
1234-
"ScrollSnapType": impl_simple,
1235-
"Float": impl_simple,
1236-
"Overflow": impl_simple,
1237-
"BreakBetween": impl_simple,
1238-
"BreakWithin": impl_simple,
1239-
"Resize": impl_simple,
12401230
"Color": impl_color,
12411231
"ColorOrAuto": impl_color,
1242-
"GreaterThanOrEqualToOneNumber": impl_simple,
1243-
"Integer": impl_simple,
12441232
"length::LengthOrAuto": impl_style_coord,
12451233
"length::LengthOrNormal": impl_style_coord,
12461234
"length::NonNegativeLengthOrAuto": impl_style_coord,
12471235
"length::NonNegativeLengthPercentageOrNormal": impl_style_coord,
1248-
"FillRule": impl_simple,
1249-
"FlexBasis": impl_simple,
12501236
"Length": impl_absolute_length,
12511237
"LengthOrNormal": impl_style_coord,
1252-
"LengthPercentage": impl_simple,
12531238
"LengthPercentageOrAuto": impl_style_coord,
1254-
"MaxSize": impl_simple,
1255-
"Size": impl_simple,
12561239
"MozScriptMinSize": impl_absolute_length,
1257-
"MozScriptSizeMultiplier": impl_simple,
1258-
"NonNegativeLengthPercentage": impl_simple,
1259-
"NonNegativeLengthOrNumber": impl_simple,
1260-
"NonNegativeLengthOrNumberRect": impl_simple,
1261-
"BorderImageSlice": impl_simple,
1262-
"NonNegativeNumber": impl_simple,
1263-
"Number": impl_simple,
1264-
"Opacity": impl_simple,
1265-
"OverflowWrap": impl_simple,
1266-
"OverflowAnchor": impl_simple,
1267-
"Perspective": impl_simple,
1268-
"Position": impl_simple,
12691240
"RGBAColor": impl_rgba_color,
12701241
"SVGLength": impl_svg_length,
12711242
"SVGOpacity": impl_svg_opacity,
12721243
"SVGPaint": impl_svg_paint,
12731244
"SVGWidth": impl_svg_length,
12741245
"Transform": impl_transform,
1275-
"TransformOrigin": impl_simple,
1276-
"UserSelect": impl_simple,
12771246
"url::UrlOrNone": impl_css_url,
1278-
"WordBreak": impl_simple,
1279-
"ZIndex": impl_simple,
12801247
}
12811248

12821249
def longhand_method(longhand):
@@ -1291,15 +1258,12 @@ impl Clone for ${style_struct.gecko_struct_name} {
12911258
args.update(keyword=longhand.keyword)
12921259
if "font" in longhand.ident:
12931260
args.update(cast_type=longhand.cast_type)
1294-
else:
1261+
elif longhand.predefined_type in predefined_types:
12951262
method = predefined_types[longhand.predefined_type]
1263+
else:
1264+
method = impl_simple
12961265

12971266
method(**args)
1298-
1299-
picked_longhands = []
1300-
for x in longhands:
1301-
if x.keyword or x.predefined_type in predefined_types or x.logical:
1302-
picked_longhands.append(x)
13031267
%>
13041268
impl ${style_struct.gecko_struct_name} {
13051269
/*
@@ -1311,7 +1275,7 @@ impl ${style_struct.gecko_struct_name} {
13111275
* Auto-Generated Methods.
13121276
*/
13131277
<%
1314-
for longhand in picked_longhands:
1278+
for longhand in longhands:
13151279
longhand_method(longhand)
13161280
%>
13171281
}
@@ -1992,6 +1956,7 @@ fn static_assert() {
19921956

19931957
<%
19941958
skip_font_longhands = """font-family font-size font-size-adjust font-weight
1959+
font-style font-stretch -moz-script-level
19951960
font-synthesis -x-lang font-variant-alternates
19961961
font-variant-east-asian font-variant-ligatures
19971962
font-variant-numeric font-language-override
@@ -2783,6 +2748,7 @@ fn static_assert() {
27832748
animation-iteration-count animation-timing-function
27842749
clear transition-duration transition-delay
27852750
transition-timing-function transition-property
2751+
transform-style
27862752
rotate scroll-snap-points-x scroll-snap-points-y
27872753
scroll-snap-coordinate -moz-binding will-change
27882754
offset-path shape-outside contain touch-action
@@ -4158,7 +4124,7 @@ fn static_assert() {
41584124

41594125

41604126
<%self:impl_trait style_struct_name="InheritedText"
4161-
skip_longhands="text-align text-emphasis-style text-shadow line-height letter-spacing word-spacing
4127+
skip_longhands="text-align text-emphasis-style text-shadow
41624128
-webkit-text-stroke-width text-emphasis-position">
41634129

41644130
<% text_align_keyword = Keyword("text-align",
@@ -4190,78 +4156,6 @@ fn static_assert() {
41904156
longhands::text_shadow::computed_value::List(buf)
41914157
}
41924158

4193-
pub fn set_line_height(&mut self, v: longhands::line_height::computed_value::T) {
4194-
use crate::values::generics::text::LineHeight;
4195-
// FIXME: Align binary representations and ditch |match| for cast + static_asserts
4196-
let en = match v {
4197-
LineHeight::Normal => CoordDataValue::Normal,
4198-
LineHeight::Length(val) => CoordDataValue::Coord(val.0.to_i32_au()),
4199-
LineHeight::Number(val) => CoordDataValue::Factor(val.0),
4200-
LineHeight::MozBlockHeight =>
4201-
CoordDataValue::Enumerated(structs::NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT),
4202-
};
4203-
self.gecko.mLineHeight.set_value(en);
4204-
}
4205-
4206-
pub fn clone_line_height(&self) -> longhands::line_height::computed_value::T {
4207-
use crate::values::generics::text::LineHeight;
4208-
return match self.gecko.mLineHeight.as_value() {
4209-
CoordDataValue::Normal => LineHeight::Normal,
4210-
CoordDataValue::Coord(coord) => LineHeight::Length(Au(coord).into()),
4211-
CoordDataValue::Factor(n) => LineHeight::Number(n.into()),
4212-
CoordDataValue::Enumerated(val) if val == structs::NS_STYLE_LINE_HEIGHT_BLOCK_HEIGHT =>
4213-
LineHeight::MozBlockHeight,
4214-
_ => panic!("this should not happen"),
4215-
}
4216-
}
4217-
4218-
<%call expr="impl_coord_copy('line_height', 'mLineHeight')"></%call>
4219-
4220-
pub fn set_letter_spacing(&mut self, v: longhands::letter_spacing::computed_value::T) {
4221-
use crate::values::generics::text::Spacing;
4222-
match v {
4223-
Spacing::Value(value) => self.gecko.mLetterSpacing.set(value),
4224-
Spacing::Normal => self.gecko.mLetterSpacing.set_value(CoordDataValue::Normal)
4225-
}
4226-
}
4227-
4228-
pub fn clone_letter_spacing(&self) -> longhands::letter_spacing::computed_value::T {
4229-
use crate::values::computed::Length;
4230-
use crate::values::generics::text::Spacing;
4231-
debug_assert!(
4232-
matches!(self.gecko.mLetterSpacing.as_value(),
4233-
CoordDataValue::Normal |
4234-
CoordDataValue::Coord(_)),
4235-
"Unexpected computed value for letter-spacing");
4236-
Length::from_gecko_style_coord(&self.gecko.mLetterSpacing).map_or(Spacing::Normal, Spacing::Value)
4237-
}
4238-
4239-
<%call expr="impl_coord_copy('letter_spacing', 'mLetterSpacing')"></%call>
4240-
4241-
pub fn set_word_spacing(&mut self, v: longhands::word_spacing::computed_value::T) {
4242-
use crate::values::generics::text::Spacing;
4243-
match v {
4244-
Spacing::Value(lp) => self.gecko.mWordSpacing.set(lp),
4245-
// https://drafts.csswg.org/css-text-3/#valdef-word-spacing-normal
4246-
Spacing::Normal => self.gecko.mWordSpacing.set_value(CoordDataValue::Coord(0)),
4247-
}
4248-
}
4249-
4250-
pub fn clone_word_spacing(&self) -> longhands::word_spacing::computed_value::T {
4251-
use crate::values::computed::LengthPercentage;
4252-
use crate::values::generics::text::Spacing;
4253-
debug_assert!(
4254-
matches!(self.gecko.mWordSpacing.as_value(),
4255-
CoordDataValue::Normal |
4256-
CoordDataValue::Coord(_) |
4257-
CoordDataValue::Percent(_) |
4258-
CoordDataValue::Calc(_)),
4259-
"Unexpected computed value for word-spacing");
4260-
LengthPercentage::from_gecko_style_coord(&self.gecko.mWordSpacing).map_or(Spacing::Normal, Spacing::Value)
4261-
}
4262-
4263-
<%call expr="impl_coord_copy('word_spacing', 'mWordSpacing')"></%call>
4264-
42654159
fn clear_text_emphasis_style_if_string(&mut self) {
42664160
if self.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING as u8 {
42674161
self.gecko.mTextEmphasisStyleString.truncate();

components/style/properties/longhands/inherited_text.mako.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ ${helpers.predefined_type(
157157
${helpers.predefined_type(
158158
"word-spacing",
159159
"WordSpacing",
160-
"computed::WordSpacing::normal()",
160+
"computed::WordSpacing::zero()",
161161
animation_value_type="ComputedValue",
162162
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
163163
spec="https://drafts.csswg.org/css-text/#propdef-word-spacing",

components/style/values/computed/text.rs

+73-4
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@
77
#[cfg(feature = "servo")]
88
use crate::properties::StyleBuilder;
99
use crate::values::computed::length::{Length, LengthPercentage};
10-
use crate::values::computed::{NonNegativeLength, NonNegativeNumber};
10+
use crate::values::computed::{Context, NonNegativeLength, NonNegativeNumber, ToComputedValue};
1111
use crate::values::generics::text::InitialLetter as GenericInitialLetter;
1212
use crate::values::generics::text::LineHeight as GenericLineHeight;
1313
use crate::values::generics::text::Spacing;
14-
use crate::values::specified::text::TextOverflowSide;
14+
use crate::values::specified::text::{self as specified, TextOverflowSide};
1515
use crate::values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword};
1616
use crate::values::{CSSFloat, CSSInteger};
17+
use crate::Zero;
1718
use std::fmt::{self, Write};
1819
use style_traits::{CssWriter, ToCss};
1920

@@ -25,10 +26,78 @@ pub use crate::values::specified::TextEmphasisPosition;
2526
pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
2627

2728
/// A computed value for the `letter-spacing` property.
28-
pub type LetterSpacing = Spacing<Length>;
29+
#[repr(transparent)]
30+
#[derive(
31+
Animate,
32+
Clone,
33+
ComputeSquaredDistance,
34+
Copy,
35+
Debug,
36+
MallocSizeOf,
37+
PartialEq,
38+
ToAnimatedValue,
39+
ToAnimatedZero,
40+
)]
41+
pub struct LetterSpacing(Length);
42+
43+
impl LetterSpacing {
44+
/// Return the `normal` computed value, which is just zero.
45+
#[inline]
46+
pub fn normal() -> Self {
47+
LetterSpacing(Length::zero())
48+
}
49+
}
50+
51+
impl ToCss for LetterSpacing {
52+
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
53+
where
54+
W: Write,
55+
{
56+
// https://drafts.csswg.org/css-text/#propdef-letter-spacing
57+
//
58+
// For legacy reasons, a computed letter-spacing of zero yields a
59+
// resolved value (getComputedStyle() return value) of normal.
60+
if self.0.is_zero() {
61+
return dest.write_str("normal");
62+
}
63+
self.0.to_css(dest)
64+
}
65+
}
66+
67+
impl ToComputedValue for specified::LetterSpacing {
68+
type ComputedValue = LetterSpacing;
69+
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
70+
match *self {
71+
Spacing::Normal => LetterSpacing(Length::zero()),
72+
Spacing::Value(ref v) => LetterSpacing(v.to_computed_value(context)),
73+
}
74+
}
75+
76+
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
77+
if computed.0.is_zero() {
78+
return Spacing::Normal;
79+
}
80+
Spacing::Value(ToComputedValue::from_computed_value(&computed.0))
81+
}
82+
}
2983

3084
/// A computed value for the `word-spacing` property.
31-
pub type WordSpacing = Spacing<LengthPercentage>;
85+
pub type WordSpacing = LengthPercentage;
86+
87+
impl ToComputedValue for specified::WordSpacing {
88+
type ComputedValue = WordSpacing;
89+
90+
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
91+
match *self {
92+
Spacing::Normal => LengthPercentage::zero(),
93+
Spacing::Value(ref v) => v.to_computed_value(context),
94+
}
95+
}
96+
97+
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
98+
Spacing::Value(ToComputedValue::from_computed_value(computed))
99+
}
100+
}
32101

33102
/// A computed value for the `line-height` property.
34103
pub type LineHeight = GenericLineHeight<NonNegativeNumber, NonNegativeLength>;

0 commit comments

Comments
 (0)