1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 <%namespace name="helpers" file="/helpers.mako.rs" />
6 <% from data import Method, to_camel_case, to_rust_ident, to_camel_case_lower, SYSTEM_FONT_LONGHANDS %>
7 
8 <% data.new_style_struct("Font", inherited=True) %>
9 
10 ${helpers.predefined_type("font-family",
11                           "FontFamily",
12                           initial_value="computed::FontFamily::serif()",
13                           animation_value_type="discrete",
14                           flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
15                           spec="https://drafts.csswg.org/css-fonts/#propdef-font-family",
16                           servo_restyle_damage="rebuild_and_reflow")}
17 
18 ${helpers.single_keyword_system(
19     "font-style",
20     "normal italic oblique",
21     gecko_constant_prefix="NS_FONT_STYLE",
22     gecko_ffi_name="mFont.style",
23     spec="https://drafts.csswg.org/css-fonts/#propdef-font-style",
24     flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
25     animation_value_type="discrete",
26     servo_restyle_damage="rebuild_and_reflow"
27 )}
28 
29 <% font_variant_caps_custom_consts= { "small-caps": "SMALLCAPS",
30                                       "all-small-caps": "ALLSMALL",
31                                       "petite-caps": "PETITECAPS",
32                                       "all-petite-caps": "ALLPETITE",
33                                       "titling-caps": "TITLING" } %>
34 
35 ${helpers.single_keyword_system("font-variant-caps",
36                                 "normal small-caps",
37                                 extra_gecko_values="all-small-caps petite-caps all-petite-caps unicase titling-caps",
38                                 gecko_constant_prefix="NS_FONT_VARIANT_CAPS",
39                                 gecko_ffi_name="mFont.variantCaps",
40                                 spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-caps",
41                                 custom_consts=font_variant_caps_custom_consts,
42                                 flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
43                                 animation_value_type="discrete",
44                                 servo_restyle_damage="rebuild_and_reflow")}
45 
46 ${helpers.predefined_type("font-weight",
47                           "FontWeight",
48                           initial_value="computed::FontWeight::normal()",
49                           initial_specified_value="specified::FontWeight::Normal",
50                           animation_value_type="ComputedValue",
51                           flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
52                           spec="https://drafts.csswg.org/css-fonts/#propdef-font-weight",
53                           servo_restyle_damage="rebuild_and_reflow")}
54 
55 ${helpers.predefined_type("font-size",
56                           "FontSize",
57                           initial_value="computed::FontSize::medium()",
58                           initial_specified_value="specified::FontSize::medium()",
59                           animation_value_type="NonNegativeLength",
60                           allow_quirks=True,
61                           flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
62                           spec="https://drafts.csswg.org/css-fonts/#propdef-font-size",
63                           servo_restyle_damage="rebuild_and_reflow")}
64 
65 ${helpers.predefined_type("font-size-adjust",
66                           "FontSizeAdjust",
67                           products="gecko",
68                           initial_value="computed::FontSizeAdjust::none()",
69                           initial_specified_value="specified::FontSizeAdjust::none()",
70                           animation_value_type="ComputedValue",
71                           flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
72                           spec="https://drafts.csswg.org/css-fonts/#propdef-font-size-adjust")}
73 
74 ${helpers.predefined_type("font-synthesis",
75                           "FontSynthesis",
76                           products="gecko",
77                           initial_value="specified::FontSynthesis::get_initial_value()",
78                           animation_value_type="discrete",
79                           flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
80                           spec="https://drafts.csswg.org/css-fonts/#propdef-font-synthesis")}
81 
82 ${helpers.single_keyword_system("font-stretch",
83                                 "normal ultra-condensed extra-condensed condensed \
84                                  semi-condensed semi-expanded expanded extra-expanded \
85                                  ultra-expanded",
86                                 gecko_ffi_name="mFont.stretch",
87                                 gecko_constant_prefix="NS_FONT_STRETCH",
88                                 cast_type='i16',
89                                 spec="https://drafts.csswg.org/css-fonts/#propdef-font-stretch",
90                                 flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
91                                 animation_value_type="ComputedValue",
92                                 servo_restyle_damage="rebuild_and_reflow")}
93 
94 ${helpers.single_keyword_system("font-kerning",
95                                 "auto none normal",
96                                 products="gecko",
97                                 gecko_ffi_name="mFont.kerning",
98                                 gecko_constant_prefix="NS_FONT_KERNING",
99                                 spec="https://drafts.csswg.org/css-fonts/#propdef-font-kerning",
100                                 flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
101                                 animation_value_type="discrete")}
102 
103 ${helpers.predefined_type("font-variant-alternates",
104                           "FontVariantAlternates",
105                           products="gecko",
106                           initial_value="computed::FontVariantAlternates::get_initial_value()",
107                           initial_specified_value="specified::FontVariantAlternates::get_initial_specified_value()",
108                           animation_value_type="discrete",
109                           flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
110                           spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-alternates")}
111 
112 ${helpers.predefined_type("font-variant-east-asian",
113                           "FontVariantEastAsian",
114                           products="gecko",
115                           initial_value="computed::FontVariantEastAsian::empty()",
116                           initial_specified_value="specified::FontVariantEastAsian::empty()",
117                           animation_value_type="discrete",
118                           flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
119                           spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-east-asian")}
120 
121 ${helpers.predefined_type("font-variant-ligatures",
122                           "FontVariantLigatures",
123                           products="gecko",
124                           initial_value="computed::FontVariantLigatures::empty()",
125                           initial_specified_value="specified::FontVariantLigatures::empty()",
126                           animation_value_type="discrete",
127                           flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
128                           spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-ligatures")}
129 
130 ${helpers.predefined_type("font-variant-numeric",
131                           "FontVariantNumeric",
132                           products="gecko",
133                           initial_value="computed::FontVariantNumeric::empty()",
134                           initial_specified_value="specified::FontVariantNumeric::empty()",
135                           animation_value_type="discrete",
136                           flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
137                           spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-numeric")}
138 
139 ${helpers.single_keyword_system("font-variant-position",
140                                 "normal sub super",
141                                 products="gecko",
142                                 gecko_ffi_name="mFont.variantPosition",
143                                 gecko_constant_prefix="NS_FONT_VARIANT_POSITION",
144                                 spec="https://drafts.csswg.org/css-fonts/#propdef-font-variant-position",
145                                 flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
146                                 animation_value_type="discrete")}
147 
148 ${helpers.predefined_type("font-feature-settings",
149                           "FontFeatureSettings",
150                           products="gecko",
151                           initial_value="computed::FontFeatureSettings::normal()",
152                           initial_specified_value="specified::FontFeatureSettings::normal()",
153                           extra_prefixes="moz",
154                           animation_value_type="discrete",
155                           flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
156                           spec="https://drafts.csswg.org/css-fonts/#propdef-font-feature-settings")}
157 
158 <%
159 # This spec link is too long to fit elsewhere
160 variation_spec = """\
161 https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control-the-font-variation-settings-property\
162 """
163 %>
164 
165 ${helpers.predefined_type("font-variation-settings",
166                           "FontVariationSettings",
167                           products="gecko",
168                           gecko_pref="layout.css.font-variations.enabled",
169                           initial_value="computed::FontVariationSettings::normal()",
170                           initial_specified_value="specified::FontVariationSettings::normal()",
171                           animation_value_type="ComputedValue",
172                           flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
173                           spec="${variation_spec}")}
174 
175 ${helpers.predefined_type("font-language-override",
176                           "FontLanguageOverride",
177                           products="gecko",
178                           initial_value="computed::FontLanguageOverride::zero()",
179                           initial_specified_value="specified::FontLanguageOverride::normal()",
180                           animation_value_type="discrete",
181                           extra_prefixes="moz",
182                           flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
183                           spec="https://drafts.csswg.org/css-fonts-3/#propdef-font-language-override")}
184 
185 ${helpers.single_keyword_system("font-optical-sizing",
186                                 "auto none",
187                                 products="gecko",
188                                 gecko_pref="layout.css.font-variations.enabled",
189                                 gecko_ffi_name="mFont.opticalSizing",
190                                 gecko_constant_prefix="NS_FONT_OPTICAL_SIZING",
191                                 animation_value_type="discrete",
192                                 flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
193                                 spec="https://www.w3.org/TR/css-fonts-4/#font-optical-sizing-def")}
194 
195 ${helpers.predefined_type("-x-lang",
196                           "XLang",
197                           products="gecko",
198                           initial_value="computed::XLang::get_initial_value()",
199                           animation_value_type="none",
200                           enabled_in="",
201                           spec="Internal (not web-exposed)")}
202 
203 ${helpers.predefined_type("-moz-script-size-multiplier",
204                           "MozScriptSizeMultiplier",
205                           products="gecko",
206                           initial_value="computed::MozScriptSizeMultiplier::get_initial_value()",
207                           animation_value_type="none",
208                           gecko_ffi_name="mScriptSizeMultiplier",
209                           enabled_in="",
210                           spec="Internal (not web-exposed)")}
211 
212 ${helpers.predefined_type("-moz-script-level",
213                           "MozScriptLevel",
214                           0,
215                           animation_value_type="none",
216                           products="gecko",
217                           enabled_in="ua",
218                           gecko_ffi_name="mScriptLevel",
219                           spec="Internal (not web-exposed)")}
220 
221 ${helpers.single_keyword("-moz-math-display",
222                          "inline block",
223                          gecko_constant_prefix="NS_MATHML_DISPLAYSTYLE",
224                          gecko_ffi_name="mMathDisplay",
225                          products="gecko",
226                          enabled_in="ua",
227                          spec="Internal (not web-exposed)",
228                          animation_value_type="none")}
229 
230 ${helpers.single_keyword("-moz-math-variant",
231                          """none normal bold italic bold-italic script bold-script
232                             fraktur double-struck bold-fraktur sans-serif
233                             bold-sans-serif sans-serif-italic sans-serif-bold-italic
234                             monospace initial tailed looped stretched""",
235                          gecko_constant_prefix="NS_MATHML_MATHVARIANT",
236                          gecko_ffi_name="mMathVariant",
237                          products="gecko",
238                          spec="Internal (not web-exposed)",
239                          animation_value_type="none",
240                          enabled_in="",
241                          needs_conversion=True)}
242 
243 ${helpers.predefined_type("-moz-script-min-size",
244                           "MozScriptMinSize",
245                           "specified::MozScriptMinSize::get_initial_value()",
246                           animation_value_type="none",
247                           products="gecko",
248                           enabled_in="",
249                           gecko_ffi_name="mScriptMinSize",
250                           spec="Internal (not web-exposed)")}
251 
252 ${helpers.predefined_type("-x-text-zoom",
253                           "XTextZoom",
254                           "computed::XTextZoom(true)",
255                           animation_value_type="none",
256                           products="gecko",
257                           enabled_in="",
258                           spec="Internal (not web-exposed)")}
259 
260 % if product == "gecko":
261     pub mod system_font {
262         //! We deal with system fonts here
263         //!
264         //! System fonts can only be set as a group via the font shorthand.
265         //! They resolve at compute time (not parse time -- this lets the
266         //! browser respond to changes to the OS font settings).
267         //!
268         //! While Gecko handles these as a separate property and keyword
269         //! values on each property indicating that the font should be picked
270         //! from the -x-system-font property, we avoid this. Instead,
271         //! each font longhand has a special SystemFont variant which contains
272         //! the specified system font. When the cascade function (in helpers)
273         //! detects that a value has a system font, it will resolve it, and
274         //! cache it on the ComputedValues. After this, it can be just fetched
275         //! whenever a font longhand on the same element needs the system font.
276 
277         use app_units::Au;
278         use cssparser::{Parser, ToCss};
279         use gecko_bindings::structs::FontFamilyType;
280         use properties::longhands;
281         use std::fmt;
282         use std::hash::{Hash, Hasher};
283         use style_traits::ParseError;
284         use values::computed::{ToComputedValue, Context};
285 
286         <%
287             system_fonts = """caption icon menu message-box small-caption status-bar
288                               -moz-window -moz-document -moz-workspace -moz-desktop
289                               -moz-info -moz-dialog -moz-button -moz-pull-down-menu
290                               -moz-list -moz-field""".split()
291             kw_font_props = """font_style font_variant_caps font_stretch
292                                font_kerning font_variant_position font_variant_ligatures
293                                font_variant_east_asian font_variant_numeric
294                                font_optical_sizing""".split()
295             kw_cast = """font_style font_variant_caps font_stretch
296                          font_kerning font_variant_position
297                          font_optical_sizing""".split()
298         %>
299         #[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq, ToCss)]
300         pub enum SystemFont {
301             % for font in system_fonts:
302                 ${to_camel_case(font)},
303             % endfor
304         }
305 
306         // ComputedValues are compared at times
307         // so we need these impls. We don't want to
308         // add Eq to Number (which contains a float)
309         // so instead we have an eq impl which skips the
310         // cached values
311         impl PartialEq for ComputedSystemFont {
eq(&self, other: &Self) -> bool312             fn eq(&self, other: &Self) -> bool {
313                 self.system_font == other.system_font
314             }
315         }
316         impl Eq for ComputedSystemFont {}
317 
318         impl Hash for ComputedSystemFont {
hash<H: Hasher>(&self, hasher: &mut H)319             fn hash<H: Hasher>(&self, hasher: &mut H) {
320                 self.system_font.hash(hasher)
321             }
322         }
323 
324         impl ToComputedValue for SystemFont {
325             type ComputedValue = ComputedSystemFont;
326 
to_computed_value(&self, cx: &Context) -> Self::ComputedValue327             fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
328                 use gecko_bindings::bindings;
329                 use gecko_bindings::structs::{LookAndFeel_FontID, nsFont};
330                 use std::mem;
331                 use values::computed::font::{FontSize, FontFamilyList};
332 
333                 let id = match *self {
334                     % for font in system_fonts:
335                         SystemFont::${to_camel_case(font)} => {
336                             LookAndFeel_FontID::eFont_${to_camel_case(font.replace("-moz-", ""))}
337                         }
338                     % endfor
339                 };
340 
341                 let mut system: nsFont = unsafe { mem::uninitialized() };
342                 unsafe {
343                     bindings::Gecko_nsFont_InitSystem(
344                         &mut system,
345                         id as i32,
346                         cx.style().get_font().gecko(),
347                         cx.device().pres_context()
348                     )
349                 }
350                 let weight = longhands::font_weight::computed_value::T::from_gecko_weight(system.weight);
351                 let ret = ComputedSystemFont {
352                     font_family: longhands::font_family::computed_value::T(
353                         FontFamilyList(
354                             unsafe { system.fontlist.mFontlist.mBasePtr.to_safe() }
355                         )
356                     ),
357                     font_size: FontSize {
358                             size: Au(system.size).into(),
359                             keyword_info: None
360                     },
361                     font_weight: weight,
362                     font_size_adjust: longhands::font_size_adjust::computed_value
363                                                ::T::from_gecko_adjust(system.sizeAdjust),
364                     % for kwprop in kw_font_props:
365                         ${kwprop}: longhands::${kwprop}::computed_value::T::from_gecko_keyword(
366                             system.${to_camel_case_lower(kwprop.replace('font_', ''))}
367                             % if kwprop in kw_cast:
368                                 as u32
369                             % endif
370                         ),
371                     % endfor
372                     font_language_override: longhands::font_language_override::computed_value
373                                                      ::T(system.languageOverride),
374                     font_feature_settings: longhands::font_feature_settings::get_initial_value(),
375                     font_variation_settings: longhands::font_variation_settings::get_initial_value(),
376                     font_variant_alternates: longhands::font_variant_alternates::get_initial_value(),
377                     system_font: *self,
378                     default_font_type: system.fontlist.mDefaultFontType,
379                 };
380                 unsafe { bindings::Gecko_nsFont_Destroy(&mut system); }
381                 ret
382             }
383 
from_computed_value(_: &ComputedSystemFont) -> Self384             fn from_computed_value(_: &ComputedSystemFont) -> Self {
385                 unreachable!()
386             }
387         }
388 
389         #[inline]
390         /// Compute and cache a system font
391         ///
392         /// Must be called before attempting to compute a system font
393         /// specified value
resolve_system_font(system: SystemFont, context: &mut Context)394         pub fn resolve_system_font(system: SystemFont, context: &mut Context) {
395             // Checking if context.cached_system_font.is_none() isn't enough,
396             // if animating from one system font to another the cached system font
397             // may change
398             if Some(system) != context.cached_system_font.as_ref().map(|x| x.system_font) {
399                 let computed = system.to_computed_value(context);
400                 context.cached_system_font = Some(computed);
401             }
402         }
403 
404         #[derive(Clone, Debug)]
405         pub struct ComputedSystemFont {
406             % for name in SYSTEM_FONT_LONGHANDS:
407                 pub ${name}: longhands::${name}::computed_value::T,
408             % endfor
409             pub system_font: SystemFont,
410             pub default_font_type: FontFamilyType,
411         }
412 
413         impl SystemFont {
parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>>414             pub fn parse<'i, 't>(input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
415                 try_match_ident_ignore_ascii_case! { input,
416                     % for font in system_fonts:
417                         "${font}" => Ok(SystemFont::${to_camel_case(font)}),
418                     % endfor
419                 }
420             }
421         }
422 
423         impl ToCss for SystemFont {
to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write424             fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
425                 // We may want to do something better in the future, see
426                 // w3c/csswg-drafts#1586.
427                 dest.write_str("-moz-use-system-font")
428             }
429         }
430     }
431 % else:
432     pub mod system_font {
433         use cssparser::Parser;
434 
435         // We don't parse system fonts, but in the interest of not littering
436         // a lot of code with `if product == gecko` conditionals, we have a
437         // dummy system font module that does nothing
438 
439         #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, ToCss)]
440         #[cfg_attr(feature = "servo", derive(MallocSizeOf))]
441         /// void enum for system font, can never exist
442         pub enum SystemFont {}
443         impl SystemFont {
parse(_: &mut Parser) -> Result<Self, ()>444             pub fn parse(_: &mut Parser) -> Result<Self, ()> {
445                 Err(())
446             }
447         }
448     }
449 % endif
450 
451 ${helpers.single_keyword("-moz-osx-font-smoothing",
452                          "auto grayscale",
453                          gecko_constant_prefix="NS_FONT_SMOOTHING",
454                          gecko_ffi_name="mFont.smoothing",
455                          gecko_pref="layout.css.osx-font-smoothing.enabled",
456                          products="gecko",
457                          spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/font-smooth)",
458                          flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
459                          animation_value_type="discrete")}
460 
461 ${helpers.predefined_type("-moz-font-smoothing-background-color",
462                           "RGBAColor",
463                           "RGBA::transparent()",
464                           animation_value_type="AnimatedRGBA",
465                           products="gecko",
466                           gecko_ffi_name="mFont.fontSmoothingBackgroundColor",
467                           enabled_in="chrome",
468                           spec="None (Nonstandard internal property)")}
469 
470 ${helpers.predefined_type("-moz-min-font-size-ratio",
471                           "Percentage",
472                           "computed::Percentage::hundred()",
473                           animation_value_type="none",
474                           products="gecko",
475                           enabled_in="ua",
476                           spec="Nonstandard (Internal-only)")}
477