inset-embedder 0.19.0

dart:ui host traits and value types for Inset
Documentation
//! The nodes of a frame's layer tree, after the engine's `flow/layers`: containers that do one
//! thing to their children, the pictures the framework recorded, the composition layers it
//! places, and the video frames it draws.
//!
//! A node never changes once built: a container the framework retains is the same `Arc` in every
//! scene that holds it, so a host compares it by pointer and a later frame walks it again. The
//! invariant a later editor must keep: nothing here draws or composites; the drawing is the
//! pictures', and what the containers do is replayed by whoever walks the tree (`slices.rs`).

use std::fmt;
use std::sync::Arc;

use crate::composition::CompositionLayer;
use crate::geometry::{Clip, Matrix4, Offset, RRect, Rect};
use crate::media::VideoFrameReader;
use crate::painting::{BlendMode, ImageFilter, Path, Picture};

/// One node of a frame's layer tree: the engine's `flow::Layer`.
#[derive(Clone, Debug)]
pub enum Layer {
    /// Children under one effect: what a `push_*` opens and `pop` closes, or a subtree a
    /// previous frame built, added again.
    Container(EngineLayer),
    /// A recorded picture at an offset: flow's `DisplayListLayer`, from `add_picture`.
    DisplayList(DisplayListLayer),
    /// A composition layer at its place in paint order: flow's `PlatformViewLayer`, from
    /// `add_embedded_layer`. It draws nothing; the host places the layer and makes room for it.
    Embedded(EmbeddedLayer),
    /// A video, drawn as part of the picture at its place in paint order: Chromium's
    /// `cc::VideoLayer`, from `add_video`. The host supplies the frame when it draws.
    Video(VideoLayer),
}

/// Two layers are equal when they are the same node or show the same: a container by pointer
/// first, so a retained subtree compares at once.
impl PartialEq for Layer {
    fn eq(&self, other: &Layer) -> bool {
        match (self, other) {
            (Layer::Container(a), Layer::Container(b)) => Arc::ptr_eq(a, b) || a == b,
            (Layer::DisplayList(a), Layer::DisplayList(b)) => a == b,
            (Layer::Embedded(a), Layer::Embedded(b)) => a == b,
            (Layer::Video(a), Layer::Video(b)) => a == b,
            _ => false,
        }
    }
}

/// dart:ui's `EngineLayer`: a container of the tree, which [`pop`](crate::SceneBuilder::pop)
/// returns and [`add_retained`](crate::SceneBuilder::add_retained) adds again, as the same node,
/// while the framework's subtree has not changed.
pub type EngineLayer = Arc<ContainerLayer>;

/// flow's `ContainerLayer` and the containers derived from it: children in paint order, the
/// bottom-most first, under one effect.
#[derive(Debug, PartialEq)]
pub struct ContainerLayer {
    pub effect: Effect,
    pub children: Vec<Layer>,
}

/// What a container does to its children: which of flow's containers it is.
#[derive(Clone, Debug, PartialEq)]
pub enum Effect {
    /// flow's `ContainerLayer` itself, which does nothing: the scene's root.
    None,
    /// `TransformLayer`: the children's coordinates taken through the matrix. `push_transform`,
    /// and `push_offset` as a translation.
    Transform(Matrix4),
    /// `ClipRectLayer`: nothing of the children outside the rectangle.
    ClipRect { rect: Rect, clip_behavior: Clip },
    /// `ClipRRectLayer`: nothing of the children outside the rounded rectangle.
    ClipRRect { rrect: RRect, clip_behavior: Clip },
    /// `ClipPathLayer`: nothing of the children outside the path, filled non-zero.
    ClipPath {
        path: Arc<Path>,
        clip_behavior: Clip,
    },
    /// `OpacityLayer`: the children moved by `offset` and composited as one at `alpha`, out of
    /// 255.
    Opacity { alpha: u8, offset: Offset },
    /// `BackdropFilterLayer`: what lies beneath filtered, then blended back with `blend_mode`,
    /// before the children paint. Filters sharing a `backdrop_id` sample one backdrop.
    BackdropFilter {
        filter: ImageFilter,
        blend_mode: BlendMode,
        backdrop_id: Option<u64>,
    },
}

/// flow's `DisplayListLayer`: a picture the framework recorded, drawn at `offset`.
#[derive(Clone, Debug, PartialEq)]
pub struct DisplayListLayer {
    pub offset: Offset,
    pub picture: Arc<Picture>,
}

/// flow's `PlatformViewLayer`, named after Flutter's embedded views: a composition layer the
/// host composites, embedded in the frame at `rect` in its container's coordinates.
#[derive(Clone)]
pub struct EmbeddedLayer {
    /// The producer's own handle, so a host reaches the native object behind it directly.
    pub layer: Arc<dyn CompositionLayer>,
    pub rect: Rect,
}

/// Two are equal when they put the same composition layer, by pointer, at the same place.
impl PartialEq for EmbeddedLayer {
    fn eq(&self, other: &EmbeddedLayer) -> bool {
        Arc::ptr_eq(&self.layer, &other.layer) && self.rect == other.rect
    }
}

impl fmt::Debug for EmbeddedLayer {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("EmbeddedLayer")
            .field("layer", &Arc::as_ptr(&self.layer).cast::<()>())
            .field("rect", &self.rect)
            .finish()
    }
}

/// A video, drawn into `rect` in its container's coordinates: Chromium's `cc::VideoLayer` over its
/// frame provider. The layer holds the reader, never a frame: whoever draws the scene asks the
/// reader then for the frame of the moment the picture reaches the screen, so a frame is held only
/// while it is on screen.
#[derive(Clone)]
pub struct VideoLayer {
    pub reader: Arc<dyn VideoFrameReader>,
    pub rect: Rect,
}

/// Two are equal when they draw the same reader, by pointer, into the same place: a new frame of
/// the reader is not a change of the scene.
impl PartialEq for VideoLayer {
    fn eq(&self, other: &VideoLayer) -> bool {
        Arc::ptr_eq(&self.reader, &other.reader) && self.rect == other.rect
    }
}

impl fmt::Debug for VideoLayer {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("VideoLayer")
            .field("reader", &Arc::as_ptr(&self.reader).cast::<()>())
            .field("rect", &self.rect)
            .finish()
    }
}