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 #[cfg(any(feature = "serialize", feature = "deserialize"))] 6 use GlyphInstance; 7 use euclid::{SideOffsets2D, TypedRect}; 8 use std::ops::Not; 9 use {ColorF, FontInstanceKey, GlyphOptions, ImageKey, LayerPixel, LayoutPixel, LayoutPoint}; 10 use {LayoutRect, LayoutSize, LayoutTransform, LayoutVector2D, PipelineId, PropertyBinding}; 11 12 13 // NOTE: some of these structs have an "IMPLICIT" comment. 14 // This indicates that the BuiltDisplayList will have serialized 15 // a list of values nearby that this item consumes. The traversal 16 // iterator should handle finding these. 17 18 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] 19 pub struct ClipAndScrollInfo { 20 pub scroll_node_id: ClipId, 21 pub clip_node_id: Option<ClipId>, 22 } 23 24 impl ClipAndScrollInfo { simple(node_id: ClipId) -> ClipAndScrollInfo25 pub fn simple(node_id: ClipId) -> ClipAndScrollInfo { 26 ClipAndScrollInfo { 27 scroll_node_id: node_id, 28 clip_node_id: None, 29 } 30 } 31 new(scroll_node_id: ClipId, clip_node_id: ClipId) -> ClipAndScrollInfo32 pub fn new(scroll_node_id: ClipId, clip_node_id: ClipId) -> ClipAndScrollInfo { 33 ClipAndScrollInfo { 34 scroll_node_id, 35 clip_node_id: Some(clip_node_id), 36 } 37 } 38 clip_node_id(&self) -> ClipId39 pub fn clip_node_id(&self) -> ClipId { 40 self.clip_node_id.unwrap_or(self.scroll_node_id) 41 } 42 } 43 44 /// A tag that can be used to identify items during hit testing. If the tag 45 /// is missing then the item doesn't take part in hit testing at all. This 46 /// is composed of two numbers. In Servo, the first is an identifier while the 47 /// second is used to select the cursor that should be used during mouse 48 /// movement. In Gecko, the first is a scrollframe identifier, while the second 49 /// is used to store various flags that APZ needs to properly process input 50 /// events. 51 pub type ItemTag = (u64, u16); 52 53 /// The DI is generic over the specifics, while allows to use 54 /// the "complete" version of it for convenient serialization. 55 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 56 pub struct GenericDisplayItem<T> { 57 pub item: T, 58 pub clip_and_scroll: ClipAndScrollInfo, 59 pub info: LayoutPrimitiveInfo, 60 } 61 62 pub type DisplayItem = GenericDisplayItem<SpecificDisplayItem>; 63 64 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 65 pub struct PrimitiveInfo<T> { 66 pub rect: TypedRect<f32, T>, 67 pub local_clip: LocalClip, 68 pub is_backface_visible: bool, 69 pub tag: Option<ItemTag>, 70 } 71 72 impl LayerPrimitiveInfo { new(rect: TypedRect<f32, LayerPixel>) -> Self73 pub fn new(rect: TypedRect<f32, LayerPixel>) -> Self { 74 Self::with_clip_rect(rect, rect) 75 } 76 with_clip_rect( rect: TypedRect<f32, LayerPixel>, clip_rect: TypedRect<f32, LayerPixel>, ) -> Self77 pub fn with_clip_rect( 78 rect: TypedRect<f32, LayerPixel>, 79 clip_rect: TypedRect<f32, LayerPixel>, 80 ) -> Self { 81 Self::with_clip(rect, LocalClip::from(clip_rect)) 82 } 83 with_clip(rect: TypedRect<f32, LayerPixel>, clip: LocalClip) -> Self84 pub fn with_clip(rect: TypedRect<f32, LayerPixel>, clip: LocalClip) -> Self { 85 PrimitiveInfo { 86 rect: rect, 87 local_clip: clip, 88 is_backface_visible: true, 89 tag: None, 90 } 91 } 92 } 93 94 pub type LayoutPrimitiveInfo = PrimitiveInfo<LayoutPixel>; 95 pub type LayerPrimitiveInfo = PrimitiveInfo<LayerPixel>; 96 97 #[repr(u8)] 98 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 99 pub enum SpecificDisplayItem { 100 Clip(ClipDisplayItem), 101 ScrollFrame(ScrollFrameDisplayItem), 102 StickyFrame(StickyFrameDisplayItem), 103 Rectangle(RectangleDisplayItem), 104 ClearRectangle, 105 Line(LineDisplayItem), 106 Text(TextDisplayItem), 107 Image(ImageDisplayItem), 108 YuvImage(YuvImageDisplayItem), 109 Border(BorderDisplayItem), 110 BoxShadow(BoxShadowDisplayItem), 111 Gradient(GradientDisplayItem), 112 RadialGradient(RadialGradientDisplayItem), 113 ClipChain(ClipChainItem), 114 Iframe(IframeDisplayItem), 115 PushStackingContext(PushStackingContextDisplayItem), 116 PopStackingContext, 117 SetGradientStops, 118 PushShadow(Shadow), 119 PopAllShadows, 120 } 121 122 /// This is a "complete" version of the DI specifics, 123 /// containing the auxiliary data within the corresponding 124 /// enumeration variants, to be used for debug serialization. 125 #[cfg(any(feature = "serialize", feature = "deserialize"))] 126 #[cfg_attr(feature = "serialize", derive(Serialize))] 127 #[cfg_attr(feature = "deserialize", derive(Deserialize))] 128 pub enum CompletelySpecificDisplayItem { 129 Clip(ClipDisplayItem, Vec<ComplexClipRegion>), 130 ClipChain(ClipChainItem, Vec<ClipId>), 131 ScrollFrame(ScrollFrameDisplayItem, Vec<ComplexClipRegion>), 132 StickyFrame(StickyFrameDisplayItem), 133 Rectangle(RectangleDisplayItem), 134 ClearRectangle, 135 Line(LineDisplayItem), 136 Text(TextDisplayItem, Vec<GlyphInstance>), 137 Image(ImageDisplayItem), 138 YuvImage(YuvImageDisplayItem), 139 Border(BorderDisplayItem), 140 BoxShadow(BoxShadowDisplayItem), 141 Gradient(GradientDisplayItem), 142 RadialGradient(RadialGradientDisplayItem), 143 Iframe(IframeDisplayItem), 144 PushStackingContext(PushStackingContextDisplayItem, Vec<FilterOp>), 145 PopStackingContext, 146 SetGradientStops(Vec<GradientStop>), 147 PushShadow(Shadow), 148 PopAllShadows, 149 } 150 151 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 152 pub struct ClipDisplayItem { 153 pub id: ClipId, 154 pub image_mask: Option<ImageMask>, 155 } 156 157 /// The minimum and maximum allowable offset for a sticky frame in a single dimension. 158 #[repr(C)] 159 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 160 pub struct StickyOffsetBounds { 161 /// The minimum offset for this frame, typically a negative value, which specifies how 162 /// far in the negative direction the sticky frame can offset its contents in this 163 /// dimension. 164 pub min: f32, 165 166 /// The maximum offset for this frame, typically a positive value, which specifies how 167 /// far in the positive direction the sticky frame can offset its contents in this 168 /// dimension. 169 pub max: f32, 170 } 171 172 impl StickyOffsetBounds { new(min: f32, max: f32) -> StickyOffsetBounds173 pub fn new(min: f32, max: f32) -> StickyOffsetBounds { 174 StickyOffsetBounds { min, max } 175 } 176 } 177 178 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 179 pub struct StickyFrameDisplayItem { 180 pub id: ClipId, 181 182 /// The margins that should be maintained between the edge of the parent viewport and this 183 /// sticky frame. A margin of None indicates that the sticky frame should not stick at all 184 /// to that particular edge of the viewport. 185 pub margins: SideOffsets2D<Option<f32>>, 186 187 /// The minimum and maximum vertical offsets for this sticky frame. Ignoring these constraints, 188 /// the sticky frame will continue to stick to the edge of the viewport as its original 189 /// position is scrolled out of view. Constraints specify a maximum and minimum offset from the 190 /// original position relative to non-sticky content within the same scrolling frame. 191 pub vertical_offset_bounds: StickyOffsetBounds, 192 193 /// The minimum and maximum horizontal offsets for this sticky frame. Ignoring these constraints, 194 /// the sticky frame will continue to stick to the edge of the viewport as its original 195 /// position is scrolled out of view. Constraints specify a maximum and minimum offset from the 196 /// original position relative to non-sticky content within the same scrolling frame. 197 pub horizontal_offset_bounds: StickyOffsetBounds, 198 199 /// The amount of offset that has already been applied to the sticky frame. A positive y 200 /// component this field means that a top-sticky item was in a scrollframe that has been 201 /// scrolled down, such that the sticky item's position needed to be offset downwards by 202 /// `previously_applied_offset.y`. A negative y component corresponds to the upward offset 203 /// applied due to bottom-stickiness. The x-axis works analogously. 204 pub previously_applied_offset: LayoutVector2D, 205 } 206 207 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 208 pub enum ScrollSensitivity { 209 ScriptAndInputEvents, 210 Script, 211 } 212 213 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 214 pub struct ScrollFrameDisplayItem { 215 pub clip_id: ClipId, 216 pub scroll_frame_id: ClipId, 217 pub external_id: Option<ExternalScrollId>, 218 pub image_mask: Option<ImageMask>, 219 pub scroll_sensitivity: ScrollSensitivity, 220 } 221 222 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 223 pub struct RectangleDisplayItem { 224 pub color: ColorF, 225 } 226 227 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 228 pub struct LineDisplayItem { 229 pub orientation: LineOrientation, // toggles whether above values are interpreted as x/y values 230 pub wavy_line_thickness: f32, 231 pub color: ColorF, 232 pub style: LineStyle, 233 } 234 235 #[repr(u8)] 236 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 237 pub enum LineOrientation { 238 Vertical, 239 Horizontal, 240 } 241 242 #[repr(u8)] 243 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 244 pub enum LineStyle { 245 Solid, 246 Dotted, 247 Dashed, 248 Wavy, 249 } 250 251 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 252 pub struct TextDisplayItem { 253 pub font_key: FontInstanceKey, 254 pub color: ColorF, 255 pub glyph_options: Option<GlyphOptions>, 256 } // IMPLICIT: glyphs: Vec<GlyphInstance> 257 258 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 259 pub struct NormalBorder { 260 pub left: BorderSide, 261 pub right: BorderSide, 262 pub top: BorderSide, 263 pub bottom: BorderSide, 264 pub radius: BorderRadius, 265 } 266 267 #[repr(u32)] 268 #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] 269 pub enum RepeatMode { 270 Stretch, 271 Repeat, 272 Round, 273 Space, 274 } 275 276 #[repr(C)] 277 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 278 pub struct NinePatchDescriptor { 279 pub width: u32, 280 pub height: u32, 281 pub slice: SideOffsets2D<u32>, 282 } 283 284 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 285 pub struct ImageBorder { 286 pub image_key: ImageKey, 287 pub patch: NinePatchDescriptor, 288 /// Controls whether the center of the 9 patch image is 289 /// rendered or ignored. 290 pub fill: bool, 291 pub outset: SideOffsets2D<f32>, 292 pub repeat_horizontal: RepeatMode, 293 pub repeat_vertical: RepeatMode, 294 } 295 296 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 297 pub struct GradientBorder { 298 pub gradient: Gradient, 299 pub outset: SideOffsets2D<f32>, 300 } 301 302 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 303 pub struct RadialGradientBorder { 304 pub gradient: RadialGradient, 305 pub outset: SideOffsets2D<f32>, 306 } 307 308 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 309 pub enum BorderDetails { 310 Normal(NormalBorder), 311 Image(ImageBorder), 312 Gradient(GradientBorder), 313 RadialGradient(RadialGradientBorder), 314 } 315 316 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 317 pub struct BorderDisplayItem { 318 pub widths: BorderWidths, 319 pub details: BorderDetails, 320 } 321 322 #[repr(C)] 323 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 324 pub enum BorderRadiusKind { 325 Uniform, 326 NonUniform, 327 } 328 329 #[repr(C)] 330 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 331 pub struct BorderRadius { 332 pub top_left: LayoutSize, 333 pub top_right: LayoutSize, 334 pub bottom_left: LayoutSize, 335 pub bottom_right: LayoutSize, 336 } 337 338 #[repr(C)] 339 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 340 pub struct BorderWidths { 341 pub left: f32, 342 pub top: f32, 343 pub right: f32, 344 pub bottom: f32, 345 } 346 347 #[repr(C)] 348 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 349 pub struct BorderSide { 350 pub color: ColorF, 351 pub style: BorderStyle, 352 } 353 354 #[repr(u32)] 355 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 356 pub enum BorderStyle { 357 None = 0, 358 Solid = 1, 359 Double = 2, 360 Dotted = 3, 361 Dashed = 4, 362 Hidden = 5, 363 Groove = 6, 364 Ridge = 7, 365 Inset = 8, 366 Outset = 9, 367 } 368 369 #[repr(u32)] 370 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] 371 pub enum BoxShadowClipMode { 372 Outset = 0, 373 Inset = 1, 374 } 375 376 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 377 pub struct BoxShadowDisplayItem { 378 pub box_bounds: LayoutRect, 379 pub offset: LayoutVector2D, 380 pub color: ColorF, 381 pub blur_radius: f32, 382 pub spread_radius: f32, 383 pub border_radius: BorderRadius, 384 pub clip_mode: BoxShadowClipMode, 385 } 386 387 #[repr(C)] 388 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 389 pub struct Shadow { 390 pub offset: LayoutVector2D, 391 pub color: ColorF, 392 pub blur_radius: f32, 393 } 394 395 #[repr(u32)] 396 #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)] 397 pub enum ExtendMode { 398 Clamp, 399 Repeat, 400 } 401 402 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 403 pub struct Gradient { 404 pub start_point: LayoutPoint, 405 pub end_point: LayoutPoint, 406 pub extend_mode: ExtendMode, 407 } // IMPLICIT: stops: Vec<GradientStop> 408 409 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 410 pub struct GradientDisplayItem { 411 pub gradient: Gradient, 412 pub tile_size: LayoutSize, 413 pub tile_spacing: LayoutSize, 414 } 415 416 #[repr(C)] 417 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 418 pub struct GradientStop { 419 pub offset: f32, 420 pub color: ColorF, 421 } 422 423 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 424 pub struct RadialGradient { 425 pub start_center: LayoutPoint, 426 pub start_radius: f32, 427 pub end_center: LayoutPoint, 428 pub end_radius: f32, 429 pub ratio_xy: f32, 430 pub extend_mode: ExtendMode, 431 } // IMPLICIT stops: Vec<GradientStop> 432 433 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 434 pub struct ClipChainItem { 435 pub id: ClipChainId, 436 pub parent: Option<ClipChainId>, 437 } // IMPLICIT stops: Vec<ClipId> 438 439 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 440 pub struct RadialGradientDisplayItem { 441 pub gradient: RadialGradient, 442 pub tile_size: LayoutSize, 443 pub tile_spacing: LayoutSize, 444 } 445 446 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 447 pub struct PushStackingContextDisplayItem { 448 pub stacking_context: StackingContext, 449 } 450 451 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 452 pub struct StackingContext { 453 pub scroll_policy: ScrollPolicy, 454 pub transform: Option<PropertyBinding<LayoutTransform>>, 455 pub transform_style: TransformStyle, 456 pub perspective: Option<LayoutTransform>, 457 pub mix_blend_mode: MixBlendMode, 458 pub reference_frame_id: Option<ClipId>, 459 } // IMPLICIT: filters: Vec<FilterOp> 460 461 #[repr(u32)] 462 #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] 463 pub enum ScrollPolicy { 464 Scrollable = 0, 465 Fixed = 1, 466 } 467 468 #[repr(u32)] 469 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] 470 pub enum TransformStyle { 471 Flat = 0, 472 Preserve3D = 1, 473 } 474 475 #[repr(u32)] 476 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] 477 pub enum MixBlendMode { 478 Normal = 0, 479 Multiply = 1, 480 Screen = 2, 481 Overlay = 3, 482 Darken = 4, 483 Lighten = 5, 484 ColorDodge = 6, 485 ColorBurn = 7, 486 HardLight = 8, 487 SoftLight = 9, 488 Difference = 10, 489 Exclusion = 11, 490 Hue = 12, 491 Saturation = 13, 492 Color = 14, 493 Luminosity = 15, 494 } 495 496 #[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)] 497 pub enum FilterOp { 498 Blur(f32), 499 Brightness(f32), 500 Contrast(f32), 501 Grayscale(f32), 502 HueRotate(f32), 503 Invert(f32), 504 Opacity(PropertyBinding<f32>, f32), 505 Saturate(f32), 506 Sepia(f32), 507 DropShadow(LayoutVector2D, f32, ColorF), 508 ColorMatrix([f32; 20]), 509 } 510 511 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 512 pub struct IframeDisplayItem { 513 pub clip_id: ClipId, 514 pub pipeline_id: PipelineId, 515 } 516 517 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 518 pub struct ImageDisplayItem { 519 pub image_key: ImageKey, 520 pub stretch_size: LayoutSize, 521 pub tile_spacing: LayoutSize, 522 pub image_rendering: ImageRendering, 523 pub alpha_type: AlphaType, 524 } 525 526 #[repr(u32)] 527 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] 528 pub enum ImageRendering { 529 Auto = 0, 530 CrispEdges = 1, 531 Pixelated = 2, 532 } 533 534 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] 535 pub enum AlphaType { 536 Alpha = 0, 537 PremultipliedAlpha = 1, 538 } 539 540 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 541 pub struct YuvImageDisplayItem { 542 pub yuv_data: YuvData, 543 pub color_space: YuvColorSpace, 544 pub image_rendering: ImageRendering, 545 } 546 547 #[repr(u32)] 548 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] 549 pub enum YuvColorSpace { 550 Rec601 = 0, 551 Rec709 = 1, 552 } 553 pub const YUV_COLOR_SPACES: [YuvColorSpace; 2] = [YuvColorSpace::Rec601, YuvColorSpace::Rec709]; 554 555 impl YuvColorSpace { get_feature_string(&self) -> &'static str556 pub fn get_feature_string(&self) -> &'static str { 557 match *self { 558 YuvColorSpace::Rec601 => "YUV_REC601", 559 YuvColorSpace::Rec709 => "YUV_REC709", 560 } 561 } 562 } 563 564 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] 565 pub enum YuvData { 566 NV12(ImageKey, ImageKey), // (Y channel, CbCr interleaved channel) 567 PlanarYCbCr(ImageKey, ImageKey, ImageKey), // (Y channel, Cb channel, Cr Channel) 568 InterleavedYCbCr(ImageKey), // (YCbCr interleaved channel) 569 } 570 571 impl YuvData { get_format(&self) -> YuvFormat572 pub fn get_format(&self) -> YuvFormat { 573 match *self { 574 YuvData::NV12(..) => YuvFormat::NV12, 575 YuvData::PlanarYCbCr(..) => YuvFormat::PlanarYCbCr, 576 YuvData::InterleavedYCbCr(..) => YuvFormat::InterleavedYCbCr, 577 } 578 } 579 } 580 581 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] 582 pub enum YuvFormat { 583 NV12 = 0, 584 PlanarYCbCr = 1, 585 InterleavedYCbCr = 2, 586 } 587 pub const YUV_FORMATS: [YuvFormat; 3] = [ 588 YuvFormat::NV12, 589 YuvFormat::PlanarYCbCr, 590 YuvFormat::InterleavedYCbCr, 591 ]; 592 593 impl YuvFormat { get_plane_num(&self) -> usize594 pub fn get_plane_num(&self) -> usize { 595 match *self { 596 YuvFormat::NV12 => 2, 597 YuvFormat::PlanarYCbCr => 3, 598 YuvFormat::InterleavedYCbCr => 1, 599 } 600 } 601 get_feature_string(&self) -> &'static str602 pub fn get_feature_string(&self) -> &'static str { 603 match *self { 604 YuvFormat::NV12 => "YUV_NV12", 605 YuvFormat::PlanarYCbCr => "YUV_PLANAR", 606 YuvFormat::InterleavedYCbCr => "YUV_INTERLEAVED", 607 } 608 } 609 } 610 611 #[repr(C)] 612 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 613 pub struct ImageMask { 614 pub image: ImageKey, 615 pub rect: LayoutRect, 616 pub repeat: bool, 617 } 618 619 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 620 pub enum LocalClip { 621 Rect(LayoutRect), 622 RoundedRect(LayoutRect, ComplexClipRegion), 623 } 624 625 impl From<LayoutRect> for LocalClip { from(rect: LayoutRect) -> Self626 fn from(rect: LayoutRect) -> Self { 627 LocalClip::Rect(rect) 628 } 629 } 630 631 impl LocalClip { clip_rect(&self) -> &LayoutRect632 pub fn clip_rect(&self) -> &LayoutRect { 633 match *self { 634 LocalClip::Rect(ref rect) => rect, 635 LocalClip::RoundedRect(ref rect, _) => &rect, 636 } 637 } 638 create_with_offset(&self, offset: &LayoutVector2D) -> LocalClip639 pub fn create_with_offset(&self, offset: &LayoutVector2D) -> LocalClip { 640 match *self { 641 LocalClip::Rect(rect) => LocalClip::from(rect.translate(offset)), 642 LocalClip::RoundedRect(rect, complex) => LocalClip::RoundedRect( 643 rect.translate(offset), 644 ComplexClipRegion { 645 rect: complex.rect.translate(offset), 646 radii: complex.radii, 647 mode: complex.mode, 648 }, 649 ), 650 } 651 } 652 clip_by(&self, rect: &LayoutRect) -> LocalClip653 pub fn clip_by(&self, rect: &LayoutRect) -> LocalClip { 654 match *self { 655 LocalClip::Rect(clip_rect) => { 656 LocalClip::Rect( 657 clip_rect.intersection(rect).unwrap_or(LayoutRect::zero()) 658 ) 659 } 660 LocalClip::RoundedRect(clip_rect, complex) => { 661 LocalClip::RoundedRect( 662 clip_rect.intersection(rect).unwrap_or(LayoutRect::zero()), 663 complex, 664 ) 665 } 666 } 667 } 668 } 669 670 #[repr(C)] 671 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] 672 pub enum ClipMode { 673 Clip, // Pixels inside the region are visible. 674 ClipOut, // Pixels outside the region are visible. 675 } 676 677 impl Not for ClipMode { 678 type Output = ClipMode; 679 not(self) -> ClipMode680 fn not(self) -> ClipMode { 681 match self { 682 ClipMode::Clip => ClipMode::ClipOut, 683 ClipMode::ClipOut => ClipMode::Clip, 684 } 685 } 686 } 687 688 #[repr(C)] 689 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] 690 pub struct ComplexClipRegion { 691 /// The boundaries of the rectangle. 692 pub rect: LayoutRect, 693 /// Border radii of this rectangle. 694 pub radii: BorderRadius, 695 /// Whether we are clipping inside or outside 696 /// the region. 697 pub mode: ClipMode, 698 } 699 700 impl BorderRadius { zero() -> BorderRadius701 pub fn zero() -> BorderRadius { 702 BorderRadius { 703 top_left: LayoutSize::new(0.0, 0.0), 704 top_right: LayoutSize::new(0.0, 0.0), 705 bottom_left: LayoutSize::new(0.0, 0.0), 706 bottom_right: LayoutSize::new(0.0, 0.0), 707 } 708 } 709 uniform(radius: f32) -> BorderRadius710 pub fn uniform(radius: f32) -> BorderRadius { 711 BorderRadius { 712 top_left: LayoutSize::new(radius, radius), 713 top_right: LayoutSize::new(radius, radius), 714 bottom_left: LayoutSize::new(radius, radius), 715 bottom_right: LayoutSize::new(radius, radius), 716 } 717 } 718 uniform_size(radius: LayoutSize) -> BorderRadius719 pub fn uniform_size(radius: LayoutSize) -> BorderRadius { 720 BorderRadius { 721 top_left: radius, 722 top_right: radius, 723 bottom_left: radius, 724 bottom_right: radius, 725 } 726 } 727 is_uniform(&self) -> Option<f32>728 pub fn is_uniform(&self) -> Option<f32> { 729 match self.is_uniform_size() { 730 Some(radius) if radius.width == radius.height => Some(radius.width), 731 _ => None, 732 } 733 } 734 is_uniform_size(&self) -> Option<LayoutSize>735 pub fn is_uniform_size(&self) -> Option<LayoutSize> { 736 let uniform_radius = self.top_left; 737 if self.top_right == uniform_radius && self.bottom_left == uniform_radius && 738 self.bottom_right == uniform_radius 739 { 740 Some(uniform_radius) 741 } else { 742 None 743 } 744 } 745 is_zero(&self) -> bool746 pub fn is_zero(&self) -> bool { 747 if let Some(radius) = self.is_uniform() { 748 radius == 0.0 749 } else { 750 false 751 } 752 } 753 } 754 755 impl ComplexClipRegion { 756 /// Create a new complex clip region. new( rect: LayoutRect, radii: BorderRadius, mode: ClipMode, ) -> Self757 pub fn new( 758 rect: LayoutRect, 759 radii: BorderRadius, 760 mode: ClipMode, 761 ) -> Self { 762 ComplexClipRegion { rect, radii, mode } 763 } 764 } 765 766 767 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] 768 pub struct ClipChainId(pub u64, pub PipelineId); 769 770 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] 771 pub enum ClipId { 772 Clip(usize, PipelineId), 773 ClipChain(ClipChainId), 774 } 775 776 const ROOT_REFERENCE_FRAME_CLIP_ID: usize = 0; 777 const ROOT_SCROLL_NODE_CLIP_ID: usize = 1; 778 779 impl ClipId { root_scroll_node(pipeline_id: PipelineId) -> ClipId780 pub fn root_scroll_node(pipeline_id: PipelineId) -> ClipId { 781 ClipId::Clip(ROOT_SCROLL_NODE_CLIP_ID, pipeline_id) 782 } 783 root_reference_frame(pipeline_id: PipelineId) -> ClipId784 pub fn root_reference_frame(pipeline_id: PipelineId) -> ClipId { 785 ClipId::Clip(ROOT_REFERENCE_FRAME_CLIP_ID, pipeline_id) 786 } 787 pipeline_id(&self) -> PipelineId788 pub fn pipeline_id(&self) -> PipelineId { 789 match *self { 790 ClipId::Clip(_, pipeline_id) | 791 ClipId::ClipChain(ClipChainId(_, pipeline_id)) => pipeline_id, 792 } 793 } 794 is_root_scroll_node(&self) -> bool795 pub fn is_root_scroll_node(&self) -> bool { 796 match *self { 797 ClipId::Clip(1, _) => true, 798 _ => false, 799 } 800 } 801 } 802 803 /// An external identifier that uniquely identifies a scroll frame independent of its ClipId, which 804 /// may change from frame to frame. This should be unique within a pipeline. WebRender makes no 805 /// attempt to ensure uniqueness. The zero value is reserved for use by the root scroll node of 806 /// every pipeline, which always has an external id. 807 /// 808 /// When setting display lists with the `preserve_frame_state` this id is used to preserve scroll 809 /// offsets between different sets of ClipScrollNodes which are ScrollFrames. 810 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] 811 pub struct ExternalScrollId(pub u64, pub PipelineId); 812 813 impl ExternalScrollId { pipeline_id(&self) -> PipelineId814 pub fn pipeline_id(&self) -> PipelineId { 815 self.1 816 } 817 is_root(&self) -> bool818 pub fn is_root(&self) -> bool { 819 self.0 == 0 820 } 821 } 822