style/values/computed/
text.rs1use crate::Zero;
8use crate::derives::*;
9#[cfg(feature = "gecko")]
10use crate::gecko_bindings::bindings;
11use crate::typed_om::{KeywordValue, ToTyped, TypedValue};
12use crate::values::animated::text::TextDecorationInset as AnimatedTextDecorationInset;
13use crate::values::animated::{Context as AnimatedContext, ToAnimatedValue};
14use crate::values::computed::length::{CSSPixelLength, LengthPercentage};
15use crate::values::generics::NumberOrAuto;
16use crate::values::generics::text::{
17 GenericHyphenateLimitChars, GenericInitialLetter, GenericTextDecorationInset,
18 GenericTextDecorationLength, GenericTextIndent,
19};
20use crate::values::specified::text as specified;
21use crate::values::specified::text::{TextEmphasisFillMode, TextEmphasisShapeKeyword};
22use crate::values::{CSSFloat, CSSInteger, ComputeSquaredDistance};
23use std::fmt::{self, Write};
24use style_traits::{CssString, CssWriter, ToCss};
25use thin_vec::ThinVec;
26
27pub use crate::values::specified::text::{
28 HyphenateCharacter, Hyphens, LineBreak, MozControlCharacterVisibility, OverflowWrap, RubyAlign,
29 RubyPosition, TextAlignLast, TextAutospace, TextBoxEdge, TextBoxTrim, TextCombineUpright,
30 TextDecorationLine, TextDecorationSkipInk, TextDecorationStyle, TextEmphasisPosition,
31 TextJustify, TextOverflow, TextRendering, TextSecurity, TextSizeAdjust, TextTransform,
32 TextUnderlinePosition, TextWrapMode, TextWrapStyle, UnicodeBidi, WhiteSpaceCollapse, WordBreak,
33};
34
35pub type InitialLetter = GenericInitialLetter<CSSFloat, CSSInteger>;
37
38pub type TextDecorationLength = GenericTextDecorationLength<LengthPercentage>;
40
41pub type TextDecorationInset = GenericTextDecorationInset<LengthPercentage>;
43
44impl ToAnimatedValue for TextDecorationInset {
45 type AnimatedValue = AnimatedTextDecorationInset;
46
47 fn to_animated_value(self, context: &AnimatedContext) -> Self::AnimatedValue {
48 match self {
49 Self::Auto => {
50 let font_size_px = context
51 .style
52 .get_font()
53 .slow_clone_font_size()
54 .computed_size()
55 .px();
56 #[cfg(feature = "gecko")]
57 let auto_length = unsafe { bindings::Gecko_CalcAutoDecorationInset(font_size_px) };
58 #[cfg(feature = "servo")]
59 let auto_length = {
60 let auto_inset_factor = 1.0 / 12.5;
63
64 (font_size_px * auto_inset_factor).max(1.0)
67 };
68 let auto_length = CSSPixelLength::new(auto_length);
69 Self::AnimatedValue {
70 start: LengthPercentage::new_length(auto_length),
71 end: LengthPercentage::new_length(auto_length),
72 is_auto: true,
73 }
74 },
75 Self::LengthPercentage { start, end } => Self::AnimatedValue {
76 start: start.to_animated_value(context),
77 end: end.to_animated_value(context),
78 is_auto: false,
79 },
80 }
81 }
82
83 #[inline]
84 fn from_animated_value(value: Self::AnimatedValue) -> Self {
85 if value.is_auto {
86 Self::Auto
87 } else {
88 Self::LengthPercentage {
89 start: value.start,
90 end: value.end,
91 }
92 }
93 }
94}
95
96pub type TextAlign = specified::TextAlignKeyword;
98
99pub type TextIndent = GenericTextIndent<LengthPercentage>;
101
102pub type HyphenateLimitChars = GenericHyphenateLimitChars<CSSInteger>;
104
105impl HyphenateLimitChars {
106 #[inline]
108 pub fn auto() -> Self {
109 Self {
110 total_word_length: NumberOrAuto::Auto,
111 pre_hyphen_length: NumberOrAuto::Auto,
112 post_hyphen_length: NumberOrAuto::Auto,
113 }
114 }
115}
116
117#[repr(transparent)]
119#[derive(
120 Animate,
121 Clone,
122 ComputeSquaredDistance,
123 Copy,
124 Debug,
125 MallocSizeOf,
126 PartialEq,
127 ToAnimatedValue,
128 ToAnimatedZero,
129 ToResolvedValue,
130)]
131pub struct GenericLetterSpacing<L>(pub L);
132pub type LetterSpacing = GenericLetterSpacing<LengthPercentage>;
134
135impl LetterSpacing {
136 #[inline]
138 pub fn normal() -> Self {
139 Self(LengthPercentage::zero())
140 }
141}
142
143impl ToCss for LetterSpacing {
144 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
145 where
146 W: Write,
147 {
148 if self.0.is_zero() {
153 return dest.write_str("normal");
154 }
155 self.0.to_css(dest)
156 }
157}
158
159impl ToTyped for LetterSpacing {
160 fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
165 if !self.0.has_percentage() && self.0.is_zero() {
166 dest.push(TypedValue::Keyword(KeywordValue(CssString::from("normal"))));
167 return Ok(());
168 }
169 self.0.to_typed(dest)
170 }
171}
172
173pub type WordSpacing = LengthPercentage;
175
176impl WordSpacing {
177 #[inline]
179 pub fn normal() -> Self {
180 LengthPercentage::zero()
181 }
182}
183
184#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue, ToTyped)]
186#[allow(missing_docs)]
187#[repr(C, u8)]
188#[typed(todo_derive_fields)]
189pub enum TextEmphasisStyle {
190 Keyword {
192 #[css(skip_if = "TextEmphasisFillMode::is_filled")]
193 fill: TextEmphasisFillMode,
194 shape: TextEmphasisShapeKeyword,
195 },
196 None,
198 String(crate::OwnedStr),
200}