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