display_item.rs (94028B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use euclid::{SideOffsets2D, Angle}; 6 use peek_poke::PeekPoke; 7 use std::ops::Not; 8 // local imports 9 use crate::{font, SnapshotImageKey}; 10 use crate::{APZScrollGeneration, HasScrollLinkedEffect, PipelineId, PropertyBinding}; 11 use crate::serde::{Serialize, Deserialize}; 12 use crate::color::ColorF; 13 use crate::image::{ColorDepth, ImageKey}; 14 use crate::units::*; 15 use std::hash::{Hash, Hasher}; 16 17 // ****************************************************************** 18 // * NOTE: some of these structs have an "IMPLICIT" comment. * 19 // * This indicates that the BuiltDisplayList will have serialized * 20 // * a list of values nearby that this item consumes. The traversal * 21 // * iterator should handle finding these. DebugDisplayItem should * 22 // * make them explicit. * 23 // ****************************************************************** 24 25 /// A tag that can be used to identify items during hit testing. If the tag 26 /// is missing then the item doesn't take part in hit testing at all. This 27 /// is composed of two numbers. In Servo, the first is an identifier while the 28 /// second is used to select the cursor that should be used during mouse 29 /// movement. In Gecko, the first is a scrollframe identifier, while the second 30 /// is used to store various flags that APZ needs to properly process input 31 /// events. 32 pub type ItemTag = (u64, u16); 33 34 /// An identifier used to refer to previously sent display items. Currently it 35 /// refers to individual display items, but this may change later. 36 pub type ItemKey = u16; 37 38 #[repr(C)] 39 #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Deserialize, MallocSizeOf, Serialize, PeekPoke)] 40 pub struct PrimitiveFlags(u8); 41 42 bitflags! { 43 impl PrimitiveFlags: u8 { 44 /// The CSS backface-visibility property (yes, it can be really granular) 45 const IS_BACKFACE_VISIBLE = 1 << 0; 46 /// If set, this primitive represents a scroll bar container 47 const IS_SCROLLBAR_CONTAINER = 1 << 1; 48 /// This is used as a performance hint - this primitive may be promoted to a native 49 /// compositor surface under certain (implementation specific) conditions. This 50 /// is typically used for large videos, and canvas elements. 51 const PREFER_COMPOSITOR_SURFACE = 1 << 2; 52 /// If set, this primitive can be passed directly to the compositor via its 53 /// ExternalImageId, and the compositor will use the native image directly. 54 /// Used as a further extension on top of PREFER_COMPOSITOR_SURFACE. 55 const SUPPORTS_EXTERNAL_COMPOSITOR_SURFACE = 1 << 3; 56 /// This flags disables snapping and forces anti-aliasing even if the primitive is axis-aligned. 57 const ANTIALISED = 1 << 4; 58 /// If true, this primitive is used as a background for checkerboarding 59 const CHECKERBOARD_BACKGROUND = 1 << 5; 60 } 61 } 62 63 impl core::fmt::Debug for PrimitiveFlags { 64 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 65 if self.is_empty() { 66 write!(f, "{:#x}", Self::empty().bits()) 67 } else { 68 bitflags::parser::to_writer(self, f) 69 } 70 } 71 } 72 73 impl Default for PrimitiveFlags { 74 fn default() -> Self { 75 PrimitiveFlags::IS_BACKFACE_VISIBLE 76 } 77 } 78 79 /// A grouping of fields a lot of display items need, just to avoid 80 /// repeating these over and over in this file. 81 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 82 pub struct CommonItemProperties { 83 /// Bounds of the display item to clip to. Many items are logically 84 /// infinite, and rely on this clip_rect to define their bounds 85 /// (solid colors, background-images, gradients, etc). 86 pub clip_rect: LayoutRect, 87 /// Additional clips 88 pub clip_chain_id: ClipChainId, 89 /// The coordinate-space the item is in (yes, it can be really granular) 90 pub spatial_id: SpatialId, 91 /// Various flags describing properties of this primitive. 92 pub flags: PrimitiveFlags, 93 } 94 95 impl CommonItemProperties { 96 /// Convenience for tests. 97 pub fn new( 98 clip_rect: LayoutRect, 99 space_and_clip: SpaceAndClipInfo, 100 ) -> Self { 101 Self { 102 clip_rect, 103 spatial_id: space_and_clip.spatial_id, 104 clip_chain_id: space_and_clip.clip_chain_id, 105 flags: PrimitiveFlags::default(), 106 } 107 } 108 } 109 110 /// Per-primitive information about the nodes in the clip tree and 111 /// the spatial tree that the primitive belongs to. 112 /// 113 /// Note: this is a separate struct from `PrimitiveInfo` because 114 /// it needs indirectional mapping during the DL flattening phase, 115 /// turning into `ScrollNodeAndClipChain`. 116 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 117 pub struct SpaceAndClipInfo { 118 pub spatial_id: SpatialId, 119 pub clip_chain_id: ClipChainId, 120 } 121 122 impl SpaceAndClipInfo { 123 /// Create a new space/clip info associated with the root 124 /// scroll frame. 125 pub fn root_scroll(pipeline_id: PipelineId) -> Self { 126 SpaceAndClipInfo { 127 spatial_id: SpatialId::root_scroll_node(pipeline_id), 128 clip_chain_id: ClipChainId::INVALID, 129 } 130 } 131 } 132 133 /// Defines a caller provided key that is unique for a given spatial node, and is stable across 134 /// display lists. WR uses this to determine which spatial nodes are added / removed for a new 135 /// display list. The content itself is arbitrary and opaque to WR, the only thing that matters 136 /// is that it's unique and stable between display lists. 137 #[repr(C)] 138 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke, Default, Eq, Hash)] 139 pub struct SpatialTreeItemKey { 140 key0: u64, 141 key1: u64, 142 } 143 144 impl SpatialTreeItemKey { 145 pub fn new(key0: u64, key1: u64) -> Self { 146 SpatialTreeItemKey { 147 key0, 148 key1, 149 } 150 } 151 } 152 153 #[repr(u8)] 154 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] 155 pub enum SpatialTreeItem { 156 ScrollFrame(ScrollFrameDescriptor), 157 ReferenceFrame(ReferenceFrameDescriptor), 158 StickyFrame(StickyFrameDescriptor), 159 Invalid, 160 } 161 162 #[repr(u8)] 163 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] 164 pub enum DisplayItem { 165 // These are the "real content" display items 166 Rectangle(RectangleDisplayItem), 167 HitTest(HitTestDisplayItem), 168 Text(TextDisplayItem), 169 Line(LineDisplayItem), 170 Border(BorderDisplayItem), 171 BoxShadow(BoxShadowDisplayItem), 172 PushShadow(PushShadowDisplayItem), 173 Gradient(GradientDisplayItem), 174 RadialGradient(RadialGradientDisplayItem), 175 ConicGradient(ConicGradientDisplayItem), 176 Image(ImageDisplayItem), 177 RepeatingImage(RepeatingImageDisplayItem), 178 YuvImage(YuvImageDisplayItem), 179 BackdropFilter(BackdropFilterDisplayItem), 180 181 // Clips 182 RectClip(RectClipDisplayItem), 183 RoundedRectClip(RoundedRectClipDisplayItem), 184 ImageMaskClip(ImageMaskClipDisplayItem), 185 ClipChain(ClipChainItem), 186 187 // Spaces and Frames that content can be scoped under. 188 Iframe(IframeDisplayItem), 189 PushReferenceFrame(ReferenceFrameDisplayListItem), 190 PushStackingContext(PushStackingContextDisplayItem), 191 192 // These marker items indicate an array of data follows, to be used for the 193 // next non-marker item. 194 SetGradientStops, 195 SetFilterOps, 196 SetFilterData, 197 SetPoints, 198 199 // These marker items terminate a scope introduced by a previous item. 200 PopReferenceFrame, 201 PopStackingContext, 202 PopAllShadows, 203 204 ReuseItems(ItemKey), 205 RetainedItems(ItemKey), 206 207 // For debugging purposes. 208 DebugMarker(u32), 209 } 210 211 /// This is a "complete" version of the DisplayItem, with all implicit trailing 212 /// arrays included, for debug serialization (captures). 213 #[cfg(any(feature = "serialize", feature = "deserialize"))] 214 #[cfg_attr(feature = "serialize", derive(Serialize))] 215 #[cfg_attr(feature = "deserialize", derive(Deserialize))] 216 pub enum DebugDisplayItem { 217 Rectangle(RectangleDisplayItem), 218 HitTest(HitTestDisplayItem), 219 Text(TextDisplayItem, Vec<font::GlyphInstance>), 220 Line(LineDisplayItem), 221 Border(BorderDisplayItem), 222 BoxShadow(BoxShadowDisplayItem), 223 PushShadow(PushShadowDisplayItem), 224 Gradient(GradientDisplayItem), 225 RadialGradient(RadialGradientDisplayItem), 226 ConicGradient(ConicGradientDisplayItem), 227 Image(ImageDisplayItem), 228 RepeatingImage(RepeatingImageDisplayItem), 229 YuvImage(YuvImageDisplayItem), 230 BackdropFilter(BackdropFilterDisplayItem), 231 232 ImageMaskClip(ImageMaskClipDisplayItem), 233 RoundedRectClip(RoundedRectClipDisplayItem), 234 RectClip(RectClipDisplayItem), 235 ClipChain(ClipChainItem, Vec<ClipId>), 236 237 Iframe(IframeDisplayItem), 238 PushReferenceFrame(ReferenceFrameDisplayListItem), 239 PushStackingContext(PushStackingContextDisplayItem), 240 241 SetGradientStops(Vec<GradientStop>), 242 SetFilterOps(Vec<FilterOp>), 243 SetFilterData(FilterData), 244 SetPoints(Vec<LayoutPoint>), 245 246 PopReferenceFrame, 247 PopStackingContext, 248 PopAllShadows, 249 250 DebugMarker(u32) 251 } 252 253 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 254 pub struct ImageMaskClipDisplayItem { 255 pub id: ClipId, 256 pub spatial_id: SpatialId, 257 pub image_mask: ImageMask, 258 pub fill_rule: FillRule, 259 } // IMPLICIT points: Vec<LayoutPoint> 260 261 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 262 pub struct RectClipDisplayItem { 263 pub id: ClipId, 264 pub spatial_id: SpatialId, 265 pub clip_rect: LayoutRect, 266 } 267 268 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 269 pub struct RoundedRectClipDisplayItem { 270 pub id: ClipId, 271 pub spatial_id: SpatialId, 272 pub clip: ComplexClipRegion, 273 } 274 275 /// The minimum and maximum allowable offset for a sticky frame in a single dimension. 276 #[repr(C)] 277 #[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 278 pub struct StickyOffsetBounds { 279 /// The minimum offset for this frame, typically a negative value, which specifies how 280 /// far in the negative direction the sticky frame can offset its contents in this 281 /// dimension. 282 pub min: f32, 283 284 /// The maximum offset for this frame, typically a positive value, which specifies how 285 /// far in the positive direction the sticky frame can offset its contents in this 286 /// dimension. 287 pub max: f32, 288 } 289 290 impl StickyOffsetBounds { 291 pub fn new(min: f32, max: f32) -> StickyOffsetBounds { 292 StickyOffsetBounds { min, max } 293 } 294 } 295 296 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 297 pub struct StickyFrameDescriptor { 298 pub id: SpatialId, 299 pub parent_spatial_id: SpatialId, 300 pub bounds: LayoutRect, 301 302 /// The margins that should be maintained between the edge of the parent viewport and this 303 /// sticky frame. A margin of None indicates that the sticky frame should not stick at all 304 /// to that particular edge of the viewport. 305 pub margins: SideOffsets2D<Option<f32>, LayoutPixel>, 306 307 /// The minimum and maximum vertical offsets for this sticky frame. Ignoring these constraints, 308 /// the sticky frame will continue to stick to the edge of the viewport as its original 309 /// position is scrolled out of view. Constraints specify a maximum and minimum offset from the 310 /// original position relative to non-sticky content within the same scrolling frame. 311 pub vertical_offset_bounds: StickyOffsetBounds, 312 313 /// The minimum and maximum horizontal offsets for this sticky frame. Ignoring these constraints, 314 /// the sticky frame will continue to stick to the edge of the viewport as its original 315 /// position is scrolled out of view. Constraints specify a maximum and minimum offset from the 316 /// original position relative to non-sticky content within the same scrolling frame. 317 pub horizontal_offset_bounds: StickyOffsetBounds, 318 319 /// The amount of offset that has already been applied to the sticky frame. A positive y 320 /// component this field means that a top-sticky item was in a scrollframe that has been 321 /// scrolled down, such that the sticky item's position needed to be offset downwards by 322 /// `previously_applied_offset.y`. A negative y component corresponds to the upward offset 323 /// applied due to bottom-stickiness. The x-axis works analogously. 324 pub previously_applied_offset: LayoutVector2D, 325 326 /// A unique (per-pipeline) key for this spatial that is stable across display lists. 327 pub key: SpatialTreeItemKey, 328 329 /// A property binding that we use to store an animation ID for APZ 330 pub transform: Option<PropertyBinding<LayoutTransform>>, 331 } 332 333 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 334 pub struct ScrollFrameDescriptor { 335 /// The id of the space this scroll frame creates 336 pub scroll_frame_id: SpatialId, 337 /// The size of the contents this contains (so the backend knows how far it can scroll). 338 // FIXME: this can *probably* just be a size? Origin seems to just get thrown out. 339 pub content_rect: LayoutRect, 340 pub frame_rect: LayoutRect, 341 pub parent_space: SpatialId, 342 pub external_id: ExternalScrollId, 343 /// The amount this scrollframe has already been scrolled by, in the caller. 344 /// This means that all the display items that are inside the scrollframe 345 /// will have their coordinates shifted by this amount, and this offset 346 /// should be added to those display item coordinates in order to get a 347 /// normalized value that is consistent across display lists. 348 pub external_scroll_offset: LayoutVector2D, 349 /// The generation of the external_scroll_offset. 350 pub scroll_offset_generation: APZScrollGeneration, 351 /// Whether this scrollframe document has any scroll-linked effect or not. 352 pub has_scroll_linked_effect: HasScrollLinkedEffect, 353 /// A unique (per-pipeline) key for this spatial that is stable across display lists. 354 pub key: SpatialTreeItemKey, 355 } 356 357 /// A solid or an animating color to draw (may not actually be a rectangle due to complex clips) 358 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 359 pub struct RectangleDisplayItem { 360 pub common: CommonItemProperties, 361 pub bounds: LayoutRect, 362 pub color: PropertyBinding<ColorF>, 363 } 364 365 /// A minimal hit-testable item for the parent browser's convenience, and is 366 /// slimmer than a RectangleDisplayItem (no color). The existence of this as a 367 /// distinct item also makes it easier to inspect/debug display items. 368 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 369 pub struct HitTestDisplayItem { 370 pub rect: LayoutRect, 371 pub clip_chain_id: ClipChainId, 372 pub spatial_id: SpatialId, 373 pub flags: PrimitiveFlags, 374 pub tag: ItemTag, 375 } 376 377 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 378 pub struct LineDisplayItem { 379 pub common: CommonItemProperties, 380 /// We need a separate rect from common.clip_rect to encode cute 381 /// tricks that firefox does to make a series of text-decorations seamlessly 382 /// line up -- snapping the decorations to a multiple of their period, and 383 /// then clipping them to their "proper" area. This rect is that "logical" 384 /// snapped area that may be clipped to the right size by the clip_rect. 385 pub area: LayoutRect, 386 /// Whether the rect is interpretted as vertical or horizontal 387 pub orientation: LineOrientation, 388 /// This could potentially be implied from area, but we currently prefer 389 /// that this is the responsibility of the layout engine. Value irrelevant 390 /// for non-wavy lines. 391 // FIXME: this was done before we could use tagged unions in enums, but now 392 // it should just be part of LineStyle::Wavy. 393 pub wavy_line_thickness: f32, 394 pub color: ColorF, 395 pub style: LineStyle, 396 } 397 398 #[repr(u8)] 399 #[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)] 400 pub enum LineOrientation { 401 Vertical, 402 Horizontal, 403 } 404 405 #[repr(u8)] 406 #[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)] 407 pub enum LineStyle { 408 Solid, 409 Dotted, 410 Dashed, 411 Wavy, 412 } 413 414 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 415 pub struct TextDisplayItem { 416 pub common: CommonItemProperties, 417 /// The area all the glyphs should be found in. Strictly speaking this isn't 418 /// necessarily needed, but layout engines should already "know" this, and we 419 /// use it cull and size things quickly before glyph layout is done. Currently 420 /// the glyphs *can* be outside these bounds, but that should imply they 421 /// can be cut off. 422 // FIXME: these are currently sometimes ignored to keep some old wrench tests 423 // working, but we should really just fix the tests! 424 pub bounds: LayoutRect, 425 pub font_key: font::FontInstanceKey, 426 pub color: ColorF, 427 pub glyph_options: Option<font::GlyphOptions>, 428 pub ref_frame_offset: LayoutVector2D, 429 } // IMPLICIT: glyphs: Vec<font::GlyphInstance> 430 431 #[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 432 pub struct NormalBorder { 433 pub left: BorderSide, 434 pub right: BorderSide, 435 pub top: BorderSide, 436 pub bottom: BorderSide, 437 pub radius: BorderRadius, 438 /// Whether to apply anti-aliasing on the border corners. 439 /// 440 /// Note that for this to be `false` and work, this requires the borders to 441 /// be solid, and no border-radius. 442 pub do_aa: bool, 443 } 444 445 impl NormalBorder { 446 fn can_disable_antialiasing(&self) -> bool { 447 fn is_valid(style: BorderStyle) -> bool { 448 style == BorderStyle::Solid || style == BorderStyle::None 449 } 450 451 self.radius.is_zero() && 452 is_valid(self.top.style) && 453 is_valid(self.left.style) && 454 is_valid(self.bottom.style) && 455 is_valid(self.right.style) 456 } 457 458 /// Normalizes a border so that we don't render disallowed stuff, like inset 459 /// borders that are less than two pixels wide. 460 #[inline] 461 pub fn normalize(&mut self, widths: &LayoutSideOffsets) { 462 debug_assert!( 463 self.do_aa || self.can_disable_antialiasing(), 464 "Unexpected disabled-antialiasing in a border, likely won't work or will be ignored" 465 ); 466 467 #[inline] 468 fn renders_small_border_solid(style: BorderStyle) -> bool { 469 match style { 470 BorderStyle::Groove | 471 BorderStyle::Ridge => true, 472 _ => false, 473 } 474 } 475 476 let normalize_side = |side: &mut BorderSide, width: f32| { 477 if renders_small_border_solid(side.style) && width < 2. { 478 side.style = BorderStyle::Solid; 479 } 480 }; 481 482 normalize_side(&mut self.left, widths.left); 483 normalize_side(&mut self.right, widths.right); 484 normalize_side(&mut self.top, widths.top); 485 normalize_side(&mut self.bottom, widths.bottom); 486 } 487 } 488 489 #[repr(u8)] 490 #[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash, PeekPoke)] 491 pub enum RepeatMode { 492 Stretch, 493 Repeat, 494 Round, 495 Space, 496 } 497 498 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] 499 pub enum NinePatchBorderSource { 500 Image(ImageKey, ImageRendering), 501 Gradient(Gradient), 502 RadialGradient(RadialGradient), 503 ConicGradient(ConicGradient), 504 } 505 506 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 507 pub struct NinePatchBorder { 508 /// Describes what to use as the 9-patch source image. If this is an image, 509 /// it will be stretched to fill the size given by width x height. 510 pub source: NinePatchBorderSource, 511 512 /// The width of the 9-part image. 513 pub width: i32, 514 515 /// The height of the 9-part image. 516 pub height: i32, 517 518 /// Distances from each edge where the image should be sliced up. These 519 /// values are in 9-part-image space (the same space as width and height), 520 /// and the resulting image parts will be used to fill the corresponding 521 /// parts of the border as given by the border widths. This can lead to 522 /// stretching. 523 /// Slices can be overlapping. In that case, the same pixels from the 524 /// 9-part image will show up in multiple parts of the resulting border. 525 pub slice: DeviceIntSideOffsets, 526 527 /// Controls whether the center of the 9 patch image is rendered or 528 /// ignored. The center is never rendered if the slices are overlapping. 529 pub fill: bool, 530 531 /// Determines what happens if the horizontal side parts of the 9-part 532 /// image have a different size than the horizontal parts of the border. 533 pub repeat_horizontal: RepeatMode, 534 535 /// Determines what happens if the vertical side parts of the 9-part 536 /// image have a different size than the vertical parts of the border. 537 pub repeat_vertical: RepeatMode, 538 } 539 540 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] 541 pub enum BorderDetails { 542 Normal(NormalBorder), 543 NinePatch(NinePatchBorder), 544 } 545 546 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 547 pub struct BorderDisplayItem { 548 pub common: CommonItemProperties, 549 pub bounds: LayoutRect, 550 pub widths: LayoutSideOffsets, 551 pub details: BorderDetails, 552 } 553 554 #[repr(C)] 555 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] 556 pub enum BorderRadiusKind { 557 Uniform, 558 NonUniform, 559 } 560 561 #[repr(C)] 562 #[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 563 pub struct BorderRadius { 564 pub top_left: LayoutSize, 565 pub top_right: LayoutSize, 566 pub bottom_left: LayoutSize, 567 pub bottom_right: LayoutSize, 568 } 569 570 impl Default for BorderRadius { 571 fn default() -> Self { 572 BorderRadius { 573 top_left: LayoutSize::zero(), 574 top_right: LayoutSize::zero(), 575 bottom_left: LayoutSize::zero(), 576 bottom_right: LayoutSize::zero(), 577 } 578 } 579 } 580 581 #[repr(C)] 582 #[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 583 pub struct BorderSide { 584 pub color: ColorF, 585 pub style: BorderStyle, 586 } 587 588 #[repr(u32)] 589 #[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Hash, Eq, PeekPoke)] 590 pub enum BorderStyle { 591 None = 0, 592 Solid = 1, 593 Double = 2, 594 Dotted = 3, 595 Dashed = 4, 596 Hidden = 5, 597 Groove = 6, 598 Ridge = 7, 599 Inset = 8, 600 Outset = 9, 601 } 602 603 impl BorderStyle { 604 pub fn is_hidden(self) -> bool { 605 self == BorderStyle::Hidden || self == BorderStyle::None 606 } 607 } 608 609 #[repr(u8)] 610 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 611 pub enum BoxShadowClipMode { 612 Outset = 0, 613 Inset = 1, 614 } 615 616 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 617 pub struct BoxShadowDisplayItem { 618 pub common: CommonItemProperties, 619 pub box_bounds: LayoutRect, 620 pub offset: LayoutVector2D, 621 pub color: ColorF, 622 pub blur_radius: f32, 623 pub spread_radius: f32, 624 pub border_radius: BorderRadius, 625 pub clip_mode: BoxShadowClipMode, 626 } 627 628 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 629 pub struct PushShadowDisplayItem { 630 pub space_and_clip: SpaceAndClipInfo, 631 pub shadow: Shadow, 632 pub should_inflate: bool, 633 } 634 635 #[repr(C)] 636 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 637 pub struct Shadow { 638 pub offset: LayoutVector2D, 639 pub color: ColorF, 640 pub blur_radius: f32, 641 } 642 643 #[repr(u8)] 644 #[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd, PeekPoke)] 645 pub enum ExtendMode { 646 Clamp, 647 Repeat, 648 } 649 650 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 651 pub struct Gradient { 652 pub start_point: LayoutPoint, 653 pub end_point: LayoutPoint, 654 pub extend_mode: ExtendMode, 655 } // IMPLICIT: stops: Vec<GradientStop> 656 657 impl Gradient { 658 pub fn is_valid(&self) -> bool { 659 self.start_point.x.is_finite() && 660 self.start_point.y.is_finite() && 661 self.end_point.x.is_finite() && 662 self.end_point.y.is_finite() 663 } 664 } 665 666 /// The area 667 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 668 pub struct GradientDisplayItem { 669 /// NOTE: common.clip_rect is the area the gradient covers 670 pub common: CommonItemProperties, 671 /// The area to tile the gradient over (first tile starts at origin of this rect) 672 // FIXME: this should ideally just be `tile_origin` here, with the clip_rect 673 // defining the bounds of the item. Needs non-trivial backend changes. 674 pub bounds: LayoutRect, 675 /// How big a tile of the of the gradient should be (common case: bounds.size) 676 pub tile_size: LayoutSize, 677 /// The space between tiles of the gradient (common case: 0) 678 pub tile_spacing: LayoutSize, 679 pub gradient: Gradient, 680 } 681 682 #[repr(C)] 683 #[derive(Clone, Copy, Debug, Default, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 684 pub struct GradientStop { 685 pub offset: f32, 686 pub color: ColorF, 687 } 688 689 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 690 pub struct RadialGradient { 691 pub center: LayoutPoint, 692 pub radius: LayoutSize, 693 pub start_offset: f32, 694 pub end_offset: f32, 695 pub extend_mode: ExtendMode, 696 } // IMPLICIT stops: Vec<GradientStop> 697 698 impl RadialGradient { 699 pub fn is_valid(&self) -> bool { 700 self.center.x.is_finite() && 701 self.center.y.is_finite() && 702 self.start_offset.is_finite() && 703 self.end_offset.is_finite() 704 } 705 } 706 707 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 708 pub struct ConicGradient { 709 pub center: LayoutPoint, 710 pub angle: f32, 711 pub start_offset: f32, 712 pub end_offset: f32, 713 pub extend_mode: ExtendMode, 714 } // IMPLICIT stops: Vec<GradientStop> 715 716 impl ConicGradient { 717 pub fn is_valid(&self) -> bool { 718 self.center.x.is_finite() && 719 self.center.y.is_finite() && 720 self.angle.is_finite() && 721 self.start_offset.is_finite() && 722 self.end_offset.is_finite() 723 } 724 } 725 726 /// Just an abstraction for bundling up a bunch of clips into a "super clip". 727 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 728 pub struct ClipChainItem { 729 pub id: ClipChainId, 730 pub parent: Option<ClipChainId>, 731 } // IMPLICIT clip_ids: Vec<ClipId> 732 733 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 734 pub struct RadialGradientDisplayItem { 735 pub common: CommonItemProperties, 736 /// The area to tile the gradient over (first tile starts at origin of this rect) 737 // FIXME: this should ideally just be `tile_origin` here, with the clip_rect 738 // defining the bounds of the item. Needs non-trivial backend changes. 739 pub bounds: LayoutRect, 740 pub gradient: RadialGradient, 741 pub tile_size: LayoutSize, 742 pub tile_spacing: LayoutSize, 743 } 744 745 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 746 pub struct ConicGradientDisplayItem { 747 pub common: CommonItemProperties, 748 /// The area to tile the gradient over (first tile starts at origin of this rect) 749 // FIXME: this should ideally just be `tile_origin` here, with the clip_rect 750 // defining the bounds of the item. Needs non-trivial backend changes. 751 pub bounds: LayoutRect, 752 pub gradient: ConicGradient, 753 pub tile_size: LayoutSize, 754 pub tile_spacing: LayoutSize, 755 } 756 757 /// Renders a filtered region of its backdrop 758 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 759 pub struct BackdropFilterDisplayItem { 760 pub common: CommonItemProperties, 761 } 762 // IMPLICIT: filters: Vec<FilterOp>, filter_datas: Vec<FilterData>, filter_primitives: Vec<FilterPrimitive> 763 764 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 765 pub struct ReferenceFrameDisplayListItem { 766 } 767 768 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 769 pub struct ReferenceFrameDescriptor { 770 pub origin: LayoutPoint, 771 pub parent_spatial_id: SpatialId, 772 pub reference_frame: ReferenceFrame, 773 } 774 775 #[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 776 pub enum ReferenceFrameKind { 777 /// A normal transform matrix, may contain perspective (the CSS transform property) 778 Transform { 779 /// Optionally marks the transform as only ever having a simple 2D scale or translation, 780 /// allowing for optimizations. 781 is_2d_scale_translation: bool, 782 /// Marks that the transform should be snapped. Used for transforms which animate in 783 /// response to scrolling, eg for zooming or dynamic toolbar fixed-positioning. 784 should_snap: bool, 785 /// Marks the transform being a part of the CSS stacking context that also has 786 /// a perspective. In this case, backface visibility takes this perspective into 787 /// account. 788 paired_with_perspective: bool, 789 }, 790 /// A perspective transform, that optionally scrolls relative to a specific scroll node 791 Perspective { 792 scrolling_relative_to: Option<ExternalScrollId>, 793 } 794 } 795 796 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] 797 pub enum Rotation { 798 Degree0, 799 Degree90, 800 Degree180, 801 Degree270, 802 } 803 804 impl Rotation { 805 pub fn to_matrix( 806 &self, 807 size: LayoutSize, 808 ) -> LayoutTransform { 809 let (shift_center_to_origin, angle) = match self { 810 Rotation::Degree0 => { 811 (LayoutTransform::translation(-size.width / 2., -size.height / 2., 0.), Angle::degrees(0.)) 812 }, 813 Rotation::Degree90 => { 814 (LayoutTransform::translation(-size.height / 2., -size.width / 2., 0.), Angle::degrees(90.)) 815 }, 816 Rotation::Degree180 => { 817 (LayoutTransform::translation(-size.width / 2., -size.height / 2., 0.), Angle::degrees(180.)) 818 }, 819 Rotation::Degree270 => { 820 (LayoutTransform::translation(-size.height / 2., -size.width / 2., 0.), Angle::degrees(270.)) 821 }, 822 }; 823 let shift_origin_to_center = LayoutTransform::translation(size.width / 2., size.height / 2., 0.); 824 825 shift_center_to_origin 826 .then(&LayoutTransform::rotation(0., 0., 1.0, angle)) 827 .then(&shift_origin_to_center) 828 } 829 } 830 831 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] 832 pub enum ReferenceTransformBinding { 833 /// Standard reference frame which contains a precomputed transform. 834 Static { 835 binding: PropertyBinding<LayoutTransform>, 836 }, 837 /// Computed reference frame which dynamically calculates the transform 838 /// based on the given parameters. The reference is the content size of 839 /// the parent iframe, which is affected by snapping. 840 /// 841 /// This is used when a transform depends on the layout size of an 842 /// element, otherwise the difference between the unsnapped size 843 /// used in the transform, and the snapped size calculated during scene 844 /// building can cause seaming. 845 Computed { 846 scale_from: Option<LayoutSize>, 847 vertical_flip: bool, 848 rotation: Rotation, 849 }, 850 } 851 852 impl Default for ReferenceTransformBinding { 853 fn default() -> Self { 854 ReferenceTransformBinding::Static { 855 binding: Default::default(), 856 } 857 } 858 } 859 860 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 861 pub struct ReferenceFrame { 862 pub kind: ReferenceFrameKind, 863 pub transform_style: TransformStyle, 864 /// The transform matrix, either the perspective matrix or the transform 865 /// matrix. 866 pub transform: ReferenceTransformBinding, 867 pub id: SpatialId, 868 /// A unique (per-pipeline) key for this spatial that is stable across display lists. 869 pub key: SpatialTreeItemKey, 870 } 871 872 /// If passed in a stacking context display item, inform WebRender that 873 /// the contents of the stacking context should be retained into a texture 874 /// and associated to an image key. 875 /// 876 /// Image display items can then display the cached snapshot using the 877 /// same image key. 878 /// 879 /// The flow for creating/using/deleting snapshots is the same as with 880 /// regular images: 881 /// - The image key must have been created with `Transaction::add_snapshot_image`. 882 /// - The current scene must not contain references to the snapshot when 883 /// `Transaction::delete_snapshot_image` is called. 884 #[repr(C)] 885 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 886 pub struct SnapshotInfo { 887 /// The image key to associate the snapshot with. 888 pub key: SnapshotImageKey, 889 /// The bounds of the snapshot in local space. 890 /// 891 /// This rectangle is relative to the same coordinate space as the 892 /// child items of the stacking context. 893 pub area: LayoutRect, 894 /// If true, detach the stacking context from the scene and only 895 /// render it into the snapshot. 896 /// If false, the stacking context rendered in the frame normally 897 /// in addition to being cached into the snapshot. 898 pub detached: bool, 899 } 900 901 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 902 pub struct PushStackingContextDisplayItem { 903 pub origin: LayoutPoint, 904 pub spatial_id: SpatialId, 905 pub snapshot: Option<SnapshotInfo>, 906 pub prim_flags: PrimitiveFlags, 907 pub ref_frame_offset: LayoutVector2D, 908 pub stacking_context: StackingContext, 909 } 910 911 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 912 pub struct StackingContext { 913 pub transform_style: TransformStyle, 914 pub mix_blend_mode: MixBlendMode, 915 pub clip_chain_id: Option<ClipChainId>, 916 pub raster_space: RasterSpace, 917 pub flags: StackingContextFlags, 918 } 919 // IMPLICIT: filters: Vec<FilterOp>, filter_datas: Vec<FilterData>, filter_primitives: Vec<FilterPrimitive> 920 921 #[repr(u8)] 922 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 923 pub enum TransformStyle { 924 Flat = 0, 925 Preserve3D = 1, 926 } 927 928 /// Configure whether the contents of a stacking context 929 /// should be rasterized in local space or screen space. 930 /// Local space rasterized pictures are typically used 931 /// when we want to cache the output, and performance is 932 /// important. Note that this is a performance hint only, 933 /// which WR may choose to ignore. 934 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, MallocSizeOf, Serialize, PeekPoke)] 935 #[repr(u8)] 936 pub enum RasterSpace { 937 // Rasterize in local-space, applying supplied scale to primitives. 938 // Best performance, but lower quality. 939 Local(f32), 940 941 // Rasterize the picture in screen-space, including rotation / skew etc in 942 // the rasterized element. Best quality, but slower performance. Note that 943 // any stacking context with a perspective transform will be rasterized 944 // in local-space, even if this is set. 945 Screen, 946 } 947 948 impl RasterSpace { 949 pub fn local_scale(self) -> Option<f32> { 950 match self { 951 RasterSpace::Local(scale) => Some(scale), 952 RasterSpace::Screen => None, 953 } 954 } 955 } 956 957 impl Eq for RasterSpace {} 958 959 impl Hash for RasterSpace { 960 fn hash<H: Hasher>(&self, state: &mut H) { 961 match self { 962 RasterSpace::Screen => { 963 0.hash(state); 964 } 965 RasterSpace::Local(scale) => { 966 // Note: this is inconsistent with the Eq impl for -0.0 (don't care). 967 1.hash(state); 968 scale.to_bits().hash(state); 969 } 970 } 971 } 972 } 973 974 #[repr(C)] 975 #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Deserialize, MallocSizeOf, Serialize, PeekPoke)] 976 pub struct StackingContextFlags(u8); 977 978 bitflags! { 979 impl StackingContextFlags: u8 { 980 /// If true, this stacking context is a blend container than contains 981 /// mix-blend-mode children (and should thus be isolated). 982 const IS_BLEND_CONTAINER = 1 << 0; 983 /// If true, this stacking context is a wrapper around a backdrop-filter (e.g. for 984 /// a clip-mask). This is needed to allow the correct selection of a backdrop root 985 /// since a clip-mask stacking context creates a parent surface. 986 const WRAPS_BACKDROP_FILTER = 1 << 1; 987 /// If true, this stacking context must be isolated from parent by a surface. 988 const FORCED_ISOLATION = 1 << 2; 989 } 990 } 991 992 impl core::fmt::Debug for StackingContextFlags { 993 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 994 if self.is_empty() { 995 write!(f, "{:#x}", Self::empty().bits()) 996 } else { 997 bitflags::parser::to_writer(self, f) 998 } 999 } 1000 } 1001 1002 impl Default for StackingContextFlags { 1003 fn default() -> Self { 1004 StackingContextFlags::empty() 1005 } 1006 } 1007 1008 #[repr(u8)] 1009 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 1010 pub enum MixBlendMode { 1011 Normal = 0, 1012 Multiply = 1, 1013 Screen = 2, 1014 Overlay = 3, 1015 Darken = 4, 1016 Lighten = 5, 1017 ColorDodge = 6, 1018 ColorBurn = 7, 1019 HardLight = 8, 1020 SoftLight = 9, 1021 Difference = 10, 1022 Exclusion = 11, 1023 Hue = 12, 1024 Saturation = 13, 1025 Color = 14, 1026 Luminosity = 15, 1027 PlusLighter = 16, 1028 } 1029 1030 #[repr(C)] 1031 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 1032 pub enum ColorSpace { 1033 Srgb, 1034 LinearRgb, 1035 } 1036 1037 /// Available composite operoations for the composite filter primitive 1038 #[repr(C)] 1039 #[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 1040 pub enum CompositeOperator { 1041 Over, 1042 In, 1043 Atop, 1044 Out, 1045 Xor, 1046 Lighter, 1047 Arithmetic([f32; 4]), 1048 } 1049 1050 impl CompositeOperator { 1051 // This must stay in sync with the composite operator defines in cs_svg_filter.glsl 1052 pub fn as_int(&self) -> u32 { 1053 match self { 1054 CompositeOperator::Over => 0, 1055 CompositeOperator::In => 1, 1056 CompositeOperator::Out => 2, 1057 CompositeOperator::Atop => 3, 1058 CompositeOperator::Xor => 4, 1059 CompositeOperator::Lighter => 5, 1060 CompositeOperator::Arithmetic(..) => 6, 1061 } 1062 } 1063 } 1064 1065 /// An input to a SVG filter primitive. 1066 #[repr(C)] 1067 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 1068 pub enum FilterPrimitiveInput { 1069 /// The input is the original graphic that the filter is being applied to. 1070 Original, 1071 /// The input is the output of the previous filter primitive in the filter primitive chain. 1072 Previous, 1073 /// The input is the output of the filter primitive at the given index in the filter primitive chain. 1074 OutputOfPrimitiveIndex(usize), 1075 } 1076 1077 impl FilterPrimitiveInput { 1078 /// Gets the index of the input. 1079 /// Returns `None` if the source graphic is the input. 1080 pub fn to_index(self, cur_index: usize) -> Option<usize> { 1081 match self { 1082 FilterPrimitiveInput::Previous if cur_index > 0 => Some(cur_index - 1), 1083 FilterPrimitiveInput::OutputOfPrimitiveIndex(index) => Some(index), 1084 _ => None, 1085 } 1086 } 1087 } 1088 1089 #[repr(C)] 1090 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1091 pub struct BlendPrimitive { 1092 pub input1: FilterPrimitiveInput, 1093 pub input2: FilterPrimitiveInput, 1094 pub mode: MixBlendMode, 1095 } 1096 1097 #[repr(C)] 1098 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1099 pub struct FloodPrimitive { 1100 pub color: ColorF, 1101 } 1102 1103 impl FloodPrimitive { 1104 pub fn sanitize(&mut self) { 1105 self.color.r = self.color.r.clamp(0.0, 1.0); 1106 self.color.g = self.color.g.clamp(0.0, 1.0); 1107 self.color.b = self.color.b.clamp(0.0, 1.0); 1108 self.color.a = self.color.a.clamp(0.0, 1.0); 1109 } 1110 } 1111 1112 #[repr(C)] 1113 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1114 pub struct BlurPrimitive { 1115 pub input: FilterPrimitiveInput, 1116 pub width: f32, 1117 pub height: f32, 1118 } 1119 1120 #[repr(C)] 1121 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1122 pub struct OpacityPrimitive { 1123 pub input: FilterPrimitiveInput, 1124 pub opacity: f32, 1125 } 1126 1127 impl OpacityPrimitive { 1128 pub fn sanitize(&mut self) { 1129 self.opacity = self.opacity.clamp(0.0, 1.0); 1130 } 1131 } 1132 1133 /// cbindgen:derive-eq=false 1134 #[repr(C)] 1135 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1136 pub struct ColorMatrixPrimitive { 1137 pub input: FilterPrimitiveInput, 1138 pub matrix: [f32; 20], 1139 } 1140 1141 #[repr(C)] 1142 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1143 pub struct DropShadowPrimitive { 1144 pub input: FilterPrimitiveInput, 1145 pub shadow: Shadow, 1146 } 1147 1148 #[repr(C)] 1149 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1150 pub struct ComponentTransferPrimitive { 1151 pub input: FilterPrimitiveInput, 1152 // Component transfer data is stored in FilterData. 1153 } 1154 1155 #[repr(C)] 1156 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1157 pub struct IdentityPrimitive { 1158 pub input: FilterPrimitiveInput, 1159 } 1160 1161 #[repr(C)] 1162 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1163 pub struct OffsetPrimitive { 1164 pub input: FilterPrimitiveInput, 1165 pub offset: LayoutVector2D, 1166 } 1167 1168 #[repr(C)] 1169 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1170 pub struct CompositePrimitive { 1171 pub input1: FilterPrimitiveInput, 1172 pub input2: FilterPrimitiveInput, 1173 pub operator: CompositeOperator, 1174 } 1175 1176 /// See: https://github.com/eqrion/cbindgen/issues/9 1177 /// cbindgen:derive-eq=false 1178 #[repr(C)] 1179 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)] 1180 pub enum FilterPrimitiveKind { 1181 Identity(IdentityPrimitive), 1182 Blend(BlendPrimitive), 1183 Flood(FloodPrimitive), 1184 Blur(BlurPrimitive), 1185 // TODO: Support animated opacity? 1186 Opacity(OpacityPrimitive), 1187 /// cbindgen:derive-eq=false 1188 ColorMatrix(ColorMatrixPrimitive), 1189 DropShadow(DropShadowPrimitive), 1190 ComponentTransfer(ComponentTransferPrimitive), 1191 Offset(OffsetPrimitive), 1192 Composite(CompositePrimitive), 1193 } 1194 1195 impl Default for FilterPrimitiveKind { 1196 fn default() -> Self { 1197 FilterPrimitiveKind::Identity(IdentityPrimitive::default()) 1198 } 1199 } 1200 1201 impl FilterPrimitiveKind { 1202 pub fn sanitize(&mut self) { 1203 match self { 1204 FilterPrimitiveKind::Flood(flood) => flood.sanitize(), 1205 FilterPrimitiveKind::Opacity(opacity) => opacity.sanitize(), 1206 1207 // No sanitization needed. 1208 FilterPrimitiveKind::Identity(..) | 1209 FilterPrimitiveKind::Blend(..) | 1210 FilterPrimitiveKind::ColorMatrix(..) | 1211 FilterPrimitiveKind::Offset(..) | 1212 FilterPrimitiveKind::Composite(..) | 1213 FilterPrimitiveKind::Blur(..) | 1214 FilterPrimitiveKind::DropShadow(..) | 1215 // Component transfer's filter data is sanitized separately. 1216 FilterPrimitiveKind::ComponentTransfer(..) => {} 1217 } 1218 } 1219 } 1220 1221 /// SVG Filter Primitive. 1222 /// See: https://github.com/eqrion/cbindgen/issues/9 1223 /// cbindgen:derive-eq=false 1224 #[repr(C)] 1225 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1226 pub struct FilterPrimitive { 1227 pub kind: FilterPrimitiveKind, 1228 pub color_space: ColorSpace, 1229 } 1230 1231 impl FilterPrimitive { 1232 pub fn sanitize(&mut self) { 1233 self.kind.sanitize(); 1234 } 1235 } 1236 1237 #[repr(C)] 1238 #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize, PeekPoke)] 1239 pub enum FilterOpGraphPictureBufferId { 1240 #[default] 1241 /// empty slot in feMerge inputs 1242 None, 1243 /// reference to another (earlier) node in filter graph 1244 BufferId(i16), 1245 } 1246 1247 #[repr(C)] 1248 #[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PeekPoke)] 1249 pub struct FilterOpGraphPictureReference { 1250 /// Id of the picture in question in a namespace unique to this filter DAG 1251 pub buffer_id: FilterOpGraphPictureBufferId, 1252 } 1253 1254 #[repr(C)] 1255 #[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PeekPoke)] 1256 pub struct FilterOpGraphNode { 1257 /// True if color_interpolation_filter == LinearRgb; shader will convert 1258 /// sRGB texture pixel colors on load and convert back on store, for correct 1259 /// interpolation 1260 pub linear: bool, 1261 /// virtualized picture input binding 1 (i.e. texture source), typically 1262 /// this is used, but certain filters do not use it 1263 pub input: FilterOpGraphPictureReference, 1264 /// virtualized picture input binding 2 (i.e. texture sources), only certain 1265 /// filters use this 1266 pub input2: FilterOpGraphPictureReference, 1267 /// rect this node will render into, in filter space 1268 pub subregion: LayoutRect, 1269 } 1270 1271 /// Maximum number of SVGFE filters in one graph, this is constant size to avoid 1272 /// allocating anything, and the SVG spec allows us to drop all filters on an 1273 /// item if the graph is excessively complex - a graph this large will never be 1274 /// a good user experience, performance-wise. 1275 pub const SVGFE_GRAPH_MAX: usize = 256; 1276 1277 #[repr(C)] 1278 #[derive(Clone, Copy, Debug, Deserialize, Serialize, PeekPoke)] 1279 pub enum FilterOp { 1280 /// Filter that does no transformation of the colors, needed for 1281 /// debug purposes, and is the default value in impl_default_for_enums. 1282 /// parameters: none 1283 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1284 Identity, 1285 /// apply blur effect 1286 /// parameters: stdDeviationX, stdDeviationY 1287 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1288 Blur(f32, f32), 1289 /// apply brightness effect 1290 /// parameters: amount 1291 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1292 Brightness(f32), 1293 /// apply contrast effect 1294 /// parameters: amount 1295 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1296 Contrast(f32), 1297 /// fade image toward greyscale version of image 1298 /// parameters: amount 1299 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1300 Grayscale(f32), 1301 /// fade image toward hue-rotated version of image (rotate RGB around color wheel) 1302 /// parameters: angle 1303 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1304 HueRotate(f32), 1305 /// fade image toward inverted image (1 - RGB) 1306 /// parameters: amount 1307 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1308 Invert(f32), 1309 /// multiplies color and alpha by opacity 1310 /// parameters: amount 1311 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1312 Opacity(PropertyBinding<f32>, f32), 1313 /// multiply saturation of colors 1314 /// parameters: amount 1315 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1316 Saturate(f32), 1317 /// fade image toward sepia tone version of image 1318 /// parameters: amount 1319 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1320 Sepia(f32), 1321 /// add drop shadow version of image to the image 1322 /// parameters: shadow 1323 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1324 DropShadow(Shadow), 1325 /// transform color and alpha in image through 4x5 color matrix (transposed for efficiency) 1326 /// parameters: matrix[5][4] 1327 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1328 ColorMatrix([f32; 20]), 1329 /// internal use - convert sRGB input to linear output 1330 /// parameters: none 1331 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1332 SrgbToLinear, 1333 /// internal use - convert linear input to sRGB output 1334 /// parameters: none 1335 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1336 LinearToSrgb, 1337 /// remap RGBA with color gradients and component swizzle 1338 /// parameters: FilterData 1339 /// CSS filter semantics - operates on previous picture, uses sRGB space (non-linear) 1340 ComponentTransfer, 1341 /// replace image with a solid color 1342 /// NOTE: UNUSED; Gecko never produces this filter 1343 /// parameters: color 1344 /// CSS filter semantics - operates on previous picture,uses sRGB space (non-linear) 1345 Flood(ColorF), 1346 /// Filter that copies the SourceGraphic image into the specified subregion, 1347 /// This is intentionally the only way to get SourceGraphic into the graph, 1348 /// as the filter region must be applied before it is used. 1349 /// parameters: FilterOpGraphNode 1350 /// SVG filter semantics - no inputs, no linear 1351 SVGFESourceGraphic{node: FilterOpGraphNode}, 1352 /// Filter that copies the SourceAlpha image into the specified subregion, 1353 /// This is intentionally the only way to get SourceGraphic into the graph, 1354 /// as the filter region must be applied before it is used. 1355 /// parameters: FilterOpGraphNode 1356 /// SVG filter semantics - no inputs, no linear 1357 SVGFESourceAlpha{node: FilterOpGraphNode}, 1358 /// Filter that does no transformation of the colors, used for subregion 1359 /// cropping only. 1360 SVGFEIdentity{node: FilterOpGraphNode}, 1361 /// represents CSS opacity property as a graph node like the rest of the SVGFE* filters 1362 /// parameters: FilterOpGraphNode 1363 /// SVG filter semantics - selectable input(s), selectable between linear 1364 /// (default) and sRGB color space for calculations 1365 SVGFEOpacity{node: FilterOpGraphNode, valuebinding: PropertyBinding<f32>, value: f32}, 1366 /// convert a color image to an alpha channel - internal use; generated by 1367 /// SVGFilterInstance::GetOrCreateSourceAlphaIndex(). 1368 SVGFEToAlpha{node: FilterOpGraphNode}, 1369 /// combine 2 images with SVG_FEBLEND_MODE_DARKEN 1370 /// parameters: FilterOpGraphNode 1371 /// SVG filter semantics - selectable input(s), selectable between linear 1372 /// (default) and sRGB color space for calculations 1373 /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement 1374 SVGFEBlendDarken{node: FilterOpGraphNode}, 1375 /// combine 2 images with SVG_FEBLEND_MODE_LIGHTEN 1376 /// parameters: FilterOpGraphNode 1377 /// SVG filter semantics - selectable input(s), selectable between linear 1378 /// (default) and sRGB color space for calculations 1379 /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement 1380 SVGFEBlendLighten{node: FilterOpGraphNode}, 1381 /// combine 2 images with SVG_FEBLEND_MODE_MULTIPLY 1382 /// parameters: FilterOpGraphNode 1383 /// SVG filter semantics - selectable input(s), selectable between linear 1384 /// (default) and sRGB color space for calculations 1385 /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement 1386 SVGFEBlendMultiply{node: FilterOpGraphNode}, 1387 /// combine 2 images with SVG_FEBLEND_MODE_NORMAL 1388 /// parameters: FilterOpGraphNode 1389 /// SVG filter semantics - selectable input(s), selectable between linear 1390 /// (default) and sRGB color space for calculations 1391 /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement 1392 SVGFEBlendNormal{node: FilterOpGraphNode}, 1393 /// combine 2 images with SVG_FEBLEND_MODE_SCREEN 1394 /// parameters: FilterOpGraphNode 1395 /// SVG filter semantics - selectable input(s), selectable between linear 1396 /// (default) and sRGB color space for calculations 1397 /// Spec: https://www.w3.org/TR/filter-effects-1/#feBlendElement 1398 SVGFEBlendScreen{node: FilterOpGraphNode}, 1399 /// combine 2 images with SVG_FEBLEND_MODE_OVERLAY 1400 /// parameters: FilterOpGraphNode 1401 /// SVG filter semantics - selectable input(s), selectable between linear 1402 /// (default) and sRGB color space for calculations 1403 /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode 1404 SVGFEBlendOverlay{node: FilterOpGraphNode}, 1405 /// combine 2 images with SVG_FEBLEND_MODE_COLOR_DODGE 1406 /// parameters: FilterOpGraphNode 1407 /// SVG filter semantics - selectable input(s), selectable between linear 1408 /// (default) and sRGB color space for calculations 1409 /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode 1410 SVGFEBlendColorDodge{node: FilterOpGraphNode}, 1411 /// combine 2 images with SVG_FEBLEND_MODE_COLOR_BURN 1412 /// parameters: FilterOpGraphNode 1413 /// SVG filter semantics - selectable input(s), selectable between linear 1414 /// (default) and sRGB color space for calculations 1415 /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode 1416 SVGFEBlendColorBurn{node: FilterOpGraphNode}, 1417 /// combine 2 images with SVG_FEBLEND_MODE_HARD_LIGHT 1418 /// parameters: FilterOpGraphNode 1419 /// SVG filter semantics - selectable input(s), selectable between linear 1420 /// (default) and sRGB color space for calculations 1421 /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode 1422 SVGFEBlendHardLight{node: FilterOpGraphNode}, 1423 /// combine 2 images with SVG_FEBLEND_MODE_SOFT_LIGHT 1424 /// parameters: FilterOpGraphNode 1425 /// SVG filter semantics - selectable input(s), selectable between linear 1426 /// (default) and sRGB color space for calculations 1427 /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode 1428 SVGFEBlendSoftLight{node: FilterOpGraphNode}, 1429 /// combine 2 images with SVG_FEBLEND_MODE_DIFFERENCE 1430 /// parameters: FilterOpGraphNode 1431 /// SVG filter semantics - selectable input(s), selectable between linear 1432 /// (default) and sRGB color space for calculations 1433 /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode 1434 SVGFEBlendDifference{node: FilterOpGraphNode}, 1435 /// combine 2 images with SVG_FEBLEND_MODE_EXCLUSION 1436 /// parameters: FilterOpGraphNode 1437 /// SVG filter semantics - selectable input(s), selectable between linear 1438 /// (default) and sRGB color space for calculations 1439 /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode 1440 SVGFEBlendExclusion{node: FilterOpGraphNode}, 1441 /// combine 2 images with SVG_FEBLEND_MODE_HUE 1442 /// parameters: FilterOpGraphNode 1443 /// SVG filter semantics - selectable input(s), selectable between linear 1444 /// (default) and sRGB color space for calculations 1445 /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode 1446 SVGFEBlendHue{node: FilterOpGraphNode}, 1447 /// combine 2 images with SVG_FEBLEND_MODE_SATURATION 1448 /// parameters: FilterOpGraphNode 1449 /// SVG filter semantics - selectable input(s), selectable between linear 1450 /// (default) and sRGB color space for calculations 1451 /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode 1452 SVGFEBlendSaturation{node: FilterOpGraphNode}, 1453 /// combine 2 images with SVG_FEBLEND_MODE_COLOR 1454 /// parameters: FilterOpGraphNode 1455 /// SVG filter semantics - selectable input(s), selectable between linear 1456 /// (default) and sRGB color space for calculations 1457 /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode 1458 SVGFEBlendColor{node: FilterOpGraphNode}, 1459 /// combine 2 images with SVG_FEBLEND_MODE_LUMINOSITY 1460 /// parameters: FilterOpGraphNode 1461 /// SVG filter semantics - selectable input(s), selectable between linear 1462 /// (default) and sRGB color space for calculations 1463 /// Source: https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode 1464 SVGFEBlendLuminosity{node: FilterOpGraphNode}, 1465 /// transform colors of image through 5x4 color matrix (transposed for efficiency) 1466 /// parameters: FilterOpGraphNode, matrix[5][4] 1467 /// SVG filter semantics - selectable input(s), selectable between linear 1468 /// (default) and sRGB color space for calculations 1469 /// Spec: https://www.w3.org/TR/filter-effects-1/#feColorMatrixElement 1470 SVGFEColorMatrix{node: FilterOpGraphNode, values: [f32; 20]}, 1471 /// transform colors of image through configurable gradients with component swizzle 1472 /// parameters: FilterOpGraphNode, FilterData 1473 /// SVG filter semantics - selectable input(s), selectable between linear 1474 /// (default) and sRGB color space for calculations 1475 /// Spec: https://www.w3.org/TR/filter-effects-1/#feComponentTransferElement 1476 SVGFEComponentTransfer{node: FilterOpGraphNode}, 1477 /// composite 2 images with chosen composite mode with parameters for that mode 1478 /// parameters: FilterOpGraphNode, k1, k2, k3, k4 1479 /// SVG filter semantics - selectable input(s), selectable between linear 1480 /// (default) and sRGB color space for calculations 1481 /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement 1482 SVGFECompositeArithmetic{node: FilterOpGraphNode, k1: f32, k2: f32, k3: f32, 1483 k4: f32}, 1484 /// composite 2 images with chosen composite mode with parameters for that mode 1485 /// parameters: FilterOpGraphNode 1486 /// SVG filter semantics - selectable input(s), selectable between linear 1487 /// (default) and sRGB color space for calculations 1488 /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement 1489 SVGFECompositeATop{node: FilterOpGraphNode}, 1490 /// composite 2 images with chosen composite mode with parameters for that mode 1491 /// parameters: FilterOpGraphNode 1492 /// SVG filter semantics - selectable input(s), selectable between linear 1493 /// (default) and sRGB color space for calculations 1494 /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement 1495 SVGFECompositeIn{node: FilterOpGraphNode}, 1496 /// composite 2 images with chosen composite mode with parameters for that mode 1497 /// parameters: FilterOpGraphNode 1498 /// SVG filter semantics - selectable input(s), selectable between linear 1499 /// (default) and sRGB color space for calculations 1500 /// Docs: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feComposite 1501 SVGFECompositeLighter{node: FilterOpGraphNode}, 1502 /// composite 2 images with chosen composite mode with parameters for that mode 1503 /// parameters: FilterOpGraphNode 1504 /// SVG filter semantics - selectable input(s), selectable between linear 1505 /// (default) and sRGB color space for calculations 1506 /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement 1507 SVGFECompositeOut{node: FilterOpGraphNode}, 1508 /// composite 2 images with chosen composite mode with parameters for that mode 1509 /// parameters: FilterOpGraphNode 1510 /// SVG filter semantics - selectable input(s), selectable between linear 1511 /// (default) and sRGB color space for calculations 1512 /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement 1513 SVGFECompositeOver{node: FilterOpGraphNode}, 1514 /// composite 2 images with chosen composite mode with parameters for that mode 1515 /// parameters: FilterOpGraphNode 1516 /// SVG filter semantics - selectable input(s), selectable between linear 1517 /// (default) and sRGB color space for calculations 1518 /// Spec: https://www.w3.org/TR/filter-effects-1/#feCompositeElement 1519 SVGFECompositeXOR{node: FilterOpGraphNode}, 1520 /// transform image through convolution matrix of up to 25 values (spec 1521 /// allows more but for performance reasons we do not) 1522 /// parameters: FilterOpGraphNode, orderX, orderY, kernelValues[25], 1523 /// divisor, bias, targetX, targetY, kernelUnitLengthX, kernelUnitLengthY, 1524 /// preserveAlpha 1525 /// SVG filter semantics - selectable input(s), selectable between linear 1526 /// (default) and sRGB color space for calculations 1527 /// Spec: https://www.w3.org/TR/filter-effects-1/#feConvolveMatrixElement 1528 SVGFEConvolveMatrixEdgeModeDuplicate{node: FilterOpGraphNode, order_x: i32, 1529 order_y: i32, kernel: [f32; 25], divisor: f32, bias: f32, target_x: i32, 1530 target_y: i32, kernel_unit_length_x: f32, kernel_unit_length_y: f32, 1531 preserve_alpha: i32}, 1532 /// transform image through convolution matrix of up to 25 values (spec 1533 /// allows more but for performance reasons we do not) 1534 /// parameters: FilterOpGraphNode, orderX, orderY, kernelValues[25], 1535 /// divisor, bias, targetX, targetY, kernelUnitLengthX, kernelUnitLengthY, 1536 /// preserveAlpha 1537 /// SVG filter semantics - selectable input(s), selectable between linear 1538 /// (default) and sRGB color space for calculations 1539 /// Spec: https://www.w3.org/TR/filter-effects-1/#feConvolveMatrixElement 1540 SVGFEConvolveMatrixEdgeModeNone{node: FilterOpGraphNode, order_x: i32, 1541 order_y: i32, kernel: [f32; 25], divisor: f32, bias: f32, target_x: i32, 1542 target_y: i32, kernel_unit_length_x: f32, kernel_unit_length_y: f32, 1543 preserve_alpha: i32}, 1544 /// transform image through convolution matrix of up to 25 values (spec 1545 /// allows more but for performance reasons we do not) 1546 /// parameters: FilterOpGraphNode, orderX, orderY, kernelValues[25], 1547 /// divisor, bias, targetX, targetY, kernelUnitLengthX, kernelUnitLengthY, 1548 /// preserveAlpha 1549 /// SVG filter semantics - selectable input(s), selectable between linear 1550 /// (default) and sRGB color space for calculations 1551 /// Spec: https://www.w3.org/TR/filter-effects-1/#feConvolveMatrixElement 1552 SVGFEConvolveMatrixEdgeModeWrap{node: FilterOpGraphNode, order_x: i32, 1553 order_y: i32, kernel: [f32; 25], divisor: f32, bias: f32, target_x: i32, 1554 target_y: i32, kernel_unit_length_x: f32, kernel_unit_length_y: f32, 1555 preserve_alpha: i32}, 1556 /// calculate lighting based on heightmap image with provided values for a 1557 /// distant light source with specified direction 1558 /// parameters: FilterOpGraphNode, surfaceScale, diffuseConstant, 1559 /// kernelUnitLengthX, kernelUnitLengthY, azimuth, elevation 1560 /// SVG filter semantics - selectable input(s), selectable between linear 1561 /// (default) and sRGB color space for calculations 1562 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDiffuseLightingElement 1563 /// https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDistantLightElement 1564 SVGFEDiffuseLightingDistant{node: FilterOpGraphNode, surface_scale: f32, 1565 diffuse_constant: f32, kernel_unit_length_x: f32, 1566 kernel_unit_length_y: f32, azimuth: f32, elevation: f32}, 1567 /// calculate lighting based on heightmap image with provided values for a 1568 /// point light source at specified location 1569 /// parameters: FilterOpGraphNode, surfaceScale, diffuseConstant, 1570 /// kernelUnitLengthX, kernelUnitLengthY, x, y, z 1571 /// SVG filter semantics - selectable input(s), selectable between linear 1572 /// (default) and sRGB color space for calculations 1573 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDiffuseLightingElement 1574 /// https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEPointLightElement 1575 SVGFEDiffuseLightingPoint{node: FilterOpGraphNode, surface_scale: f32, 1576 diffuse_constant: f32, kernel_unit_length_x: f32, 1577 kernel_unit_length_y: f32, x: f32, y: f32, z: f32}, 1578 /// calculate lighting based on heightmap image with provided values for a 1579 /// spot light source at specified location pointing at specified target 1580 /// location with specified hotspot sharpness and cone angle 1581 /// parameters: FilterOpGraphNode, surfaceScale, diffuseConstant, 1582 /// kernelUnitLengthX, kernelUnitLengthY, x, y, z, pointsAtX, pointsAtY, 1583 /// pointsAtZ, specularExponent, limitingConeAngle 1584 /// SVG filter semantics - selectable input(s), selectable between linear 1585 /// (default) and sRGB color space for calculations 1586 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDiffuseLightingElement 1587 /// https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpotLightElement 1588 SVGFEDiffuseLightingSpot{node: FilterOpGraphNode, surface_scale: f32, 1589 diffuse_constant: f32, kernel_unit_length_x: f32, 1590 kernel_unit_length_y: f32, x: f32, y: f32, z: f32, points_at_x: f32, 1591 points_at_y: f32, points_at_z: f32, cone_exponent: f32, 1592 limiting_cone_angle: f32}, 1593 /// calculate a distorted version of first input image using offset values 1594 /// from second input image at specified intensity 1595 /// parameters: FilterOpGraphNode, scale, xChannelSelector, yChannelSelector 1596 /// SVG filter semantics - selectable input(s), selectable between linear 1597 /// (default) and sRGB color space for calculations 1598 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDisplacementMapElement 1599 SVGFEDisplacementMap{node: FilterOpGraphNode, scale: f32, 1600 x_channel_selector: u32, y_channel_selector: u32}, 1601 /// create and merge a dropshadow version of the specified image's alpha 1602 /// channel with specified offset and blur radius 1603 /// parameters: FilterOpGraphNode, flood_color, flood_opacity, dx, dy, 1604 /// stdDeviationX, stdDeviationY 1605 /// SVG filter semantics - selectable input(s), selectable between linear 1606 /// (default) and sRGB color space for calculations 1607 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDropShadowElement 1608 SVGFEDropShadow{node: FilterOpGraphNode, color: ColorF, dx: f32, dy: f32, 1609 std_deviation_x: f32, std_deviation_y: f32}, 1610 /// synthesize a new image of specified size containing a solid color 1611 /// parameters: FilterOpGraphNode, color 1612 /// SVG filter semantics - selectable input(s), selectable between linear 1613 /// (default) and sRGB color space for calculations 1614 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEFloodElement 1615 SVGFEFlood{node: FilterOpGraphNode, color: ColorF}, 1616 /// create a blurred version of the input image 1617 /// parameters: FilterOpGraphNode, stdDeviationX, stdDeviationY 1618 /// SVG filter semantics - selectable input(s), selectable between linear 1619 /// (default) and sRGB color space for calculations 1620 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEGaussianBlurElement 1621 SVGFEGaussianBlur{node: FilterOpGraphNode, std_deviation_x: f32, std_deviation_y: f32}, 1622 /// synthesize a new image based on a url (i.e. blob image source) 1623 /// parameters: FilterOpGraphNode, sampling_filter (see SamplingFilter in Types.h), transform 1624 /// SVG filter semantics - selectable input(s), selectable between linear 1625 /// (default) and sRGB color space for calculations 1626 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEImageElement 1627 SVGFEImage{node: FilterOpGraphNode, sampling_filter: u32, matrix: [f32; 6]}, 1628 /// create a new image based on the input image with the contour stretched 1629 /// outward (dilate operator) 1630 /// parameters: FilterOpGraphNode, radiusX, radiusY 1631 /// SVG filter semantics - selectable input(s), selectable between linear 1632 /// (default) and sRGB color space for calculations 1633 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEMorphologyElement 1634 SVGFEMorphologyDilate{node: FilterOpGraphNode, radius_x: f32, radius_y: f32}, 1635 /// create a new image based on the input image with the contour shrunken 1636 /// inward (erode operator) 1637 /// parameters: FilterOpGraphNode, radiusX, radiusY 1638 /// SVG filter semantics - selectable input(s), selectable between linear 1639 /// (default) and sRGB color space for calculations 1640 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEMorphologyElement 1641 SVGFEMorphologyErode{node: FilterOpGraphNode, radius_x: f32, radius_y: f32}, 1642 /// create a new image that is a scrolled version of the input image, this 1643 /// is basically a no-op as we support offset in the graph node 1644 /// parameters: FilterOpGraphNode 1645 /// SVG filter semantics - selectable input(s), selectable between linear 1646 /// (default) and sRGB color space for calculations 1647 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEOffsetElement 1648 SVGFEOffset{node: FilterOpGraphNode, offset_x: f32, offset_y: f32}, 1649 /// calculate lighting based on heightmap image with provided values for a 1650 /// distant light source with specified direction 1651 /// parameters: FilerData, surfaceScale, specularConstant, specularExponent, 1652 /// kernelUnitLengthX, kernelUnitLengthY, azimuth, elevation 1653 /// SVG filter semantics - selectable input(s), selectable between linear 1654 /// (default) and sRGB color space for calculations 1655 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpecularLightingElement 1656 /// https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEDistantLightElement 1657 SVGFESpecularLightingDistant{node: FilterOpGraphNode, surface_scale: f32, 1658 specular_constant: f32, specular_exponent: f32, 1659 kernel_unit_length_x: f32, kernel_unit_length_y: f32, azimuth: f32, 1660 elevation: f32}, 1661 /// calculate lighting based on heightmap image with provided values for a 1662 /// point light source at specified location 1663 /// parameters: FilterOpGraphNode, surfaceScale, specularConstant, 1664 /// specularExponent, kernelUnitLengthX, kernelUnitLengthY, x, y, z 1665 /// SVG filter semantics - selectable input(s), selectable between linear 1666 /// (default) and sRGB color space for calculations 1667 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpecularLightingElement 1668 /// https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFEPointLightElement 1669 SVGFESpecularLightingPoint{node: FilterOpGraphNode, surface_scale: f32, 1670 specular_constant: f32, specular_exponent: f32, 1671 kernel_unit_length_x: f32, kernel_unit_length_y: f32, x: f32, y: f32, 1672 z: f32}, 1673 /// calculate lighting based on heightmap image with provided values for a 1674 /// spot light source at specified location pointing at specified target 1675 /// location with specified hotspot sharpness and cone angle 1676 /// parameters: FilterOpGraphNode, surfaceScale, specularConstant, 1677 /// specularExponent, kernelUnitLengthX, kernelUnitLengthY, x, y, z, 1678 /// pointsAtX, pointsAtY, pointsAtZ, specularExponent, limitingConeAngle 1679 /// SVG filter semantics - selectable input(s), selectable between linear 1680 /// (default) and sRGB color space for calculations 1681 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpecularLightingElement 1682 /// https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFESpotLightElement 1683 SVGFESpecularLightingSpot{node: FilterOpGraphNode, surface_scale: f32, 1684 specular_constant: f32, specular_exponent: f32, 1685 kernel_unit_length_x: f32, kernel_unit_length_y: f32, x: f32, y: f32, 1686 z: f32, points_at_x: f32, points_at_y: f32, points_at_z: f32, 1687 cone_exponent: f32, limiting_cone_angle: f32}, 1688 /// create a new image based on the input image, repeated throughout the 1689 /// output rectangle 1690 /// parameters: FilterOpGraphNode 1691 /// SVG filter semantics - selectable input(s), selectable between linear 1692 /// (default) and sRGB color space for calculations 1693 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETileElement 1694 SVGFETile{node: FilterOpGraphNode}, 1695 /// synthesize a new image based on Fractal Noise (Perlin) with the chosen 1696 /// stitching mode 1697 /// parameters: FilterOpGraphNode, baseFrequencyX, baseFrequencyY, 1698 /// numOctaves, seed 1699 /// SVG filter semantics - selectable input(s), selectable between linear 1700 /// (default) and sRGB color space for calculations 1701 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement 1702 SVGFETurbulenceWithFractalNoiseWithNoStitching{node: FilterOpGraphNode, 1703 base_frequency_x: f32, base_frequency_y: f32, num_octaves: u32, 1704 seed: u32}, 1705 /// synthesize a new image based on Fractal Noise (Perlin) with the chosen 1706 /// stitching mode 1707 /// parameters: FilterOpGraphNode, baseFrequencyX, baseFrequencyY, 1708 /// numOctaves, seed 1709 /// SVG filter semantics - selectable input(s), selectable between linear 1710 /// (default) and sRGB color space for calculations 1711 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement 1712 SVGFETurbulenceWithFractalNoiseWithStitching{node: FilterOpGraphNode, 1713 base_frequency_x: f32, base_frequency_y: f32, num_octaves: u32, 1714 seed: u32}, 1715 /// synthesize a new image based on Turbulence Noise (offset vectors) 1716 /// parameters: FilterOpGraphNode, baseFrequencyX, baseFrequencyY, 1717 /// numOctaves, seed 1718 /// SVG filter semantics - selectable input(s), selectable between linear 1719 /// (default) and sRGB color space for calculations 1720 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement 1721 SVGFETurbulenceWithTurbulenceNoiseWithNoStitching{node: FilterOpGraphNode, 1722 base_frequency_x: f32, base_frequency_y: f32, num_octaves: u32, 1723 seed: u32}, 1724 /// synthesize a new image based on Turbulence Noise (offset vectors) 1725 /// parameters: FilterOpGraphNode, baseFrequencyX, baseFrequencyY, 1726 /// numOctaves, seed 1727 /// SVG filter semantics - selectable input(s), selectable between linear 1728 /// (default) and sRGB color space for calculations 1729 /// Spec: https://www.w3.org/TR/filter-effects-1/#InterfaceSVGFETurbulenceElement 1730 SVGFETurbulenceWithTurbulenceNoiseWithStitching{node: FilterOpGraphNode, 1731 base_frequency_x: f32, base_frequency_y: f32, num_octaves: u32, seed: u32}, 1732 } 1733 1734 #[repr(u8)] 1735 #[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize, PeekPoke)] 1736 pub enum ComponentTransferFuncType { 1737 Identity = 0, 1738 Table = 1, 1739 Discrete = 2, 1740 Linear = 3, 1741 Gamma = 4, 1742 } 1743 1744 #[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] 1745 pub struct FilterData { 1746 /// ComponentTransfer / SVGFEComponentTransfer 1747 pub func_r_type: ComponentTransferFuncType, 1748 pub r_values: Vec<f32>, 1749 pub func_g_type: ComponentTransferFuncType, 1750 pub g_values: Vec<f32>, 1751 pub func_b_type: ComponentTransferFuncType, 1752 pub b_values: Vec<f32>, 1753 pub func_a_type: ComponentTransferFuncType, 1754 pub a_values: Vec<f32>, 1755 } 1756 1757 fn sanitize_func_type( 1758 func_type: ComponentTransferFuncType, 1759 values: &[f32], 1760 ) -> ComponentTransferFuncType { 1761 if values.is_empty() { 1762 return ComponentTransferFuncType::Identity; 1763 } 1764 if values.len() < 2 && func_type == ComponentTransferFuncType::Linear { 1765 return ComponentTransferFuncType::Identity; 1766 } 1767 if values.len() < 3 && func_type == ComponentTransferFuncType::Gamma { 1768 return ComponentTransferFuncType::Identity; 1769 } 1770 func_type 1771 } 1772 1773 fn sanitize_values( 1774 func_type: ComponentTransferFuncType, 1775 values: &[f32], 1776 ) -> bool { 1777 if values.len() < 2 && func_type == ComponentTransferFuncType::Linear { 1778 return false; 1779 } 1780 if values.len() < 3 && func_type == ComponentTransferFuncType::Gamma { 1781 return false; 1782 } 1783 true 1784 } 1785 1786 impl FilterData { 1787 /// Ensure that the number of values matches up with the function type. 1788 pub fn sanitize(&self) -> FilterData { 1789 FilterData { 1790 func_r_type: sanitize_func_type(self.func_r_type, &self.r_values), 1791 r_values: 1792 if sanitize_values(self.func_r_type, &self.r_values) { 1793 self.r_values.clone() 1794 } else { 1795 Vec::new() 1796 }, 1797 func_g_type: sanitize_func_type(self.func_g_type, &self.g_values), 1798 g_values: 1799 if sanitize_values(self.func_g_type, &self.g_values) { 1800 self.g_values.clone() 1801 } else { 1802 Vec::new() 1803 }, 1804 1805 func_b_type: sanitize_func_type(self.func_b_type, &self.b_values), 1806 b_values: 1807 if sanitize_values(self.func_b_type, &self.b_values) { 1808 self.b_values.clone() 1809 } else { 1810 Vec::new() 1811 }, 1812 1813 func_a_type: sanitize_func_type(self.func_a_type, &self.a_values), 1814 a_values: 1815 if sanitize_values(self.func_a_type, &self.a_values) { 1816 self.a_values.clone() 1817 } else { 1818 Vec::new() 1819 }, 1820 1821 } 1822 } 1823 1824 pub fn is_identity(&self) -> bool { 1825 self.func_r_type == ComponentTransferFuncType::Identity && 1826 self.func_g_type == ComponentTransferFuncType::Identity && 1827 self.func_b_type == ComponentTransferFuncType::Identity && 1828 self.func_a_type == ComponentTransferFuncType::Identity 1829 } 1830 } 1831 1832 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1833 pub struct IframeDisplayItem { 1834 pub bounds: LayoutRect, 1835 pub clip_rect: LayoutRect, 1836 pub space_and_clip: SpaceAndClipInfo, 1837 pub pipeline_id: PipelineId, 1838 pub ignore_missing_pipeline: bool, 1839 } 1840 1841 /// This describes an image that fills the specified area. It stretches or shrinks 1842 /// the image as necessary. While RepeatingImageDisplayItem could otherwise provide 1843 /// a superset of the functionality, it has been problematic inferring the desired 1844 /// repetition properties when snapping changes the size of the primitive. 1845 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1846 pub struct ImageDisplayItem { 1847 pub common: CommonItemProperties, 1848 /// The area to tile the image over (first tile starts at origin of this rect) 1849 // FIXME: this should ideally just be `tile_origin` here, with the clip_rect 1850 // defining the bounds of the item. Needs non-trivial backend changes. 1851 pub bounds: LayoutRect, 1852 pub image_key: ImageKey, 1853 pub image_rendering: ImageRendering, 1854 pub alpha_type: AlphaType, 1855 /// A hack used by gecko to color a simple bitmap font used for tofu glyphs 1856 pub color: ColorF, 1857 } 1858 1859 /// This describes a background-image and its tiling. It repeats in a grid to fill 1860 /// the specified area. 1861 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1862 pub struct RepeatingImageDisplayItem { 1863 pub common: CommonItemProperties, 1864 /// The area to tile the image over (first tile starts at origin of this rect) 1865 // FIXME: this should ideally just be `tile_origin` here, with the clip_rect 1866 // defining the bounds of the item. Needs non-trivial backend changes. 1867 pub bounds: LayoutRect, 1868 /// How large to make a single tile of the image (common case: bounds.size) 1869 pub stretch_size: LayoutSize, 1870 /// The space between tiles (common case: 0) 1871 pub tile_spacing: LayoutSize, 1872 pub image_key: ImageKey, 1873 pub image_rendering: ImageRendering, 1874 pub alpha_type: AlphaType, 1875 /// A hack used by gecko to color a simple bitmap font used for tofu glyphs 1876 pub color: ColorF, 1877 } 1878 1879 #[repr(u8)] 1880 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 1881 pub enum ImageRendering { 1882 Auto = 0, 1883 CrispEdges = 1, 1884 Pixelated = 2, 1885 } 1886 1887 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 1888 pub enum AlphaType { 1889 Alpha = 0, 1890 PremultipliedAlpha = 1, 1891 } 1892 1893 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 1894 pub struct YuvImageDisplayItem { 1895 pub common: CommonItemProperties, 1896 pub bounds: LayoutRect, 1897 pub yuv_data: YuvData, 1898 pub color_depth: ColorDepth, 1899 pub color_space: YuvColorSpace, 1900 pub color_range: ColorRange, 1901 pub image_rendering: ImageRendering, 1902 } 1903 1904 #[repr(u8)] 1905 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 1906 pub enum YuvColorSpace { 1907 Rec601 = 0, 1908 Rec709 = 1, 1909 Rec2020 = 2, 1910 Identity = 3, // aka GBR as per ISO/IEC 23091-2:2019 1911 } 1912 1913 #[repr(u8)] 1914 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 1915 pub enum ColorRange { 1916 Limited = 0, 1917 Full = 1, 1918 } 1919 1920 #[repr(u8)] 1921 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 1922 pub enum YuvRangedColorSpace { 1923 Rec601Narrow = 0, 1924 Rec601Full = 1, 1925 Rec709Narrow = 2, 1926 Rec709Full = 3, 1927 Rec2020Narrow = 4, 1928 Rec2020Full = 5, 1929 GbrIdentity = 6, 1930 } 1931 1932 impl YuvColorSpace { 1933 pub fn with_range(self, range: ColorRange) -> YuvRangedColorSpace { 1934 match self { 1935 YuvColorSpace::Identity => YuvRangedColorSpace::GbrIdentity, 1936 YuvColorSpace::Rec601 => { 1937 match range { 1938 ColorRange::Limited => YuvRangedColorSpace::Rec601Narrow, 1939 ColorRange::Full => YuvRangedColorSpace::Rec601Full, 1940 } 1941 } 1942 YuvColorSpace::Rec709 => { 1943 match range { 1944 ColorRange::Limited => YuvRangedColorSpace::Rec709Narrow, 1945 ColorRange::Full => YuvRangedColorSpace::Rec709Full, 1946 } 1947 } 1948 YuvColorSpace::Rec2020 => { 1949 match range { 1950 ColorRange::Limited => YuvRangedColorSpace::Rec2020Narrow, 1951 ColorRange::Full => YuvRangedColorSpace::Rec2020Full, 1952 } 1953 } 1954 } 1955 } 1956 } 1957 1958 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] 1959 pub enum YuvData { 1960 NV12(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel) 1961 P010(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel) 1962 NV16(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel) 1963 PlanarYCbCr(ImageKey, ImageKey, ImageKey), // (Y channel, Cb channel, Cr Channel) 1964 InterleavedYCbCr(ImageKey), // (YCbCr interleaved channel) 1965 } 1966 1967 impl YuvData { 1968 pub fn get_format(&self) -> YuvFormat { 1969 match *self { 1970 YuvData::NV12(..) => YuvFormat::NV12, 1971 YuvData::P010(..) => YuvFormat::P010, 1972 YuvData::NV16(..) => YuvFormat::NV16, 1973 YuvData::PlanarYCbCr(..) => YuvFormat::PlanarYCbCr, 1974 YuvData::InterleavedYCbCr(..) => YuvFormat::InterleavedYCbCr, 1975 } 1976 } 1977 } 1978 1979 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 1980 pub enum YuvFormat { 1981 // These enum values need to be kept in sync with yuv.glsl. 1982 NV12 = 0, 1983 P010 = 1, 1984 NV16 = 2, 1985 PlanarYCbCr = 3, 1986 InterleavedYCbCr = 4, 1987 } 1988 1989 impl YuvFormat { 1990 pub fn get_plane_num(self) -> usize { 1991 match self { 1992 YuvFormat::NV12 | YuvFormat::P010 | YuvFormat::NV16 => 2, 1993 YuvFormat::PlanarYCbCr => 3, 1994 YuvFormat::InterleavedYCbCr => 1, 1995 } 1996 } 1997 } 1998 1999 #[repr(C)] 2000 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 2001 pub struct ImageMask { 2002 pub image: ImageKey, 2003 pub rect: LayoutRect, 2004 } 2005 2006 impl ImageMask { 2007 /// Get a local clipping rect contributed by this mask. 2008 pub fn get_local_clip_rect(&self) -> Option<LayoutRect> { 2009 Some(self.rect) 2010 } 2011 } 2012 2013 #[repr(C)] 2014 #[derive(Copy, Clone, Debug, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash, PeekPoke)] 2015 pub enum ClipMode { 2016 Clip, // Pixels inside the region are visible. 2017 ClipOut, // Pixels outside the region are visible. 2018 } 2019 2020 impl Not for ClipMode { 2021 type Output = ClipMode; 2022 2023 fn not(self) -> ClipMode { 2024 match self { 2025 ClipMode::Clip => ClipMode::ClipOut, 2026 ClipMode::ClipOut => ClipMode::Clip, 2027 } 2028 } 2029 } 2030 2031 #[repr(C)] 2032 #[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)] 2033 pub struct ComplexClipRegion { 2034 /// The boundaries of the rectangle. 2035 pub rect: LayoutRect, 2036 /// Border radii of this rectangle. 2037 pub radii: BorderRadius, 2038 /// Whether we are clipping inside or outside 2039 /// the region. 2040 pub mode: ClipMode, 2041 } 2042 2043 impl BorderRadius { 2044 pub fn zero() -> BorderRadius { 2045 BorderRadius { 2046 top_left: LayoutSize::new(0.0, 0.0), 2047 top_right: LayoutSize::new(0.0, 0.0), 2048 bottom_left: LayoutSize::new(0.0, 0.0), 2049 bottom_right: LayoutSize::new(0.0, 0.0), 2050 } 2051 } 2052 2053 pub fn uniform(radius: f32) -> BorderRadius { 2054 BorderRadius { 2055 top_left: LayoutSize::new(radius, radius), 2056 top_right: LayoutSize::new(radius, radius), 2057 bottom_left: LayoutSize::new(radius, radius), 2058 bottom_right: LayoutSize::new(radius, radius), 2059 } 2060 } 2061 2062 pub fn uniform_size(radius: LayoutSize) -> BorderRadius { 2063 BorderRadius { 2064 top_left: radius, 2065 top_right: radius, 2066 bottom_left: radius, 2067 bottom_right: radius, 2068 } 2069 } 2070 2071 pub fn all_sides_uniform(&self) -> bool { 2072 let corner_is_uniform = |corner: &LayoutSize| corner.width == corner.height; 2073 corner_is_uniform(&self.top_left) && 2074 corner_is_uniform(&self.top_right) && 2075 corner_is_uniform(&self.bottom_right) && 2076 corner_is_uniform(&self.bottom_left) 2077 } 2078 2079 pub fn can_use_fast_path_in(&self, rect: &LayoutRect) -> bool { 2080 if !self.all_sides_uniform() { 2081 // The fast path needs uniform sides. 2082 return false; 2083 } 2084 // The shader code that evaluates the rounded corners in the fast path relies on each 2085 // corner fitting into their quadrant of the quad. In other words the radius cannot 2086 // exceed half of the length of the sides they are on. That necessarily holds if all the 2087 // radii are the same. 2088 let tl = self.top_left.width; 2089 if tl == self.bottom_right.width && tl == self.top_right.width && tl == self.bottom_left.width { 2090 return true; 2091 } 2092 let half_size = rect.size() * 0.5; 2093 let fits = |v: f32| v <= half_size.width && v <= half_size.height; 2094 fits(tl) && fits(self.bottom_right.width) && fits(self.top_right.width) && fits(self.bottom_left.width) 2095 } 2096 2097 /// Return whether, in each corner, the radius in *either* direction is zero. 2098 /// This means that none of the corners are rounded. 2099 pub fn is_zero(&self) -> bool { 2100 let corner_is_zero = |corner: &LayoutSize| corner.width == 0.0 || corner.height == 0.0; 2101 corner_is_zero(&self.top_left) && 2102 corner_is_zero(&self.top_right) && 2103 corner_is_zero(&self.bottom_right) && 2104 corner_is_zero(&self.bottom_left) 2105 } 2106 } 2107 2108 impl ComplexClipRegion { 2109 /// Create a new complex clip region. 2110 pub fn new( 2111 rect: LayoutRect, 2112 radii: BorderRadius, 2113 mode: ClipMode, 2114 ) -> Self { 2115 ComplexClipRegion { rect, radii, mode } 2116 } 2117 } 2118 2119 impl ComplexClipRegion { 2120 /// Get a local clipping rect contributed by this clip region. 2121 pub fn get_local_clip_rect(&self) -> Option<LayoutRect> { 2122 match self.mode { 2123 ClipMode::Clip => { 2124 Some(self.rect) 2125 } 2126 ClipMode::ClipOut => { 2127 None 2128 } 2129 } 2130 } 2131 } 2132 2133 pub const POLYGON_CLIP_VERTEX_MAX: usize = 32; 2134 2135 #[repr(u8)] 2136 #[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, PartialEq, Serialize, Eq, Hash, PeekPoke)] 2137 pub enum FillRule { 2138 Nonzero = 0x1, // Behaves as the SVG fill-rule definition for nonzero. 2139 Evenodd = 0x2, // Behaves as the SVG fill-rule definition for evenodd. 2140 } 2141 2142 impl From<u8> for FillRule { 2143 fn from(fill_rule: u8) -> Self { 2144 match fill_rule { 2145 0x1 => FillRule::Nonzero, 2146 0x2 => FillRule::Evenodd, 2147 _ => panic!("Unexpected FillRule value."), 2148 } 2149 } 2150 } 2151 2152 impl From<FillRule> for u8 { 2153 fn from(fill_rule: FillRule) -> Self { 2154 match fill_rule { 2155 FillRule::Nonzero => 0x1, 2156 FillRule::Evenodd => 0x2, 2157 } 2158 } 2159 } 2160 2161 #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] 2162 pub struct ClipChainId(pub u64, pub PipelineId); 2163 2164 impl ClipChainId { 2165 pub const INVALID: Self = ClipChainId(!0, PipelineId::INVALID); 2166 } 2167 2168 /// A reference to a clipping node defining how an item is clipped. 2169 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)] 2170 pub struct ClipId(pub usize, pub PipelineId); 2171 2172 impl Default for ClipId { 2173 fn default() -> Self { 2174 ClipId::invalid() 2175 } 2176 } 2177 2178 const ROOT_CLIP_ID: usize = 0; 2179 2180 impl ClipId { 2181 /// Return the root clip ID - effectively doing no clipping. 2182 pub fn root(pipeline_id: PipelineId) -> Self { 2183 ClipId(ROOT_CLIP_ID, pipeline_id) 2184 } 2185 2186 /// Return an invalid clip ID - needed in places where we carry 2187 /// one but need to not attempt to use it. 2188 pub fn invalid() -> Self { 2189 ClipId(!0, PipelineId::dummy()) 2190 } 2191 2192 pub fn pipeline_id(&self) -> PipelineId { 2193 match *self { 2194 ClipId(_, pipeline_id) => pipeline_id, 2195 } 2196 } 2197 2198 pub fn is_root(&self) -> bool { 2199 match *self { 2200 ClipId(id, _) => id == ROOT_CLIP_ID, 2201 } 2202 } 2203 2204 pub fn is_valid(&self) -> bool { 2205 match *self { 2206 ClipId(id, _) => id != !0, 2207 } 2208 } 2209 } 2210 2211 /// A reference to a spatial node defining item positioning. 2212 #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 2213 pub struct SpatialId(pub usize, PipelineId); 2214 2215 const ROOT_REFERENCE_FRAME_SPATIAL_ID: usize = 0; 2216 const ROOT_SCROLL_NODE_SPATIAL_ID: usize = 1; 2217 2218 impl SpatialId { 2219 pub fn new(spatial_node_index: usize, pipeline_id: PipelineId) -> Self { 2220 SpatialId(spatial_node_index, pipeline_id) 2221 } 2222 2223 pub fn root_reference_frame(pipeline_id: PipelineId) -> Self { 2224 SpatialId(ROOT_REFERENCE_FRAME_SPATIAL_ID, pipeline_id) 2225 } 2226 2227 pub fn root_scroll_node(pipeline_id: PipelineId) -> Self { 2228 SpatialId(ROOT_SCROLL_NODE_SPATIAL_ID, pipeline_id) 2229 } 2230 2231 pub fn pipeline_id(&self) -> PipelineId { 2232 self.1 2233 } 2234 } 2235 2236 /// An external identifier that uniquely identifies a scroll frame independent of its ClipId, which 2237 /// may change from frame to frame. This should be unique within a pipeline. WebRender makes no 2238 /// attempt to ensure uniqueness. The zero value is reserved for use by the root scroll node of 2239 /// every pipeline, which always has an external id. 2240 /// 2241 /// When setting display lists with the `preserve_frame_state` this id is used to preserve scroll 2242 /// offsets between different sets of SpatialNodes which are ScrollFrames. 2243 #[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize, PeekPoke)] 2244 #[repr(C)] 2245 pub struct ExternalScrollId(pub u64, pub PipelineId); 2246 2247 impl ExternalScrollId { 2248 pub fn pipeline_id(&self) -> PipelineId { 2249 self.1 2250 } 2251 2252 pub fn is_root(&self) -> bool { 2253 self.0 == 0 2254 } 2255 } 2256 2257 impl DisplayItem { 2258 pub fn debug_name(&self) -> &'static str { 2259 match *self { 2260 DisplayItem::Border(..) => "border", 2261 DisplayItem::BoxShadow(..) => "box_shadow", 2262 DisplayItem::HitTest(..) => "hit_test", 2263 DisplayItem::RectClip(..) => "rect_clip", 2264 DisplayItem::RoundedRectClip(..) => "rounded_rect_clip", 2265 DisplayItem::ImageMaskClip(..) => "image_mask_clip", 2266 DisplayItem::ClipChain(..) => "clip_chain", 2267 DisplayItem::ConicGradient(..) => "conic_gradient", 2268 DisplayItem::Gradient(..) => "gradient", 2269 DisplayItem::Iframe(..) => "iframe", 2270 DisplayItem::Image(..) => "image", 2271 DisplayItem::RepeatingImage(..) => "repeating_image", 2272 DisplayItem::Line(..) => "line", 2273 DisplayItem::PopAllShadows => "pop_all_shadows", 2274 DisplayItem::PopReferenceFrame => "pop_reference_frame", 2275 DisplayItem::PopStackingContext => "pop_stacking_context", 2276 DisplayItem::PushShadow(..) => "push_shadow", 2277 DisplayItem::PushReferenceFrame(..) => "push_reference_frame", 2278 DisplayItem::PushStackingContext(..) => "push_stacking_context", 2279 DisplayItem::SetFilterOps => "set_filter_ops", 2280 DisplayItem::SetFilterData => "set_filter_data", 2281 DisplayItem::SetPoints => "set_points", 2282 DisplayItem::RadialGradient(..) => "radial_gradient", 2283 DisplayItem::Rectangle(..) => "rectangle", 2284 DisplayItem::SetGradientStops => "set_gradient_stops", 2285 DisplayItem::ReuseItems(..) => "reuse_item", 2286 DisplayItem::RetainedItems(..) => "retained_items", 2287 DisplayItem::Text(..) => "text", 2288 DisplayItem::YuvImage(..) => "yuv_image", 2289 DisplayItem::BackdropFilter(..) => "backdrop_filter", 2290 DisplayItem::DebugMarker(..) => "debug", 2291 } 2292 } 2293 } 2294 2295 macro_rules! impl_default_for_enums { 2296 ($($enum:ident => $init:expr ),+) => { 2297 $(impl Default for $enum { 2298 #[allow(unused_imports)] 2299 fn default() -> Self { 2300 use $enum::*; 2301 $init 2302 } 2303 })* 2304 } 2305 } 2306 2307 impl_default_for_enums! { 2308 DisplayItem => PopStackingContext, 2309 LineOrientation => Vertical, 2310 LineStyle => Solid, 2311 RepeatMode => Stretch, 2312 NinePatchBorderSource => Image(ImageKey::default(), ImageRendering::Auto), 2313 BorderDetails => Normal(NormalBorder::default()), 2314 BorderRadiusKind => Uniform, 2315 BorderStyle => None, 2316 BoxShadowClipMode => Outset, 2317 ExtendMode => Clamp, 2318 FilterOp => Identity, 2319 ComponentTransferFuncType => Identity, 2320 ClipMode => Clip, 2321 FillRule => Nonzero, 2322 ReferenceFrameKind => Transform { 2323 is_2d_scale_translation: false, 2324 should_snap: false, 2325 paired_with_perspective: false, 2326 }, 2327 Rotation => Degree0, 2328 TransformStyle => Flat, 2329 RasterSpace => Local(f32::default()), 2330 MixBlendMode => Normal, 2331 ImageRendering => Auto, 2332 AlphaType => Alpha, 2333 YuvColorSpace => Rec601, 2334 YuvRangedColorSpace => Rec601Narrow, 2335 ColorRange => Limited, 2336 YuvData => NV12(ImageKey::default(), ImageKey::default()), 2337 YuvFormat => NV12, 2338 FilterPrimitiveInput => Original, 2339 ColorSpace => Srgb, 2340 CompositeOperator => Over 2341 }