use api::{BorderRadius, ClipMode, ColorF};
use api::{ImageRendering, RepeatMode, PrimitiveFlags};
use api::{FillRule, POLYGON_CLIP_VERTEX_MAX};
use api::units::*;
use euclid::{SideOffsets2D, Size2D};
use malloc_size_of::MallocSizeOf;
use crate::clip::ClipLeafId;
use crate::quad::QuadTileClassifier;
use crate::renderer::{GpuBufferAddress, GpuBufferHandle, GpuBufferWriterF};
use crate::segment::EdgeMask;
use crate::border::BorderSegmentCacheKey;
use crate::debug_item::{DebugItem, DebugMessage};
use crate::debug_colors;
use glyph_rasterizer::GlyphKey;
use crate::gpu_types::{BrushFlags, BrushSegmentGpuData, QuadSegment};
use crate::intern;
use crate::picture::{PictureInstance, PictureScratch};
use crate::render_task_graph::RenderTaskId;
use crate::resource_cache::ImageProperties;
use std::{hash, u32, usize};
use crate::util::Recycler;
use crate::internal_types::{FastHashSet, LayoutPrimitiveInfo};
use crate::visibility::PrimitiveDrawHeader;
pub mod backdrop;
pub mod borders;
pub mod gradient;
pub mod image;
pub mod line_dec;
pub mod picture;
pub mod rectangle;
pub mod text_run;
pub mod interned;
pub mod storage;
use backdrop::{BackdropCaptureDataHandle, BackdropRenderDataHandle, BackdropRenderScratch};
use borders::{ImageBorderDataHandle, ImageBorderScratch, NormalBorderDataHandle, NormalBorderScratch};
use gradient::{LinearGradientDataHandle, RadialGradientDataHandle, ConicGradientDataHandle};
use image::{ImageDataHandle, ImageScratch, VisibleImageTile, YuvImageDataHandle};
use line_dec::{LineDecorationDataHandle, LineDecorationScratch};
use picture::PictureDataHandle;
use rectangle::RectangleDataHandle;
use text_run::{TextRunDataHandle, TextRunScratch};
use crate::box_shadow::BoxShadowDataHandle;
pub const VECS_PER_SEGMENT: usize = 2;
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Copy, Clone, MallocSizeOf)]
pub struct PrimitiveOpacity {
pub is_opaque: bool,
}
impl PrimitiveOpacity {
pub fn opaque() -> PrimitiveOpacity {
PrimitiveOpacity { is_opaque: true }
}
pub fn translucent() -> PrimitiveOpacity {
PrimitiveOpacity { is_opaque: false }
}
pub fn from_alpha(alpha: f32) -> PrimitiveOpacity {
PrimitiveOpacity {
is_opaque: alpha >= 1.0,
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct DeferredResolve {
pub handle: GpuBufferHandle,
pub image_properties: ImageProperties,
pub rendering: ImageRendering,
pub is_composited: bool,
}
#[derive(Debug, Copy, Clone, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
pub struct ClipTaskIndex(pub u32);
impl ClipTaskIndex {
pub const INVALID: ClipTaskIndex = ClipTaskIndex(0);
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, MallocSizeOf, Ord, PartialOrd)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PictureIndex(pub usize);
impl PictureIndex {
pub const INVALID: PictureIndex = PictureIndex(!0);
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
pub struct RectKey {
pub x0: f32,
pub y0: f32,
pub x1: f32,
pub y1: f32,
}
impl RectKey {
pub fn intersects(&self, other: &Self) -> bool {
self.x0 < other.x1
&& other.x0 < self.x1
&& self.y0 < other.y1
&& other.y0 < self.y1
}
}
impl Eq for RectKey {}
impl hash::Hash for RectKey {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.x0.to_bits().hash(state);
self.y0.to_bits().hash(state);
self.x1.to_bits().hash(state);
self.y1.to_bits().hash(state);
}
}
impl From<RectKey> for LayoutRect {
fn from(key: RectKey) -> LayoutRect {
LayoutRect {
min: LayoutPoint::new(key.x0, key.y0),
max: LayoutPoint::new(key.x1, key.y1),
}
}
}
impl From<RectKey> for WorldRect {
fn from(key: RectKey) -> WorldRect {
WorldRect {
min: WorldPoint::new(key.x0, key.y0),
max: WorldPoint::new(key.x1, key.y1),
}
}
}
impl From<LayoutRect> for RectKey {
fn from(rect: LayoutRect) -> RectKey {
RectKey {
x0: rect.min.x,
y0: rect.min.y,
x1: rect.max.x,
y1: rect.max.y,
}
}
}
impl From<PictureRect> for RectKey {
fn from(rect: PictureRect) -> RectKey {
RectKey {
x0: rect.min.x,
y0: rect.min.y,
x1: rect.max.x,
y1: rect.max.y,
}
}
}
impl From<WorldRect> for RectKey {
fn from(rect: WorldRect) -> RectKey {
RectKey {
x0: rect.min.x,
y0: rect.min.y,
x1: rect.max.x,
y1: rect.max.y,
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Copy, Debug, Clone, Hash, MallocSizeOf, PartialEq)]
pub struct PolygonKey {
pub point_count: u8,
pub points: [PointKey; POLYGON_CLIP_VERTEX_MAX],
pub fill_rule: FillRule,
}
impl PolygonKey {
pub fn new(
points_layout: &Vec<LayoutPoint>,
fill_rule: FillRule,
) -> Self {
let mut points: [PointKey; POLYGON_CLIP_VERTEX_MAX] = [PointKey { x: 0.0, y: 0.0}; POLYGON_CLIP_VERTEX_MAX];
let mut point_count: u8 = 0;
for (src, dest) in points_layout.iter().zip(points.iter_mut()) {
*dest = (*src as LayoutPoint).into();
point_count = point_count + 1;
}
PolygonKey {
point_count,
points,
fill_rule,
}
}
}
impl Eq for PolygonKey {}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Clone, MallocSizeOf, PartialEq)]
pub struct SideOffsetsKey {
pub top: f32,
pub right: f32,
pub bottom: f32,
pub left: f32,
}
impl Eq for SideOffsetsKey {}
impl hash::Hash for SideOffsetsKey {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.top.to_bits().hash(state);
self.right.to_bits().hash(state);
self.bottom.to_bits().hash(state);
self.left.to_bits().hash(state);
}
}
impl From<SideOffsetsKey> for LayoutSideOffsets {
fn from(key: SideOffsetsKey) -> LayoutSideOffsets {
LayoutSideOffsets::new(
key.top,
key.right,
key.bottom,
key.left,
)
}
}
impl<U> From<SideOffsets2D<f32, U>> for SideOffsetsKey {
fn from(offsets: SideOffsets2D<f32, U>) -> SideOffsetsKey {
SideOffsetsKey {
top: offsets.top,
right: offsets.right,
bottom: offsets.bottom,
left: offsets.left,
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
pub struct SizeKey {
w: f32,
h: f32,
}
impl Eq for SizeKey {}
impl hash::Hash for SizeKey {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.w.to_bits().hash(state);
self.h.to_bits().hash(state);
}
}
impl From<SizeKey> for LayoutSize {
fn from(key: SizeKey) -> LayoutSize {
LayoutSize::new(key.w, key.h)
}
}
impl<U> From<Size2D<f32, U>> for SizeKey {
fn from(size: Size2D<f32, U>) -> SizeKey {
SizeKey {
w: size.width,
h: size.height,
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
pub struct VectorKey {
pub x: f32,
pub y: f32,
}
impl Eq for VectorKey {}
impl hash::Hash for VectorKey {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.x.to_bits().hash(state);
self.y.to_bits().hash(state);
}
}
impl From<VectorKey> for LayoutVector2D {
fn from(key: VectorKey) -> LayoutVector2D {
LayoutVector2D::new(key.x, key.y)
}
}
impl From<VectorKey> for WorldVector2D {
fn from(key: VectorKey) -> WorldVector2D {
WorldVector2D::new(key.x, key.y)
}
}
impl From<LayoutVector2D> for VectorKey {
fn from(vec: LayoutVector2D) -> VectorKey {
VectorKey {
x: vec.x,
y: vec.y,
}
}
}
impl From<WorldVector2D> for VectorKey {
fn from(vec: WorldVector2D) -> VectorKey {
VectorKey {
x: vec.x,
y: vec.y,
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)]
pub struct PointKey {
pub x: f32,
pub y: f32,
}
impl Eq for PointKey {}
impl hash::Hash for PointKey {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
self.x.to_bits().hash(state);
self.y.to_bits().hash(state);
}
}
impl From<PointKey> for LayoutPoint {
fn from(key: PointKey) -> LayoutPoint {
LayoutPoint::new(key.x, key.y)
}
}
impl From<LayoutPoint> for PointKey {
fn from(p: LayoutPoint) -> PointKey {
PointKey {
x: p.x,
y: p.y,
}
}
}
impl From<PicturePoint> for PointKey {
fn from(p: PicturePoint) -> PointKey {
PointKey {
x: p.x,
y: p.y,
}
}
}
impl From<WorldPoint> for PointKey {
fn from(p: WorldPoint) -> PointKey {
PointKey {
x: p.x,
y: p.y,
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
pub struct PrimKeyCommonData {
pub flags: PrimitiveFlags,
pub aligned_aa_edges: EdgeMask,
pub transformed_aa_edges: EdgeMask,
}
impl From<&LayoutPrimitiveInfo> for PrimKeyCommonData {
fn from(info: &LayoutPrimitiveInfo) -> Self {
PrimKeyCommonData {
flags: info.flags,
aligned_aa_edges: info.aligned_aa_edges,
transformed_aa_edges: info.transformed_aa_edges,
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
pub struct PrimKey<T: MallocSizeOf> {
pub common: PrimKeyCommonData,
pub kind: T,
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
#[derive(Debug)]
pub struct PrimTemplateCommonData {
pub flags: PrimitiveFlags,
pub opacity: PrimitiveOpacity,
pub gpu_buffer_address: GpuBufferAddress,
pub aligned_aa_edges: EdgeMask,
pub transformed_aa_edges: EdgeMask,
}
impl PrimTemplateCommonData {
pub fn with_key_common(common: PrimKeyCommonData) -> Self {
PrimTemplateCommonData {
flags: common.flags,
gpu_buffer_address: GpuBufferAddress::INVALID,
opacity: PrimitiveOpacity::translucent(),
aligned_aa_edges: common.aligned_aa_edges,
transformed_aa_edges: common.transformed_aa_edges,
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
pub struct PrimTemplate<T> {
pub common: PrimTemplateCommonData,
pub kind: T,
}
#[derive(Debug, MallocSizeOf)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct VisibleMaskImageTile {
pub tile_offset: TileOffset,
pub tile_rect: LayoutRect,
pub task_id: RenderTaskId,
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, MallocSizeOf)]
pub struct BorderSegmentInfo {
pub local_task_size: LayoutSize,
pub cache_key: BorderSegmentCacheKey,
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[derive(Debug, Clone)]
pub enum ClipMaskKind {
Mask(RenderTaskId),
None,
Clipped,
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Debug, Clone, MallocSizeOf)]
pub struct BrushSegment {
pub local_rect: LayoutRect,
pub may_need_clip_mask: bool,
pub edge_flags: EdgeMask,
pub extra_data: [f32; 4],
pub brush_flags: BrushFlags,
}
impl BrushSegment {
pub fn new(
local_rect: LayoutRect,
may_need_clip_mask: bool,
edge_flags: EdgeMask,
extra_data: [f32; 4],
brush_flags: BrushFlags,
) -> Self {
Self {
local_rect,
may_need_clip_mask,
edge_flags,
extra_data,
brush_flags,
}
}
pub fn gpu_data(&self) -> BrushSegmentGpuData {
BrushSegmentGpuData {
local_rect: self.local_rect,
extra_data: self.extra_data,
}
}
pub fn write_gpu_blocks(&self, writer: &mut GpuBufferWriterF) {
writer.push(&self.gpu_data());
}
}
#[derive(Debug, Clone)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
struct ClipRect {
rect: LayoutRect,
mode: f32,
}
#[derive(Debug, Clone)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
struct ClipCorner {
rect: LayoutRect,
outer_radius_x: f32,
outer_radius_y: f32,
inner_radius_x: f32,
inner_radius_y: f32,
}
impl ClipCorner {
fn uniform(rect: LayoutRect, outer_radius: f32, inner_radius: f32) -> ClipCorner {
ClipCorner {
rect,
outer_radius_x: outer_radius,
outer_radius_y: outer_radius,
inner_radius_x: inner_radius,
inner_radius_y: inner_radius,
}
}
}
#[derive(Debug, Clone)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ClipData {
rect: ClipRect,
top_left: ClipCorner,
top_right: ClipCorner,
bottom_left: ClipCorner,
bottom_right: ClipCorner,
}
impl ClipData {
pub fn rounded_rect(size: LayoutSize, radii: &BorderRadius, mode: ClipMode) -> ClipData {
let rect = LayoutRect::from_size(size);
ClipData {
rect: ClipRect {
rect,
mode: mode as u32 as f32,
},
top_left: ClipCorner {
rect: LayoutRect::from_origin_and_size(
LayoutPoint::new(rect.min.x, rect.min.y),
LayoutSize::new(radii.top_left.width, radii.top_left.height),
),
outer_radius_x: radii.top_left.width,
outer_radius_y: radii.top_left.height,
inner_radius_x: 0.0,
inner_radius_y: 0.0,
},
top_right: ClipCorner {
rect: LayoutRect::from_origin_and_size(
LayoutPoint::new(
rect.max.x - radii.top_right.width,
rect.min.y,
),
LayoutSize::new(radii.top_right.width, radii.top_right.height),
),
outer_radius_x: radii.top_right.width,
outer_radius_y: radii.top_right.height,
inner_radius_x: 0.0,
inner_radius_y: 0.0,
},
bottom_left: ClipCorner {
rect: LayoutRect::from_origin_and_size(
LayoutPoint::new(
rect.min.x,
rect.max.y - radii.bottom_left.height,
),
LayoutSize::new(radii.bottom_left.width, radii.bottom_left.height),
),
outer_radius_x: radii.bottom_left.width,
outer_radius_y: radii.bottom_left.height,
inner_radius_x: 0.0,
inner_radius_y: 0.0,
},
bottom_right: ClipCorner {
rect: LayoutRect::from_origin_and_size(
LayoutPoint::new(
rect.max.x - radii.bottom_right.width,
rect.max.y - radii.bottom_right.height,
),
LayoutSize::new(radii.bottom_right.width, radii.bottom_right.height),
),
outer_radius_x: radii.bottom_right.width,
outer_radius_y: radii.bottom_right.height,
inner_radius_x: 0.0,
inner_radius_y: 0.0,
},
}
}
pub fn uniform(size: LayoutSize, radius: f32, mode: ClipMode) -> ClipData {
let rect = LayoutRect::from_size(size);
ClipData {
rect: ClipRect {
rect,
mode: mode as u32 as f32,
},
top_left: ClipCorner::uniform(
LayoutRect::from_origin_and_size(
LayoutPoint::new(rect.min.x, rect.min.y),
LayoutSize::new(radius, radius),
),
radius,
0.0,
),
top_right: ClipCorner::uniform(
LayoutRect::from_origin_and_size(
LayoutPoint::new(rect.max.x - radius, rect.min.y),
LayoutSize::new(radius, radius),
),
radius,
0.0,
),
bottom_left: ClipCorner::uniform(
LayoutRect::from_origin_and_size(
LayoutPoint::new(rect.min.x, rect.max.y - radius),
LayoutSize::new(radius, radius),
),
radius,
0.0,
),
bottom_right: ClipCorner::uniform(
LayoutRect::from_origin_and_size(
LayoutPoint::new(
rect.max.x - radius,
rect.max.y - radius,
),
LayoutSize::new(radius, radius),
),
radius,
0.0,
),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, MallocSizeOf)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct NinePatchDescriptor {
pub width: i32,
pub height: i32,
pub slice: DeviceIntSideOffsets,
pub fill: bool,
pub repeat_horizontal: RepeatMode,
pub repeat_vertical: RepeatMode,
pub widths: SideOffsetsKey,
}
#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
pub enum PrimitiveKind {
Picture {
data_handle: PictureDataHandle,
pic_index: PictureIndex,
},
TextRun {
data_handle: TextRunDataHandle,
},
LineDecoration {
data_handle: LineDecorationDataHandle,
},
NormalBorder {
data_handle: NormalBorderDataHandle,
},
ImageBorder {
data_handle: ImageBorderDataHandle,
},
Rectangle {
data_handle: RectangleDataHandle,
},
YuvImage {
data_handle: YuvImageDataHandle,
},
Image {
data_handle: ImageDataHandle,
},
LinearGradient {
data_handle: LinearGradientDataHandle,
},
RadialGradient {
data_handle: RadialGradientDataHandle,
},
ConicGradient {
data_handle: ConicGradientDataHandle,
},
BackdropCapture {
data_handle: BackdropCaptureDataHandle,
},
BackdropRender {
data_handle: BackdropRenderDataHandle,
pic_index: PictureIndex,
},
BoxShadow {
data_handle: BoxShadowDataHandle,
},
}
impl PrimitiveKind {
pub fn as_pic(&self) -> PictureIndex {
match self {
PrimitiveKind::Picture { pic_index, .. } => *pic_index,
_ => panic!("bug: as_pic called on a prim that is not a picture"),
}
}
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PrimitiveInstanceIndex(pub u32);
impl PrimitiveInstanceIndex {
pub const INVALID: PrimitiveInstanceIndex = PrimitiveInstanceIndex(!0);
}
#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
pub struct PrimitiveInstance {
pub kind: PrimitiveKind,
pub clip_leaf_id: ClipLeafId,
pub unsnapped_prim_rect: LayoutRect,
}
impl PrimitiveInstance {
pub fn new(
kind: PrimitiveKind,
clip_leaf_id: ClipLeafId,
unsnapped_prim_rect: LayoutRect,
) -> Self {
PrimitiveInstance {
kind,
clip_leaf_id,
unsnapped_prim_rect,
}
}
pub fn uid(&self) -> intern::ItemUid {
match &self.kind {
PrimitiveKind::Rectangle { data_handle, .. } => {
data_handle.uid()
}
PrimitiveKind::Image { data_handle, .. } => {
data_handle.uid()
}
PrimitiveKind::ImageBorder { data_handle, .. } => {
data_handle.uid()
}
PrimitiveKind::LineDecoration { data_handle, .. } => {
data_handle.uid()
}
PrimitiveKind::LinearGradient { data_handle, .. } => {
data_handle.uid()
}
PrimitiveKind::NormalBorder { data_handle, .. } => {
data_handle.uid()
}
PrimitiveKind::Picture { data_handle, .. } => {
data_handle.uid()
}
PrimitiveKind::RadialGradient { data_handle, .. } => {
data_handle.uid()
}
PrimitiveKind::ConicGradient { data_handle, .. } => {
data_handle.uid()
}
PrimitiveKind::TextRun { data_handle, .. } => {
data_handle.uid()
}
PrimitiveKind::YuvImage { data_handle, .. } => {
data_handle.uid()
}
PrimitiveKind::BackdropCapture { data_handle, .. } => {
data_handle.uid()
}
PrimitiveKind::BackdropRender { data_handle, .. } => {
data_handle.uid()
}
PrimitiveKind::BoxShadow { data_handle, .. } => {
data_handle.uid()
}
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[derive(Debug)]
pub struct BrushSegmentation {
pub gpu_data: GpuBufferAddress,
pub segments_range: SegmentsRange,
}
pub type GlyphKeyStorage = storage::Storage<GlyphKey>;
pub type SegmentStorage = storage::Storage<BrushSegment>;
pub type SegmentsRange = storage::Range<BrushSegment>;
pub type SegmentInstanceStorage = storage::Storage<BrushSegmentation>;
pub type SegmentInstanceIndex = storage::Index<BrushSegmentation>;
#[cfg_attr(feature = "capture", derive(Serialize))]
pub struct PrimitiveFrameScratch {
pub draws: Vec<PrimitiveDrawHeader>,
pub line_decoration: storage::Storage<LineDecorationScratch>,
pub normal_border: storage::Storage<NormalBorderScratch>,
pub backdrop_render: storage::Storage<BackdropRenderScratch>,
pub pictures: storage::Storage<PictureScratch>,
pub images: storage::Storage<ImageScratch>,
pub visible_image_tiles: storage::Storage<VisibleImageTile>,
pub text_runs: storage::Storage<TextRunScratch>,
pub glyph_keys: GlyphKeyStorage,
pub segments: SegmentStorage,
pub segment_instances: SegmentInstanceStorage,
pub border_task_ids: storage::Storage<RenderTaskId>,
pub border_segments: storage::Storage<BorderSegmentInfo>,
pub image_border: storage::Storage<ImageBorderScratch>,
pub clip_mask_instances: Vec<ClipMaskKind>,
pub debug_items: Vec<DebugItem>,
pub required_sub_graphs: FastHashSet<PictureIndex>,
pub quad_direct_segments: Vec<QuadSegment>,
pub quad_indirect_segments: Vec<QuadSegment>,
}
impl Default for PrimitiveFrameScratch {
fn default() -> Self {
PrimitiveFrameScratch {
draws: Vec::new(),
line_decoration: storage::Storage::new(0),
normal_border: storage::Storage::new(0),
backdrop_render: storage::Storage::new(0),
pictures: storage::Storage::new(0),
images: storage::Storage::new(0),
visible_image_tiles: storage::Storage::new(0),
text_runs: storage::Storage::new(0),
glyph_keys: GlyphKeyStorage::new(0),
segments: SegmentStorage::new(0),
segment_instances: SegmentInstanceStorage::new(0),
border_task_ids: storage::Storage::new(0),
border_segments: storage::Storage::new(0),
image_border: storage::Storage::new(0),
clip_mask_instances: Vec::new(),
debug_items: Vec::new(),
required_sub_graphs: FastHashSet::default(),
quad_direct_segments: Vec::new(),
quad_indirect_segments: Vec::new(),
}
}
}
impl PrimitiveFrameScratch {
pub fn recycle(&mut self, recycler: &mut Recycler) {
recycler.recycle_vec(&mut self.draws);
self.line_decoration.recycle(recycler);
self.normal_border.recycle(recycler);
self.backdrop_render.recycle(recycler);
self.pictures.recycle(recycler);
self.images.recycle(recycler);
self.visible_image_tiles.recycle(recycler);
self.text_runs.recycle(recycler);
self.glyph_keys.recycle(recycler);
self.segments.recycle(recycler);
self.segment_instances.recycle(recycler);
self.border_task_ids.recycle(recycler);
self.border_segments.recycle(recycler);
self.image_border.recycle(recycler);
recycler.recycle_vec(&mut self.clip_mask_instances);
recycler.recycle_vec(&mut self.debug_items);
recycler.recycle_vec(&mut self.quad_direct_segments);
recycler.recycle_vec(&mut self.quad_indirect_segments);
}
pub fn begin_frame(&mut self) {
self.line_decoration.clear();
self.normal_border.clear();
self.backdrop_render.clear();
self.pictures.clear();
self.images.clear();
self.visible_image_tiles.clear();
self.text_runs.clear();
self.glyph_keys.clear();
self.segments.clear();
self.segment_instances.clear();
self.border_task_ids.clear();
self.border_segments.clear();
self.image_border.clear();
self.clip_mask_instances.clear();
self.clip_mask_instances.push(ClipMaskKind::None);
self.quad_direct_segments.clear();
self.quad_indirect_segments.clear();
self.required_sub_graphs.clear();
self.debug_items.clear();
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[derive(Default)]
pub struct PrimitiveSceneCache {}
impl PrimitiveSceneCache {
pub fn recycle(&mut self, _recycler: &mut Recycler) {}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
pub struct PrimitiveRetained {
messages: Vec<DebugMessage>,
pub quad_tile_classifier: QuadTileClassifier,
}
impl Default for PrimitiveRetained {
fn default() -> Self {
PrimitiveRetained {
messages: Vec::new(),
quad_tile_classifier: QuadTileClassifier::new(),
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[derive(Default)]
pub struct PrimitiveScratchBuffer {
pub frame: PrimitiveFrameScratch,
pub scene: PrimitiveSceneCache,
pub retained: PrimitiveRetained,
}
impl PrimitiveScratchBuffer {
pub fn recycle(&mut self, recycler: &mut Recycler) {
self.frame.recycle(recycler);
self.scene.recycle(recycler);
}
pub fn begin_frame(&mut self) {
self.frame.begin_frame();
}
pub fn end_frame(&mut self) {
const MSGS_TO_RETAIN: usize = 32;
const TIME_TO_RETAIN: u64 = 2000000000;
const LINE_HEIGHT: f32 = 20.0;
const X0: f32 = 32.0;
const Y0: f32 = 32.0;
let now = zeitstempel::now();
let messages = &mut self.retained.messages;
let msgs_to_remove = messages.len().max(MSGS_TO_RETAIN) - MSGS_TO_RETAIN;
let mut msgs_removed = 0;
messages.retain(|msg| {
if msgs_removed < msgs_to_remove {
msgs_removed += 1;
return false;
}
if msg.timestamp + TIME_TO_RETAIN < now {
return false;
}
true
});
let mut y = Y0 + messages.len() as f32 * LINE_HEIGHT;
let shadow_offset = 1.0;
let debug_items = &mut self.frame.debug_items;
for msg in messages.iter() {
debug_items.push(DebugItem::Text {
position: DevicePoint::new(X0 + shadow_offset, y + shadow_offset),
color: debug_colors::BLACK,
msg: msg.msg.clone(),
});
debug_items.push(DebugItem::Text {
position: DevicePoint::new(X0, y),
color: debug_colors::RED,
msg: msg.msg.clone(),
});
y -= LINE_HEIGHT;
}
}
pub fn push_debug_rect_with_stroke_width(
&mut self,
rect: WorldRect,
border: ColorF,
stroke_width: f32
) {
let top_edge = WorldRect::new(
WorldPoint::new(rect.min.x + stroke_width, rect.min.y),
WorldPoint::new(rect.max.x - stroke_width, rect.min.y + stroke_width)
);
self.push_debug_rect(top_edge * DevicePixelScale::new(1.0), 1, border, border);
let bottom_edge = WorldRect::new(
WorldPoint::new(rect.min.x + stroke_width, rect.max.y - stroke_width),
WorldPoint::new(rect.max.x - stroke_width, rect.max.y)
);
self.push_debug_rect(bottom_edge * DevicePixelScale::new(1.0), 1, border, border);
let right_edge = WorldRect::new(
WorldPoint::new(rect.max.x - stroke_width, rect.min.y),
rect.max
);
self.push_debug_rect(right_edge * DevicePixelScale::new(1.0), 1, border, border);
let left_edge = WorldRect::new(
rect.min,
WorldPoint::new(rect.min.x + stroke_width, rect.max.y)
);
self.push_debug_rect(left_edge * DevicePixelScale::new(1.0), 1, border, border);
}
#[allow(dead_code)]
pub fn push_debug_rect(
&mut self,
rect: DeviceRect,
thickness: i32,
outer_color: ColorF,
inner_color: ColorF,
) {
self.frame.debug_items.push(DebugItem::Rect {
rect,
outer_color,
inner_color,
thickness,
});
}
#[allow(dead_code)]
pub fn push_debug_string(
&mut self,
position: DevicePoint,
color: ColorF,
msg: String,
) {
self.frame.debug_items.push(DebugItem::Text {
position,
color,
msg,
});
}
#[allow(dead_code)]
pub fn log(
&mut self,
msg: String,
) {
self.retained.messages.push(DebugMessage {
msg,
timestamp: zeitstempel::now(),
})
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone, Debug)]
pub struct PrimitiveStoreStats {
picture_count: usize,
}
impl PrimitiveStoreStats {
pub fn empty() -> Self {
PrimitiveStoreStats {
picture_count: 0,
}
}
}
#[cfg_attr(feature = "capture", derive(Serialize))]
pub struct PrimitiveStore {
pub pictures: Vec<PictureInstance>,
}
impl PrimitiveStore {
pub fn new(stats: &PrimitiveStoreStats) -> PrimitiveStore {
PrimitiveStore {
pictures: Vec::with_capacity(stats.picture_count),
}
}
pub fn reset(&mut self) {
self.pictures.clear();
}
pub fn get_stats(&self) -> PrimitiveStoreStats {
PrimitiveStoreStats {
picture_count: self.pictures.len(),
}
}
#[allow(unused)]
pub fn print_picture_tree(&self, root: PictureIndex) {
use crate::print_tree::PrintTree;
let mut pt = PrintTree::new("picture tree");
self.pictures[root.0].print(&self.pictures, root, &mut pt);
}
}
impl Default for PrimitiveStore {
fn default() -> Self {
PrimitiveStore::new(&PrimitiveStoreStats::empty())
}
}
pub trait InternablePrimitive: intern::Internable<InternData = ()> + Sized {
fn into_key(
self,
info: &LayoutPrimitiveInfo,
) -> Self::Key;
fn make_instance_kind(
key: Self::Key,
data_handle: intern::Handle<Self>,
prim_store: &mut PrimitiveStore,
) -> PrimitiveKind;
}
#[test]
#[cfg(target_pointer_width = "64")]
fn test_struct_sizes() {
use std::mem;
assert_eq!(mem::size_of::<PrimitiveInstance>(), 48, "PrimitiveInstance size changed");
assert_eq!(mem::size_of::<PrimitiveKind>(), 24, "PrimitiveKind size changed");
}