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 <%! 6 from data import Keyword, to_rust_ident, to_phys, to_camel_case, SYSTEM_FONT_LONGHANDS 7 from data import (LOGICAL_CORNERS, PHYSICAL_CORNERS, LOGICAL_SIDES, 8 PHYSICAL_SIDES, LOGICAL_SIZES, LOGICAL_AXES) 9 %> 10 11 <%def name="predefined_type(name, type, initial_value, parse_method='parse', 12 vector=False, 13 computed_type=None, initial_specified_value=None, 14 allow_quirks='No', allow_empty=False, **kwargs)"> 15 <%def name="predefined_type_inner(name, type, initial_value, parse_method)"> 16 #[allow(unused_imports)] 17 use app_units::Au; 18 #[allow(unused_imports)] 19 use cssparser::{Color as CSSParserColor, RGBA}; 20 #[allow(unused_imports)] 21 use crate::values::specified::AllowQuirks; 22 #[allow(unused_imports)] 23 use crate::Zero; 24 #[allow(unused_imports)] 25 use smallvec::SmallVec; 26 pub use crate::values::specified::${type} as SpecifiedValue; 27 pub mod computed_value { 28 % if computed_type: 29 pub use ${computed_type} as T; 30 % else: 31 pub use crate::values::computed::${type} as T; 32 % endif 33 } 34 % if initial_value: get_initial_value() -> computed_value::T35 #[inline] pub fn get_initial_value() -> computed_value::T { ${initial_value} } 36 % endif 37 % if initial_specified_value: get_initial_specified_value() -> SpecifiedValue38 #[inline] pub fn get_initial_specified_value() -> SpecifiedValue { ${initial_specified_value} } 39 % endif 40 #[allow(unused_variables)] 41 #[inline] parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<SpecifiedValue, ParseError<'i>>42 pub fn parse<'i, 't>( 43 context: &ParserContext, 44 input: &mut Parser<'i, 't>, 45 ) -> Result<SpecifiedValue, ParseError<'i>> { 46 % if allow_quirks != "No": 47 specified::${type}::${parse_method}_quirky(context, input, AllowQuirks::${allow_quirks}) 48 % elif parse_method != "parse": 49 specified::${type}::${parse_method}(context, input) 50 % else: 51 <specified::${type} as crate::parser::Parse>::parse(context, input) 52 % endif 53 } 54 </%def> 55 % if vector: 56 <%call 57 expr="vector_longhand(name, predefined_type=type, allow_empty=allow_empty or not initial_value, **kwargs)" 58 > 59 ${predefined_type_inner(name, type, initial_value, parse_method)} 60 % if caller: 61 ${caller.body()} 62 % endif 63 </%call> 64 % else: 65 <%call expr="longhand(name, predefined_type=type, **kwargs)"> 66 ${predefined_type_inner(name, type, initial_value, parse_method)} 67 % if caller: 68 ${caller.body()} 69 % endif 70 </%call> 71 % endif 72 </%def> 73 74 // FIXME (Manishearth): Add computed_value_as_specified argument 75 // and handle the empty case correctly 76 <%doc> 77 To be used in cases where we have a grammar like "<thing> [ , <thing> ]*". 78 79 Setting allow_empty to False allows for cases where the vector 80 is empty. The grammar for these is usually "none | <thing> [ , <thing> ]*". 81 We assume that the default/initial value is an empty vector for these. 82 `initial_value` need not be defined for these. 83 </%doc> 84 85 // The setup here is roughly: 86 // 87 // * UnderlyingList is the list that is stored in the computed value. This may 88 // be a shared ArcSlice if the property is inherited. 89 // * UnderlyingOwnedList is the list that is used for animation. 90 // * Specified values always use OwnedSlice, since it's more compact. 91 // * computed_value::List is just a convenient alias that you can use for the 92 // computed value list, since this is in the computed_value module. 93 // 94 // If simple_vector_bindings is true, then we don't use the complex iterator 95 // machinery and set_foo_from, and just compute the value like any other 96 // longhand. 97 <%def name="vector_longhand(name, animation_value_type=None, 98 vector_animation_type=None, allow_empty=False, 99 simple_vector_bindings=False, 100 separator='Comma', 101 **kwargs)"> 102 <%call expr="longhand(name, animation_value_type=animation_value_type, vector=True, 103 simple_vector_bindings=simple_vector_bindings, **kwargs)"> 104 #[allow(unused_imports)] 105 use smallvec::SmallVec; 106 107 pub mod single_value { 108 #[allow(unused_imports)] 109 use cssparser::{Parser, BasicParseError}; 110 #[allow(unused_imports)] 111 use crate::parser::{Parse, ParserContext}; 112 #[allow(unused_imports)] 113 use crate::properties::ShorthandId; 114 #[allow(unused_imports)] 115 use selectors::parser::SelectorParseErrorKind; 116 #[allow(unused_imports)] 117 use style_traits::{ParseError, StyleParseErrorKind}; 118 #[allow(unused_imports)] 119 use crate::values::computed::{Context, ToComputedValue}; 120 #[allow(unused_imports)] 121 use crate::values::{computed, specified}; 122 #[allow(unused_imports)] 123 use crate::values::{Auto, Either, None_}; 124 ${caller.body()} 125 } 126 127 /// The definition of the computed value for ${name}. 128 pub mod computed_value { 129 #[allow(unused_imports)] 130 use crate::values::animated::ToAnimatedValue; 131 #[allow(unused_imports)] 132 use crate::values::resolved::ToResolvedValue; 133 pub use super::single_value::computed_value as single_value; 134 pub use self::single_value::T as SingleComputedValue; 135 % if not allow_empty or allow_empty == "NotInitial": 136 use smallvec::SmallVec; 137 % endif 138 use crate::values::computed::ComputedVecIter; 139 140 <% 141 is_shared_list = allow_empty and allow_empty != "NotInitial" and \ 142 data.longhands_by_name[name].style_struct.inherited 143 %> 144 145 // FIXME(emilio): Add an OwnedNonEmptySlice type, and figure out 146 // something for transition-name, which is the only remaining user 147 // of NotInitial. 148 pub type UnderlyingList<T> = 149 % if allow_empty and allow_empty != "NotInitial": 150 % if data.longhands_by_name[name].style_struct.inherited: 151 crate::ArcSlice<T>; 152 % else: 153 crate::OwnedSlice<T>; 154 % endif 155 % else: 156 SmallVec<[T; 1]>; 157 % endif 158 159 pub type UnderlyingOwnedList<T> = 160 % if allow_empty and allow_empty != "NotInitial": 161 crate::OwnedSlice<T>; 162 % else: 163 SmallVec<[T; 1]>; 164 % endif 165 166 167 /// The generic type defining the animated and resolved values for 168 /// this property. 169 /// 170 /// Making this type generic allows the compiler to figure out the 171 /// animated value for us, instead of having to implement it 172 /// manually for every type we care about. 173 #[derive( 174 Clone, 175 Debug, 176 MallocSizeOf, 177 PartialEq, 178 ToAnimatedValue, 179 ToResolvedValue, 180 ToCss, 181 )] 182 % if separator == "Comma": 183 #[css(comma)] 184 % endif 185 pub struct OwnedList<T>( 186 % if not allow_empty: 187 #[css(iterable)] 188 % else: 189 #[css(if_empty = "none", iterable)] 190 % endif 191 pub UnderlyingOwnedList<T>, 192 ); 193 194 /// The computed value for this property. 195 % if not is_shared_list: 196 pub type ComputedList = OwnedList<single_value::T>; 197 pub use self::OwnedList as List; 198 % else: 199 pub use self::ComputedList as List; 200 201 #[derive( 202 Clone, 203 Debug, 204 MallocSizeOf, 205 PartialEq, 206 ToCss, 207 )] 208 % if separator == "Comma": 209 #[css(comma)] 210 % endif 211 pub struct ComputedList( 212 % if not allow_empty: 213 #[css(iterable)] 214 % else: 215 #[css(if_empty = "none", iterable)] 216 % endif 217 % if is_shared_list: 218 #[ignore_malloc_size_of = "Arc"] 219 % endif 220 pub UnderlyingList<single_value::T>, 221 ); 222 223 type ResolvedList = OwnedList<<single_value::T as ToResolvedValue>::ResolvedValue>; 224 impl ToResolvedValue for ComputedList { 225 type ResolvedValue = ResolvedList; 226 to_resolved_value(self, context: &crate::values::resolved::Context) -> Self::ResolvedValue227 fn to_resolved_value(self, context: &crate::values::resolved::Context) -> Self::ResolvedValue { 228 OwnedList( 229 self.0 230 .iter() 231 .cloned() 232 .map(|v| v.to_resolved_value(context)) 233 .collect() 234 ) 235 } 236 from_resolved_value(resolved: Self::ResolvedValue) -> Self237 fn from_resolved_value(resolved: Self::ResolvedValue) -> Self { 238 % if not is_shared_list: 239 use std::iter::FromIterator; 240 % endif 241 let iter = 242 resolved.0.into_iter().map(ToResolvedValue::from_resolved_value); 243 ComputedList(UnderlyingList::from_iter(iter)) 244 } 245 } 246 % endif 247 248 % if simple_vector_bindings: 249 impl From<ComputedList> for UnderlyingList<single_value::T> { 250 #[inline] from(l: ComputedList) -> Self251 fn from(l: ComputedList) -> Self { 252 l.0 253 } 254 } 255 impl From<UnderlyingList<single_value::T>> for ComputedList { 256 #[inline] from(l: UnderlyingList<single_value::T>) -> Self257 fn from(l: UnderlyingList<single_value::T>) -> Self { 258 List(l) 259 } 260 } 261 % endif 262 263 % if vector_animation_type: 264 % if not animation_value_type: 265 Sorry, this is stupid but needed for now. 266 % endif 267 268 use crate::properties::animated_properties::ListAnimation; 269 use crate::values::animated::{Animate, ToAnimatedZero, Procedure}; 270 use crate::values::distance::{SquaredDistance, ComputeSquaredDistance}; 271 272 // FIXME(emilio): For some reason rust thinks that this alias is 273 // unused, even though it's clearly used below? 274 #[allow(unused)] 275 type AnimatedList = OwnedList<<single_value::T as ToAnimatedValue>::AnimatedValue>; 276 277 % if is_shared_list: 278 impl ToAnimatedValue for ComputedList { 279 type AnimatedValue = AnimatedList; 280 to_animated_value(self) -> Self::AnimatedValue281 fn to_animated_value(self) -> Self::AnimatedValue { 282 OwnedList( 283 self.0.iter().map(|v| v.clone().to_animated_value()).collect() 284 ) 285 } 286 from_animated_value(animated: Self::AnimatedValue) -> Self287 fn from_animated_value(animated: Self::AnimatedValue) -> Self { 288 let iter = 289 animated.0.into_iter().map(ToAnimatedValue::from_animated_value); 290 ComputedList(UnderlyingList::from_iter(iter)) 291 } 292 } 293 % endif 294 295 impl ToAnimatedZero for AnimatedList { to_animated_zero(&self) -> Result<Self, ()>296 fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) } 297 } 298 299 impl Animate for AnimatedList { animate( &self, other: &Self, procedure: Procedure, ) -> Result<Self, ()>300 fn animate( 301 &self, 302 other: &Self, 303 procedure: Procedure, 304 ) -> Result<Self, ()> { 305 Ok(OwnedList( 306 self.0.animate_${vector_animation_type}(&other.0, procedure)? 307 )) 308 } 309 } 310 impl ComputeSquaredDistance for AnimatedList { compute_squared_distance( &self, other: &Self, ) -> Result<SquaredDistance, ()>311 fn compute_squared_distance( 312 &self, 313 other: &Self, 314 ) -> Result<SquaredDistance, ()> { 315 self.0.squared_distance_${vector_animation_type}(&other.0) 316 } 317 } 318 % endif 319 320 /// The computed value, effectively a list of single values. 321 pub use self::ComputedList as T; 322 323 pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>; 324 } 325 326 /// The specified value of ${name}. 327 #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] 328 % if separator == "Comma": 329 #[css(comma)] 330 % endif 331 pub struct SpecifiedValue( 332 % if not allow_empty: 333 #[css(iterable)] 334 % else: 335 #[css(if_empty = "none", iterable)] 336 % endif 337 pub crate::OwnedSlice<single_value::SpecifiedValue>, 338 ); 339 get_initial_value() -> computed_value::T340 pub fn get_initial_value() -> computed_value::T { 341 % if allow_empty and allow_empty != "NotInitial": 342 computed_value::List(Default::default()) 343 % else: 344 let mut v = SmallVec::new(); 345 v.push(single_value::get_initial_value()); 346 computed_value::List(v) 347 % endif 348 } 349 parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<SpecifiedValue, ParseError<'i>>350 pub fn parse<'i, 't>( 351 context: &ParserContext, 352 input: &mut Parser<'i, 't>, 353 ) -> Result<SpecifiedValue, ParseError<'i>> { 354 use style_traits::Separator; 355 356 % if allow_empty: 357 if input.try_parse(|input| input.expect_ident_matching("none")).is_ok() { 358 return Ok(SpecifiedValue(Default::default())) 359 } 360 % endif 361 362 let v = style_traits::${separator}::parse(input, |parser| { 363 single_value::parse(context, parser) 364 })?; 365 Ok(SpecifiedValue(v.into())) 366 } 367 368 pub use self::single_value::SpecifiedValue as SingleSpecifiedValue; 369 370 % if not simple_vector_bindings and engine == "gecko": 371 impl SpecifiedValue { compute_iter<'a, 'cx, 'cx_a>( &'a self, context: &'cx Context<'cx_a>, ) -> computed_value::Iter<'a, 'cx, 'cx_a>372 fn compute_iter<'a, 'cx, 'cx_a>( 373 &'a self, 374 context: &'cx Context<'cx_a>, 375 ) -> computed_value::Iter<'a, 'cx, 'cx_a> { 376 computed_value::Iter::new(context, &self.0) 377 } 378 } 379 % endif 380 381 impl ToComputedValue for SpecifiedValue { 382 type ComputedValue = computed_value::T; 383 384 #[inline] to_computed_value(&self, context: &Context) -> computed_value::T385 fn to_computed_value(&self, context: &Context) -> computed_value::T { 386 % if not is_shared_list: 387 use std::iter::FromIterator; 388 % endif 389 computed_value::List(computed_value::UnderlyingList::from_iter( 390 self.0.iter().map(|i| i.to_computed_value(context)) 391 )) 392 } 393 394 #[inline] from_computed_value(computed: &computed_value::T) -> Self395 fn from_computed_value(computed: &computed_value::T) -> Self { 396 let iter = computed.0.iter().map(ToComputedValue::from_computed_value); 397 SpecifiedValue(iter.collect()) 398 } 399 } 400 </%call> 401 </%def> 402 <%def name="longhand(*args, **kwargs)"> 403 <% 404 property = data.declare_longhand(*args, **kwargs) 405 if property is None: 406 return "" 407 %> 408 /// ${property.spec} 409 pub mod ${property.ident} { 410 #[allow(unused_imports)] 411 use cssparser::{Parser, BasicParseError, Token}; 412 #[allow(unused_imports)] 413 use crate::parser::{Parse, ParserContext}; 414 #[allow(unused_imports)] 415 use crate::properties::{UnparsedValue, ShorthandId}; 416 #[allow(unused_imports)] 417 use crate::values::{Auto, Either, None_}; 418 #[allow(unused_imports)] 419 use crate::error_reporting::ParseErrorReporter; 420 #[allow(unused_imports)] 421 use crate::properties::longhands; 422 #[allow(unused_imports)] 423 use crate::properties::{LonghandId, LonghandIdSet}; 424 #[allow(unused_imports)] 425 use crate::properties::{CSSWideKeyword, ComputedValues, PropertyDeclaration}; 426 #[allow(unused_imports)] 427 use crate::properties::style_structs; 428 #[allow(unused_imports)] 429 use selectors::parser::SelectorParseErrorKind; 430 #[allow(unused_imports)] 431 use servo_arc::Arc; 432 #[allow(unused_imports)] 433 use style_traits::{ParseError, StyleParseErrorKind}; 434 #[allow(unused_imports)] 435 use crate::values::computed::{Context, ToComputedValue}; 436 #[allow(unused_imports)] 437 use crate::values::{computed, generics, specified}; 438 #[allow(unused_imports)] 439 use crate::Atom; 440 ${caller.body()} 441 #[allow(unused_variables)] cascade_property( declaration: &PropertyDeclaration, context: &mut computed::Context, )442 pub fn cascade_property( 443 declaration: &PropertyDeclaration, 444 context: &mut computed::Context, 445 ) { 446 context.for_non_inherited_property = 447 % if property.style_struct.inherited: 448 None; 449 % else: 450 Some(LonghandId::${property.camel_case}); 451 % endif 452 453 let specified_value = match *declaration { 454 PropertyDeclaration::${property.camel_case}(ref value) => value, 455 PropertyDeclaration::CSSWideKeyword(ref declaration) => { 456 debug_assert_eq!(declaration.id, LonghandId::${property.camel_case}); 457 match declaration.keyword { 458 % if not property.style_struct.inherited: 459 CSSWideKeyword::Unset | 460 % endif 461 CSSWideKeyword::Initial => { 462 % if not property.style_struct.inherited: 463 debug_assert!(false, "Should be handled in apply_properties"); 464 % else: 465 context.builder.reset_${property.ident}(); 466 % endif 467 }, 468 % if property.style_struct.inherited: 469 CSSWideKeyword::Unset | 470 % endif 471 CSSWideKeyword::Inherit => { 472 % if property.style_struct.inherited: 473 debug_assert!(false, "Should be handled in apply_properties"); 474 % else: 475 context.rule_cache_conditions.borrow_mut().set_uncacheable(); 476 context.builder.inherit_${property.ident}(); 477 % endif 478 } 479 CSSWideKeyword::Revert => unreachable!("Should never get here"), 480 } 481 return; 482 } 483 PropertyDeclaration::WithVariables(..) => { 484 panic!("variables should already have been substituted") 485 } 486 _ => panic!("entered the wrong cascade_property() implementation"), 487 }; 488 489 % if property.ident in SYSTEM_FONT_LONGHANDS and engine == "gecko": 490 if let Some(sf) = specified_value.get_system() { 491 longhands::system_font::resolve_system_font(sf, context); 492 } 493 % endif 494 495 % if not property.style_struct.inherited and property.logical: 496 context.rule_cache_conditions.borrow_mut() 497 .set_writing_mode_dependency(context.builder.writing_mode); 498 % endif 499 500 % if property.is_vector and not property.simple_vector_bindings and engine == "gecko": 501 // In the case of a vector property we want to pass down an 502 // iterator so that this can be computed without allocation. 503 // 504 // However, computing requires a context, but the style struct 505 // being mutated is on the context. We temporarily remove it, 506 // mutate it, and then put it back. Vector longhands cannot 507 // touch their own style struct whilst computing, else this will 508 // panic. 509 let mut s = 510 context.builder.take_${data.current_style_struct.name_lower}(); 511 { 512 let iter = specified_value.compute_iter(context); 513 s.set_${property.ident}(iter); 514 } 515 context.builder.put_${data.current_style_struct.name_lower}(s); 516 % else: 517 % if property.boxed: 518 let computed = (**specified_value).to_computed_value(context); 519 % else: 520 let computed = specified_value.to_computed_value(context); 521 % endif 522 context.builder.set_${property.ident}(computed) 523 % endif 524 } 525 parse_declared<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<PropertyDeclaration, ParseError<'i>>526 pub fn parse_declared<'i, 't>( 527 context: &ParserContext, 528 input: &mut Parser<'i, 't>, 529 ) -> Result<PropertyDeclaration, ParseError<'i>> { 530 % if property.allow_quirks != "No": 531 parse_quirky(context, input, specified::AllowQuirks::${property.allow_quirks}) 532 % else: 533 parse(context, input) 534 % endif 535 % if property.boxed: 536 .map(Box::new) 537 % endif 538 .map(PropertyDeclaration::${property.camel_case}) 539 } 540 } 541 </%def> 542 543 <%def name="single_keyword_system(name, values, **kwargs)"> 544 <% 545 keyword_kwargs = {a: kwargs.pop(a, None) for a in [ 546 'gecko_constant_prefix', 547 'gecko_enum_prefix', 548 'extra_gecko_values', 549 'extra_servo_2013_values', 550 'extra_servo_2020_values', 551 'custom_consts', 552 'gecko_inexhaustive', 553 ]} 554 keyword = keyword=Keyword(name, values, **keyword_kwargs) 555 %> 556 <%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)"> 557 use crate::values::specified::font::SystemFont; 558 559 pub mod computed_value { 560 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] 561 #[derive( 562 Clone, 563 Copy, 564 Debug, 565 Eq, 566 FromPrimitive, 567 Hash, 568 MallocSizeOf, 569 Parse, 570 PartialEq, 571 SpecifiedValueInfo, 572 ToCss, 573 ToResolvedValue, 574 ToShmem, 575 )] 576 pub enum T { 577 % for value in keyword.values_for(engine): 578 ${to_camel_case(value)}, 579 % endfor 580 } 581 582 ${gecko_keyword_conversion(keyword, keyword.values_for(engine), type="T", cast_to="i32")} 583 } 584 585 #[cfg_attr(feature = "gecko", derive(MallocSizeOf))] 586 #[derive(Clone, Copy, Debug, Eq, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)] 587 pub enum SpecifiedValue { 588 Keyword(computed_value::T), 589 #[css(skip)] 590 System(SystemFont), 591 } 592 parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<SpecifiedValue, ParseError<'i>>593 pub fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<SpecifiedValue, ParseError<'i>> { 594 Ok(SpecifiedValue::Keyword(computed_value::T::parse(input)?)) 595 } 596 597 impl ToComputedValue for SpecifiedValue { 598 type ComputedValue = computed_value::T; to_computed_value(&self, _cx: &Context) -> Self::ComputedValue599 fn to_computed_value(&self, _cx: &Context) -> Self::ComputedValue { 600 match *self { 601 SpecifiedValue::Keyword(v) => v, 602 % if engine == "gecko": 603 SpecifiedValue::System(_) => { 604 _cx.cached_system_font.as_ref().unwrap().${to_rust_ident(name)} 605 } 606 % else: 607 SpecifiedValue::System(system_font) => { 608 match system_font {} 609 } 610 % endif 611 } 612 } from_computed_value(other: &computed_value::T) -> Self613 fn from_computed_value(other: &computed_value::T) -> Self { 614 SpecifiedValue::Keyword(*other) 615 } 616 } 617 618 #[inline] get_initial_value() -> computed_value::T619 pub fn get_initial_value() -> computed_value::T { 620 computed_value::T::${to_camel_case(values.split()[0])} 621 } 622 #[inline] get_initial_specified_value() -> SpecifiedValue623 pub fn get_initial_specified_value() -> SpecifiedValue { 624 SpecifiedValue::Keyword(computed_value::T::${to_camel_case(values.split()[0])}) 625 } 626 627 impl SpecifiedValue { system_font(f: SystemFont) -> Self628 pub fn system_font(f: SystemFont) -> Self { 629 SpecifiedValue::System(f) 630 } get_system(&self) -> Option<SystemFont>631 pub fn get_system(&self) -> Option<SystemFont> { 632 if let SpecifiedValue::System(s) = *self { 633 Some(s) 634 } else { 635 None 636 } 637 } 638 } 639 </%call> 640 </%def> 641 642 <%def name="gecko_keyword_conversion(keyword, values=None, type='SpecifiedValue', cast_to=None)"> 643 <% 644 if not values: 645 values = keyword.values_for(engine) 646 maybe_cast = "as %s" % cast_to if cast_to else "" 647 const_type = cast_to if cast_to else "u32" 648 %> 649 #[cfg(feature = "gecko")] 650 impl ${type} { 651 /// Obtain a specified value from a Gecko keyword value 652 /// 653 /// Intended for use with presentation attributes, not style structs from_gecko_keyword(kw: u32) -> Self654 pub fn from_gecko_keyword(kw: u32) -> Self { 655 use crate::gecko_bindings::structs; 656 % for value in values: 657 // We can't match on enum values if we're matching on a u32 658 const ${to_rust_ident(value).upper()}: ${const_type} 659 = structs::${keyword.gecko_constant(value)} as ${const_type}; 660 % endfor 661 match kw ${maybe_cast} { 662 % for value in values: 663 ${to_rust_ident(value).upper()} => ${type}::${to_camel_case(value)}, 664 % endfor 665 _ => panic!("Found unexpected value in style struct for ${keyword.name} property"), 666 } 667 } 668 } 669 </%def> 670 671 <%def name="gecko_bitflags_conversion(bit_map, gecko_bit_prefix, type, kw_type='u8')"> 672 #[cfg(feature = "gecko")] 673 impl ${type} { 674 /// Obtain a specified value from a Gecko keyword value 675 /// 676 /// Intended for use with presentation attributes, not style structs 677 pub fn from_gecko_keyword(kw: ${kw_type}) -> Self { 678 % for gecko_bit in bit_map.values(): 679 use crate::gecko_bindings::structs::${gecko_bit_prefix}${gecko_bit}; 680 % endfor 681 682 let mut bits = ${type}::empty(); 683 % for servo_bit, gecko_bit in bit_map.items(): 684 if kw & (${gecko_bit_prefix}${gecko_bit} as ${kw_type}) != 0 { 685 bits |= ${servo_bit}; 686 } 687 % endfor 688 bits 689 } 690 to_gecko_keyword(self) -> $691 pub fn to_gecko_keyword(self) -> ${kw_type} { 692 % for gecko_bit in bit_map.values(): 693 use crate::gecko_bindings::structs::${gecko_bit_prefix}${gecko_bit}; 694 % endfor 695 696 let mut bits: ${kw_type} = 0; 697 // FIXME: if we ensure that the Servo bitflags storage is the same 698 // as Gecko's one, we can just copy it. 699 % for servo_bit, gecko_bit in bit_map.items(): 700 if self.contains(${servo_bit}) { 701 bits |= ${gecko_bit_prefix}${gecko_bit} as ${kw_type}; 702 } 703 % endfor 704 bits 705 } 706 } 707 </%def> 708 709 <%def name="single_keyword(name, values, vector=False, 710 needs_conversion=False, **kwargs)"> 711 <% 712 keyword_kwargs = {a: kwargs.pop(a, None) for a in [ 713 'gecko_constant_prefix', 714 'gecko_enum_prefix', 715 'extra_gecko_values', 716 'extra_servo_2013_values', 717 'extra_servo_2020_values', 718 'gecko_aliases', 719 'servo_2013_aliases', 720 'servo_2020_aliases', 721 'custom_consts', 722 'gecko_inexhaustive', 723 'gecko_strip_moz_prefix', 724 ]} 725 %> 726 727 <%def name="inner_body(keyword, needs_conversion=False)"> 728 pub use self::computed_value::T as SpecifiedValue; 729 pub mod computed_value { 730 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] 731 #[derive(Clone, Copy, Debug, Eq, FromPrimitive, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToResolvedValue, ToShmem)] 732 pub enum T { 733 % for variant in keyword.values_for(engine): 734 <% 735 aliases = [] 736 for alias, v in keyword.aliases_for(engine).items(): 737 if variant == v: 738 aliases.append(alias) 739 %> 740 % if aliases: 741 #[parse(aliases = "${','.join(sorted(aliases))}")] 742 % endif 743 ${to_camel_case(variant)}, 744 % endfor 745 } 746 } 747 #[inline] get_initial_value() -> computed_value::T748 pub fn get_initial_value() -> computed_value::T { 749 computed_value::T::${to_camel_case(values.split()[0])} 750 } 751 #[inline] get_initial_specified_value() -> SpecifiedValue752 pub fn get_initial_specified_value() -> SpecifiedValue { 753 SpecifiedValue::${to_camel_case(values.split()[0])} 754 } 755 #[inline] parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<SpecifiedValue, ParseError<'i>>756 pub fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) 757 -> Result<SpecifiedValue, ParseError<'i>> { 758 SpecifiedValue::parse(input) 759 } 760 761 % if needs_conversion: 762 <% 763 conversion_values = keyword.values_for(engine) + list(keyword.aliases_for(engine).keys()) 764 %> 765 ${gecko_keyword_conversion(keyword, values=conversion_values)} 766 % endif 767 </%def> 768 % if vector: 769 <%call expr="vector_longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)"> 770 ${inner_body(Keyword(name, values, **keyword_kwargs))} 771 % if caller: 772 ${caller.body()} 773 % endif 774 </%call> 775 % else: 776 <%call expr="longhand(name, keyword=Keyword(name, values, **keyword_kwargs), **kwargs)"> 777 ${inner_body(Keyword(name, values, **keyword_kwargs), 778 needs_conversion=needs_conversion)} 779 % if caller: 780 ${caller.body()} 781 % endif 782 </%call> 783 % endif 784 </%def> 785 786 <%def name="shorthand(name, sub_properties, derive_serialize=False, 787 derive_value_info=True, **kwargs)"> 788 <% 789 shorthand = data.declare_shorthand(name, sub_properties.split(), **kwargs) 790 # mako doesn't accept non-string value in parameters with <% %> form, so 791 # we have to workaround it this way. 792 if not isinstance(derive_value_info, bool): 793 derive_value_info = eval(derive_value_info) 794 %> 795 % if shorthand: 796 /// ${shorthand.spec} 797 pub mod ${shorthand.ident} { 798 use cssparser::Parser; 799 use crate::parser::ParserContext; 800 use crate::properties::{PropertyDeclaration, SourcePropertyDeclaration, MaybeBoxed, longhands}; 801 #[allow(unused_imports)] 802 use selectors::parser::SelectorParseErrorKind; 803 #[allow(unused_imports)] 804 use std::fmt::{self, Write}; 805 #[allow(unused_imports)] 806 use style_traits::{ParseError, StyleParseErrorKind}; 807 #[allow(unused_imports)] 808 use style_traits::{CssWriter, KeywordsCollectFn, SpecifiedValueInfo, ToCss}; 809 810 % if derive_value_info: 811 #[derive(SpecifiedValueInfo)] 812 % endif 813 pub struct Longhands { 814 % for sub_property in shorthand.sub_properties: 815 pub ${sub_property.ident}: 816 % if sub_property.boxed: 817 Box< 818 % endif 819 longhands::${sub_property.ident}::SpecifiedValue 820 % if sub_property.boxed: 821 > 822 % endif 823 , 824 % endfor 825 } 826 827 /// Represents a serializable set of all of the longhand properties that 828 /// correspond to a shorthand. 829 % if derive_serialize: 830 #[derive(ToCss)] 831 % endif 832 pub struct LonghandsToSerialize<'a> { 833 % for sub_property in shorthand.sub_properties: 834 pub ${sub_property.ident}: 835 % if sub_property.may_be_disabled_in(shorthand, engine): 836 Option< 837 % endif 838 &'a longhands::${sub_property.ident}::SpecifiedValue, 839 % if sub_property.may_be_disabled_in(shorthand, engine): 840 >, 841 % endif 842 % endfor 843 } 844 845 impl<'a> LonghandsToSerialize<'a> { 846 /// Tries to get a serializable set of longhands given a set of 847 /// property declarations. from_iter(iter: impl Iterator<Item = &'a PropertyDeclaration>) -> Result<Self, ()>848 pub fn from_iter(iter: impl Iterator<Item = &'a PropertyDeclaration>) -> Result<Self, ()> { 849 // Define all of the expected variables that correspond to the shorthand 850 % for sub_property in shorthand.sub_properties: 851 let mut ${sub_property.ident} = 852 None::< &'a longhands::${sub_property.ident}::SpecifiedValue>; 853 % endfor 854 855 // Attempt to assign the incoming declarations to the expected variables 856 for declaration in iter { 857 match *declaration { 858 % for sub_property in shorthand.sub_properties: 859 PropertyDeclaration::${sub_property.camel_case}(ref value) => { 860 ${sub_property.ident} = Some(value) 861 }, 862 % endfor 863 _ => {} 864 }; 865 } 866 867 // If any of the expected variables are missing, return an error 868 match ( 869 % for sub_property in shorthand.sub_properties: 870 ${sub_property.ident}, 871 % endfor 872 ) { 873 874 ( 875 % for sub_property in shorthand.sub_properties: 876 % if sub_property.may_be_disabled_in(shorthand, engine): 877 ${sub_property.ident}, 878 % else: 879 Some(${sub_property.ident}), 880 % endif 881 % endfor 882 ) => 883 Ok(LonghandsToSerialize { 884 % for sub_property in shorthand.sub_properties: 885 ${sub_property.ident}, 886 % endfor 887 }), 888 _ => Err(()) 889 } 890 } 891 } 892 893 /// Parse the given shorthand and fill the result into the 894 /// `declarations` vector. parse_into<'i, 't>( declarations: &mut SourcePropertyDeclaration, context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<(), ParseError<'i>>895 pub fn parse_into<'i, 't>( 896 declarations: &mut SourcePropertyDeclaration, 897 context: &ParserContext, 898 input: &mut Parser<'i, 't>, 899 ) -> Result<(), ParseError<'i>> { 900 #[allow(unused_imports)] 901 use crate::properties::{NonCustomPropertyId, LonghandId}; 902 input.parse_entirely(|input| parse_value(context, input)).map(|longhands| { 903 % for sub_property in shorthand.sub_properties: 904 % if sub_property.may_be_disabled_in(shorthand, engine): 905 if NonCustomPropertyId::from(LonghandId::${sub_property.camel_case}) 906 .allowed_in_ignoring_rule_type(context) { 907 % endif 908 declarations.push(PropertyDeclaration::${sub_property.camel_case}( 909 longhands.${sub_property.ident} 910 )); 911 % if sub_property.may_be_disabled_in(shorthand, engine): 912 } 913 % endif 914 % endfor 915 }) 916 } 917 918 /// Try to serialize a given shorthand to a string. to_css(declarations: &[&PropertyDeclaration], dest: &mut crate::str::CssStringWriter) -> fmt::Result919 pub fn to_css(declarations: &[&PropertyDeclaration], dest: &mut crate::str::CssStringWriter) -> fmt::Result { 920 match LonghandsToSerialize::from_iter(declarations.iter().cloned()) { 921 Ok(longhands) => longhands.to_css(&mut CssWriter::new(dest)), 922 Err(_) => Ok(()) 923 } 924 } 925 926 ${caller.body()} 927 } 928 % endif 929 </%def> 930 931 // A shorthand of kind `<property-1> <property-2>?` where both properties have 932 // the same type. 933 <%def name="two_properties_shorthand( 934 name, 935 first_property, 936 second_property, 937 parser_function='crate::parser::Parse::parse', 938 **kwargs 939 )"> 940 <%call expr="self.shorthand(name, sub_properties=' '.join([first_property, second_property]), **kwargs)"> 941 #[allow(unused_imports)] 942 use crate::parser::Parse; 943 #[allow(unused_imports)] 944 use crate::values::specified; 945 parse_value<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Longhands, ParseError<'i>>946 fn parse_value<'i, 't>( 947 context: &ParserContext, 948 input: &mut Parser<'i, 't>, 949 ) -> Result<Longhands, ParseError<'i>> { 950 let parse_one = |c: &ParserContext, input: &mut Parser<'i, 't>| -> Result< 951 crate::properties::longhands::${to_rust_ident(first_property)}::SpecifiedValue, 952 ParseError<'i> 953 > { 954 ${parser_function}(c, input) 955 }; 956 957 let first = parse_one(context, input)?; 958 let second = 959 input.try_parse(|input| parse_one(context, input)).unwrap_or_else(|_| first.clone()); 960 Ok(expanded! { 961 ${to_rust_ident(first_property)}: first, 962 ${to_rust_ident(second_property)}: second, 963 }) 964 } 965 966 impl<'a> ToCss for LonghandsToSerialize<'a> { to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write967 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write { 968 let first = &self.${to_rust_ident(first_property)}; 969 let second = &self.${to_rust_ident(second_property)}; 970 971 first.to_css(dest)?; 972 if first != second { 973 dest.write_str(" ")?; 974 second.to_css(dest)?; 975 } 976 Ok(()) 977 } 978 } 979 </%call> 980 </%def> 981 982 <%def name="four_sides_shorthand(name, sub_property_pattern, 983 parser_function='crate::parser::Parse::parse', 984 allow_quirks='No', **kwargs)"> 985 <% sub_properties=' '.join(sub_property_pattern % side for side in PHYSICAL_SIDES) %> 986 <%call expr="self.shorthand(name, sub_properties=sub_properties, **kwargs)"> 987 #[allow(unused_imports)] 988 use crate::parser::Parse; 989 use crate::values::generics::rect::Rect; 990 #[allow(unused_imports)] 991 use crate::values::specified; 992 parse_value<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result<Longhands, ParseError<'i>>993 fn parse_value<'i, 't>( 994 context: &ParserContext, 995 input: &mut Parser<'i, 't>, 996 ) -> Result<Longhands, ParseError<'i>> { 997 let rect = Rect::parse_with(context, input, |c, i| -> Result< 998 crate::properties::longhands::${to_rust_ident(sub_property_pattern % "top")}::SpecifiedValue, 999 ParseError<'i> 1000 > { 1001 % if allow_quirks != "No": 1002 ${parser_function}_quirky(c, i, specified::AllowQuirks::${allow_quirks}) 1003 % else: 1004 ${parser_function}(c, i) 1005 % endif 1006 })?; 1007 Ok(expanded! { 1008 % for index, side in enumerate(["top", "right", "bottom", "left"]): 1009 ${to_rust_ident(sub_property_pattern % side)}: rect.${index}, 1010 % endfor 1011 }) 1012 } 1013 1014 impl<'a> ToCss for LonghandsToSerialize<'a> { to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: Write,1015 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result 1016 where 1017 W: Write, 1018 { 1019 let rect = Rect::new( 1020 % for side in ["top", "right", "bottom", "left"]: 1021 &self.${to_rust_ident(sub_property_pattern % side)}, 1022 % endfor 1023 ); 1024 rect.to_css(dest) 1025 } 1026 } 1027 </%call> 1028 </%def> 1029 1030 <%def name="logical_setter_helper(name)"> 1031 <% 1032 side = None 1033 size = None 1034 corner = None 1035 axis = None 1036 maybe_side = [s for s in LOGICAL_SIDES if s in name] 1037 maybe_size = [s for s in LOGICAL_SIZES if s in name] 1038 maybe_corner = [s for s in LOGICAL_CORNERS if s in name] 1039 maybe_axis = [s for s in LOGICAL_AXES if name.endswith(s)] 1040 if len(maybe_side) == 1: 1041 side = maybe_side[0] 1042 elif len(maybe_size) == 1: 1043 size = maybe_size[0] 1044 elif len(maybe_corner) == 1: 1045 corner = maybe_corner[0] 1046 elif len(maybe_axis) == 1: 1047 axis = maybe_axis[0] 1048 def phys_ident(side, phy_side): 1049 return to_rust_ident(to_phys(name, side, phy_side)) 1050 %> 1051 % if side is not None: 1052 use crate::logical_geometry::PhysicalSide; 1053 match wm.${to_rust_ident(side)}_physical_side() { 1054 % for phy_side in PHYSICAL_SIDES: 1055 PhysicalSide::${phy_side.title()} => { 1056 ${caller.inner(physical_ident=phys_ident(side, phy_side))} 1057 } 1058 % endfor 1059 } 1060 % elif corner is not None: 1061 use crate::logical_geometry::PhysicalCorner; 1062 match wm.${to_rust_ident(corner)}_physical_corner() { 1063 % for phy_corner in PHYSICAL_CORNERS: 1064 PhysicalCorner::${to_camel_case(phy_corner)} => { 1065 ${caller.inner(physical_ident=phys_ident(corner, phy_corner))} 1066 } 1067 % endfor 1068 } 1069 % elif size is not None: 1070 <% 1071 # (horizontal, vertical) 1072 physical_size = ("height", "width") 1073 if size == "inline-size": 1074 physical_size = ("width", "height") 1075 %> 1076 if wm.is_vertical() { 1077 ${caller.inner(physical_ident=phys_ident(size, physical_size[1]))} 1078 } else { 1079 ${caller.inner(physical_ident=phys_ident(size, physical_size[0]))} 1080 } 1081 % elif axis is not None: 1082 <% 1083 if axis == "inline": 1084 me, other = "x", "y" 1085 else: 1086 assert(axis == "block") 1087 me, other = "y", "x" 1088 %> 1089 if wm.is_vertical() { 1090 ${caller.inner(physical_ident=phys_ident(axis, other))} 1091 } else { 1092 ${caller.inner(physical_ident=phys_ident(axis, me))} 1093 } 1094 % else: 1095 <% raise Exception("Don't know what to do with logical property %s" % name) %> 1096 % endif 1097 </%def> 1098 1099 <%def name="logical_setter(name)"> 1100 /// Set the appropriate physical property for ${name} given a writing mode. 1101 pub fn set_${to_rust_ident(name)}(&mut self, 1102 v: longhands::${to_rust_ident(name)}::computed_value::T, 1103 wm: WritingMode) { 1104 <%self:logical_setter_helper name="${name}"> 1105 <%def name="inner(physical_ident)"> 1106 self.set_${physical_ident}(v) 1107 </%def> 1108 </%self:logical_setter_helper> 1109 } 1110 1111 /// Copy the appropriate physical property from another struct for ${name} 1112 /// given a writing mode. 1113 pub fn copy_${to_rust_ident(name)}_from(&mut self, 1114 other: &Self, 1115 wm: WritingMode) { 1116 <%self:logical_setter_helper name="${name}"> 1117 <%def name="inner(physical_ident)"> 1118 self.copy_${physical_ident}_from(other) 1119 </%def> 1120 </%self:logical_setter_helper> 1121 } 1122 1123 /// Copy the appropriate physical property from another struct for ${name} 1124 /// given a writing mode. 1125 pub fn reset_${to_rust_ident(name)}(&mut self, 1126 other: &Self, 1127 wm: WritingMode) { 1128 self.copy_${to_rust_ident(name)}_from(other, wm) 1129 } 1130 1131 /// Get the computed value for the appropriate physical property for 1132 /// ${name} given a writing mode. 1133 pub fn clone_${to_rust_ident(name)}(&self, wm: WritingMode) 1134 -> longhands::${to_rust_ident(name)}::computed_value::T { 1135 <%self:logical_setter_helper name="${name}"> 1136 <%def name="inner(physical_ident)"> 1137 self.clone_${physical_ident}() 1138 </%def> 1139 </%self:logical_setter_helper> 1140 } 1141 </%def> 1142