tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

mod.rs (49881B)


      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 api::{BorderRadius, ClipMode, ColorF, ColorU, RasterSpace};
      6 use api::{ImageRendering, RepeatMode, PrimitiveFlags};
      7 use api::{PropertyBinding, Shadow};
      8 use api::{PrimitiveKeyKind, FillRule, POLYGON_CLIP_VERTEX_MAX};
      9 use api::units::*;
     10 use euclid::{SideOffsets2D, Size2D};
     11 use malloc_size_of::MallocSizeOf;
     12 use crate::composite::CompositorSurfaceKind;
     13 use crate::clip::ClipLeafId;
     14 use crate::pattern::{Pattern, PatternBuilder, PatternBuilderContext, PatternBuilderState};
     15 use crate::quad::QuadTileClassifier;
     16 use crate::renderer::{GpuBufferAddress, GpuBufferHandle, GpuBufferWriterF};
     17 use crate::segment::EdgeAaSegmentMask;
     18 use crate::border::BorderSegmentCacheKey;
     19 use crate::debug_item::{DebugItem, DebugMessage};
     20 use crate::debug_colors;
     21 use crate::scene_building::{CreateShadow, IsVisible};
     22 use crate::frame_builder::FrameBuildingState;
     23 use glyph_rasterizer::GlyphKey;
     24 use crate::gpu_types::{BrushFlags, BrushSegmentGpuData, QuadSegment};
     25 use crate::intern;
     26 use crate::picture::PicturePrimitive;
     27 use crate::render_task_graph::RenderTaskId;
     28 use crate::resource_cache::ImageProperties;
     29 use crate::scene::SceneProperties;
     30 use std::{hash, ops, u32, usize};
     31 use crate::util::Recycler;
     32 use crate::internal_types::{FastHashSet, LayoutPrimitiveInfo};
     33 use crate::visibility::PrimitiveVisibility;
     34 
     35 pub mod backdrop;
     36 pub mod borders;
     37 pub mod gradient;
     38 pub mod image;
     39 pub mod line_dec;
     40 pub mod picture;
     41 pub mod text_run;
     42 pub mod interned;
     43 
     44 mod storage;
     45 
     46 use backdrop::{BackdropCaptureDataHandle, BackdropRenderDataHandle};
     47 use borders::{ImageBorderDataHandle, NormalBorderDataHandle};
     48 use gradient::{LinearGradientPrimitive, LinearGradientDataHandle, RadialGradientDataHandle, ConicGradientDataHandle};
     49 use image::{ImageDataHandle, ImageInstance, YuvImageDataHandle};
     50 use line_dec::LineDecorationDataHandle;
     51 use picture::PictureDataHandle;
     52 use text_run::{TextRunDataHandle, TextRunPrimitive};
     53 use crate::box_shadow::BoxShadowDataHandle;
     54 
     55 pub const VECS_PER_SEGMENT: usize = 2;
     56 
     57 #[cfg_attr(feature = "capture", derive(Serialize))]
     58 #[cfg_attr(feature = "replay", derive(Deserialize))]
     59 #[derive(Debug, Copy, Clone, MallocSizeOf)]
     60 pub struct PrimitiveOpacity {
     61    pub is_opaque: bool,
     62 }
     63 
     64 impl PrimitiveOpacity {
     65    pub fn opaque() -> PrimitiveOpacity {
     66        PrimitiveOpacity { is_opaque: true }
     67    }
     68 
     69    pub fn translucent() -> PrimitiveOpacity {
     70        PrimitiveOpacity { is_opaque: false }
     71    }
     72 
     73    pub fn from_alpha(alpha: f32) -> PrimitiveOpacity {
     74        PrimitiveOpacity {
     75            is_opaque: alpha >= 1.0,
     76        }
     77    }
     78 }
     79 
     80 /// For external images, it's not possible to know the
     81 /// UV coords of the image (or the image data itself)
     82 /// until the render thread receives the frame and issues
     83 /// callbacks to the client application. For external
     84 /// images that are visible, a DeferredResolve is created
     85 /// that is stored in the frame. This allows the render
     86 /// thread to iterate this list and update any changed
     87 /// texture data and update the UV rect. Any filtering
     88 /// is handled externally for NativeTexture external
     89 /// images.
     90 #[cfg_attr(feature = "capture", derive(Serialize))]
     91 #[cfg_attr(feature = "replay", derive(Deserialize))]
     92 pub struct DeferredResolve {
     93    pub handle: GpuBufferHandle,
     94    pub image_properties: ImageProperties,
     95    pub rendering: ImageRendering,
     96    pub is_composited: bool,
     97 }
     98 
     99 #[derive(Debug, Copy, Clone, PartialEq)]
    100 #[cfg_attr(feature = "capture", derive(Serialize))]
    101 pub struct ClipTaskIndex(pub u32);
    102 
    103 impl ClipTaskIndex {
    104    pub const INVALID: ClipTaskIndex = ClipTaskIndex(0);
    105 }
    106 
    107 #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, MallocSizeOf, Ord, PartialOrd)]
    108 #[cfg_attr(feature = "capture", derive(Serialize))]
    109 #[cfg_attr(feature = "replay", derive(Deserialize))]
    110 pub struct PictureIndex(pub usize);
    111 
    112 impl PictureIndex {
    113    pub const INVALID: PictureIndex = PictureIndex(!0);
    114 }
    115 
    116 #[cfg_attr(feature = "capture", derive(Serialize))]
    117 #[cfg_attr(feature = "replay", derive(Deserialize))]
    118 #[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
    119 pub struct RectangleKey {
    120    pub x0: f32,
    121    pub y0: f32,
    122    pub x1: f32,
    123    pub y1: f32,
    124 }
    125 
    126 impl RectangleKey {
    127    pub fn intersects(&self, other: &Self) -> bool {
    128        self.x0 < other.x1
    129            && other.x0 < self.x1
    130            && self.y0 < other.y1
    131            && other.y0 < self.y1
    132    }
    133 }
    134 
    135 impl Eq for RectangleKey {}
    136 
    137 impl hash::Hash for RectangleKey {
    138    fn hash<H: hash::Hasher>(&self, state: &mut H) {
    139        self.x0.to_bits().hash(state);
    140        self.y0.to_bits().hash(state);
    141        self.x1.to_bits().hash(state);
    142        self.y1.to_bits().hash(state);
    143    }
    144 }
    145 
    146 impl From<RectangleKey> for LayoutRect {
    147    fn from(key: RectangleKey) -> LayoutRect {
    148        LayoutRect {
    149            min: LayoutPoint::new(key.x0, key.y0),
    150            max: LayoutPoint::new(key.x1, key.y1),
    151        }
    152    }
    153 }
    154 
    155 impl From<RectangleKey> for WorldRect {
    156    fn from(key: RectangleKey) -> WorldRect {
    157        WorldRect {
    158            min: WorldPoint::new(key.x0, key.y0),
    159            max: WorldPoint::new(key.x1, key.y1),
    160        }
    161    }
    162 }
    163 
    164 impl From<LayoutRect> for RectangleKey {
    165    fn from(rect: LayoutRect) -> RectangleKey {
    166        RectangleKey {
    167            x0: rect.min.x,
    168            y0: rect.min.y,
    169            x1: rect.max.x,
    170            y1: rect.max.y,
    171        }
    172    }
    173 }
    174 
    175 impl From<PictureRect> for RectangleKey {
    176    fn from(rect: PictureRect) -> RectangleKey {
    177        RectangleKey {
    178            x0: rect.min.x,
    179            y0: rect.min.y,
    180            x1: rect.max.x,
    181            y1: rect.max.y,
    182        }
    183    }
    184 }
    185 
    186 impl From<WorldRect> for RectangleKey {
    187    fn from(rect: WorldRect) -> RectangleKey {
    188        RectangleKey {
    189            x0: rect.min.x,
    190            y0: rect.min.y,
    191            x1: rect.max.x,
    192            y1: rect.max.y,
    193        }
    194    }
    195 }
    196 
    197 /// To create a fixed-size representation of a polygon, we use a fixed
    198 /// number of points. Our initialization method restricts us to values
    199 /// <= 32. If our constant POLYGON_CLIP_VERTEX_MAX is > 32, the Rust
    200 /// compiler will complain.
    201 #[cfg_attr(feature = "capture", derive(Serialize))]
    202 #[cfg_attr(feature = "replay", derive(Deserialize))]
    203 #[derive(Copy, Debug, Clone, Hash, MallocSizeOf, PartialEq)]
    204 pub struct PolygonKey {
    205    pub point_count: u8,
    206    pub points: [PointKey; POLYGON_CLIP_VERTEX_MAX],
    207    pub fill_rule: FillRule,
    208 }
    209 
    210 impl PolygonKey {
    211    pub fn new(
    212        points_layout: &Vec<LayoutPoint>,
    213        fill_rule: FillRule,
    214    ) -> Self {
    215        // We have to fill fixed-size arrays with data from a Vec.
    216        // We'll do this by initializing the arrays to known-good
    217        // values then overwriting those values as long as our
    218        // iterator provides values.
    219        let mut points: [PointKey; POLYGON_CLIP_VERTEX_MAX] = [PointKey { x: 0.0, y: 0.0}; POLYGON_CLIP_VERTEX_MAX];
    220 
    221        let mut point_count: u8 = 0;
    222        for (src, dest) in points_layout.iter().zip(points.iter_mut()) {
    223            *dest = (*src as LayoutPoint).into();
    224            point_count = point_count + 1;
    225        }
    226 
    227        PolygonKey {
    228            point_count,
    229            points,
    230            fill_rule,
    231        }
    232    }
    233 }
    234 
    235 impl Eq for PolygonKey {}
    236 
    237 /// A hashable SideOffset2D that can be used in primitive keys.
    238 #[cfg_attr(feature = "capture", derive(Serialize))]
    239 #[cfg_attr(feature = "replay", derive(Deserialize))]
    240 #[derive(Debug, Clone, MallocSizeOf, PartialEq)]
    241 pub struct SideOffsetsKey {
    242    pub top: f32,
    243    pub right: f32,
    244    pub bottom: f32,
    245    pub left: f32,
    246 }
    247 
    248 impl Eq for SideOffsetsKey {}
    249 
    250 impl hash::Hash for SideOffsetsKey {
    251    fn hash<H: hash::Hasher>(&self, state: &mut H) {
    252        self.top.to_bits().hash(state);
    253        self.right.to_bits().hash(state);
    254        self.bottom.to_bits().hash(state);
    255        self.left.to_bits().hash(state);
    256    }
    257 }
    258 
    259 impl From<SideOffsetsKey> for LayoutSideOffsets {
    260    fn from(key: SideOffsetsKey) -> LayoutSideOffsets {
    261        LayoutSideOffsets::new(
    262            key.top,
    263            key.right,
    264            key.bottom,
    265            key.left,
    266        )
    267    }
    268 }
    269 
    270 impl<U> From<SideOffsets2D<f32, U>> for SideOffsetsKey {
    271    fn from(offsets: SideOffsets2D<f32, U>) -> SideOffsetsKey {
    272        SideOffsetsKey {
    273            top: offsets.top,
    274            right: offsets.right,
    275            bottom: offsets.bottom,
    276            left: offsets.left,
    277        }
    278    }
    279 }
    280 
    281 /// A hashable size for using as a key during primitive interning.
    282 #[cfg_attr(feature = "capture", derive(Serialize))]
    283 #[cfg_attr(feature = "replay", derive(Deserialize))]
    284 #[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
    285 pub struct SizeKey {
    286    w: f32,
    287    h: f32,
    288 }
    289 
    290 impl Eq for SizeKey {}
    291 
    292 impl hash::Hash for SizeKey {
    293    fn hash<H: hash::Hasher>(&self, state: &mut H) {
    294        self.w.to_bits().hash(state);
    295        self.h.to_bits().hash(state);
    296    }
    297 }
    298 
    299 impl From<SizeKey> for LayoutSize {
    300    fn from(key: SizeKey) -> LayoutSize {
    301        LayoutSize::new(key.w, key.h)
    302    }
    303 }
    304 
    305 impl<U> From<Size2D<f32, U>> for SizeKey {
    306    fn from(size: Size2D<f32, U>) -> SizeKey {
    307        SizeKey {
    308            w: size.width,
    309            h: size.height,
    310        }
    311    }
    312 }
    313 
    314 /// A hashable vec for using as a key during primitive interning.
    315 #[cfg_attr(feature = "capture", derive(Serialize))]
    316 #[cfg_attr(feature = "replay", derive(Deserialize))]
    317 #[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
    318 pub struct VectorKey {
    319    pub x: f32,
    320    pub y: f32,
    321 }
    322 
    323 impl Eq for VectorKey {}
    324 
    325 impl hash::Hash for VectorKey {
    326    fn hash<H: hash::Hasher>(&self, state: &mut H) {
    327        self.x.to_bits().hash(state);
    328        self.y.to_bits().hash(state);
    329    }
    330 }
    331 
    332 impl From<VectorKey> for LayoutVector2D {
    333    fn from(key: VectorKey) -> LayoutVector2D {
    334        LayoutVector2D::new(key.x, key.y)
    335    }
    336 }
    337 
    338 impl From<VectorKey> for WorldVector2D {
    339    fn from(key: VectorKey) -> WorldVector2D {
    340        WorldVector2D::new(key.x, key.y)
    341    }
    342 }
    343 
    344 impl From<LayoutVector2D> for VectorKey {
    345    fn from(vec: LayoutVector2D) -> VectorKey {
    346        VectorKey {
    347            x: vec.x,
    348            y: vec.y,
    349        }
    350    }
    351 }
    352 
    353 impl From<WorldVector2D> for VectorKey {
    354    fn from(vec: WorldVector2D) -> VectorKey {
    355        VectorKey {
    356            x: vec.x,
    357            y: vec.y,
    358        }
    359    }
    360 }
    361 
    362 /// A hashable point for using as a key during primitive interning.
    363 #[cfg_attr(feature = "capture", derive(Serialize))]
    364 #[cfg_attr(feature = "replay", derive(Deserialize))]
    365 #[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)]
    366 pub struct PointKey {
    367    pub x: f32,
    368    pub y: f32,
    369 }
    370 
    371 impl Eq for PointKey {}
    372 
    373 impl hash::Hash for PointKey {
    374    fn hash<H: hash::Hasher>(&self, state: &mut H) {
    375        self.x.to_bits().hash(state);
    376        self.y.to_bits().hash(state);
    377    }
    378 }
    379 
    380 impl From<PointKey> for LayoutPoint {
    381    fn from(key: PointKey) -> LayoutPoint {
    382        LayoutPoint::new(key.x, key.y)
    383    }
    384 }
    385 
    386 impl From<LayoutPoint> for PointKey {
    387    fn from(p: LayoutPoint) -> PointKey {
    388        PointKey {
    389            x: p.x,
    390            y: p.y,
    391        }
    392    }
    393 }
    394 
    395 impl From<PicturePoint> for PointKey {
    396    fn from(p: PicturePoint) -> PointKey {
    397        PointKey {
    398            x: p.x,
    399            y: p.y,
    400        }
    401    }
    402 }
    403 
    404 impl From<WorldPoint> for PointKey {
    405    fn from(p: WorldPoint) -> PointKey {
    406        PointKey {
    407            x: p.x,
    408            y: p.y,
    409        }
    410    }
    411 }
    412 
    413 /// A hashable float for using as a key during primitive interning.
    414 #[cfg_attr(feature = "capture", derive(Serialize))]
    415 #[cfg_attr(feature = "replay", derive(Deserialize))]
    416 #[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)]
    417 pub struct FloatKey(f32);
    418 
    419 impl Eq for FloatKey {}
    420 
    421 impl hash::Hash for FloatKey {
    422    fn hash<H: hash::Hasher>(&self, state: &mut H) {
    423        self.0.to_bits().hash(state);
    424    }
    425 }
    426 
    427 
    428 #[cfg_attr(feature = "capture", derive(Serialize))]
    429 #[cfg_attr(feature = "replay", derive(Deserialize))]
    430 #[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
    431 pub struct PrimKeyCommonData {
    432    pub flags: PrimitiveFlags,
    433    pub prim_rect: RectangleKey,
    434 }
    435 
    436 impl From<&LayoutPrimitiveInfo> for PrimKeyCommonData {
    437    fn from(info: &LayoutPrimitiveInfo) -> Self {
    438        PrimKeyCommonData {
    439            flags: info.flags,
    440            prim_rect: info.rect.into(),
    441        }
    442    }
    443 }
    444 
    445 #[cfg_attr(feature = "capture", derive(Serialize))]
    446 #[cfg_attr(feature = "replay", derive(Deserialize))]
    447 #[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
    448 pub struct PrimKey<T: MallocSizeOf> {
    449    pub common: PrimKeyCommonData,
    450    pub kind: T,
    451 }
    452 
    453 #[cfg_attr(feature = "capture", derive(Serialize))]
    454 #[cfg_attr(feature = "replay", derive(Deserialize))]
    455 #[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
    456 pub struct PrimitiveKey {
    457    pub common: PrimKeyCommonData,
    458    pub kind: PrimitiveKeyKind,
    459 }
    460 
    461 impl PrimitiveKey {
    462    pub fn new(
    463        info: &LayoutPrimitiveInfo,
    464        kind: PrimitiveKeyKind,
    465    ) -> Self {
    466        PrimitiveKey {
    467            common: info.into(),
    468            kind,
    469        }
    470    }
    471 }
    472 
    473 impl intern::InternDebug for PrimitiveKey {}
    474 
    475 /// The shared information for a given primitive. This is interned and retained
    476 /// both across frames and display lists, by comparing the matching PrimitiveKey.
    477 #[cfg_attr(feature = "capture", derive(Serialize))]
    478 #[cfg_attr(feature = "replay", derive(Deserialize))]
    479 #[derive(MallocSizeOf)]
    480 pub enum PrimitiveTemplateKind {
    481    Rectangle {
    482        color: PropertyBinding<ColorF>,
    483    },
    484 }
    485 
    486 impl PrimitiveTemplateKind {
    487    /// Write any GPU blocks for the primitive template to the given request object.
    488    pub fn write_prim_gpu_blocks(
    489        &self,
    490        writer: &mut GpuBufferWriterF,
    491        scene_properties: &SceneProperties,
    492    ) {
    493        match *self {
    494            PrimitiveTemplateKind::Rectangle { ref color, .. } => {
    495                writer.push_one(scene_properties.resolve_color(color).premultiplied())
    496            }
    497        }
    498    }
    499 }
    500 
    501 /// Construct the primitive template data from a primitive key. This
    502 /// is invoked when a primitive key is created and the interner
    503 /// doesn't currently contain a primitive with this key.
    504 impl From<PrimitiveKeyKind> for PrimitiveTemplateKind {
    505    fn from(kind: PrimitiveKeyKind) -> Self {
    506        match kind {
    507            PrimitiveKeyKind::Rectangle { color, .. } => {
    508                PrimitiveTemplateKind::Rectangle {
    509                    color: color.into(),
    510                }
    511            }
    512        }
    513    }
    514 }
    515 
    516 #[cfg_attr(feature = "capture", derive(Serialize))]
    517 #[cfg_attr(feature = "replay", derive(Deserialize))]
    518 #[derive(MallocSizeOf)]
    519 #[derive(Debug)]
    520 pub struct PrimTemplateCommonData {
    521    pub flags: PrimitiveFlags,
    522    pub may_need_repetition: bool,
    523    pub prim_rect: LayoutRect,
    524    pub opacity: PrimitiveOpacity,
    525    /// Address of the per-primitive data in the GPU cache.
    526    ///
    527    /// TODO: This is only valid during the current frame and must
    528    /// be overwritten each frame. We should move this out of the
    529    /// common data to avoid accidental reuse.
    530    pub gpu_buffer_address: GpuBufferAddress,
    531    /// Specifies the edges that are *allowed* to have anti-aliasing.
    532    /// In other words EdgeAaSegmentFlags::all() does not necessarily mean all edges will
    533    /// be anti-aliased, only that they could be.
    534    ///
    535    /// Use this to force disable anti-alasing on edges of the primitives.
    536    pub edge_aa_mask: EdgeAaSegmentMask,
    537 }
    538 
    539 impl PrimTemplateCommonData {
    540    pub fn with_key_common(common: PrimKeyCommonData) -> Self {
    541        PrimTemplateCommonData {
    542            flags: common.flags,
    543            may_need_repetition: true,
    544            prim_rect: common.prim_rect.into(),
    545            gpu_buffer_address: GpuBufferAddress::INVALID,
    546            opacity: PrimitiveOpacity::translucent(),
    547            edge_aa_mask: EdgeAaSegmentMask::all(),
    548        }
    549    }
    550 }
    551 
    552 #[cfg_attr(feature = "capture", derive(Serialize))]
    553 #[cfg_attr(feature = "replay", derive(Deserialize))]
    554 #[derive(MallocSizeOf)]
    555 pub struct PrimTemplate<T> {
    556    pub common: PrimTemplateCommonData,
    557    pub kind: T,
    558 }
    559 
    560 #[cfg_attr(feature = "capture", derive(Serialize))]
    561 #[cfg_attr(feature = "replay", derive(Deserialize))]
    562 #[derive(MallocSizeOf)]
    563 pub struct PrimitiveTemplate {
    564    pub common: PrimTemplateCommonData,
    565    pub kind: PrimitiveTemplateKind,
    566 }
    567 
    568 impl PatternBuilder for PrimitiveTemplate {
    569    fn build(
    570        &self,
    571        _sub_rect: Option<DeviceRect>,
    572        ctx: &PatternBuilderContext,
    573        _state: &mut PatternBuilderState,
    574    ) -> crate::pattern::Pattern {
    575        match self.kind {
    576            PrimitiveTemplateKind::Rectangle { ref color, .. } => {
    577                let color = ctx.scene_properties.resolve_color(color);
    578                Pattern::color(color)
    579            }
    580        }
    581    }
    582 
    583    fn get_base_color(
    584        &self,
    585        ctx: &PatternBuilderContext,
    586    ) -> ColorF {
    587        match self.kind {
    588            PrimitiveTemplateKind::Rectangle { ref color, .. } => {
    589                ctx.scene_properties.resolve_color(color)
    590            }
    591        }
    592    }
    593 
    594    fn use_shared_pattern(
    595        &self,
    596    ) -> bool {
    597        true
    598    }
    599 }
    600 
    601 impl ops::Deref for PrimitiveTemplate {
    602    type Target = PrimTemplateCommonData;
    603    fn deref(&self) -> &Self::Target {
    604        &self.common
    605    }
    606 }
    607 
    608 impl ops::DerefMut for PrimitiveTemplate {
    609    fn deref_mut(&mut self) -> &mut Self::Target {
    610        &mut self.common
    611    }
    612 }
    613 
    614 impl From<PrimitiveKey> for PrimitiveTemplate {
    615    fn from(item: PrimitiveKey) -> Self {
    616        PrimitiveTemplate {
    617            common: PrimTemplateCommonData::with_key_common(item.common),
    618            kind: item.kind.into(),
    619        }
    620    }
    621 }
    622 
    623 impl PrimitiveTemplate {
    624    /// Update the GPU cache for a given primitive template. This may be called multiple
    625    /// times per frame, by each primitive reference that refers to this interned
    626    /// template. The initial request call to the GPU cache ensures that work is only
    627    /// done if the cache entry is invalid (due to first use or eviction).
    628    pub fn update(
    629        &mut self,
    630        frame_state: &mut FrameBuildingState,
    631        scene_properties: &SceneProperties,
    632    ) {
    633        let mut writer = frame_state.frame_gpu_data.f32.write_blocks(1);
    634        self.kind.write_prim_gpu_blocks(&mut writer, scene_properties);
    635        self.common.gpu_buffer_address = writer.finish();
    636 
    637        self.opacity = match self.kind {
    638            PrimitiveTemplateKind::Rectangle { ref color, .. } => {
    639                PrimitiveOpacity::from_alpha(scene_properties.resolve_color(color).a)
    640            }
    641        };
    642    }
    643 }
    644 
    645 type PrimitiveDataHandle = intern::Handle<PrimitiveKeyKind>;
    646 
    647 impl intern::Internable for PrimitiveKeyKind {
    648    type Key = PrimitiveKey;
    649    type StoreData = PrimitiveTemplate;
    650    type InternData = ();
    651    const PROFILE_COUNTER: usize = crate::profiler::INTERNED_PRIMITIVES;
    652 }
    653 
    654 impl InternablePrimitive for PrimitiveKeyKind {
    655    fn into_key(
    656        self,
    657        info: &LayoutPrimitiveInfo,
    658    ) -> PrimitiveKey {
    659        PrimitiveKey::new(info, self)
    660    }
    661 
    662    fn make_instance_kind(
    663        key: PrimitiveKey,
    664        data_handle: PrimitiveDataHandle,
    665        prim_store: &mut PrimitiveStore,
    666    ) -> PrimitiveInstanceKind {
    667        match key.kind {
    668            PrimitiveKeyKind::Rectangle { color, .. } => {
    669                let color_binding_index = match color {
    670                    PropertyBinding::Binding(..) => {
    671                        prim_store.color_bindings.push(color)
    672                    }
    673                    PropertyBinding::Value(..) => ColorBindingIndex::INVALID,
    674                };
    675                PrimitiveInstanceKind::Rectangle {
    676                    data_handle,
    677                    segment_instance_index: SegmentInstanceIndex::INVALID,
    678                    color_binding_index,
    679                    use_legacy_path: false,
    680                }
    681            }
    682        }
    683    }
    684 }
    685 
    686 #[derive(Debug, MallocSizeOf)]
    687 #[cfg_attr(feature = "capture", derive(Serialize))]
    688 #[cfg_attr(feature = "replay", derive(Deserialize))]
    689 pub struct VisibleMaskImageTile {
    690    pub tile_offset: TileOffset,
    691    pub tile_rect: LayoutRect,
    692    pub task_id: RenderTaskId,
    693 }
    694 
    695 #[derive(Debug)]
    696 #[cfg_attr(feature = "capture", derive(Serialize))]
    697 pub struct VisibleGradientTile {
    698    pub address: GpuBufferAddress,
    699    pub local_rect: LayoutRect,
    700    pub local_clip_rect: LayoutRect,
    701 }
    702 
    703 /// Information about how to cache a border segment,
    704 /// along with the current render task cache entry.
    705 #[cfg_attr(feature = "capture", derive(Serialize))]
    706 #[cfg_attr(feature = "replay", derive(Deserialize))]
    707 #[derive(Debug, MallocSizeOf)]
    708 pub struct BorderSegmentInfo {
    709    pub local_task_size: LayoutSize,
    710    pub cache_key: BorderSegmentCacheKey,
    711 }
    712 
    713 /// Represents the visibility state of a segment (wrt clip masks).
    714 #[cfg_attr(feature = "capture", derive(Serialize))]
    715 #[derive(Debug, Clone)]
    716 pub enum ClipMaskKind {
    717    /// The segment has a clip mask, specified by the render task.
    718    Mask(RenderTaskId),
    719    /// The segment has no clip mask.
    720    None,
    721    /// The segment is made invisible / clipped completely.
    722    Clipped,
    723 }
    724 
    725 #[cfg_attr(feature = "capture", derive(Serialize))]
    726 #[cfg_attr(feature = "replay", derive(Deserialize))]
    727 #[derive(Debug, Clone, MallocSizeOf)]
    728 pub struct BrushSegment {
    729    pub local_rect: LayoutRect,
    730    pub may_need_clip_mask: bool,
    731    pub edge_flags: EdgeAaSegmentMask,
    732    pub extra_data: [f32; 4],
    733    pub brush_flags: BrushFlags,
    734 }
    735 
    736 impl BrushSegment {
    737    pub fn new(
    738        local_rect: LayoutRect,
    739        may_need_clip_mask: bool,
    740        edge_flags: EdgeAaSegmentMask,
    741        extra_data: [f32; 4],
    742        brush_flags: BrushFlags,
    743    ) -> Self {
    744        Self {
    745            local_rect,
    746            may_need_clip_mask,
    747            edge_flags,
    748            extra_data,
    749            brush_flags,
    750        }
    751    }
    752 
    753    pub fn gpu_data(&self) -> BrushSegmentGpuData {
    754        BrushSegmentGpuData {
    755            local_rect: self.local_rect,
    756            extra_data: self.extra_data,
    757        }
    758    }
    759 
    760    pub fn write_gpu_blocks(&self, writer: &mut GpuBufferWriterF) {
    761        writer.push(&self.gpu_data());
    762    }
    763 }
    764 
    765 #[derive(Debug, Clone)]
    766 #[repr(C)]
    767 #[cfg_attr(feature = "capture", derive(Serialize))]
    768 #[cfg_attr(feature = "replay", derive(Deserialize))]
    769 struct ClipRect {
    770    rect: LayoutRect,
    771    mode: f32,
    772 }
    773 
    774 #[derive(Debug, Clone)]
    775 #[repr(C)]
    776 #[cfg_attr(feature = "capture", derive(Serialize))]
    777 #[cfg_attr(feature = "replay", derive(Deserialize))]
    778 struct ClipCorner {
    779    rect: LayoutRect,
    780    outer_radius_x: f32,
    781    outer_radius_y: f32,
    782    inner_radius_x: f32,
    783    inner_radius_y: f32,
    784 }
    785 
    786 impl ClipCorner {
    787    fn uniform(rect: LayoutRect, outer_radius: f32, inner_radius: f32) -> ClipCorner {
    788        ClipCorner {
    789            rect,
    790            outer_radius_x: outer_radius,
    791            outer_radius_y: outer_radius,
    792            inner_radius_x: inner_radius,
    793            inner_radius_y: inner_radius,
    794        }
    795    }
    796 }
    797 
    798 #[derive(Debug, Clone)]
    799 #[repr(C)]
    800 #[cfg_attr(feature = "capture", derive(Serialize))]
    801 #[cfg_attr(feature = "replay", derive(Deserialize))]
    802 pub struct ClipData {
    803    rect: ClipRect,
    804    top_left: ClipCorner,
    805    top_right: ClipCorner,
    806    bottom_left: ClipCorner,
    807    bottom_right: ClipCorner,
    808 }
    809 
    810 impl ClipData {
    811    pub fn rounded_rect(size: LayoutSize, radii: &BorderRadius, mode: ClipMode) -> ClipData {
    812        // TODO(gw): For simplicity, keep most of the clip GPU structs the
    813        //           same as they were, even though the origin is now always
    814        //           zero, since they are in the clip's local space. In future,
    815        //           we could reduce the GPU cache size of ClipData.
    816        let rect = LayoutRect::from_size(size);
    817 
    818        ClipData {
    819            rect: ClipRect {
    820                rect,
    821                mode: mode as u32 as f32,
    822            },
    823            top_left: ClipCorner {
    824                rect: LayoutRect::from_origin_and_size(
    825                    LayoutPoint::new(rect.min.x, rect.min.y),
    826                    LayoutSize::new(radii.top_left.width, radii.top_left.height),
    827                ),
    828                outer_radius_x: radii.top_left.width,
    829                outer_radius_y: radii.top_left.height,
    830                inner_radius_x: 0.0,
    831                inner_radius_y: 0.0,
    832            },
    833            top_right: ClipCorner {
    834                rect: LayoutRect::from_origin_and_size(
    835                    LayoutPoint::new(
    836                        rect.max.x - radii.top_right.width,
    837                        rect.min.y,
    838                    ),
    839                    LayoutSize::new(radii.top_right.width, radii.top_right.height),
    840                ),
    841                outer_radius_x: radii.top_right.width,
    842                outer_radius_y: radii.top_right.height,
    843                inner_radius_x: 0.0,
    844                inner_radius_y: 0.0,
    845            },
    846            bottom_left: ClipCorner {
    847                rect: LayoutRect::from_origin_and_size(
    848                    LayoutPoint::new(
    849                        rect.min.x,
    850                        rect.max.y - radii.bottom_left.height,
    851                    ),
    852                    LayoutSize::new(radii.bottom_left.width, radii.bottom_left.height),
    853                ),
    854                outer_radius_x: radii.bottom_left.width,
    855                outer_radius_y: radii.bottom_left.height,
    856                inner_radius_x: 0.0,
    857                inner_radius_y: 0.0,
    858            },
    859            bottom_right: ClipCorner {
    860                rect: LayoutRect::from_origin_and_size(
    861                    LayoutPoint::new(
    862                        rect.max.x - radii.bottom_right.width,
    863                        rect.max.y - radii.bottom_right.height,
    864                    ),
    865                    LayoutSize::new(radii.bottom_right.width, radii.bottom_right.height),
    866                ),
    867                outer_radius_x: radii.bottom_right.width,
    868                outer_radius_y: radii.bottom_right.height,
    869                inner_radius_x: 0.0,
    870                inner_radius_y: 0.0,
    871            },
    872        }
    873    }
    874 
    875    pub fn uniform(size: LayoutSize, radius: f32, mode: ClipMode) -> ClipData {
    876        // TODO(gw): For simplicity, keep most of the clip GPU structs the
    877        //           same as they were, even though the origin is now always
    878        //           zero, since they are in the clip's local space. In future,
    879        //           we could reduce the GPU cache size of ClipData.
    880        let rect = LayoutRect::from_size(size);
    881 
    882        ClipData {
    883            rect: ClipRect {
    884                rect,
    885                mode: mode as u32 as f32,
    886            },
    887            top_left: ClipCorner::uniform(
    888                LayoutRect::from_origin_and_size(
    889                    LayoutPoint::new(rect.min.x, rect.min.y),
    890                    LayoutSize::new(radius, radius),
    891                ),
    892                radius,
    893                0.0,
    894            ),
    895            top_right: ClipCorner::uniform(
    896                LayoutRect::from_origin_and_size(
    897                    LayoutPoint::new(rect.max.x - radius, rect.min.y),
    898                    LayoutSize::new(radius, radius),
    899                ),
    900                radius,
    901                0.0,
    902            ),
    903            bottom_left: ClipCorner::uniform(
    904                LayoutRect::from_origin_and_size(
    905                    LayoutPoint::new(rect.min.x, rect.max.y - radius),
    906                    LayoutSize::new(radius, radius),
    907                ),
    908                radius,
    909                0.0,
    910            ),
    911            bottom_right: ClipCorner::uniform(
    912                LayoutRect::from_origin_and_size(
    913                    LayoutPoint::new(
    914                        rect.max.x - radius,
    915                        rect.max.y - radius,
    916                    ),
    917                    LayoutSize::new(radius, radius),
    918                ),
    919                radius,
    920                0.0,
    921            ),
    922        }
    923    }
    924 }
    925 
    926 /// A hashable descriptor for nine-patches, used by image and
    927 /// gradient borders.
    928 #[derive(Debug, Clone, PartialEq, Eq, Hash, MallocSizeOf)]
    929 #[cfg_attr(feature = "capture", derive(Serialize))]
    930 #[cfg_attr(feature = "replay", derive(Deserialize))]
    931 pub struct NinePatchDescriptor {
    932    pub width: i32,
    933    pub height: i32,
    934    pub slice: DeviceIntSideOffsets,
    935    pub fill: bool,
    936    pub repeat_horizontal: RepeatMode,
    937    pub repeat_vertical: RepeatMode,
    938    pub widths: SideOffsetsKey,
    939 }
    940 
    941 impl IsVisible for PrimitiveKeyKind {
    942    // Return true if the primary primitive is visible.
    943    // Used to trivially reject non-visible primitives.
    944    // TODO(gw): Currently, primitives other than those
    945    //           listed here are handled before the
    946    //           add_primitive() call. In the future
    947    //           we should move the logic for all other
    948    //           primitive types to use this.
    949    fn is_visible(&self) -> bool {
    950        match *self {
    951            PrimitiveKeyKind::Rectangle { ref color, .. } => {
    952                match *color {
    953                    PropertyBinding::Value(value) => value.a > 0,
    954                    PropertyBinding::Binding(..) => true,
    955                }
    956            }
    957        }
    958    }
    959 }
    960 
    961 impl CreateShadow for PrimitiveKeyKind {
    962    // Create a clone of this PrimitiveContainer, applying whatever
    963    // changes are necessary to the primitive to support rendering
    964    // it as part of the supplied shadow.
    965    fn create_shadow(
    966        &self,
    967        shadow: &Shadow,
    968        _: bool,
    969        _: RasterSpace,
    970    ) -> PrimitiveKeyKind {
    971        match *self {
    972            PrimitiveKeyKind::Rectangle { .. } => {
    973                PrimitiveKeyKind::Rectangle {
    974                    color: PropertyBinding::Value(shadow.color.into()),
    975                }
    976            }
    977        }
    978    }
    979 }
    980 
    981 #[derive(Debug)]
    982 #[cfg_attr(feature = "capture", derive(Serialize))]
    983 pub enum PrimitiveInstanceKind {
    984    /// Direct reference to a Picture
    985    Picture {
    986        /// Handle to the common interned data for this primitive.
    987        data_handle: PictureDataHandle,
    988        pic_index: PictureIndex,
    989    },
    990    /// A run of glyphs, with associated font parameters.
    991    TextRun {
    992        /// Handle to the common interned data for this primitive.
    993        data_handle: TextRunDataHandle,
    994        /// Index to the per instance scratch data for this primitive.
    995        run_index: TextRunIndex,
    996    },
    997    /// A line decoration. cache_handle refers to a cached render
    998    /// task handle, if this line decoration is not a simple solid.
    999    LineDecoration {
   1000        /// Handle to the common interned data for this primitive.
   1001        data_handle: LineDecorationDataHandle,
   1002        // TODO(gw): For now, we need to store some information in
   1003        //           the primitive instance that is created during
   1004        //           prepare_prims and read during the batching pass.
   1005        //           Once we unify the prepare_prims and batching to
   1006        //           occur at the same time, we can remove most of
   1007        //           the things we store here in the instance, and
   1008        //           use them directly. This will remove cache_handle,
   1009        //           but also the opacity, clip_task_id etc below.
   1010        render_task: Option<RenderTaskId>,
   1011    },
   1012    NormalBorder {
   1013        /// Handle to the common interned data for this primitive.
   1014        data_handle: NormalBorderDataHandle,
   1015        render_task_ids: storage::Range<RenderTaskId>,
   1016    },
   1017    ImageBorder {
   1018        /// Handle to the common interned data for this primitive.
   1019        data_handle: ImageBorderDataHandle,
   1020    },
   1021    Rectangle {
   1022        /// Handle to the common interned data for this primitive.
   1023        data_handle: PrimitiveDataHandle,
   1024        segment_instance_index: SegmentInstanceIndex,
   1025        color_binding_index: ColorBindingIndex,
   1026        use_legacy_path: bool,
   1027    },
   1028    YuvImage {
   1029        /// Handle to the common interned data for this primitive.
   1030        data_handle: YuvImageDataHandle,
   1031        segment_instance_index: SegmentInstanceIndex,
   1032        compositor_surface_kind: CompositorSurfaceKind,
   1033    },
   1034    Image {
   1035        /// Handle to the common interned data for this primitive.
   1036        data_handle: ImageDataHandle,
   1037        image_instance_index: ImageInstanceIndex,
   1038        compositor_surface_kind: CompositorSurfaceKind,
   1039    },
   1040    /// Always rendered directly into the picture. This tends to be
   1041    /// faster with SWGL.
   1042    LinearGradient {
   1043        /// Handle to the common interned data for this primitive.
   1044        data_handle: LinearGradientDataHandle,
   1045        visible_tiles_range: GradientTileRange,
   1046        use_legacy_path: bool,
   1047    },
   1048    /// Always rendered via a cached render task. Usually faster with
   1049    /// a GPU.
   1050    CachedLinearGradient {
   1051        /// Handle to the common interned data for this primitive.
   1052        data_handle: LinearGradientDataHandle,
   1053        visible_tiles_range: GradientTileRange,
   1054    },
   1055    RadialGradient {
   1056        /// Handle to the common interned data for this primitive.
   1057        data_handle: RadialGradientDataHandle,
   1058        visible_tiles_range: GradientTileRange,
   1059        use_legacy_path: bool,
   1060    },
   1061    ConicGradient {
   1062        /// Handle to the common interned data for this primitive.
   1063        data_handle: ConicGradientDataHandle,
   1064        visible_tiles_range: GradientTileRange,
   1065        use_legacy_path: bool,
   1066    },
   1067    /// Render a portion of a specified backdrop.
   1068    BackdropCapture {
   1069        data_handle: BackdropCaptureDataHandle,
   1070    },
   1071    BackdropRender {
   1072        data_handle: BackdropRenderDataHandle,
   1073        pic_index: PictureIndex,
   1074    },
   1075    BoxShadow {
   1076        data_handle: BoxShadowDataHandle,
   1077    },
   1078 }
   1079 
   1080 impl PrimitiveInstanceKind {
   1081    pub fn as_pic(&self) -> PictureIndex {
   1082        match self {
   1083            PrimitiveInstanceKind::Picture { pic_index, .. } => *pic_index,
   1084            _ => panic!("bug: as_pic called on a prim that is not a picture"),
   1085        }
   1086    }
   1087 }
   1088 
   1089 #[derive(Debug, Copy, Clone)]
   1090 #[cfg_attr(feature = "capture", derive(Serialize))]
   1091 #[cfg_attr(feature = "replay", derive(Deserialize))]
   1092 pub struct PrimitiveInstanceIndex(pub u32);
   1093 
   1094 #[derive(Debug)]
   1095 #[cfg_attr(feature = "capture", derive(Serialize))]
   1096 pub struct PrimitiveInstance {
   1097    /// Identifies the kind of primitive this
   1098    /// instance is, and references to where
   1099    /// the relevant information for the primitive
   1100    /// can be found.
   1101    pub kind: PrimitiveInstanceKind,
   1102 
   1103    /// All information and state related to clip(s) for this primitive
   1104    pub clip_leaf_id: ClipLeafId,
   1105 
   1106    /// Information related to the current visibility state of this
   1107    /// primitive.
   1108    // TODO(gw): Currently built each frame, but can be retained.
   1109    pub vis: PrimitiveVisibility,
   1110 }
   1111 
   1112 impl PrimitiveInstance {
   1113    pub fn new(
   1114        kind: PrimitiveInstanceKind,
   1115        clip_leaf_id: ClipLeafId,
   1116    ) -> Self {
   1117        PrimitiveInstance {
   1118            kind,
   1119            vis: PrimitiveVisibility::new(),
   1120            clip_leaf_id,
   1121        }
   1122    }
   1123 
   1124    // Reset any pre-frame state for this primitive.
   1125    pub fn reset(&mut self) {
   1126        self.vis.reset();
   1127    }
   1128 
   1129    pub fn clear_visibility(&mut self) {
   1130        self.vis.reset();
   1131    }
   1132 
   1133    pub fn uid(&self) -> intern::ItemUid {
   1134        match &self.kind {
   1135            PrimitiveInstanceKind::Rectangle { data_handle, .. } => {
   1136                data_handle.uid()
   1137            }
   1138            PrimitiveInstanceKind::Image { data_handle, .. } => {
   1139                data_handle.uid()
   1140            }
   1141            PrimitiveInstanceKind::ImageBorder { data_handle, .. } => {
   1142                data_handle.uid()
   1143            }
   1144            PrimitiveInstanceKind::LineDecoration { data_handle, .. } => {
   1145                data_handle.uid()
   1146            }
   1147            PrimitiveInstanceKind::LinearGradient { data_handle, .. } => {
   1148                data_handle.uid()
   1149            }
   1150            PrimitiveInstanceKind::CachedLinearGradient { data_handle, .. } => {
   1151                data_handle.uid()
   1152            }
   1153            PrimitiveInstanceKind::NormalBorder { data_handle, .. } => {
   1154                data_handle.uid()
   1155            }
   1156            PrimitiveInstanceKind::Picture { data_handle, .. } => {
   1157                data_handle.uid()
   1158            }
   1159            PrimitiveInstanceKind::RadialGradient { data_handle, .. } => {
   1160                data_handle.uid()
   1161            }
   1162            PrimitiveInstanceKind::ConicGradient { data_handle, .. } => {
   1163                data_handle.uid()
   1164            }
   1165            PrimitiveInstanceKind::TextRun { data_handle, .. } => {
   1166                data_handle.uid()
   1167            }
   1168            PrimitiveInstanceKind::YuvImage { data_handle, .. } => {
   1169                data_handle.uid()
   1170            }
   1171            PrimitiveInstanceKind::BackdropCapture { data_handle, .. } => {
   1172                data_handle.uid()
   1173            }
   1174            PrimitiveInstanceKind::BackdropRender { data_handle, .. } => {
   1175                data_handle.uid()
   1176            }
   1177            PrimitiveInstanceKind::BoxShadow { data_handle, .. } => {
   1178                data_handle.uid()
   1179            }
   1180        }
   1181    }
   1182 }
   1183 
   1184 #[cfg_attr(feature = "capture", derive(Serialize))]
   1185 #[derive(Debug)]
   1186 pub struct SegmentedInstance {
   1187    pub gpu_data: GpuBufferAddress,
   1188    pub segments_range: SegmentsRange,
   1189 }
   1190 
   1191 pub type GlyphKeyStorage = storage::Storage<GlyphKey>;
   1192 pub type TextRunIndex = storage::Index<TextRunPrimitive>;
   1193 pub type TextRunStorage = storage::Storage<TextRunPrimitive>;
   1194 pub type ColorBindingIndex = storage::Index<PropertyBinding<ColorU>>;
   1195 pub type ColorBindingStorage = storage::Storage<PropertyBinding<ColorU>>;
   1196 pub type BorderHandleStorage = storage::Storage<RenderTaskId>;
   1197 pub type SegmentStorage = storage::Storage<BrushSegment>;
   1198 pub type SegmentsRange = storage::Range<BrushSegment>;
   1199 pub type SegmentInstanceStorage = storage::Storage<SegmentedInstance>;
   1200 pub type SegmentInstanceIndex = storage::Index<SegmentedInstance>;
   1201 pub type ImageInstanceStorage = storage::Storage<ImageInstance>;
   1202 pub type ImageInstanceIndex = storage::Index<ImageInstance>;
   1203 pub type GradientTileStorage = storage::Storage<VisibleGradientTile>;
   1204 pub type GradientTileRange = storage::Range<VisibleGradientTile>;
   1205 pub type LinearGradientStorage = storage::Storage<LinearGradientPrimitive>;
   1206 
   1207 /// Contains various vecs of data that is used only during frame building,
   1208 /// where we want to recycle the memory each new display list, to avoid constantly
   1209 /// re-allocating and moving memory around. Written during primitive preparation,
   1210 /// and read during batching.
   1211 #[cfg_attr(feature = "capture", derive(Serialize))]
   1212 pub struct PrimitiveScratchBuffer {
   1213    /// Contains a list of clip mask instance parameters
   1214    /// per segment generated.
   1215    pub clip_mask_instances: Vec<ClipMaskKind>,
   1216 
   1217    /// List of glyphs keys that are allocated by each
   1218    /// text run instance.
   1219    pub glyph_keys: GlyphKeyStorage,
   1220 
   1221    /// List of render task handles for border segment instances
   1222    /// that have been added this frame.
   1223    pub border_cache_handles: BorderHandleStorage,
   1224 
   1225    /// A list of brush segments that have been built for this scene.
   1226    pub segments: SegmentStorage,
   1227 
   1228    /// A list of segment ranges and GPU cache handles for prim instances
   1229    /// that have opted into segment building. In future, this should be
   1230    /// removed in favor of segment building during primitive interning.
   1231    pub segment_instances: SegmentInstanceStorage,
   1232 
   1233    /// A list of visible tiles that tiled gradients use to store
   1234    /// per-tile information.
   1235    pub gradient_tiles: GradientTileStorage,
   1236 
   1237    /// List of debug display items for rendering.
   1238    pub debug_items: Vec<DebugItem>,
   1239 
   1240    /// List of current debug messages to log on screen
   1241    messages: Vec<DebugMessage>,
   1242 
   1243    /// Set of sub-graphs that are required, determined during visibility pass
   1244    pub required_sub_graphs: FastHashSet<PictureIndex>,
   1245 
   1246    /// Temporary buffers for building segments in to during prepare pass
   1247    pub quad_direct_segments: Vec<QuadSegment>,
   1248    pub quad_color_segments: Vec<QuadSegment>,
   1249    pub quad_indirect_segments: Vec<QuadSegment>,
   1250 
   1251    /// A retained classifier for checking which segments of a tiled primitive
   1252    /// need a mask / are clipped / can be rendered directly
   1253    pub quad_tile_classifier: QuadTileClassifier,
   1254 }
   1255 
   1256 impl Default for PrimitiveScratchBuffer {
   1257    fn default() -> Self {
   1258        PrimitiveScratchBuffer {
   1259            clip_mask_instances: Vec::new(),
   1260            glyph_keys: GlyphKeyStorage::new(0),
   1261            border_cache_handles: BorderHandleStorage::new(0),
   1262            segments: SegmentStorage::new(0),
   1263            segment_instances: SegmentInstanceStorage::new(0),
   1264            gradient_tiles: GradientTileStorage::new(0),
   1265            debug_items: Vec::new(),
   1266            messages: Vec::new(),
   1267            required_sub_graphs: FastHashSet::default(),
   1268            quad_direct_segments: Vec::new(),
   1269            quad_color_segments: Vec::new(),
   1270            quad_indirect_segments: Vec::new(),
   1271            quad_tile_classifier: QuadTileClassifier::new(),
   1272        }
   1273    }
   1274 }
   1275 
   1276 impl PrimitiveScratchBuffer {
   1277    pub fn recycle(&mut self, recycler: &mut Recycler) {
   1278        recycler.recycle_vec(&mut self.clip_mask_instances);
   1279        self.glyph_keys.recycle(recycler);
   1280        self.border_cache_handles.recycle(recycler);
   1281        self.segments.recycle(recycler);
   1282        self.segment_instances.recycle(recycler);
   1283        self.gradient_tiles.recycle(recycler);
   1284        recycler.recycle_vec(&mut self.debug_items);
   1285        recycler.recycle_vec(&mut self.quad_direct_segments);
   1286        recycler.recycle_vec(&mut self.quad_color_segments);
   1287        recycler.recycle_vec(&mut self.quad_indirect_segments);
   1288    }
   1289 
   1290    pub fn begin_frame(&mut self) {
   1291        // Clear the clip mask tasks for the beginning of the frame. Append
   1292        // a single kind representing no clip mask, at the ClipTaskIndex::INVALID
   1293        // location.
   1294        self.clip_mask_instances.clear();
   1295        self.clip_mask_instances.push(ClipMaskKind::None);
   1296        self.quad_direct_segments.clear();
   1297        self.quad_color_segments.clear();
   1298        self.quad_indirect_segments.clear();
   1299 
   1300        self.border_cache_handles.clear();
   1301 
   1302        // TODO(gw): As in the previous code, the gradient tiles store GPU cache
   1303        //           handles that are cleared (and thus invalidated + re-uploaded)
   1304        //           every frame. This maintains the existing behavior, but we
   1305        //           should fix this in the future to retain handles.
   1306        self.gradient_tiles.clear();
   1307 
   1308        self.required_sub_graphs.clear();
   1309 
   1310        self.debug_items.clear();
   1311    }
   1312 
   1313    pub fn end_frame(&mut self) {
   1314        const MSGS_TO_RETAIN: usize = 32;
   1315        const TIME_TO_RETAIN: u64 = 2000000000;
   1316        const LINE_HEIGHT: f32 = 20.0;
   1317        const X0: f32 = 32.0;
   1318        const Y0: f32 = 32.0;
   1319        let now = zeitstempel::now();
   1320 
   1321        let msgs_to_remove = self.messages.len().max(MSGS_TO_RETAIN) - MSGS_TO_RETAIN;
   1322        let mut msgs_removed = 0;
   1323 
   1324        self.messages.retain(|msg| {
   1325            if msgs_removed < msgs_to_remove {
   1326                msgs_removed += 1;
   1327                return false;
   1328            }
   1329 
   1330            if msg.timestamp + TIME_TO_RETAIN < now {
   1331                return false;
   1332            }
   1333 
   1334            true
   1335        });
   1336 
   1337        let mut y = Y0 + self.messages.len() as f32 * LINE_HEIGHT;
   1338        let shadow_offset = 1.0;
   1339 
   1340        for msg in &self.messages {
   1341            self.debug_items.push(DebugItem::Text {
   1342                position: DevicePoint::new(X0 + shadow_offset, y + shadow_offset),
   1343                color: debug_colors::BLACK,
   1344                msg: msg.msg.clone(),
   1345            });
   1346 
   1347            self.debug_items.push(DebugItem::Text {
   1348                position: DevicePoint::new(X0, y),
   1349                color: debug_colors::RED,
   1350                msg: msg.msg.clone(),
   1351            });
   1352 
   1353            y -= LINE_HEIGHT;
   1354        }
   1355    }
   1356 
   1357    pub fn push_debug_rect_with_stroke_width(
   1358        &mut self,
   1359        rect: WorldRect,
   1360        border: ColorF,
   1361        stroke_width: f32
   1362    ) {
   1363        let top_edge = WorldRect::new(
   1364            WorldPoint::new(rect.min.x + stroke_width, rect.min.y),
   1365            WorldPoint::new(rect.max.x - stroke_width, rect.min.y + stroke_width)
   1366        );
   1367        self.push_debug_rect(top_edge * DevicePixelScale::new(1.0), 1, border, border);
   1368 
   1369        let bottom_edge = WorldRect::new(
   1370            WorldPoint::new(rect.min.x + stroke_width, rect.max.y - stroke_width),
   1371            WorldPoint::new(rect.max.x - stroke_width, rect.max.y)
   1372        );
   1373        self.push_debug_rect(bottom_edge * DevicePixelScale::new(1.0), 1, border, border);
   1374 
   1375        let right_edge = WorldRect::new(
   1376            WorldPoint::new(rect.max.x - stroke_width, rect.min.y),
   1377            rect.max
   1378        );
   1379        self.push_debug_rect(right_edge * DevicePixelScale::new(1.0), 1, border, border);
   1380 
   1381        let left_edge = WorldRect::new(
   1382            rect.min,
   1383            WorldPoint::new(rect.min.x + stroke_width, rect.max.y)
   1384        );
   1385        self.push_debug_rect(left_edge * DevicePixelScale::new(1.0), 1, border, border);
   1386    }
   1387 
   1388    #[allow(dead_code)]
   1389    pub fn push_debug_rect(
   1390        &mut self,
   1391        rect: DeviceRect,
   1392        thickness: i32,
   1393        outer_color: ColorF,
   1394        inner_color: ColorF,
   1395    ) {
   1396        self.debug_items.push(DebugItem::Rect {
   1397            rect,
   1398            outer_color,
   1399            inner_color,
   1400            thickness,
   1401        });
   1402    }
   1403 
   1404    #[allow(dead_code)]
   1405    pub fn push_debug_string(
   1406        &mut self,
   1407        position: DevicePoint,
   1408        color: ColorF,
   1409        msg: String,
   1410    ) {
   1411        self.debug_items.push(DebugItem::Text {
   1412            position,
   1413            color,
   1414            msg,
   1415        });
   1416    }
   1417 
   1418    #[allow(dead_code)]
   1419    pub fn log(
   1420        &mut self,
   1421        msg: String,
   1422    ) {
   1423        self.messages.push(DebugMessage {
   1424            msg,
   1425            timestamp: zeitstempel::now(),
   1426        })
   1427    }
   1428 }
   1429 
   1430 #[cfg_attr(feature = "capture", derive(Serialize))]
   1431 #[cfg_attr(feature = "replay", derive(Deserialize))]
   1432 #[derive(Clone, Debug)]
   1433 pub struct PrimitiveStoreStats {
   1434    picture_count: usize,
   1435    text_run_count: usize,
   1436    image_count: usize,
   1437    linear_gradient_count: usize,
   1438    color_binding_count: usize,
   1439 }
   1440 
   1441 impl PrimitiveStoreStats {
   1442    pub fn empty() -> Self {
   1443        PrimitiveStoreStats {
   1444            picture_count: 0,
   1445            text_run_count: 0,
   1446            image_count: 0,
   1447            linear_gradient_count: 0,
   1448            color_binding_count: 0,
   1449        }
   1450    }
   1451 }
   1452 
   1453 #[cfg_attr(feature = "capture", derive(Serialize))]
   1454 pub struct PrimitiveStore {
   1455    pub pictures: Vec<PicturePrimitive>,
   1456    pub text_runs: TextRunStorage,
   1457    pub linear_gradients: LinearGradientStorage,
   1458 
   1459    /// A list of image instances. These are stored separately as
   1460    /// storing them inline in the instance makes the structure bigger
   1461    /// for other types.
   1462    pub images: ImageInstanceStorage,
   1463 
   1464    /// animated color bindings for this primitive.
   1465    pub color_bindings: ColorBindingStorage,
   1466 }
   1467 
   1468 impl PrimitiveStore {
   1469    pub fn new(stats: &PrimitiveStoreStats) -> PrimitiveStore {
   1470        PrimitiveStore {
   1471            pictures: Vec::with_capacity(stats.picture_count),
   1472            text_runs: TextRunStorage::new(stats.text_run_count),
   1473            images: ImageInstanceStorage::new(stats.image_count),
   1474            color_bindings: ColorBindingStorage::new(stats.color_binding_count),
   1475            linear_gradients: LinearGradientStorage::new(stats.linear_gradient_count),
   1476        }
   1477    }
   1478 
   1479    pub fn reset(&mut self) {
   1480        self.pictures.clear();
   1481        self.text_runs.clear();
   1482        self.images.clear();
   1483        self.color_bindings.clear();
   1484        self.linear_gradients.clear();
   1485    }
   1486 
   1487    pub fn get_stats(&self) -> PrimitiveStoreStats {
   1488        PrimitiveStoreStats {
   1489            picture_count: self.pictures.len(),
   1490            text_run_count: self.text_runs.len(),
   1491            image_count: self.images.len(),
   1492            linear_gradient_count: self.linear_gradients.len(),
   1493            color_binding_count: self.color_bindings.len(),
   1494        }
   1495    }
   1496 
   1497    #[allow(unused)]
   1498    pub fn print_picture_tree(&self, root: PictureIndex) {
   1499        use crate::print_tree::PrintTree;
   1500        let mut pt = PrintTree::new("picture tree");
   1501        self.pictures[root.0].print(&self.pictures, root, &mut pt);
   1502    }
   1503 }
   1504 
   1505 impl Default for PrimitiveStore {
   1506    fn default() -> Self {
   1507        PrimitiveStore::new(&PrimitiveStoreStats::empty())
   1508    }
   1509 }
   1510 
   1511 /// Trait for primitives that are directly internable.
   1512 /// see SceneBuilder::add_primitive<P>
   1513 pub trait InternablePrimitive: intern::Internable<InternData = ()> + Sized {
   1514    /// Build a new key from self with `info`.
   1515    fn into_key(
   1516        self,
   1517        info: &LayoutPrimitiveInfo,
   1518    ) -> Self::Key;
   1519 
   1520    fn make_instance_kind(
   1521        key: Self::Key,
   1522        data_handle: intern::Handle<Self>,
   1523        prim_store: &mut PrimitiveStore,
   1524    ) -> PrimitiveInstanceKind;
   1525 }
   1526 
   1527 
   1528 #[test]
   1529 #[cfg(target_pointer_width = "64")]
   1530 fn test_struct_sizes() {
   1531    use std::mem;
   1532    // The sizes of these structures are critical for performance on a number of
   1533    // talos stress tests. If you get a failure here on CI, there's two possibilities:
   1534    // (a) You made a structure smaller than it currently is. Great work! Update the
   1535    //     test expectations and move on.
   1536    // (b) You made a structure larger. This is not necessarily a problem, but should only
   1537    //     be done with care, and after checking if talos performance regresses badly.
   1538    assert_eq!(mem::size_of::<PrimitiveInstance>(), 88, "PrimitiveInstance size changed");
   1539    assert_eq!(mem::size_of::<PrimitiveInstanceKind>(), 24, "PrimitiveInstanceKind size changed");
   1540    assert_eq!(mem::size_of::<PrimitiveTemplate>(), 52, "PrimitiveTemplate size changed");
   1541    assert_eq!(mem::size_of::<PrimitiveTemplateKind>(), 28, "PrimitiveTemplateKind size changed");
   1542    assert_eq!(mem::size_of::<PrimitiveKey>(), 36, "PrimitiveKey size changed");
   1543    assert_eq!(mem::size_of::<PrimitiveKeyKind>(), 16, "PrimitiveKeyKind size changed");
   1544 }