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