gecko.mako.rs (51334B)
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 // `data` comes from components/style/properties.mako.rs; see build.rs for more details. 6 7 <%! 8 from data import to_camel_case, to_camel_case_lower 9 from data import Keyword 10 %> 11 <%namespace name="helpers" file="/helpers.mako.rs" /> 12 13 use crate::Atom; 14 use crate::logical_geometry::PhysicalSide; 15 use crate::computed_value_flags::*; 16 use crate::custom_properties::ComputedCustomProperties; 17 use crate::gecko_bindings::bindings; 18 % for style_struct in data.style_structs: 19 use crate::gecko_bindings::bindings::Gecko_Construct_Default_${style_struct.gecko_ffi_name}; 20 use crate::gecko_bindings::bindings::Gecko_CopyConstruct_${style_struct.gecko_ffi_name}; 21 use crate::gecko_bindings::bindings::Gecko_Destroy_${style_struct.gecko_ffi_name}; 22 % endfor 23 use crate::gecko_bindings::bindings::Gecko_EnsureImageLayersLength; 24 use crate::gecko_bindings::bindings::Gecko_nsStyleFont_SetLang; 25 use crate::gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom; 26 use crate::gecko_bindings::structs; 27 use crate::gecko_bindings::structs::mozilla::PseudoStyleType; 28 use crate::gecko::data::PerDocumentStyleData; 29 use crate::logical_geometry::WritingMode; 30 use crate::media_queries::Device; 31 use crate::properties::longhands; 32 use crate::rule_tree::StrongRuleNode; 33 use crate::selector_parser::PseudoElement; 34 use servo_arc::{Arc, UniqueArc}; 35 use std::mem::{forget, MaybeUninit, ManuallyDrop}; 36 use std::{ops, ptr}; 37 use crate::values; 38 use crate::values::computed::{Time, Zoom}; 39 use crate::values::computed::font::FontSize; 40 41 42 pub mod style_structs { 43 % for style_struct in data.style_structs: 44 pub use super::${style_struct.gecko_struct_name} as ${style_struct.name}; 45 46 unsafe impl Send for ${style_struct.name} {} 47 unsafe impl Sync for ${style_struct.name} {} 48 % endfor 49 } 50 51 /// FIXME(emilio): This is completely duplicated with the other properties code. 52 pub type ComputedValuesInner = structs::ServoComputedData; 53 54 #[repr(C)] 55 pub struct ComputedValues(structs::mozilla::ComputedStyle); 56 57 impl ComputedValues { 58 #[inline] 59 pub (crate) fn as_gecko_computed_style(&self) -> &structs::ComputedStyle { 60 &self.0 61 } 62 63 pub fn new( 64 pseudo: Option<&PseudoElement>, 65 custom_properties: ComputedCustomProperties, 66 writing_mode: WritingMode, 67 effective_zoom: Zoom, 68 flags: ComputedValueFlags, 69 rules: Option<StrongRuleNode>, 70 visited_style: Option<Arc<ComputedValues>>, 71 % for style_struct in data.style_structs: 72 ${style_struct.ident}: Arc<style_structs::${style_struct.name}>, 73 % endfor 74 ) -> Arc<Self> { 75 ComputedValuesInner::new( 76 custom_properties, 77 writing_mode, 78 effective_zoom, 79 flags, 80 rules, 81 visited_style, 82 % for style_struct in data.style_structs: 83 ${style_struct.ident}, 84 % endfor 85 ).to_outer(pseudo) 86 } 87 88 pub fn default_values(doc: &structs::Document) -> Arc<Self> { 89 ComputedValuesInner::new( 90 ComputedCustomProperties::default(), 91 WritingMode::empty(), // FIXME(bz): This seems dubious 92 Zoom::ONE, 93 ComputedValueFlags::empty(), 94 /* rules = */ None, 95 /* visited_style = */ None, 96 % for style_struct in data.style_structs: 97 style_structs::${style_struct.name}::default(doc), 98 % endfor 99 ).to_outer(None) 100 } 101 102 /// Converts the computed values to an Arc<> from a reference. 103 pub fn to_arc(&self) -> Arc<Self> { 104 // SAFETY: We're guaranteed to be allocated as an Arc<> since the 105 // functions above are the only ones that create ComputedValues 106 // instances in Gecko (and that must be the case since ComputedValues' 107 // member is private). 108 unsafe { Arc::from_raw_addrefed(self) } 109 } 110 111 #[inline] 112 pub fn is_pseudo_style(&self) -> bool { 113 self.0.mPseudoType != PseudoStyleType::NotPseudo 114 } 115 116 #[inline] 117 pub fn pseudo(&self) -> Option<PseudoElement> { 118 if !self.is_pseudo_style() { 119 return None; 120 } 121 PseudoElement::from_pseudo_type(self.0.mPseudoType, None) 122 } 123 124 #[inline] 125 pub fn is_first_line_style(&self) -> bool { 126 self.pseudo() == Some(PseudoElement::FirstLine) 127 } 128 129 /// Returns true if the display property is changed from 'none' to others. 130 pub fn is_display_property_changed_from_none( 131 &self, 132 old_values: Option<&ComputedValues> 133 ) -> bool { 134 use crate::properties::longhands::display::computed_value::T as Display; 135 136 old_values.map_or(false, |old| { 137 let old_display_style = old.get_box().clone_display(); 138 let new_display_style = self.get_box().clone_display(); 139 old_display_style == Display::None && 140 new_display_style != Display::None 141 }) 142 } 143 144 } 145 146 impl Drop for ComputedValues { 147 fn drop(&mut self) { 148 // XXX this still relies on the destructor of ComputedValuesInner to run on the rust side, 149 // that's pretty wild. 150 unsafe { 151 bindings::Gecko_ComputedStyle_Destroy(&mut self.0); 152 } 153 } 154 } 155 156 unsafe impl Sync for ComputedValues {} 157 unsafe impl Send for ComputedValues {} 158 159 impl Drop for ComputedValuesInner { 160 fn drop(&mut self) { 161 % for style_struct in data.style_structs: 162 let _ = unsafe { Arc::from_raw(self.${style_struct.name_lower}_ptr()) }; 163 % endfor 164 if !self.visited_style.is_null() { 165 let _ = unsafe { Arc::from_raw(self.visited_style_ptr()) }; 166 } 167 } 168 } 169 170 impl ComputedValuesInner { 171 pub fn new( 172 custom_properties: ComputedCustomProperties, 173 writing_mode: WritingMode, 174 effective_zoom: Zoom, 175 flags: ComputedValueFlags, 176 rules: Option<StrongRuleNode>, 177 visited_style: Option<Arc<ComputedValues>>, 178 % for style_struct in data.style_structs: 179 ${style_struct.ident}: Arc<style_structs::${style_struct.name}>, 180 % endfor 181 ) -> Self { 182 Self { 183 custom_properties, 184 writing_mode, 185 rules, 186 visited_style: visited_style.map_or(ptr::null(), |p| Arc::into_raw(p)) as *const _, 187 flags, 188 effective_zoom, 189 % for style_struct in data.style_structs: 190 ${style_struct.gecko_name}: Arc::into_raw(${style_struct.ident}) as *const _, 191 % endfor 192 } 193 } 194 195 fn to_outer(self, pseudo: Option<&PseudoElement>) -> Arc<ComputedValues> { 196 let pseudo_ty = match pseudo { 197 Some(p) => p.pseudo_type_and_argument().0, 198 None => structs::PseudoStyleType::NotPseudo, 199 }; 200 unsafe { 201 let mut arc = UniqueArc::<ComputedValues>::new_uninit(); 202 bindings::Gecko_ComputedStyle_Init( 203 arc.as_mut_ptr() as *mut _, 204 &self, 205 pseudo_ty, 206 ); 207 // We're simulating move semantics by having C++ do a memcpy and 208 // then forgetting it on this end. 209 forget(self); 210 UniqueArc::assume_init(arc).shareable() 211 } 212 } 213 } 214 215 impl ops::Deref for ComputedValues { 216 type Target = ComputedValuesInner; 217 #[inline] 218 fn deref(&self) -> &ComputedValuesInner { 219 &self.0.mSource 220 } 221 } 222 223 impl ops::DerefMut for ComputedValues { 224 #[inline] 225 fn deref_mut(&mut self) -> &mut ComputedValuesInner { 226 &mut self.0.mSource 227 } 228 } 229 230 impl ComputedValuesInner { 231 /// Returns true if the value of the `content` property would make a 232 /// pseudo-element not rendered. 233 #[inline] 234 pub fn ineffective_content_property(&self) -> bool { 235 self.get_counters().ineffective_content_property() 236 } 237 238 #[inline] 239 fn visited_style_ptr(&self) -> *const ComputedValues { 240 self.visited_style as *const _ 241 } 242 243 /// Returns the visited style, if any. 244 pub fn visited_style(&self) -> Option<&ComputedValues> { 245 unsafe { self.visited_style_ptr().as_ref() } 246 } 247 248 % for style_struct in data.style_structs: 249 #[inline] 250 fn ${style_struct.name_lower}_ptr(&self) -> *const style_structs::${style_struct.name} { 251 // This is sound because the wrapper we create is repr(transparent). 252 self.${style_struct.gecko_name} as *const _ 253 } 254 255 #[inline] 256 pub fn get_${style_struct.name_lower}(&self) -> &style_structs::${style_struct.name} { 257 unsafe { &*self.${style_struct.name_lower}_ptr() } 258 } 259 % endfor 260 } 261 262 <%def name="impl_simple_setter(ident, gecko_ffi_name)"> 263 #[allow(non_snake_case)] 264 pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { 265 ${set_gecko_property(gecko_ffi_name, "From::from(v)")} 266 } 267 </%def> 268 269 <%def name="impl_simple_clone(ident, gecko_ffi_name)"> 270 #[allow(non_snake_case)] 271 pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { 272 From::from(self.${gecko_ffi_name}.clone()) 273 } 274 </%def> 275 276 <%def name="impl_physical_sides(ident, props)"> 277 pub fn get_${ident}(&self, s: PhysicalSide) -> &longhands::${data.longhands_by_name[props[0]].ident}::computed_value::T { 278 match s { 279 PhysicalSide::Top => &self.${data.longhands_by_name[props[0]].gecko_ffi_name}, 280 PhysicalSide::Right => &self.${data.longhands_by_name[props[1]].gecko_ffi_name}, 281 PhysicalSide::Bottom => &self.${data.longhands_by_name[props[2]].gecko_ffi_name}, 282 PhysicalSide::Left => &self.${data.longhands_by_name[props[3]].gecko_ffi_name}, 283 } 284 } 285 pub fn set_${ident}(&mut self, s: PhysicalSide, v: longhands::${data.longhands_by_name[props[0]].ident}::computed_value::T) { 286 match s { 287 PhysicalSide::Top => self.set_${data.longhands_by_name[props[0]].ident}(v), 288 PhysicalSide::Right => self.set_${data.longhands_by_name[props[1]].ident}(v), 289 PhysicalSide::Bottom => self.set_${data.longhands_by_name[props[2]].ident}(v), 290 PhysicalSide::Left => self.set_${data.longhands_by_name[props[3]].ident}(v), 291 } 292 } 293 </%def> 294 295 <%def name="impl_simple_copy(ident, gecko_ffi_name, *kwargs)"> 296 #[allow(non_snake_case)] 297 pub fn copy_${ident}_from(&mut self, other: &Self) { 298 self.${gecko_ffi_name} = other.${gecko_ffi_name}.clone(); 299 } 300 301 #[allow(non_snake_case)] 302 pub fn reset_${ident}(&mut self, other: &Self) { 303 self.copy_${ident}_from(other) 304 } 305 </%def> 306 307 <%! 308 def get_gecko_property(ffi_name, self_param = "self"): 309 return "%s.%s" % (self_param, ffi_name) 310 311 def set_gecko_property(ffi_name, expr): 312 return "self.%s = %s;" % (ffi_name, expr) 313 %> 314 315 <%def name="impl_keyword_setter(ident, gecko_ffi_name, keyword, cast_type='u8')"> 316 #[allow(non_snake_case)] 317 pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { 318 use crate::properties::longhands::${ident}::computed_value::T as Keyword; 319 // FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts 320 let result = match v { 321 % for value in keyword.values_for('gecko'): 322 Keyword::${to_camel_case(value)} => 323 structs::${keyword.gecko_constant(value)} ${keyword.maybe_cast(cast_type)}, 324 % endfor 325 }; 326 ${set_gecko_property(gecko_ffi_name, "result")} 327 } 328 </%def> 329 330 <%def name="impl_keyword_clone(ident, gecko_ffi_name, keyword, cast_type='u8')"> 331 #[allow(non_snake_case)] 332 pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { 333 use crate::properties::longhands::${ident}::computed_value::T as Keyword; 334 // FIXME(bholley): Align binary representations and ditch |match| for cast + static_asserts 335 336 // Some constant macros in the gecko are defined as negative integer(e.g. font-stretch). 337 // And they are convert to signed integer in Rust bindings. We need to cast then 338 // as signed type when we have both signed/unsigned integer in order to use them 339 // as match's arms. 340 // Also, to use same implementation here we use casted constant if we have only singed values. 341 % if keyword.gecko_enum_prefix is None: 342 % for value in keyword.values_for('gecko'): 343 const ${keyword.casted_constant_name(value, cast_type)} : ${cast_type} = 344 structs::${keyword.gecko_constant(value)} as ${cast_type}; 345 % endfor 346 347 match ${get_gecko_property(gecko_ffi_name)} as ${cast_type} { 348 % for value in keyword.values_for('gecko'): 349 ${keyword.casted_constant_name(value, cast_type)} => Keyword::${to_camel_case(value)}, 350 % endfor 351 % if keyword.gecko_inexhaustive: 352 _ => panic!("Found unexpected value in style struct for ${ident} property"), 353 % endif 354 } 355 % else: 356 match ${get_gecko_property(gecko_ffi_name)} { 357 % for value in keyword.values_for('gecko'): 358 structs::${keyword.gecko_constant(value)} => Keyword::${to_camel_case(value)}, 359 % endfor 360 % if keyword.gecko_inexhaustive: 361 _ => panic!("Found unexpected value in style struct for ${ident} property"), 362 % endif 363 } 364 % endif 365 } 366 </%def> 367 368 <%def name="impl_keyword(ident, gecko_ffi_name, keyword, cast_type='u8', **kwargs)"> 369 <%call expr="impl_keyword_setter(ident, gecko_ffi_name, keyword, cast_type, **kwargs)"></%call> 370 <%call expr="impl_simple_copy(ident, gecko_ffi_name, **kwargs)"></%call> 371 <%call expr="impl_keyword_clone(ident, gecko_ffi_name, keyword, cast_type)"></%call> 372 </%def> 373 374 <%def name="impl_simple(ident, gecko_ffi_name)"> 375 <%call expr="impl_simple_setter(ident, gecko_ffi_name)"></%call> 376 <%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call> 377 <%call expr="impl_simple_clone(ident, gecko_ffi_name)"></%call> 378 </%def> 379 380 <%def name="impl_border_width(ident, gecko_ffi_name, inherit_from)"> 381 #[allow(non_snake_case)] 382 pub fn set_${ident}(&mut self, v: Au) { 383 let value = v.0; 384 self.${inherit_from} = value; 385 self.${gecko_ffi_name} = value; 386 } 387 388 #[allow(non_snake_case)] 389 pub fn copy_${ident}_from(&mut self, other: &Self) { 390 self.${inherit_from} = other.${inherit_from}; 391 // NOTE: This is needed to easily handle the `unset` and `initial` 392 // keywords, which are implemented calling this function. 393 // 394 // In practice, this means that we may have an incorrect value here, but 395 // we'll adjust that properly in the style fixup phase. 396 // 397 // FIXME(emilio): We could clean this up a bit special-casing the reset_ 398 // function below. 399 self.${gecko_ffi_name} = other.${inherit_from}; 400 } 401 402 #[allow(non_snake_case)] 403 pub fn reset_${ident}(&mut self, other: &Self) { 404 self.copy_${ident}_from(other) 405 } 406 407 #[allow(non_snake_case)] 408 pub fn clone_${ident}(&self) -> Au { 409 Au(self.${gecko_ffi_name}) 410 } 411 </%def> 412 413 <%def name="impl_style_struct(style_struct)"> 414 /// A wrapper for ${style_struct.gecko_ffi_name}, to be able to manually construct / destruct / 415 /// clone it. 416 #[repr(transparent)] 417 pub struct ${style_struct.gecko_struct_name}(ManuallyDrop<structs::${style_struct.gecko_ffi_name}>); 418 419 impl ops::Deref for ${style_struct.gecko_struct_name} { 420 type Target = structs::${style_struct.gecko_ffi_name}; 421 #[inline] 422 fn deref(&self) -> &Self::Target { 423 &self.0 424 } 425 } 426 427 impl ops::DerefMut for ${style_struct.gecko_struct_name} { 428 #[inline] 429 fn deref_mut(&mut self) -> &mut <Self as ops::Deref>::Target { 430 &mut self.0 431 } 432 } 433 434 impl ${style_struct.gecko_struct_name} { 435 #[allow(dead_code, unused_variables)] 436 pub fn default(document: &structs::Document) -> Arc<Self> { 437 % if style_struct.document_dependent: 438 unsafe { 439 let mut result = UniqueArc::<Self>::new_uninit(); 440 Gecko_Construct_Default_${style_struct.gecko_ffi_name}( 441 result.as_mut_ptr() as *mut _, 442 document, 443 ); 444 UniqueArc::assume_init(result).shareable() 445 } 446 % else: 447 static DEFAULT: std::sync::LazyLock<Arc<${style_struct.gecko_struct_name}>> = std::sync::LazyLock::new(|| unsafe { 448 let mut result = UniqueArc::<${style_struct.gecko_struct_name}>::new_uninit(); 449 Gecko_Construct_Default_${style_struct.gecko_ffi_name}( 450 result.as_mut_ptr() as *mut _, 451 std::ptr::null(), 452 ); 453 let arc = UniqueArc::assume_init(result).shareable(); 454 arc.mark_as_intentionally_leaked(); 455 arc 456 }); 457 DEFAULT.clone() 458 % endif 459 } 460 } 461 462 impl Drop for ${style_struct.gecko_struct_name} { 463 fn drop(&mut self) { 464 unsafe { 465 Gecko_Destroy_${style_struct.gecko_ffi_name}(&mut **self); 466 } 467 } 468 } 469 impl Clone for ${style_struct.gecko_struct_name} { 470 fn clone(&self) -> Self { 471 unsafe { 472 let mut result = MaybeUninit::<Self>::uninit(); 473 // FIXME(bug 1595895): Zero the memory to keep valgrind happy, but 474 // these looks like Valgrind false-positives at a quick glance. 475 ptr::write_bytes::<Self>(result.as_mut_ptr(), 0, 1); 476 Gecko_CopyConstruct_${style_struct.gecko_ffi_name}(result.as_mut_ptr() as *mut _, &**self); 477 result.assume_init() 478 } 479 } 480 } 481 </%def> 482 483 <%def name="impl_font_settings(ident, gecko_type, tag_type, value_type, gecko_value_type)"> 484 <% gecko_ffi_name = to_camel_case_lower(ident) %> 485 486 pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { 487 let iter = v.0.iter().map(|other| structs::${gecko_type} { 488 mTag: other.tag.0, 489 mValue: other.value as ${gecko_value_type}, 490 }); 491 self.mFont.${gecko_ffi_name}.clear(); 492 self.mFont.${gecko_ffi_name}.extend(iter); 493 } 494 495 <% impl_simple_copy(ident, "mFont." + gecko_ffi_name) %> 496 497 pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { 498 use crate::values::generics::font::{FontSettings, FontTag, ${tag_type}}; 499 500 FontSettings( 501 self.mFont.${gecko_ffi_name}.iter().map(|gecko_font_setting| { 502 ${tag_type} { 503 tag: FontTag(gecko_font_setting.mTag), 504 value: gecko_font_setting.mValue as ${value_type}, 505 } 506 }).collect() 507 ) 508 } 509 </%def> 510 511 <%def name="impl_trait(style_struct_name, skip_longhands='')"> 512 <% 513 style_struct = next(x for x in data.style_structs if x.name == style_struct_name) 514 longhands = [x for x in style_struct.longhands 515 if not (skip_longhands == "*" or x.name in skip_longhands.split())] 516 517 def longhand_method(longhand): 518 args = dict(ident=longhand.ident, gecko_ffi_name=longhand.gecko_ffi_name) 519 520 if longhand.logical: 521 return 522 # get the method and pass additional keyword or type-specific arguments 523 if longhand.keyword: 524 method = impl_keyword 525 args.update(keyword=longhand.keyword) 526 if "font" in longhand.ident: 527 args.update(cast_type=longhand.cast_type) 528 else: 529 method = impl_simple 530 531 method(**args) 532 %> 533 impl ${style_struct.gecko_struct_name} { 534 /* 535 * Manually-Implemented Methods. 536 */ 537 ${caller.body().strip()} 538 539 /* 540 * Auto-Generated Methods. 541 */ 542 <% 543 for longhand in longhands: 544 longhand_method(longhand) 545 %> 546 } 547 </%def> 548 549 <%! 550 class Side(object): 551 def __init__(self, name, index): 552 self.name = name 553 self.ident = name.lower() 554 self.index = index 555 556 SIDES = [Side("Top", 0), Side("Right", 1), Side("Bottom", 2), Side("Left", 3)] 557 %> 558 559 #[allow(dead_code)] 560 fn static_assert() { 561 // Note: using the above technique with an enum hits a rust bug when |structs| is in a different crate. 562 % for side in SIDES: 563 { const DETAIL: u32 = [0][(structs::Side::eSide${side.name} as usize != ${side.index}) as usize]; let _ = DETAIL; } 564 % endfor 565 } 566 567 568 <%self:impl_trait style_struct_name="Border"> 569 </%self:impl_trait> 570 571 <%self:impl_trait style_struct_name="Margin"> 572 ${impl_physical_sides("margin", ["margin-top", "margin-right", "margin-bottom", "margin-left"])} 573 </%self:impl_trait> 574 <%self:impl_trait style_struct_name="Padding"></%self:impl_trait> 575 <%self:impl_trait style_struct_name="Page"></%self:impl_trait> 576 577 <%self:impl_trait style_struct_name="Position"> 578 ${impl_physical_sides("inset", ["top", "right", "bottom", "left"])} 579 pub fn set_computed_justify_items(&mut self, v: values::specified::JustifyItems) { 580 debug_assert_ne!(v, values::specified::JustifyItems::legacy()); 581 self.mJustifyItems.computed = v; 582 } 583 </%self:impl_trait> 584 585 <%self:impl_trait style_struct_name="Outline"> 586 </%self:impl_trait> 587 588 <% skip_font_longhands = """font-size -x-lang font-feature-settings font-variation-settings""" %> 589 <%self:impl_trait style_struct_name="Font" 590 skip_longhands="${skip_font_longhands}"> 591 592 // Negative numbers are invalid at parse time, but <integer> is still an 593 // i32. 594 <% impl_font_settings("font_feature_settings", "gfxFontFeature", "FeatureTagValue", "i32", "u32") %> 595 <% impl_font_settings("font_variation_settings", "gfxFontVariation", "VariationValue", "f32", "f32") %> 596 597 pub fn unzoom_fonts(&mut self, device: &Device) { 598 use crate::values::generics::NonNegative; 599 self.mSize = NonNegative(device.unzoom_text(self.mSize.0)); 600 self.mScriptUnconstrainedSize = NonNegative(device.unzoom_text(self.mScriptUnconstrainedSize.0)); 601 self.mFont.size = NonNegative(device.unzoom_text(self.mFont.size.0)); 602 } 603 604 pub fn copy_font_size_from(&mut self, other: &Self) { 605 self.mScriptUnconstrainedSize = other.mScriptUnconstrainedSize; 606 607 self.mSize = other.mScriptUnconstrainedSize; 608 // NOTE: Intentionally not copying from mFont.size. The cascade process 609 // recomputes the used size as needed. 610 self.mFont.size = other.mSize; 611 self.mFontSizeKeyword = other.mFontSizeKeyword; 612 613 // TODO(emilio): Should we really copy over these two? 614 self.mFontSizeFactor = other.mFontSizeFactor; 615 self.mFontSizeOffset = other.mFontSizeOffset; 616 } 617 618 pub fn reset_font_size(&mut self, other: &Self) { 619 self.copy_font_size_from(other) 620 } 621 622 pub fn set_font_size(&mut self, v: FontSize) { 623 let computed_size = v.computed_size; 624 self.mScriptUnconstrainedSize = computed_size; 625 626 // These two may be changed from Cascade::fixup_font_stuff. 627 self.mSize = computed_size; 628 // NOTE: Intentionally not copying from used_size. The cascade process 629 // recomputes the used size as needed. 630 self.mFont.size = computed_size; 631 632 self.mFontSizeKeyword = v.keyword_info.kw; 633 self.mFontSizeFactor = v.keyword_info.factor; 634 self.mFontSizeOffset = v.keyword_info.offset; 635 } 636 637 pub fn clone_font_size(&self) -> FontSize { 638 use crate::values::specified::font::KeywordInfo; 639 640 FontSize { 641 computed_size: self.mSize, 642 used_size: self.mFont.size, 643 keyword_info: KeywordInfo { 644 kw: self.mFontSizeKeyword, 645 factor: self.mFontSizeFactor, 646 offset: self.mFontSizeOffset, 647 } 648 } 649 } 650 651 #[allow(non_snake_case)] 652 pub fn set__x_lang(&mut self, v: longhands::_x_lang::computed_value::T) { 653 let ptr = v.0.as_ptr(); 654 forget(v); 655 unsafe { 656 Gecko_nsStyleFont_SetLang(&mut **self, ptr); 657 } 658 } 659 660 #[allow(non_snake_case)] 661 pub fn copy__x_lang_from(&mut self, other: &Self) { 662 unsafe { 663 Gecko_nsStyleFont_CopyLangFrom(&mut **self, &**other); 664 } 665 } 666 667 #[allow(non_snake_case)] 668 pub fn reset__x_lang(&mut self, other: &Self) { 669 self.copy__x_lang_from(other) 670 } 671 672 #[allow(non_snake_case)] 673 pub fn clone__x_lang(&self) -> longhands::_x_lang::computed_value::T { 674 longhands::_x_lang::computed_value::T(unsafe { 675 Atom::from_raw(self.mLanguage.mRawPtr) 676 }) 677 } 678 </%self:impl_trait> 679 680 <%def name="impl_coordinated_property_copy(type, ident, gecko_ffi_name)"> 681 #[allow(non_snake_case)] 682 pub fn copy_${type}_${ident}_from(&mut self, other: &Self) { 683 self.m${to_camel_case(type)}s.ensure_len(other.m${to_camel_case(type)}s.len()); 684 685 let count = other.m${to_camel_case(type)}${gecko_ffi_name}Count; 686 self.m${to_camel_case(type)}${gecko_ffi_name}Count = count; 687 688 let iter = self.m${to_camel_case(type)}s.iter_mut().take(count as usize).zip( 689 other.m${to_camel_case(type)}s.iter() 690 ); 691 692 for (ours, others) in iter { 693 ours.m${gecko_ffi_name} = others.m${gecko_ffi_name}.clone(); 694 } 695 } 696 #[allow(non_snake_case)] 697 pub fn reset_${type}_${ident}(&mut self, other: &Self) { 698 self.copy_${type}_${ident}_from(other) 699 } 700 </%def> 701 702 <%def name="impl_coordinated_property_count(type, ident, gecko_ffi_name)"> 703 #[allow(non_snake_case)] 704 pub fn ${type}_${ident}_count(&self) -> usize { 705 self.m${to_camel_case(type)}${gecko_ffi_name}Count as usize 706 } 707 </%def> 708 709 <%def name="impl_coordinated_property(type, ident, gecko_ffi_name)"> 710 #[allow(non_snake_case)] 711 pub fn set_${type}_${ident}<I>(&mut self, v: I) 712 where 713 I: IntoIterator<Item = longhands::${type}_${ident}::computed_value::single_value::T>, 714 I::IntoIter: ExactSizeIterator + Clone 715 { 716 let v = v.into_iter(); 717 debug_assert_ne!(v.len(), 0); 718 let input_len = v.len(); 719 self.m${to_camel_case(type)}s.ensure_len(input_len); 720 721 self.m${to_camel_case(type)}${gecko_ffi_name}Count = input_len as u32; 722 for (gecko, servo) in self.m${to_camel_case(type)}s.iter_mut().take(input_len as usize).zip(v) { 723 gecko.m${gecko_ffi_name} = servo; 724 } 725 } 726 #[allow(non_snake_case)] 727 pub fn ${type}_${ident}_at(&self, index: usize) 728 -> longhands::${type}_${ident}::computed_value::SingleComputedValue { 729 self.m${to_camel_case(type)}s[index % self.${type}_${ident}_count()].m${gecko_ffi_name}.clone() 730 } 731 ${impl_coordinated_property_copy(type, ident, gecko_ffi_name)} 732 ${impl_coordinated_property_count(type, ident, gecko_ffi_name)} 733 </%def> 734 735 <% skip_box_longhands= """display contain""" %> 736 <%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}"> 737 #[inline] 738 pub fn set_display(&mut self, v: longhands::display::computed_value::T) { 739 self.mDisplay = v; 740 self.mOriginalDisplay = v; 741 } 742 743 #[inline] 744 pub fn copy_display_from(&mut self, other: &Self) { 745 self.set_display(other.mDisplay); 746 } 747 748 #[inline] 749 pub fn reset_display(&mut self, other: &Self) { 750 self.copy_display_from(other) 751 } 752 753 #[inline] 754 pub fn set_adjusted_display( 755 &mut self, 756 v: longhands::display::computed_value::T, 757 _is_item_or_root: bool 758 ) { 759 self.mDisplay = v; 760 } 761 762 #[inline] 763 pub fn clone_display(&self) -> longhands::display::computed_value::T { 764 self.mDisplay 765 } 766 767 #[inline] 768 pub fn set_contain(&mut self, v: longhands::contain::computed_value::T) { 769 self.mContain = v; 770 self.mEffectiveContainment = v; 771 } 772 773 #[inline] 774 pub fn copy_contain_from(&mut self, other: &Self) { 775 self.set_contain(other.mContain); 776 } 777 778 #[inline] 779 pub fn reset_contain(&mut self, other: &Self) { 780 self.copy_contain_from(other) 781 } 782 783 #[inline] 784 pub fn clone_contain(&self) -> longhands::contain::computed_value::T { 785 self.mContain 786 } 787 788 #[inline] 789 pub fn set_effective_containment( 790 &mut self, 791 v: longhands::contain::computed_value::T 792 ) { 793 self.mEffectiveContainment = v; 794 } 795 796 #[inline] 797 pub fn clone_effective_containment(&self) -> longhands::contain::computed_value::T { 798 self.mEffectiveContainment 799 } 800 </%self:impl_trait> 801 802 <%def name="simple_image_array_property(name, shorthand, field_name)"> 803 <% 804 image_layers_field = "mImage" if shorthand == "background" else "mMask" 805 copy_simple_image_array_property(name, shorthand, image_layers_field, field_name) 806 %> 807 808 pub fn set_${shorthand}_${name}<I>(&mut self, v: I) 809 where I: IntoIterator<Item=longhands::${shorthand}_${name}::computed_value::single_value::T>, 810 I::IntoIter: ExactSizeIterator 811 { 812 use crate::gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; 813 let v = v.into_iter(); 814 815 unsafe { 816 Gecko_EnsureImageLayersLength(&mut self.${image_layers_field}, v.len(), 817 LayerType::${shorthand.title()}); 818 } 819 820 self.${image_layers_field}.${field_name}Count = v.len() as u32; 821 for (servo, geckolayer) in v.zip(self.${image_layers_field}.mLayers.iter_mut()) { 822 geckolayer.${field_name} = { 823 ${caller.body()} 824 }; 825 } 826 } 827 </%def> 828 829 <%def name="copy_simple_image_array_property(name, shorthand, layers_field_name, field_name)"> 830 pub fn copy_${shorthand}_${name}_from(&mut self, other: &Self) { 831 use crate::gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; 832 833 let count = other.${layers_field_name}.${field_name}Count; 834 unsafe { 835 Gecko_EnsureImageLayersLength(&mut self.${layers_field_name}, 836 count as usize, 837 LayerType::${shorthand.title()}); 838 } 839 // FIXME(emilio): This may be bogus in the same way as bug 1426246. 840 for (layer, other) in self.${layers_field_name}.mLayers.iter_mut() 841 .zip(other.${layers_field_name}.mLayers.iter()) 842 .take(count as usize) { 843 layer.${field_name} = other.${field_name}.clone(); 844 } 845 self.${layers_field_name}.${field_name}Count = count; 846 } 847 848 pub fn reset_${shorthand}_${name}(&mut self, other: &Self) { 849 self.copy_${shorthand}_${name}_from(other) 850 } 851 </%def> 852 853 <%def name="impl_simple_image_array_property(name, shorthand, layer_field_name, field_name, struct_name)"> 854 <% 855 ident = "%s_%s" % (shorthand, name) 856 style_struct = next(x for x in data.style_structs if x.name == struct_name) 857 longhand = next(x for x in style_struct.longhands if x.ident == ident) 858 keyword = longhand.keyword 859 %> 860 861 <% copy_simple_image_array_property(name, shorthand, layer_field_name, field_name) %> 862 863 pub fn set_${ident}<I>(&mut self, v: I) 864 where 865 I: IntoIterator<Item=longhands::${ident}::computed_value::single_value::T>, 866 I::IntoIter: ExactSizeIterator, 867 { 868 use crate::properties::longhands::${ident}::single_value::computed_value::T as Keyword; 869 use crate::gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; 870 871 let v = v.into_iter(); 872 873 unsafe { 874 Gecko_EnsureImageLayersLength(&mut self.${layer_field_name}, v.len(), 875 LayerType::${shorthand.title()}); 876 } 877 878 self.${layer_field_name}.${field_name}Count = v.len() as u32; 879 for (servo, geckolayer) in v.zip(self.${layer_field_name}.mLayers.iter_mut()) { 880 geckolayer.${field_name} = { 881 match servo { 882 % for value in keyword.values_for("gecko"): 883 Keyword::${to_camel_case(value)} => 884 structs::${keyword.gecko_constant(value)} ${keyword.maybe_cast('u8')}, 885 % endfor 886 } 887 }; 888 } 889 } 890 891 pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { 892 use crate::properties::longhands::${ident}::single_value::computed_value::T as Keyword; 893 894 % if keyword.needs_cast(): 895 % for value in keyword.values_for('gecko'): 896 const ${keyword.casted_constant_name(value, "u8")} : u8 = 897 structs::${keyword.gecko_constant(value)} as u8; 898 % endfor 899 % endif 900 901 longhands::${ident}::computed_value::List( 902 self.${layer_field_name}.mLayers.iter() 903 .take(self.${layer_field_name}.${field_name}Count as usize) 904 .map(|ref layer| { 905 match layer.${field_name} { 906 % for value in longhand.keyword.values_for("gecko"): 907 % if keyword.needs_cast(): 908 ${keyword.casted_constant_name(value, "u8")} 909 % else: 910 structs::${keyword.gecko_constant(value)} 911 % endif 912 => Keyword::${to_camel_case(value)}, 913 % endfor 914 % if keyword.gecko_inexhaustive: 915 _ => panic!("Found unexpected value in style struct for ${ident} property"), 916 % endif 917 } 918 }).collect() 919 ) 920 } 921 </%def> 922 923 <%def name="impl_common_image_layer_properties(shorthand)"> 924 <% 925 if shorthand == "background": 926 image_layers_field = "mImage" 927 struct_name = "Background" 928 else: 929 image_layers_field = "mMask" 930 struct_name = "SVG" 931 %> 932 933 <%self:simple_image_array_property name="repeat" shorthand="${shorthand}" field_name="mRepeat"> 934 use crate::values::specified::background::BackgroundRepeatKeyword; 935 use crate::gecko_bindings::structs::nsStyleImageLayers_Repeat; 936 use crate::gecko_bindings::structs::StyleImageLayerRepeat; 937 938 fn to_ns(repeat: BackgroundRepeatKeyword) -> StyleImageLayerRepeat { 939 match repeat { 940 BackgroundRepeatKeyword::Repeat => StyleImageLayerRepeat::Repeat, 941 BackgroundRepeatKeyword::Space => StyleImageLayerRepeat::Space, 942 BackgroundRepeatKeyword::Round => StyleImageLayerRepeat::Round, 943 BackgroundRepeatKeyword::NoRepeat => StyleImageLayerRepeat::NoRepeat, 944 } 945 } 946 947 let repeat_x = to_ns(servo.0); 948 let repeat_y = to_ns(servo.1); 949 nsStyleImageLayers_Repeat { 950 mXRepeat: repeat_x, 951 mYRepeat: repeat_y, 952 } 953 </%self:simple_image_array_property> 954 955 pub fn clone_${shorthand}_repeat(&self) -> longhands::${shorthand}_repeat::computed_value::T { 956 use crate::properties::longhands::${shorthand}_repeat::single_value::computed_value::T; 957 use crate::values::specified::background::BackgroundRepeatKeyword; 958 use crate::gecko_bindings::structs::StyleImageLayerRepeat; 959 960 fn to_servo(repeat: StyleImageLayerRepeat) -> BackgroundRepeatKeyword { 961 match repeat { 962 StyleImageLayerRepeat::Repeat => BackgroundRepeatKeyword::Repeat, 963 StyleImageLayerRepeat::Space => BackgroundRepeatKeyword::Space, 964 StyleImageLayerRepeat::Round => BackgroundRepeatKeyword::Round, 965 StyleImageLayerRepeat::NoRepeat => BackgroundRepeatKeyword::NoRepeat, 966 _ => panic!("Found unexpected value in style struct for ${shorthand}_repeat property"), 967 } 968 } 969 970 longhands::${shorthand}_repeat::computed_value::List( 971 self.${image_layers_field}.mLayers.iter() 972 .take(self.${image_layers_field}.mRepeatCount as usize) 973 .map(|ref layer| { 974 T(to_servo(layer.mRepeat.mXRepeat), to_servo(layer.mRepeat.mYRepeat)) 975 }).collect() 976 ) 977 } 978 979 <% impl_simple_image_array_property("clip", shorthand, image_layers_field, "mClip", struct_name) %> 980 <% impl_simple_image_array_property("origin", shorthand, image_layers_field, "mOrigin", struct_name) %> 981 982 % for (orientation, keyword) in [("x", "horizontal"), ("y", "vertical")]: 983 pub fn copy_${shorthand}_position_${orientation}_from(&mut self, other: &Self) { 984 use crate::gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; 985 986 let count = other.${image_layers_field}.mPosition${orientation.upper()}Count; 987 988 unsafe { 989 Gecko_EnsureImageLayersLength(&mut self.${image_layers_field}, 990 count as usize, 991 LayerType::${shorthand.capitalize()}); 992 } 993 994 for (layer, other) in self.${image_layers_field}.mLayers.iter_mut() 995 .zip(other.${image_layers_field}.mLayers.iter()) 996 .take(count as usize) { 997 layer.mPosition.${keyword} = other.mPosition.${keyword}.clone(); 998 } 999 self.${image_layers_field}.mPosition${orientation.upper()}Count = count; 1000 } 1001 1002 pub fn reset_${shorthand}_position_${orientation}(&mut self, other: &Self) { 1003 self.copy_${shorthand}_position_${orientation}_from(other) 1004 } 1005 1006 pub fn clone_${shorthand}_position_${orientation}(&self) 1007 -> longhands::${shorthand}_position_${orientation}::computed_value::T { 1008 longhands::${shorthand}_position_${orientation}::computed_value::List( 1009 self.${image_layers_field}.mLayers.iter() 1010 .take(self.${image_layers_field}.mPosition${orientation.upper()}Count as usize) 1011 .map(|position| position.mPosition.${keyword}.clone()) 1012 .collect() 1013 ) 1014 } 1015 1016 pub fn set_${shorthand}_position_${orientation[0]}<I>(&mut self, 1017 v: I) 1018 where I: IntoIterator<Item = longhands::${shorthand}_position_${orientation[0]} 1019 ::computed_value::single_value::T>, 1020 I::IntoIter: ExactSizeIterator 1021 { 1022 use crate::gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; 1023 1024 let v = v.into_iter(); 1025 1026 unsafe { 1027 Gecko_EnsureImageLayersLength(&mut self.${image_layers_field}, v.len(), 1028 LayerType::${shorthand.capitalize()}); 1029 } 1030 1031 self.${image_layers_field}.mPosition${orientation[0].upper()}Count = v.len() as u32; 1032 for (servo, geckolayer) in v.zip(self.${image_layers_field} 1033 .mLayers.iter_mut()) { 1034 geckolayer.mPosition.${keyword} = servo; 1035 } 1036 } 1037 % endfor 1038 1039 <%self:simple_image_array_property name="size" shorthand="${shorthand}" field_name="mSize"> 1040 servo 1041 </%self:simple_image_array_property> 1042 1043 pub fn clone_${shorthand}_size(&self) -> longhands::${shorthand}_size::computed_value::T { 1044 longhands::${shorthand}_size::computed_value::List( 1045 self.${image_layers_field}.mLayers.iter().map(|layer| layer.mSize.clone()).collect() 1046 ) 1047 } 1048 1049 pub fn copy_${shorthand}_image_from(&mut self, other: &Self) { 1050 use crate::gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; 1051 unsafe { 1052 let count = other.${image_layers_field}.mImageCount; 1053 Gecko_EnsureImageLayersLength(&mut self.${image_layers_field}, 1054 count as usize, 1055 LayerType::${shorthand.capitalize()}); 1056 1057 for (layer, other) in self.${image_layers_field}.mLayers.iter_mut() 1058 .zip(other.${image_layers_field}.mLayers.iter()) 1059 .take(count as usize) { 1060 layer.mImage = other.mImage.clone(); 1061 } 1062 self.${image_layers_field}.mImageCount = count; 1063 } 1064 } 1065 1066 pub fn reset_${shorthand}_image(&mut self, other: &Self) { 1067 self.copy_${shorthand}_image_from(other) 1068 } 1069 1070 #[allow(unused_variables)] 1071 pub fn set_${shorthand}_image<I>(&mut self, images: I) 1072 where I: IntoIterator<Item = longhands::${shorthand}_image::computed_value::single_value::T>, 1073 I::IntoIter: ExactSizeIterator 1074 { 1075 use crate::gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; 1076 1077 let images = images.into_iter(); 1078 1079 unsafe { 1080 Gecko_EnsureImageLayersLength( 1081 &mut self.${image_layers_field}, 1082 images.len(), 1083 LayerType::${shorthand.title()}, 1084 ); 1085 } 1086 1087 self.${image_layers_field}.mImageCount = images.len() as u32; 1088 for (image, geckoimage) in images.zip(self.${image_layers_field} 1089 .mLayers.iter_mut()) { 1090 geckoimage.mImage = image; 1091 } 1092 } 1093 1094 pub fn clone_${shorthand}_image(&self) -> longhands::${shorthand}_image::computed_value::T { 1095 longhands::${shorthand}_image::computed_value::List( 1096 self.${image_layers_field}.mLayers.iter() 1097 .take(self.${image_layers_field}.mImageCount as usize) 1098 .map(|layer| layer.mImage.clone()) 1099 .collect() 1100 ) 1101 } 1102 1103 <% 1104 fill_fields = "mRepeat mClip mOrigin mPositionX mPositionY mImage mSize" 1105 if shorthand == "background": 1106 fill_fields += " mAttachment mBlendMode" 1107 else: 1108 # mSourceURI uses mImageCount 1109 fill_fields += " mMaskMode mComposite" 1110 %> 1111 pub fn fill_arrays(&mut self) { 1112 use crate::gecko_bindings::bindings::Gecko_FillAllImageLayers; 1113 use std::cmp; 1114 let mut max_len = 1; 1115 % for member in fill_fields.split(): 1116 max_len = cmp::max(max_len, self.${image_layers_field}.${member}Count); 1117 % endfor 1118 unsafe { 1119 // While we could do this manually, we'd need to also manually 1120 // run all the copy constructors, so we just delegate to gecko 1121 Gecko_FillAllImageLayers(&mut self.${image_layers_field}, max_len); 1122 } 1123 } 1124 </%def> 1125 1126 // TODO: Gecko accepts lists in most background-related properties. We just use 1127 // the first element (which is the common case), but at some point we want to 1128 // add support for parsing these lists in servo and pushing to nsTArray's. 1129 <% skip_background_longhands = """background-repeat 1130 background-image background-clip 1131 background-origin background-attachment 1132 background-size background-position 1133 background-blend-mode 1134 background-position-x 1135 background-position-y""" %> 1136 <%self:impl_trait style_struct_name="Background" 1137 skip_longhands="${skip_background_longhands}"> 1138 1139 <% impl_common_image_layer_properties("background") %> 1140 <% impl_simple_image_array_property("attachment", "background", "mImage", "mAttachment", "Background") %> 1141 <% impl_simple_image_array_property("blend_mode", "background", "mImage", "mBlendMode", "Background") %> 1142 </%self:impl_trait> 1143 1144 <%self:impl_trait style_struct_name="List"> 1145 </%self:impl_trait> 1146 1147 <%self:impl_trait style_struct_name="Table"> 1148 </%self:impl_trait> 1149 1150 <%self:impl_trait style_struct_name="Effects"> 1151 </%self:impl_trait> 1152 1153 <%self:impl_trait style_struct_name="InheritedBox"> 1154 </%self:impl_trait> 1155 1156 <%self:impl_trait style_struct_name="InheritedTable"> 1157 </%self:impl_trait> 1158 1159 <%self:impl_trait style_struct_name="InheritedText"> 1160 </%self:impl_trait> 1161 1162 <%self:impl_trait style_struct_name="Text"> 1163 </%self:impl_trait> 1164 1165 <% skip_svg_longhands = """ 1166 mask-mode mask-repeat mask-clip mask-origin mask-composite mask-position-x mask-position-y mask-size mask-image 1167 """ 1168 %> 1169 <%self:impl_trait style_struct_name="SVG" 1170 skip_longhands="${skip_svg_longhands}"> 1171 <% impl_common_image_layer_properties("mask") %> 1172 <% impl_simple_image_array_property("mode", "mask", "mMask", "mMaskMode", "SVG") %> 1173 <% impl_simple_image_array_property("composite", "mask", "mMask", "mComposite", "SVG") %> 1174 </%self:impl_trait> 1175 1176 <%self:impl_trait style_struct_name="InheritedSVG"> 1177 </%self:impl_trait> 1178 1179 <%self:impl_trait style_struct_name="InheritedUI"> 1180 #[inline] 1181 pub fn color_scheme_bits(&self) -> values::specified::color::ColorSchemeFlags { 1182 self.mColorScheme.bits 1183 } 1184 </%self:impl_trait> 1185 1186 <%self:impl_trait style_struct_name="Column"> 1187 </%self:impl_trait> 1188 1189 <%self:impl_trait style_struct_name="Counters"> 1190 pub fn ineffective_content_property(&self) -> bool { 1191 !self.mContent.is_items() 1192 } 1193 </%self:impl_trait> 1194 1195 <% skip_ui_longhands = """animation-name animation-delay animation-duration 1196 animation-direction animation-fill-mode 1197 animation-play-state animation-iteration-count 1198 animation-timing-function animation-composition animation-timeline 1199 transition-behavior transition-duration transition-delay 1200 transition-timing-function transition-property 1201 scroll-timeline-name scroll-timeline-axis 1202 view-timeline-name view-timeline-axis view-timeline-inset""" %> 1203 1204 <%self:impl_trait style_struct_name="UI" skip_longhands="${skip_ui_longhands}"> 1205 ${impl_coordinated_property('transition', 'behavior', 'Behavior')} 1206 ${impl_coordinated_property('transition', 'delay', 'Delay')} 1207 ${impl_coordinated_property('transition', 'duration', 'Duration')} 1208 ${impl_coordinated_property('transition', 'timing_function', 'TimingFunction')} 1209 ${impl_coordinated_property('transition', 'property', 'Property')} 1210 1211 pub fn transition_combined_duration_at(&self, index: usize) -> Time { 1212 // https://drafts.csswg.org/css-transitions/#transition-combined-duration 1213 Time::from_seconds( 1214 self.transition_duration_at(index).seconds().max(0.0) + 1215 self.transition_delay_at(index).seconds() 1216 ) 1217 } 1218 1219 /// Returns whether there are any transitions specified. 1220 pub fn specifies_transitions(&self) -> bool { 1221 if self.mTransitionPropertyCount == 1 && 1222 self.transition_combined_duration_at(0).seconds() <= 0.0f32 { 1223 return false; 1224 } 1225 self.mTransitionPropertyCount > 0 1226 } 1227 1228 /// Returns whether animation-timeline is initial value. We need this information to resolve 1229 /// animation-duration. 1230 pub fn has_initial_animation_timeline(&self) -> bool { 1231 self.mAnimationTimelineCount == 1 && self.animation_timeline_at(0).is_auto() 1232 } 1233 1234 pub fn animations_equals(&self, other: &Self) -> bool { 1235 return self.mAnimationNameCount == other.mAnimationNameCount 1236 && self.mAnimationDelayCount == other.mAnimationDelayCount 1237 && self.mAnimationDirectionCount == other.mAnimationDirectionCount 1238 && self.mAnimationDurationCount == other.mAnimationDurationCount 1239 && self.mAnimationFillModeCount == other.mAnimationFillModeCount 1240 && self.mAnimationIterationCountCount == other.mAnimationIterationCountCount 1241 && self.mAnimationPlayStateCount == other.mAnimationPlayStateCount 1242 && self.mAnimationTimingFunctionCount == other.mAnimationTimingFunctionCount 1243 && self.mAnimationCompositionCount == other.mAnimationCompositionCount 1244 && self.mAnimationTimelineCount == other.mAnimationTimelineCount 1245 && unsafe { bindings::Gecko_StyleAnimationsEquals(&self.mAnimations, &other.mAnimations) } 1246 } 1247 1248 ${impl_coordinated_property('animation', 'name', 'Name')} 1249 ${impl_coordinated_property('animation', 'delay', 'Delay')} 1250 ${impl_coordinated_property('animation', 'duration', 'Duration')} 1251 ${impl_coordinated_property('animation', 'direction', 'Direction')} 1252 ${impl_coordinated_property('animation', 'fill_mode', 'FillMode')} 1253 ${impl_coordinated_property('animation', 'play_state', 'PlayState')} 1254 ${impl_coordinated_property('animation', 'composition', 'Composition')} 1255 ${impl_coordinated_property('animation', 'iteration_count', 'IterationCount')} 1256 ${impl_coordinated_property('animation', 'timeline', 'Timeline')} 1257 ${impl_coordinated_property('animation', 'timing_function', 'TimingFunction')} 1258 1259 ${impl_coordinated_property('scroll_timeline', 'name', 'Name')} 1260 ${impl_coordinated_property('scroll_timeline', 'axis', 'Axis')} 1261 1262 pub fn scroll_timelines_equals(&self, other: &Self) -> bool { 1263 self.mScrollTimelineNameCount == other.mScrollTimelineNameCount 1264 && self.mScrollTimelineAxisCount == other.mScrollTimelineAxisCount 1265 && unsafe { 1266 bindings::Gecko_StyleScrollTimelinesEquals( 1267 &self.mScrollTimelines, 1268 &other.mScrollTimelines, 1269 ) 1270 } 1271 } 1272 1273 ${impl_coordinated_property('view_timeline', 'name', 'Name')} 1274 ${impl_coordinated_property('view_timeline', 'axis', 'Axis')} 1275 ${impl_coordinated_property('view_timeline', 'inset', 'Inset')} 1276 1277 pub fn view_timelines_equals(&self, other: &Self) -> bool { 1278 self.mViewTimelineNameCount == other.mViewTimelineNameCount 1279 && self.mViewTimelineAxisCount == other.mViewTimelineAxisCount 1280 && self.mViewTimelineInsetCount == other.mViewTimelineInsetCount 1281 && unsafe { 1282 bindings::Gecko_StyleViewTimelinesEquals( 1283 &self.mViewTimelines, 1284 &other.mViewTimelines, 1285 ) 1286 } 1287 } 1288 </%self:impl_trait> 1289 1290 <%self:impl_trait style_struct_name="XUL"> 1291 </%self:impl_trait> 1292 1293 % for style_struct in data.style_structs: 1294 ${impl_style_struct(style_struct)} 1295 % endfor 1296 1297 /// Assert that the initial values set in Gecko style struct constructors 1298 /// match the values returned by `get_initial_value()` for each longhand. 1299 #[cfg(feature = "gecko")] 1300 #[inline] 1301 pub fn assert_initial_values_match(data: &PerDocumentStyleData) { 1302 if cfg!(debug_assertions) { 1303 let data = data.borrow(); 1304 let cv = data.stylist.device().default_computed_values(); 1305 <% 1306 # Skip properties with initial values that change at computed 1307 # value time, or whose initial value depends on the document 1308 # / other prefs. 1309 SKIPPED = [ 1310 "border-top-width", 1311 "border-bottom-width", 1312 "border-left-width", 1313 "border-right-width", 1314 "column-rule-width", 1315 "font-family", 1316 "font-size", 1317 "outline-width", 1318 "color", 1319 ] 1320 TO_TEST = [p for p in data.longhands if p.enabled_in != "" and not p.logical and not p.name in SKIPPED] 1321 %> 1322 % for property in TO_TEST: 1323 assert_eq!( 1324 cv.clone_${property.ident}(), 1325 longhands::${property.ident}::get_initial_value(), 1326 concat!( 1327 "initial value in Gecko style struct for ", 1328 stringify!(${property.ident}), 1329 " must match longhands::", 1330 stringify!(${property.ident}), 1331 "::get_initial_value()" 1332 ) 1333 ); 1334 % endfor 1335 } 1336 }