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