mod.rs (34283B)
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 //! Computed values. 6 7 use self::transform::DirectionVector; 8 use super::animated::ToAnimatedValue; 9 use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent; 10 use super::generics::grid::ImplicitGridTracks as GenericImplicitGridTracks; 11 use super::generics::grid::{GenericGridLine, GenericTrackBreadth}; 12 use super::generics::grid::{GenericTrackSize, TrackList as GenericTrackList}; 13 use super::generics::transform::IsParallelTo; 14 use super::generics::{self, GreaterThanOrEqualToOne, NonNegative, ZeroToOne}; 15 use super::specified; 16 use super::{CSSFloat, CSSInteger}; 17 use crate::computed_value_flags::ComputedValueFlags; 18 use crate::context::QuirksMode; 19 use crate::custom_properties::ComputedCustomProperties; 20 use crate::derives::*; 21 use crate::font_metrics::{FontMetrics, FontMetricsOrientation}; 22 use crate::media_queries::Device; 23 #[cfg(feature = "gecko")] 24 use crate::properties; 25 use crate::properties::{ComputedValues, StyleBuilder}; 26 use crate::rule_cache::RuleCacheConditions; 27 use crate::stylesheets::container_rule::{ 28 ContainerInfo, ContainerSizeQuery, ContainerSizeQueryResult, 29 }; 30 use crate::stylist::Stylist; 31 use crate::values::generics::ClampToNonNegative; 32 use crate::values::specified::font::QueryFontMetricsFlags; 33 use crate::values::specified::length::FontBaseSize; 34 use crate::{ArcSlice, Atom, One}; 35 use euclid::{default, Point2D, Rect, Size2D}; 36 use servo_arc::Arc; 37 use std::cell::RefCell; 38 use std::cmp; 39 use std::f32; 40 use std::ops::{Add, Sub}; 41 42 pub use self::align::{ContentDistribution, ItemPlacement, JustifyItems, SelfAlignment}; 43 pub use self::angle::Angle; 44 pub use self::animation::{ 45 AnimationComposition, AnimationDirection, AnimationDuration, AnimationFillMode, 46 AnimationIterationCount, AnimationName, AnimationPlayState, AnimationTimeline, ScrollAxis, 47 TimelineName, TransitionBehavior, TransitionProperty, ViewTimelineInset, ViewTransitionClass, 48 ViewTransitionName, 49 }; 50 pub use self::background::{BackgroundRepeat, BackgroundSize}; 51 pub use self::basic_shape::FillRule; 52 pub use self::border::{ 53 BorderCornerRadius, BorderImageRepeat, BorderImageSideWidth, BorderImageSlice, 54 BorderImageWidth, BorderRadius, BorderSideOffset, BorderSideWidth, BorderSpacing, LineWidth, 55 }; 56 pub use self::box_::{ 57 Appearance, BaselineSource, BreakBetween, BreakWithin, Clear, Contain, ContainIntrinsicSize, 58 ContainerName, ContainerType, ContentVisibility, Display, Float, LineClamp, Overflow, 59 OverflowAnchor, OverflowClipMargin, OverscrollBehavior, Perspective, PositionProperty, Resize, 60 ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStop, ScrollSnapStrictness, ScrollSnapType, 61 ScrollbarGutter, TouchAction, VerticalAlign, WillChange, WritingModeProperty, Zoom, 62 }; 63 pub use self::color::{ 64 Color, ColorOrAuto, ColorPropertyValue, ColorScheme, ForcedColorAdjust, PrintColorAdjust, 65 }; 66 pub use self::column::ColumnCount; 67 pub use self::counters::{Content, ContentItem, CounterIncrement, CounterReset, CounterSet}; 68 pub use self::easing::TimingFunction; 69 pub use self::effects::{BoxShadow, Filter, SimpleShadow}; 70 pub use self::flex::FlexBasis; 71 pub use self::font::{FontFamily, FontLanguageOverride, FontPalette, FontStyle}; 72 pub use self::font::{FontFeatureSettings, FontVariantLigatures, FontVariantNumeric}; 73 pub use self::font::{ 74 FontSize, FontSizeAdjust, FontStretch, FontSynthesis, FontSynthesisStyle, LineHeight, 75 }; 76 pub use self::font::{FontVariantAlternates, FontWeight}; 77 pub use self::font::{FontVariantEastAsian, FontVariationSettings}; 78 pub use self::font::{MathDepth, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextScale}; 79 pub use self::image::{Gradient, Image, ImageRendering, LineDirection}; 80 pub use self::length::{CSSPixelLength, NonNegativeLength}; 81 pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber}; 82 pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, Margin, MaxSize, Size}; 83 pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageOrAuto}; 84 #[cfg(feature = "gecko")] 85 pub use self::list::ListStyleType; 86 pub use self::list::Quotes; 87 pub use self::motion::{OffsetPath, OffsetPosition, OffsetRotate}; 88 pub use self::outline::OutlineStyle; 89 pub use self::page::{PageName, PageOrientation, PageSize, PageSizeOrientation, PaperSize}; 90 pub use self::percentage::{NonNegativePercentage, Percentage}; 91 pub use self::position::AnchorFunction; 92 pub use self::position::AnchorName; 93 pub use self::position::AnchorScope; 94 pub use self::position::AspectRatio; 95 pub use self::position::DashedIdentAndOrTryTactic; 96 pub use self::position::Inset; 97 pub use self::position::PositionAnchor; 98 pub use self::position::PositionTryFallbacks; 99 pub use self::position::PositionTryOrder; 100 pub use self::position::PositionVisibility; 101 pub use self::position::{ 102 GridAutoFlow, GridTemplateAreas, MasonryAutoFlow, Position, PositionOrAuto, ZIndex, 103 }; 104 pub use self::position::{PositionArea, PositionAreaKeyword}; 105 pub use self::ratio::Ratio; 106 pub use self::rect::NonNegativeLengthOrNumberRect; 107 pub use self::resolution::Resolution; 108 pub use self::svg::{DProperty, MozContextProperties}; 109 pub use self::svg::{SVGLength, SVGOpacity, SVGPaint, SVGPaintKind}; 110 pub use self::svg::{SVGPaintOrder, SVGStrokeDashArray, SVGWidth, VectorEffect}; 111 pub use self::text::{HyphenateCharacter, HyphenateLimitChars}; 112 pub use self::text::{InitialLetter, LetterSpacing, LineBreak, TextIndent}; 113 pub use self::text::{OverflowWrap, RubyPosition, TextOverflow, WordBreak, WordSpacing}; 114 pub use self::text::{TextAlign, TextAlignLast, TextEmphasisPosition, TextEmphasisStyle}; 115 pub use self::text::{TextAutospace, TextUnderlinePosition}; 116 pub use self::text::{ 117 TextDecorationInset, TextDecorationLength, TextDecorationSkipInk, TextJustify, 118 }; 119 pub use self::time::Time; 120 pub use self::transform::{Rotate, Scale, Transform, TransformBox, TransformOperation}; 121 pub use self::transform::{TransformOrigin, TransformStyle, Translate}; 122 #[cfg(feature = "gecko")] 123 pub use self::ui::CursorImage; 124 pub use self::ui::{ 125 BoolInteger, Cursor, Inert, MozTheme, PointerEvents, ScrollbarColor, UserFocus, UserSelect, 126 }; 127 pub use super::specified::TextTransform; 128 pub use super::specified::ViewportVariant; 129 pub use super::specified::{BorderStyle, TextDecorationLine}; 130 pub use app_units::Au; 131 132 pub mod align; 133 pub mod angle; 134 pub mod animation; 135 pub mod background; 136 pub mod basic_shape; 137 pub mod border; 138 #[path = "box.rs"] 139 pub mod box_; 140 pub mod color; 141 pub mod column; 142 pub mod counters; 143 pub mod easing; 144 pub mod effects; 145 pub mod flex; 146 pub mod font; 147 pub mod image; 148 pub mod length; 149 pub mod length_percentage; 150 pub mod list; 151 pub mod motion; 152 pub mod outline; 153 pub mod page; 154 pub mod percentage; 155 pub mod position; 156 pub mod ratio; 157 pub mod rect; 158 pub mod resolution; 159 pub mod svg; 160 pub mod table; 161 pub mod text; 162 pub mod time; 163 pub mod transform; 164 pub mod ui; 165 pub mod url; 166 167 /// A `Context` is all the data a specified value could ever need to compute 168 /// itself and be transformed to a computed value. 169 pub struct Context<'a> { 170 /// Values accessed through this need to be in the properties "computed 171 /// early": color, text-decoration, font-size, display, position, float, 172 /// border-*-style, outline-style, font-family, writing-mode... 173 pub builder: StyleBuilder<'a>, 174 175 /// A cached computed system font value, for use by gecko. 176 /// 177 /// See properties/longhands/font.mako.rs 178 #[cfg(feature = "gecko")] 179 pub cached_system_font: Option<properties::longhands::system_font::ComputedSystemFont>, 180 181 /// A dummy option for servo so initializing a computed::Context isn't 182 /// painful. 183 /// 184 /// TODO(emilio): Make constructors for Context, and drop this. 185 #[cfg(feature = "servo")] 186 pub cached_system_font: Option<()>, 187 188 /// Whether or not we are computing the media list in a media query. 189 pub in_media_query: bool, 190 191 /// Whether or not we are computing the container query condition. 192 pub in_container_query: bool, 193 194 /// The quirks mode of this context. 195 pub quirks_mode: QuirksMode, 196 197 /// Whether this computation is being done for a SMIL animation. 198 /// 199 /// This is used to allow certain properties to generate out-of-range 200 /// values, which SMIL allows. 201 pub for_smil_animation: bool, 202 203 /// Returns the container information to evaluate a given container query. 204 pub container_info: Option<ContainerInfo>, 205 206 /// Whether we're computing a value for a non-inherited property. 207 /// False if we are computed a value for an inherited property or not computing for a property 208 /// at all (e.g. in a media query evaluation). 209 pub for_non_inherited_property: bool, 210 211 /// The conditions to cache a rule node on the rule cache. 212 /// 213 /// FIXME(emilio): Drop the refcell. 214 pub rule_cache_conditions: RefCell<&'a mut RuleCacheConditions>, 215 216 /// Container size query for this context. 217 container_size_query: RefCell<ContainerSizeQuery<'a>>, 218 } 219 220 impl<'a> Context<'a> { 221 /// Lazily evaluate the container size query, returning the result. 222 pub fn get_container_size_query(&self) -> ContainerSizeQueryResult { 223 let mut resolved = self.container_size_query.borrow_mut(); 224 resolved.get().clone() 225 } 226 227 /// Creates a suitable context for media query evaluation, in which 228 /// font-relative units compute against the system_font, and executes `f` 229 /// with it. 230 pub fn for_media_query_evaluation<F, R>(device: &Device, quirks_mode: QuirksMode, f: F) -> R 231 where 232 F: FnOnce(&Context) -> R, 233 { 234 let mut conditions = RuleCacheConditions::default(); 235 let context = Context { 236 builder: StyleBuilder::for_inheritance(device, None, None, None), 237 cached_system_font: None, 238 in_media_query: true, 239 in_container_query: false, 240 quirks_mode, 241 for_smil_animation: false, 242 container_info: None, 243 for_non_inherited_property: false, 244 rule_cache_conditions: RefCell::new(&mut conditions), 245 container_size_query: RefCell::new(ContainerSizeQuery::none()), 246 }; 247 f(&context) 248 } 249 250 /// Creates a suitable context for container query evaluation for the style 251 /// specified. 252 pub fn for_container_query_evaluation<F, R>( 253 device: &Device, 254 stylist: Option<&Stylist>, 255 container_info_and_style: Option<(ContainerInfo, Arc<ComputedValues>)>, 256 container_size_query: ContainerSizeQuery, 257 f: F, 258 ) -> R 259 where 260 F: FnOnce(&Context) -> R, 261 { 262 let mut conditions = RuleCacheConditions::default(); 263 264 let (container_info, style) = match container_info_and_style { 265 Some((ci, s)) => (Some(ci), Some(s)), 266 None => (None, None), 267 }; 268 269 let style = style.as_ref().map(|s| &**s); 270 let quirks_mode = device.quirks_mode(); 271 let context = Context { 272 builder: StyleBuilder::for_inheritance(device, stylist, style, None), 273 cached_system_font: None, 274 in_media_query: false, 275 in_container_query: true, 276 quirks_mode, 277 for_smil_animation: false, 278 container_info, 279 for_non_inherited_property: false, 280 rule_cache_conditions: RefCell::new(&mut conditions), 281 container_size_query: RefCell::new(container_size_query), 282 }; 283 284 f(&context) 285 } 286 287 /// Creates a context suitable for more general cases. 288 pub fn new( 289 builder: StyleBuilder<'a>, 290 quirks_mode: QuirksMode, 291 rule_cache_conditions: &'a mut RuleCacheConditions, 292 container_size_query: ContainerSizeQuery<'a>, 293 ) -> Self { 294 Self { 295 builder, 296 cached_system_font: None, 297 in_media_query: false, 298 in_container_query: false, 299 quirks_mode, 300 container_info: None, 301 for_smil_animation: false, 302 for_non_inherited_property: false, 303 rule_cache_conditions: RefCell::new(rule_cache_conditions), 304 container_size_query: RefCell::new(container_size_query), 305 } 306 } 307 308 /// Creates a context suitable for computing animations. 309 pub fn new_for_animation( 310 builder: StyleBuilder<'a>, 311 for_smil_animation: bool, 312 quirks_mode: QuirksMode, 313 rule_cache_conditions: &'a mut RuleCacheConditions, 314 container_size_query: ContainerSizeQuery<'a>, 315 ) -> Self { 316 Self { 317 builder, 318 cached_system_font: None, 319 in_media_query: false, 320 in_container_query: false, 321 quirks_mode, 322 container_info: None, 323 for_smil_animation, 324 for_non_inherited_property: false, 325 rule_cache_conditions: RefCell::new(rule_cache_conditions), 326 container_size_query: RefCell::new(container_size_query), 327 } 328 } 329 330 /// Creates a context suitable for computing the initial value of @property. 331 pub fn new_for_initial_at_property_value( 332 stylist: &'a Stylist, 333 rule_cache_conditions: &'a mut RuleCacheConditions, 334 ) -> Self { 335 Self { 336 builder: StyleBuilder::new(stylist.device(), Some(stylist), None, None, None, false), 337 cached_system_font: None, 338 // Because font-relative values are disallowed in @property initial values, we do not 339 // need to keep track of whether we're in a media query, whether we're in a container 340 // query, and so on. 341 in_media_query: false, 342 in_container_query: false, 343 quirks_mode: stylist.quirks_mode(), 344 container_info: None, 345 for_smil_animation: false, 346 for_non_inherited_property: false, 347 rule_cache_conditions: RefCell::new(rule_cache_conditions), 348 container_size_query: RefCell::new(ContainerSizeQuery::none()), 349 } 350 } 351 352 /// The current device. 353 pub fn device(&self) -> &Device { 354 self.builder.device 355 } 356 357 /// Get the inherited custom properties map. 358 pub fn inherited_custom_properties(&self) -> &ComputedCustomProperties { 359 &self.builder.inherited_custom_properties() 360 } 361 362 /// Whether the style is for the root element. 363 pub fn is_root_element(&self) -> bool { 364 self.builder.is_root_element 365 } 366 367 /// Queries font metrics. 368 pub fn query_font_metrics( 369 &self, 370 base_size: FontBaseSize, 371 orientation: FontMetricsOrientation, 372 mut flags: QueryFontMetricsFlags, 373 ) -> FontMetrics { 374 if self.for_non_inherited_property { 375 self.rule_cache_conditions.borrow_mut().set_uncacheable(); 376 } 377 self.builder.add_flags(match base_size { 378 FontBaseSize::CurrentStyle => ComputedValueFlags::DEPENDS_ON_SELF_FONT_METRICS, 379 FontBaseSize::InheritedStyle => ComputedValueFlags::DEPENDS_ON_INHERITED_FONT_METRICS, 380 }); 381 let size = base_size.resolve(self).used_size(); 382 let style = self.style(); 383 384 let (wm, font) = match base_size { 385 FontBaseSize::CurrentStyle => (style.writing_mode, style.get_font()), 386 // This is only used for font-size computation. 387 FontBaseSize::InheritedStyle => { 388 (*style.inherited_writing_mode(), style.get_parent_font()) 389 }, 390 }; 391 392 let vertical = match orientation { 393 FontMetricsOrientation::MatchContextPreferHorizontal => { 394 wm.is_vertical() && wm.is_upright() 395 }, 396 FontMetricsOrientation::MatchContextPreferVertical => wm.is_text_vertical(), 397 FontMetricsOrientation::Horizontal => false, 398 }; 399 if !self.in_media_query { 400 flags |= QueryFontMetricsFlags::USE_USER_FONT_SET 401 } 402 self.device() 403 .query_font_metrics(vertical, font, size, flags, /* track_changes = */ true) 404 } 405 406 /// The current viewport size, used to resolve viewport units. 407 pub fn viewport_size_for_viewport_unit_resolution( 408 &self, 409 variant: ViewportVariant, 410 ) -> default::Size2D<Au> { 411 self.builder 412 .add_flags(ComputedValueFlags::USES_VIEWPORT_UNITS); 413 self.builder 414 .device 415 .au_viewport_size_for_viewport_unit_resolution(variant) 416 } 417 418 /// Whether we're in a media or container query. 419 pub fn in_media_or_container_query(&self) -> bool { 420 self.in_media_query || self.in_container_query 421 } 422 423 /// The default computed style we're getting our reset style from. 424 pub fn default_style(&self) -> &ComputedValues { 425 self.builder.default_style() 426 } 427 428 /// The current style. 429 pub fn style(&self) -> &StyleBuilder<'a> { 430 &self.builder 431 } 432 433 /// Apply text-zoom if enabled. 434 #[cfg(feature = "gecko")] 435 pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength { 436 if self 437 .style() 438 .get_font() 439 .clone__x_text_scale() 440 .text_zoom_enabled() 441 { 442 self.device().zoom_text(size) 443 } else { 444 size 445 } 446 } 447 448 /// (Servo doesn't do text-zoom) 449 #[cfg(feature = "servo")] 450 pub fn maybe_zoom_text(&self, size: CSSPixelLength) -> CSSPixelLength { 451 size 452 } 453 } 454 455 /// An iterator over a slice of computed values 456 #[derive(Clone)] 457 pub struct ComputedVecIter<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> { 458 cx: &'cx Context<'cx_a>, 459 values: &'a [S], 460 } 461 462 impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ComputedVecIter<'a, 'cx, 'cx_a, S> { 463 /// Construct an iterator from a slice of specified values and a context 464 pub fn new(cx: &'cx Context<'cx_a>, values: &'a [S]) -> Self { 465 ComputedVecIter { cx, values } 466 } 467 } 468 469 impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> ExactSizeIterator 470 for ComputedVecIter<'a, 'cx, 'cx_a, S> 471 { 472 fn len(&self) -> usize { 473 self.values.len() 474 } 475 } 476 477 impl<'a, 'cx, 'cx_a: 'cx, S: ToComputedValue + 'a> Iterator for ComputedVecIter<'a, 'cx, 'cx_a, S> { 478 type Item = S::ComputedValue; 479 fn next(&mut self) -> Option<Self::Item> { 480 if let Some((next, rest)) = self.values.split_first() { 481 let ret = next.to_computed_value(self.cx); 482 self.values = rest; 483 Some(ret) 484 } else { 485 None 486 } 487 } 488 489 fn size_hint(&self) -> (usize, Option<usize>) { 490 (self.values.len(), Some(self.values.len())) 491 } 492 } 493 494 /// A trait to represent the conversion between computed and specified values. 495 /// 496 /// This trait is derivable with `#[derive(ToComputedValue)]`. The derived 497 /// implementation just calls `ToComputedValue::to_computed_value` on each field 498 /// of the passed value. The deriving code assumes that if the type isn't 499 /// generic, then the trait can be implemented as simple `Clone::clone` calls, 500 /// this means that a manual implementation with `ComputedValue = Self` is bogus 501 /// if it returns anything else than a clone. 502 pub trait ToComputedValue { 503 /// The computed value type we're going to be converted to. 504 type ComputedValue; 505 506 /// Convert a specified value to a computed value, using itself and the data 507 /// inside the `Context`. 508 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue; 509 510 /// Convert a computed value to specified value form. 511 /// 512 /// This will be used for recascading during animation. 513 /// Such from_computed_valued values should recompute to the same value. 514 fn from_computed_value(computed: &Self::ComputedValue) -> Self; 515 } 516 517 impl<A, B> ToComputedValue for (A, B) 518 where 519 A: ToComputedValue, 520 B: ToComputedValue, 521 { 522 type ComputedValue = ( 523 <A as ToComputedValue>::ComputedValue, 524 <B as ToComputedValue>::ComputedValue, 525 ); 526 527 #[inline] 528 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { 529 ( 530 self.0.to_computed_value(context), 531 self.1.to_computed_value(context), 532 ) 533 } 534 535 #[inline] 536 fn from_computed_value(computed: &Self::ComputedValue) -> Self { 537 ( 538 A::from_computed_value(&computed.0), 539 B::from_computed_value(&computed.1), 540 ) 541 } 542 } 543 544 impl<T> ToComputedValue for Option<T> 545 where 546 T: ToComputedValue, 547 { 548 type ComputedValue = Option<<T as ToComputedValue>::ComputedValue>; 549 550 #[inline] 551 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { 552 self.as_ref().map(|item| item.to_computed_value(context)) 553 } 554 555 #[inline] 556 fn from_computed_value(computed: &Self::ComputedValue) -> Self { 557 computed.as_ref().map(T::from_computed_value) 558 } 559 } 560 561 impl<T> ToComputedValue for default::Size2D<T> 562 where 563 T: ToComputedValue, 564 { 565 type ComputedValue = default::Size2D<<T as ToComputedValue>::ComputedValue>; 566 567 #[inline] 568 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { 569 Size2D::new( 570 self.width.to_computed_value(context), 571 self.height.to_computed_value(context), 572 ) 573 } 574 575 #[inline] 576 fn from_computed_value(computed: &Self::ComputedValue) -> Self { 577 Size2D::new( 578 T::from_computed_value(&computed.width), 579 T::from_computed_value(&computed.height), 580 ) 581 } 582 } 583 584 impl<T> ToComputedValue for Vec<T> 585 where 586 T: ToComputedValue, 587 { 588 type ComputedValue = Vec<<T as ToComputedValue>::ComputedValue>; 589 590 #[inline] 591 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { 592 self.iter() 593 .map(|item| item.to_computed_value(context)) 594 .collect() 595 } 596 597 #[inline] 598 fn from_computed_value(computed: &Self::ComputedValue) -> Self { 599 computed.iter().map(T::from_computed_value).collect() 600 } 601 } 602 603 impl<T> ToComputedValue for Box<T> 604 where 605 T: ToComputedValue, 606 { 607 type ComputedValue = Box<<T as ToComputedValue>::ComputedValue>; 608 609 #[inline] 610 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { 611 Box::new(T::to_computed_value(self, context)) 612 } 613 614 #[inline] 615 fn from_computed_value(computed: &Self::ComputedValue) -> Self { 616 Box::new(T::from_computed_value(computed)) 617 } 618 } 619 620 impl<T> ToComputedValue for Box<[T]> 621 where 622 T: ToComputedValue, 623 { 624 type ComputedValue = Box<[<T as ToComputedValue>::ComputedValue]>; 625 626 #[inline] 627 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { 628 self.iter() 629 .map(|item| item.to_computed_value(context)) 630 .collect() 631 } 632 633 #[inline] 634 fn from_computed_value(computed: &Self::ComputedValue) -> Self { 635 computed.iter().map(T::from_computed_value).collect() 636 } 637 } 638 639 impl<T> ToComputedValue for crate::OwnedSlice<T> 640 where 641 T: ToComputedValue, 642 { 643 type ComputedValue = crate::OwnedSlice<<T as ToComputedValue>::ComputedValue>; 644 645 #[inline] 646 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { 647 self.iter() 648 .map(|item| item.to_computed_value(context)) 649 .collect() 650 } 651 652 #[inline] 653 fn from_computed_value(computed: &Self::ComputedValue) -> Self { 654 computed.iter().map(T::from_computed_value).collect() 655 } 656 } 657 658 impl<T> ToComputedValue for thin_vec::ThinVec<T> 659 where 660 T: ToComputedValue, 661 { 662 type ComputedValue = thin_vec::ThinVec<<T as ToComputedValue>::ComputedValue>; 663 664 #[inline] 665 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { 666 self.iter() 667 .map(|item| item.to_computed_value(context)) 668 .collect() 669 } 670 671 #[inline] 672 fn from_computed_value(computed: &Self::ComputedValue) -> Self { 673 computed.iter().map(T::from_computed_value).collect() 674 } 675 } 676 677 // NOTE(emilio): This is implementable more generically, but it's unlikely 678 // what you want there, as it forces you to have an extra allocation. 679 // 680 // We could do that if needed, ideally with specialization for the case where 681 // ComputedValue = T. But we don't need it for now. 682 impl<T> ToComputedValue for Arc<T> 683 where 684 T: ToComputedValue<ComputedValue = T>, 685 { 686 type ComputedValue = Self; 687 688 #[inline] 689 fn to_computed_value(&self, _: &Context) -> Self { 690 self.clone() 691 } 692 693 #[inline] 694 fn from_computed_value(computed: &Self) -> Self { 695 computed.clone() 696 } 697 } 698 699 // Same caveat as above applies. 700 impl<T> ToComputedValue for ArcSlice<T> 701 where 702 T: ToComputedValue<ComputedValue = T>, 703 { 704 type ComputedValue = Self; 705 706 #[inline] 707 fn to_computed_value(&self, _: &Context) -> Self { 708 self.clone() 709 } 710 711 #[inline] 712 fn from_computed_value(computed: &Self) -> Self { 713 computed.clone() 714 } 715 } 716 717 trivial_to_computed_value!(()); 718 trivial_to_computed_value!(bool); 719 trivial_to_computed_value!(f32); 720 trivial_to_computed_value!(i32); 721 trivial_to_computed_value!(u8); 722 trivial_to_computed_value!(u16); 723 trivial_to_computed_value!(u32); 724 trivial_to_computed_value!(usize); 725 trivial_to_computed_value!(Atom); 726 trivial_to_computed_value!(crate::values::AtomIdent); 727 #[cfg(feature = "servo")] 728 trivial_to_computed_value!(crate::Namespace); 729 #[cfg(feature = "servo")] 730 trivial_to_computed_value!(crate::Prefix); 731 trivial_to_computed_value!(crate::stylesheets::UrlExtraData); 732 trivial_to_computed_value!(String); 733 trivial_to_computed_value!(Box<str>); 734 trivial_to_computed_value!(crate::OwnedStr); 735 trivial_to_computed_value!(style_traits::values::specified::AllowedNumericType); 736 trivial_to_computed_value!(crate::values::generics::color::ColorMixFlags); 737 738 #[allow(missing_docs)] 739 #[derive( 740 Animate, 741 Clone, 742 ComputeSquaredDistance, 743 Copy, 744 Debug, 745 MallocSizeOf, 746 PartialEq, 747 ToAnimatedZero, 748 ToCss, 749 ToResolvedValue, 750 )] 751 #[repr(C, u8)] 752 pub enum AngleOrPercentage { 753 Percentage(Percentage), 754 Angle(Angle), 755 } 756 757 impl ToComputedValue for specified::AngleOrPercentage { 758 type ComputedValue = AngleOrPercentage; 759 760 #[inline] 761 fn to_computed_value(&self, context: &Context) -> AngleOrPercentage { 762 match *self { 763 specified::AngleOrPercentage::Percentage(percentage) => { 764 AngleOrPercentage::Percentage(percentage.to_computed_value(context)) 765 }, 766 specified::AngleOrPercentage::Angle(angle) => { 767 AngleOrPercentage::Angle(angle.to_computed_value(context)) 768 }, 769 } 770 } 771 #[inline] 772 fn from_computed_value(computed: &AngleOrPercentage) -> Self { 773 match *computed { 774 AngleOrPercentage::Percentage(percentage) => specified::AngleOrPercentage::Percentage( 775 ToComputedValue::from_computed_value(&percentage), 776 ), 777 AngleOrPercentage::Angle(angle) => { 778 specified::AngleOrPercentage::Angle(ToComputedValue::from_computed_value(&angle)) 779 }, 780 } 781 } 782 } 783 784 /// A `<number>` value. 785 pub type Number = CSSFloat; 786 787 impl IsParallelTo for (Number, Number, Number) { 788 fn is_parallel_to(&self, vector: &DirectionVector) -> bool { 789 use euclid::approxeq::ApproxEq; 790 // If a and b is parallel, the angle between them is 0deg, so 791 // a x b = |a|*|b|*sin(0)*n = 0 * n, |a x b| == 0. 792 let self_vector = DirectionVector::new(self.0, self.1, self.2); 793 self_vector 794 .cross(*vector) 795 .square_length() 796 .approx_eq(&0.0f32) 797 } 798 } 799 800 /// A wrapper of Number, but the value >= 0. 801 pub type NonNegativeNumber = NonNegative<CSSFloat>; 802 803 impl From<CSSFloat> for NonNegativeNumber { 804 #[inline] 805 fn from(number: CSSFloat) -> NonNegativeNumber { 806 NonNegative::<CSSFloat>(number) 807 } 808 } 809 810 impl From<NonNegativeNumber> for CSSFloat { 811 #[inline] 812 fn from(number: NonNegativeNumber) -> CSSFloat { 813 number.0 814 } 815 } 816 817 impl One for NonNegativeNumber { 818 #[inline] 819 fn one() -> Self { 820 NonNegative(1.0) 821 } 822 823 #[inline] 824 fn is_one(&self) -> bool { 825 self.0 == 1.0 826 } 827 } 828 829 /// A wrapper of Number, but the value between 0 and 1 830 pub type ZeroToOneNumber = ZeroToOne<CSSFloat>; 831 832 impl ToAnimatedValue for ZeroToOneNumber { 833 type AnimatedValue = Self; 834 835 #[inline] 836 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue { 837 self 838 } 839 840 #[inline] 841 fn from_animated_value(animated: Self::AnimatedValue) -> Self { 842 Self(animated.0.max(0.).min(1.)) 843 } 844 } 845 846 impl From<CSSFloat> for ZeroToOneNumber { 847 #[inline] 848 fn from(number: CSSFloat) -> Self { 849 Self(number) 850 } 851 } 852 853 /// A wrapper of Number, but the value >= 1. 854 pub type GreaterThanOrEqualToOneNumber = GreaterThanOrEqualToOne<CSSFloat>; 855 856 impl ToAnimatedValue for GreaterThanOrEqualToOneNumber { 857 type AnimatedValue = CSSFloat; 858 859 #[inline] 860 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue { 861 self.0 862 } 863 864 #[inline] 865 fn from_animated_value(animated: Self::AnimatedValue) -> Self { 866 animated.max(1.).into() 867 } 868 } 869 870 impl From<CSSFloat> for GreaterThanOrEqualToOneNumber { 871 #[inline] 872 fn from(number: CSSFloat) -> GreaterThanOrEqualToOneNumber { 873 GreaterThanOrEqualToOne::<CSSFloat>(number) 874 } 875 } 876 877 impl From<GreaterThanOrEqualToOneNumber> for CSSFloat { 878 #[inline] 879 fn from(number: GreaterThanOrEqualToOneNumber) -> CSSFloat { 880 number.0 881 } 882 } 883 884 #[allow(missing_docs)] 885 #[derive( 886 Animate, 887 Clone, 888 ComputeSquaredDistance, 889 Copy, 890 Debug, 891 MallocSizeOf, 892 PartialEq, 893 ToAnimatedZero, 894 ToAnimatedValue, 895 ToCss, 896 ToResolvedValue, 897 )] 898 #[repr(C, u8)] 899 pub enum NumberOrPercentage { 900 Percentage(Percentage), 901 Number(Number), 902 } 903 904 impl ClampToNonNegative for NumberOrPercentage { 905 fn clamp_to_non_negative(self) -> Self { 906 match self { 907 NumberOrPercentage::Percentage(p) => { 908 NumberOrPercentage::Percentage(p.clamp_to_non_negative()) 909 }, 910 NumberOrPercentage::Number(n) => NumberOrPercentage::Number(n.clamp_to_non_negative()), 911 } 912 } 913 } 914 915 impl ToComputedValue for specified::NumberOrPercentage { 916 type ComputedValue = NumberOrPercentage; 917 918 #[inline] 919 fn to_computed_value(&self, context: &Context) -> NumberOrPercentage { 920 match *self { 921 specified::NumberOrPercentage::Percentage(percentage) => { 922 NumberOrPercentage::Percentage(percentage.to_computed_value(context)) 923 }, 924 specified::NumberOrPercentage::Number(number) => { 925 NumberOrPercentage::Number(number.to_computed_value(context)) 926 }, 927 } 928 } 929 #[inline] 930 fn from_computed_value(computed: &NumberOrPercentage) -> Self { 931 match *computed { 932 NumberOrPercentage::Percentage(percentage) => { 933 specified::NumberOrPercentage::Percentage(ToComputedValue::from_computed_value( 934 &percentage, 935 )) 936 }, 937 NumberOrPercentage::Number(number) => { 938 specified::NumberOrPercentage::Number(ToComputedValue::from_computed_value(&number)) 939 }, 940 } 941 } 942 } 943 944 /// A non-negative <number-percentage>. 945 pub type NonNegativeNumberOrPercentage = NonNegative<NumberOrPercentage>; 946 947 impl NonNegativeNumberOrPercentage { 948 /// Returns the `100%` value. 949 #[inline] 950 pub fn hundred_percent() -> Self { 951 NonNegative(NumberOrPercentage::Percentage(Percentage::hundred())) 952 } 953 } 954 955 /// A type used for opacity. 956 pub type Opacity = CSSFloat; 957 958 /// A `<integer>` value. 959 pub type Integer = CSSInteger; 960 961 /// A wrapper of Integer, but only accept a value >= 1. 962 pub type PositiveInteger = GreaterThanOrEqualToOne<CSSInteger>; 963 964 impl ToAnimatedValue for PositiveInteger { 965 type AnimatedValue = CSSInteger; 966 967 #[inline] 968 fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue { 969 self.0 970 } 971 972 #[inline] 973 fn from_animated_value(animated: Self::AnimatedValue) -> Self { 974 cmp::max(animated, 1).into() 975 } 976 } 977 978 impl From<CSSInteger> for PositiveInteger { 979 #[inline] 980 fn from(int: CSSInteger) -> PositiveInteger { 981 GreaterThanOrEqualToOne::<CSSInteger>(int) 982 } 983 } 984 985 /// rect(...) | auto 986 pub type ClipRect = generics::GenericClipRect<LengthOrAuto>; 987 988 /// rect(...) | auto 989 pub type ClipRectOrAuto = generics::GenericClipRectOrAuto<ClipRect>; 990 991 /// The computed value of a grid `<track-breadth>` 992 pub type TrackBreadth = GenericTrackBreadth<LengthPercentage>; 993 994 /// The computed value of a grid `<track-size>` 995 pub type TrackSize = GenericTrackSize<LengthPercentage>; 996 997 /// The computed value of a grid `<track-size>+` 998 pub type ImplicitGridTracks = GenericImplicitGridTracks<TrackSize>; 999 1000 /// The computed value of a grid `<track-list>` 1001 /// (could also be `<auto-track-list>` or `<explicit-track-list>`) 1002 pub type TrackList = GenericTrackList<LengthPercentage, Integer>; 1003 1004 /// The computed value of a `<grid-line>`. 1005 pub type GridLine = GenericGridLine<Integer>; 1006 1007 /// `<grid-template-rows> | <grid-template-columns>` 1008 pub type GridTemplateComponent = GenericGridTemplateComponent<LengthPercentage, Integer>; 1009 1010 impl ClipRect { 1011 /// Given a border box, resolves the clip rect against the border box 1012 /// in the same space the border box is in 1013 pub fn for_border_rect<T: Copy + From<Length> + Add<Output = T> + Sub<Output = T>, U>( 1014 &self, 1015 border_box: Rect<T, U>, 1016 ) -> Rect<T, U> { 1017 fn extract_clip_component<T: From<Length>>(p: &LengthOrAuto, or: T) -> T { 1018 match *p { 1019 LengthOrAuto::Auto => or, 1020 LengthOrAuto::LengthPercentage(ref length) => T::from(*length), 1021 } 1022 } 1023 1024 let clip_origin = Point2D::new( 1025 From::from(self.left.auto_is(|| Length::new(0.))), 1026 From::from(self.top.auto_is(|| Length::new(0.))), 1027 ); 1028 let right = extract_clip_component(&self.right, border_box.size.width); 1029 let bottom = extract_clip_component(&self.bottom, border_box.size.height); 1030 let clip_size = Size2D::new(right - clip_origin.x, bottom - clip_origin.y); 1031 1032 Rect::new(clip_origin, clip_size).translate(border_box.origin.to_vector()) 1033 } 1034 }