1use api::{BorderRadius, ClipMode, ColorF, ColorU, RasterSpace};
6use api::{ImageRendering, RepeatMode, PrimitiveFlags};
7use api::{PremultipliedColorF, PropertyBinding, Shadow};
8use api::{PrimitiveKeyKind, FillRule, POLYGON_CLIP_VERTEX_MAX};
9use api::units::*;
10use euclid::{SideOffsets2D, Size2D};
11use malloc_size_of::MallocSizeOf;
12use crate::composite::CompositorSurfaceKind;
13use crate::clip::ClipLeafId;
14use crate::pattern::{Pattern, PatternBuilder, PatternBuilderContext, PatternBuilderState};
15use crate::quad::QuadTileClassifier;
16use crate::segment::EdgeAaSegmentMask;
17use crate::border::BorderSegmentCacheKey;
18use crate::debug_item::{DebugItem, DebugMessage};
19use crate::debug_colors;
20use crate::scene_building::{CreateShadow, IsVisible};
21use crate::frame_builder::FrameBuildingState;
22use glyph_rasterizer::GlyphKey;
23use crate::gpu_cache::{GpuCacheAddress, GpuCacheHandle, GpuDataRequest};
24use crate::gpu_types::{BrushFlags, QuadSegment};
25use crate::intern;
26use crate::picture::PicturePrimitive;
27use crate::render_task_graph::RenderTaskId;
28use crate::resource_cache::ImageProperties;
29use crate::scene::SceneProperties;
30use std::{hash, ops, u32, usize};
31use crate::util::Recycler;
32use crate::internal_types::{FastHashSet, LayoutPrimitiveInfo};
33use crate::visibility::PrimitiveVisibility;
34
35pub mod backdrop;
36pub mod borders;
37pub mod gradient;
38pub mod image;
39pub mod line_dec;
40pub mod picture;
41pub mod text_run;
42pub mod interned;
43
44mod storage;
45
46use backdrop::{BackdropCaptureDataHandle, BackdropRenderDataHandle};
47use borders::{ImageBorderDataHandle, NormalBorderDataHandle};
48use gradient::{LinearGradientPrimitive, LinearGradientDataHandle, RadialGradientDataHandle, ConicGradientDataHandle};
49use image::{ImageDataHandle, ImageInstance, YuvImageDataHandle};
50use line_dec::LineDecorationDataHandle;
51use picture::PictureDataHandle;
52use text_run::{TextRunDataHandle, TextRunPrimitive};
53use crate::box_shadow::BoxShadowDataHandle;
54
55pub 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)]
60pub struct PrimitiveOpacity {
61 pub is_opaque: bool,
62}
63
64impl 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#[cfg_attr(feature = "capture", derive(Serialize))]
91#[cfg_attr(feature = "replay", derive(Deserialize))]
92pub struct DeferredResolve {
93 pub address: GpuCacheAddress,
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))]
101pub struct ClipTaskIndex(pub u32);
102
103impl 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))]
110pub struct PictureIndex(pub usize);
111
112impl 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)]
119pub struct RectangleKey {
120 pub x0: f32,
121 pub y0: f32,
122 pub x1: f32,
123 pub y1: f32,
124}
125
126impl 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
135impl Eq for RectangleKey {}
136
137impl 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
146impl 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
155impl 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
164impl 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
175impl 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
186impl 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#[cfg_attr(feature = "capture", derive(Serialize))]
202#[cfg_attr(feature = "replay", derive(Deserialize))]
203#[derive(Copy, Debug, Clone, Hash, MallocSizeOf, PartialEq)]
204pub struct PolygonKey {
205 pub point_count: u8,
206 pub points: [PointKey; POLYGON_CLIP_VERTEX_MAX],
207 pub fill_rule: FillRule,
208}
209
210impl PolygonKey {
211 pub fn new(
212 points_layout: &Vec<LayoutPoint>,
213 fill_rule: FillRule,
214 ) -> Self {
215 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
235impl Eq for PolygonKey {}
236
237#[cfg_attr(feature = "capture", derive(Serialize))]
239#[cfg_attr(feature = "replay", derive(Deserialize))]
240#[derive(Debug, Clone, MallocSizeOf, PartialEq)]
241pub struct SideOffsetsKey {
242 pub top: f32,
243 pub right: f32,
244 pub bottom: f32,
245 pub left: f32,
246}
247
248impl Eq for SideOffsetsKey {}
249
250impl 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
259impl 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
270impl<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#[cfg_attr(feature = "capture", derive(Serialize))]
283#[cfg_attr(feature = "replay", derive(Deserialize))]
284#[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
285pub struct SizeKey {
286 w: f32,
287 h: f32,
288}
289
290impl Eq for SizeKey {}
291
292impl 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
299impl From<SizeKey> for LayoutSize {
300 fn from(key: SizeKey) -> LayoutSize {
301 LayoutSize::new(key.w, key.h)
302 }
303}
304
305impl<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#[cfg_attr(feature = "capture", derive(Serialize))]
316#[cfg_attr(feature = "replay", derive(Deserialize))]
317#[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
318pub struct VectorKey {
319 pub x: f32,
320 pub y: f32,
321}
322
323impl Eq for VectorKey {}
324
325impl 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
332impl From<VectorKey> for LayoutVector2D {
333 fn from(key: VectorKey) -> LayoutVector2D {
334 LayoutVector2D::new(key.x, key.y)
335 }
336}
337
338impl From<VectorKey> for WorldVector2D {
339 fn from(key: VectorKey) -> WorldVector2D {
340 WorldVector2D::new(key.x, key.y)
341 }
342}
343
344impl From<LayoutVector2D> for VectorKey {
345 fn from(vec: LayoutVector2D) -> VectorKey {
346 VectorKey {
347 x: vec.x,
348 y: vec.y,
349 }
350 }
351}
352
353impl 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#[cfg_attr(feature = "capture", derive(Serialize))]
364#[cfg_attr(feature = "replay", derive(Deserialize))]
365#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)]
366pub struct PointKey {
367 pub x: f32,
368 pub y: f32,
369}
370
371impl Eq for PointKey {}
372
373impl 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
380impl From<PointKey> for LayoutPoint {
381 fn from(key: PointKey) -> LayoutPoint {
382 LayoutPoint::new(key.x, key.y)
383 }
384}
385
386impl From<LayoutPoint> for PointKey {
387 fn from(p: LayoutPoint) -> PointKey {
388 PointKey {
389 x: p.x,
390 y: p.y,
391 }
392 }
393}
394
395impl From<PicturePoint> for PointKey {
396 fn from(p: PicturePoint) -> PointKey {
397 PointKey {
398 x: p.x,
399 y: p.y,
400 }
401 }
402}
403
404impl 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#[cfg_attr(feature = "capture", derive(Serialize))]
415#[cfg_attr(feature = "replay", derive(Deserialize))]
416#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)]
417pub struct FloatKey(f32);
418
419impl Eq for FloatKey {}
420
421impl 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)]
431pub struct PrimKeyCommonData {
432 pub flags: PrimitiveFlags,
433 pub prim_rect: RectangleKey,
434}
435
436impl 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)]
448pub 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)]
456pub struct PrimitiveKey {
457 pub common: PrimKeyCommonData,
458 pub kind: PrimitiveKeyKind,
459}
460
461impl 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
473impl intern::InternDebug for PrimitiveKey {}
474
475#[cfg_attr(feature = "capture", derive(Serialize))]
478#[cfg_attr(feature = "replay", derive(Deserialize))]
479#[derive(MallocSizeOf)]
480pub enum PrimitiveTemplateKind {
481 Rectangle {
482 color: PropertyBinding<ColorF>,
483 },
484 Clear,
485}
486
487impl PrimitiveTemplateKind {
488 pub fn write_prim_gpu_blocks(
490 &self,
491 request: &mut GpuDataRequest,
492 scene_properties: &SceneProperties,
493 ) {
494 match *self {
495 PrimitiveTemplateKind::Clear => {
496 request.push(PremultipliedColorF::BLACK);
498 }
499 PrimitiveTemplateKind::Rectangle { ref color, .. } => {
500 request.push(scene_properties.resolve_color(color).premultiplied())
501 }
502 }
503 }
504}
505
506impl From<PrimitiveKeyKind> for PrimitiveTemplateKind {
510 fn from(kind: PrimitiveKeyKind) -> Self {
511 match kind {
512 PrimitiveKeyKind::Clear => {
513 PrimitiveTemplateKind::Clear
514 }
515 PrimitiveKeyKind::Rectangle { color, .. } => {
516 PrimitiveTemplateKind::Rectangle {
517 color: color.into(),
518 }
519 }
520 }
521 }
522}
523
524#[cfg_attr(feature = "capture", derive(Serialize))]
525#[cfg_attr(feature = "replay", derive(Deserialize))]
526#[derive(MallocSizeOf)]
527#[derive(Debug)]
528pub struct PrimTemplateCommonData {
529 pub flags: PrimitiveFlags,
530 pub may_need_repetition: bool,
531 pub prim_rect: LayoutRect,
532 pub opacity: PrimitiveOpacity,
533 pub gpu_cache_handle: GpuCacheHandle,
538 pub edge_aa_mask: EdgeAaSegmentMask,
544}
545
546impl PrimTemplateCommonData {
547 pub fn with_key_common(common: PrimKeyCommonData) -> Self {
548 PrimTemplateCommonData {
549 flags: common.flags,
550 may_need_repetition: true,
551 prim_rect: common.prim_rect.into(),
552 gpu_cache_handle: GpuCacheHandle::new(),
553 opacity: PrimitiveOpacity::translucent(),
554 edge_aa_mask: EdgeAaSegmentMask::all(),
555 }
556 }
557}
558
559#[cfg_attr(feature = "capture", derive(Serialize))]
560#[cfg_attr(feature = "replay", derive(Deserialize))]
561#[derive(MallocSizeOf)]
562pub struct PrimTemplate<T> {
563 pub common: PrimTemplateCommonData,
564 pub kind: T,
565}
566
567#[cfg_attr(feature = "capture", derive(Serialize))]
568#[cfg_attr(feature = "replay", derive(Deserialize))]
569#[derive(MallocSizeOf)]
570pub struct PrimitiveTemplate {
571 pub common: PrimTemplateCommonData,
572 pub kind: PrimitiveTemplateKind,
573}
574
575impl PatternBuilder for PrimitiveTemplate {
576 fn build(
577 &self,
578 _sub_rect: Option<DeviceRect>,
579 ctx: &PatternBuilderContext,
580 _state: &mut PatternBuilderState,
581 ) -> crate::pattern::Pattern {
582 match self.kind {
583 PrimitiveTemplateKind::Clear => Pattern::clear(),
584 PrimitiveTemplateKind::Rectangle { ref color, .. } => {
585 let color = ctx.scene_properties.resolve_color(color);
586 Pattern::color(color)
587 }
588 }
589 }
590
591 fn get_base_color(
592 &self,
593 ctx: &PatternBuilderContext,
594 ) -> ColorF {
595 match self.kind {
596 PrimitiveTemplateKind::Clear => ColorF::BLACK,
597 PrimitiveTemplateKind::Rectangle { ref color, .. } => {
598 ctx.scene_properties.resolve_color(color)
599 }
600 }
601 }
602
603 fn use_shared_pattern(
604 &self,
605 ) -> bool {
606 true
607 }
608}
609
610impl ops::Deref for PrimitiveTemplate {
611 type Target = PrimTemplateCommonData;
612 fn deref(&self) -> &Self::Target {
613 &self.common
614 }
615}
616
617impl ops::DerefMut for PrimitiveTemplate {
618 fn deref_mut(&mut self) -> &mut Self::Target {
619 &mut self.common
620 }
621}
622
623impl From<PrimitiveKey> for PrimitiveTemplate {
624 fn from(item: PrimitiveKey) -> Self {
625 PrimitiveTemplate {
626 common: PrimTemplateCommonData::with_key_common(item.common),
627 kind: item.kind.into(),
628 }
629 }
630}
631
632impl PrimitiveTemplate {
633 pub fn update(
638 &mut self,
639 frame_state: &mut FrameBuildingState,
640 scene_properties: &SceneProperties,
641 ) {
642 if let Some(mut request) = frame_state.gpu_cache.request(&mut self.common.gpu_cache_handle) {
643 self.kind.write_prim_gpu_blocks(&mut request, scene_properties);
644 }
645
646 self.opacity = match self.kind {
647 PrimitiveTemplateKind::Clear => {
648 PrimitiveOpacity::translucent()
649 }
650 PrimitiveTemplateKind::Rectangle { ref color, .. } => {
651 PrimitiveOpacity::from_alpha(scene_properties.resolve_color(color).a)
652 }
653 };
654 }
655}
656
657type PrimitiveDataHandle = intern::Handle<PrimitiveKeyKind>;
658
659impl intern::Internable for PrimitiveKeyKind {
660 type Key = PrimitiveKey;
661 type StoreData = PrimitiveTemplate;
662 type InternData = ();
663 const PROFILE_COUNTER: usize = crate::profiler::INTERNED_PRIMITIVES;
664}
665
666impl InternablePrimitive for PrimitiveKeyKind {
667 fn into_key(
668 self,
669 info: &LayoutPrimitiveInfo,
670 ) -> PrimitiveKey {
671 PrimitiveKey::new(info, self)
672 }
673
674 fn make_instance_kind(
675 key: PrimitiveKey,
676 data_handle: PrimitiveDataHandle,
677 prim_store: &mut PrimitiveStore,
678 ) -> PrimitiveInstanceKind {
679 match key.kind {
680 PrimitiveKeyKind::Clear => {
681 PrimitiveInstanceKind::Clear {
682 data_handle
683 }
684 }
685 PrimitiveKeyKind::Rectangle { color, .. } => {
686 let color_binding_index = match color {
687 PropertyBinding::Binding(..) => {
688 prim_store.color_bindings.push(color)
689 }
690 PropertyBinding::Value(..) => ColorBindingIndex::INVALID,
691 };
692 PrimitiveInstanceKind::Rectangle {
693 data_handle,
694 segment_instance_index: SegmentInstanceIndex::INVALID,
695 color_binding_index,
696 use_legacy_path: false,
697 }
698 }
699 }
700 }
701}
702
703#[derive(Debug, MallocSizeOf)]
704#[cfg_attr(feature = "capture", derive(Serialize))]
705#[cfg_attr(feature = "replay", derive(Deserialize))]
706pub struct VisibleMaskImageTile {
707 pub tile_offset: TileOffset,
708 pub tile_rect: LayoutRect,
709 pub task_id: RenderTaskId,
710}
711
712#[derive(Debug)]
713#[cfg_attr(feature = "capture", derive(Serialize))]
714pub struct VisibleGradientTile {
715 pub handle: GpuCacheHandle,
716 pub local_rect: LayoutRect,
717 pub local_clip_rect: LayoutRect,
718}
719
720#[cfg_attr(feature = "capture", derive(Serialize))]
723#[cfg_attr(feature = "replay", derive(Deserialize))]
724#[derive(Debug, MallocSizeOf)]
725pub struct BorderSegmentInfo {
726 pub local_task_size: LayoutSize,
727 pub cache_key: BorderSegmentCacheKey,
728}
729
730#[cfg_attr(feature = "capture", derive(Serialize))]
732#[derive(Debug, Clone)]
733pub enum ClipMaskKind {
734 Mask(RenderTaskId),
736 None,
738 Clipped,
740}
741
742#[cfg_attr(feature = "capture", derive(Serialize))]
743#[cfg_attr(feature = "replay", derive(Deserialize))]
744#[derive(Debug, Clone, MallocSizeOf)]
745pub struct BrushSegment {
746 pub local_rect: LayoutRect,
747 pub may_need_clip_mask: bool,
748 pub edge_flags: EdgeAaSegmentMask,
749 pub extra_data: [f32; 4],
750 pub brush_flags: BrushFlags,
751}
752
753impl BrushSegment {
754 pub fn new(
755 local_rect: LayoutRect,
756 may_need_clip_mask: bool,
757 edge_flags: EdgeAaSegmentMask,
758 extra_data: [f32; 4],
759 brush_flags: BrushFlags,
760 ) -> Self {
761 Self {
762 local_rect,
763 may_need_clip_mask,
764 edge_flags,
765 extra_data,
766 brush_flags,
767 }
768 }
769}
770
771#[derive(Debug, Clone)]
772#[repr(C)]
773#[cfg_attr(feature = "capture", derive(Serialize))]
774#[cfg_attr(feature = "replay", derive(Deserialize))]
775struct ClipRect {
776 rect: LayoutRect,
777 mode: f32,
778}
779
780#[derive(Debug, Clone)]
781#[repr(C)]
782#[cfg_attr(feature = "capture", derive(Serialize))]
783#[cfg_attr(feature = "replay", derive(Deserialize))]
784struct ClipCorner {
785 rect: LayoutRect,
786 outer_radius_x: f32,
787 outer_radius_y: f32,
788 inner_radius_x: f32,
789 inner_radius_y: f32,
790}
791
792impl ClipCorner {
793 fn uniform(rect: LayoutRect, outer_radius: f32, inner_radius: f32) -> ClipCorner {
794 ClipCorner {
795 rect,
796 outer_radius_x: outer_radius,
797 outer_radius_y: outer_radius,
798 inner_radius_x: inner_radius,
799 inner_radius_y: inner_radius,
800 }
801 }
802}
803
804#[derive(Debug, Clone)]
805#[repr(C)]
806#[cfg_attr(feature = "capture", derive(Serialize))]
807#[cfg_attr(feature = "replay", derive(Deserialize))]
808pub struct ClipData {
809 rect: ClipRect,
810 top_left: ClipCorner,
811 top_right: ClipCorner,
812 bottom_left: ClipCorner,
813 bottom_right: ClipCorner,
814}
815
816impl ClipData {
817 pub fn rounded_rect(size: LayoutSize, radii: &BorderRadius, mode: ClipMode) -> ClipData {
818 let rect = LayoutRect::from_size(size);
823
824 ClipData {
825 rect: ClipRect {
826 rect,
827 mode: mode as u32 as f32,
828 },
829 top_left: ClipCorner {
830 rect: LayoutRect::from_origin_and_size(
831 LayoutPoint::new(rect.min.x, rect.min.y),
832 LayoutSize::new(radii.top_left.width, radii.top_left.height),
833 ),
834 outer_radius_x: radii.top_left.width,
835 outer_radius_y: radii.top_left.height,
836 inner_radius_x: 0.0,
837 inner_radius_y: 0.0,
838 },
839 top_right: ClipCorner {
840 rect: LayoutRect::from_origin_and_size(
841 LayoutPoint::new(
842 rect.max.x - radii.top_right.width,
843 rect.min.y,
844 ),
845 LayoutSize::new(radii.top_right.width, radii.top_right.height),
846 ),
847 outer_radius_x: radii.top_right.width,
848 outer_radius_y: radii.top_right.height,
849 inner_radius_x: 0.0,
850 inner_radius_y: 0.0,
851 },
852 bottom_left: ClipCorner {
853 rect: LayoutRect::from_origin_and_size(
854 LayoutPoint::new(
855 rect.min.x,
856 rect.max.y - radii.bottom_left.height,
857 ),
858 LayoutSize::new(radii.bottom_left.width, radii.bottom_left.height),
859 ),
860 outer_radius_x: radii.bottom_left.width,
861 outer_radius_y: radii.bottom_left.height,
862 inner_radius_x: 0.0,
863 inner_radius_y: 0.0,
864 },
865 bottom_right: ClipCorner {
866 rect: LayoutRect::from_origin_and_size(
867 LayoutPoint::new(
868 rect.max.x - radii.bottom_right.width,
869 rect.max.y - radii.bottom_right.height,
870 ),
871 LayoutSize::new(radii.bottom_right.width, radii.bottom_right.height),
872 ),
873 outer_radius_x: radii.bottom_right.width,
874 outer_radius_y: radii.bottom_right.height,
875 inner_radius_x: 0.0,
876 inner_radius_y: 0.0,
877 },
878 }
879 }
880
881 pub fn uniform(size: LayoutSize, radius: f32, mode: ClipMode) -> ClipData {
882 let rect = LayoutRect::from_size(size);
887
888 ClipData {
889 rect: ClipRect {
890 rect,
891 mode: mode as u32 as f32,
892 },
893 top_left: ClipCorner::uniform(
894 LayoutRect::from_origin_and_size(
895 LayoutPoint::new(rect.min.x, rect.min.y),
896 LayoutSize::new(radius, radius),
897 ),
898 radius,
899 0.0,
900 ),
901 top_right: ClipCorner::uniform(
902 LayoutRect::from_origin_and_size(
903 LayoutPoint::new(rect.max.x - radius, rect.min.y),
904 LayoutSize::new(radius, radius),
905 ),
906 radius,
907 0.0,
908 ),
909 bottom_left: ClipCorner::uniform(
910 LayoutRect::from_origin_and_size(
911 LayoutPoint::new(rect.min.x, rect.max.y - radius),
912 LayoutSize::new(radius, radius),
913 ),
914 radius,
915 0.0,
916 ),
917 bottom_right: ClipCorner::uniform(
918 LayoutRect::from_origin_and_size(
919 LayoutPoint::new(
920 rect.max.x - radius,
921 rect.max.y - radius,
922 ),
923 LayoutSize::new(radius, radius),
924 ),
925 radius,
926 0.0,
927 ),
928 }
929 }
930}
931
932#[derive(Debug, Clone, PartialEq, Eq, Hash, MallocSizeOf)]
935#[cfg_attr(feature = "capture", derive(Serialize))]
936#[cfg_attr(feature = "replay", derive(Deserialize))]
937pub struct NinePatchDescriptor {
938 pub width: i32,
939 pub height: i32,
940 pub slice: DeviceIntSideOffsets,
941 pub fill: bool,
942 pub repeat_horizontal: RepeatMode,
943 pub repeat_vertical: RepeatMode,
944 pub widths: SideOffsetsKey,
945}
946
947impl IsVisible for PrimitiveKeyKind {
948 fn is_visible(&self) -> bool {
956 match *self {
957 PrimitiveKeyKind::Clear => {
958 true
959 }
960 PrimitiveKeyKind::Rectangle { ref color, .. } => {
961 match *color {
962 PropertyBinding::Value(value) => value.a > 0,
963 PropertyBinding::Binding(..) => true,
964 }
965 }
966 }
967 }
968}
969
970impl CreateShadow for PrimitiveKeyKind {
971 fn create_shadow(
975 &self,
976 shadow: &Shadow,
977 _: bool,
978 _: RasterSpace,
979 ) -> PrimitiveKeyKind {
980 match *self {
981 PrimitiveKeyKind::Rectangle { .. } => {
982 PrimitiveKeyKind::Rectangle {
983 color: PropertyBinding::Value(shadow.color.into()),
984 }
985 }
986 PrimitiveKeyKind::Clear => {
987 panic!("bug: this prim is not supported in shadow contexts");
988 }
989 }
990 }
991}
992
993#[derive(Debug)]
994#[cfg_attr(feature = "capture", derive(Serialize))]
995pub enum PrimitiveInstanceKind {
996 Picture {
998 data_handle: PictureDataHandle,
1000 pic_index: PictureIndex,
1001 },
1002 TextRun {
1004 data_handle: TextRunDataHandle,
1006 run_index: TextRunIndex,
1008 },
1009 LineDecoration {
1012 data_handle: LineDecorationDataHandle,
1014 render_task: Option<RenderTaskId>,
1023 },
1024 NormalBorder {
1025 data_handle: NormalBorderDataHandle,
1027 render_task_ids: storage::Range<RenderTaskId>,
1028 },
1029 ImageBorder {
1030 data_handle: ImageBorderDataHandle,
1032 },
1033 Rectangle {
1034 data_handle: PrimitiveDataHandle,
1036 segment_instance_index: SegmentInstanceIndex,
1037 color_binding_index: ColorBindingIndex,
1038 use_legacy_path: bool,
1039 },
1040 YuvImage {
1041 data_handle: YuvImageDataHandle,
1043 segment_instance_index: SegmentInstanceIndex,
1044 compositor_surface_kind: CompositorSurfaceKind,
1045 },
1046 Image {
1047 data_handle: ImageDataHandle,
1049 image_instance_index: ImageInstanceIndex,
1050 compositor_surface_kind: CompositorSurfaceKind,
1051 },
1052 LinearGradient {
1055 data_handle: LinearGradientDataHandle,
1057 visible_tiles_range: GradientTileRange,
1058 use_legacy_path: bool,
1059 },
1060 CachedLinearGradient {
1063 data_handle: LinearGradientDataHandle,
1065 visible_tiles_range: GradientTileRange,
1066 },
1067 RadialGradient {
1068 data_handle: RadialGradientDataHandle,
1070 visible_tiles_range: GradientTileRange,
1071 use_legacy_path: bool,
1072 },
1073 ConicGradient {
1074 data_handle: ConicGradientDataHandle,
1076 visible_tiles_range: GradientTileRange,
1077 use_legacy_path: bool,
1078 },
1079 Clear {
1081 data_handle: PrimitiveDataHandle,
1083 },
1084 BackdropCapture {
1086 data_handle: BackdropCaptureDataHandle,
1087 },
1088 BackdropRender {
1089 data_handle: BackdropRenderDataHandle,
1090 pic_index: PictureIndex,
1091 },
1092 BoxShadow {
1093 data_handle: BoxShadowDataHandle,
1094 },
1095}
1096
1097impl PrimitiveInstanceKind {
1098 pub fn as_pic(&self) -> PictureIndex {
1099 match self {
1100 PrimitiveInstanceKind::Picture { pic_index, .. } => *pic_index,
1101 _ => panic!("bug: as_pic called on a prim that is not a picture"),
1102 }
1103 }
1104}
1105
1106#[derive(Debug, Copy, Clone)]
1107#[cfg_attr(feature = "capture", derive(Serialize))]
1108#[cfg_attr(feature = "replay", derive(Deserialize))]
1109pub struct PrimitiveInstanceIndex(pub u32);
1110
1111#[derive(Debug)]
1112#[cfg_attr(feature = "capture", derive(Serialize))]
1113pub struct PrimitiveInstance {
1114 pub kind: PrimitiveInstanceKind,
1119
1120 pub clip_leaf_id: ClipLeafId,
1122
1123 pub vis: PrimitiveVisibility,
1127}
1128
1129impl PrimitiveInstance {
1130 pub fn new(
1131 kind: PrimitiveInstanceKind,
1132 clip_leaf_id: ClipLeafId,
1133 ) -> Self {
1134 PrimitiveInstance {
1135 kind,
1136 vis: PrimitiveVisibility::new(),
1137 clip_leaf_id,
1138 }
1139 }
1140
1141 pub fn reset(&mut self) {
1143 self.vis.reset();
1144 }
1145
1146 pub fn clear_visibility(&mut self) {
1147 self.vis.reset();
1148 }
1149
1150 pub fn uid(&self) -> intern::ItemUid {
1151 match &self.kind {
1152 PrimitiveInstanceKind::Clear { data_handle, .. } |
1153 PrimitiveInstanceKind::Rectangle { data_handle, .. } => {
1154 data_handle.uid()
1155 }
1156 PrimitiveInstanceKind::Image { data_handle, .. } => {
1157 data_handle.uid()
1158 }
1159 PrimitiveInstanceKind::ImageBorder { data_handle, .. } => {
1160 data_handle.uid()
1161 }
1162 PrimitiveInstanceKind::LineDecoration { data_handle, .. } => {
1163 data_handle.uid()
1164 }
1165 PrimitiveInstanceKind::LinearGradient { data_handle, .. } => {
1166 data_handle.uid()
1167 }
1168 PrimitiveInstanceKind::CachedLinearGradient { data_handle, .. } => {
1169 data_handle.uid()
1170 }
1171 PrimitiveInstanceKind::NormalBorder { data_handle, .. } => {
1172 data_handle.uid()
1173 }
1174 PrimitiveInstanceKind::Picture { data_handle, .. } => {
1175 data_handle.uid()
1176 }
1177 PrimitiveInstanceKind::RadialGradient { data_handle, .. } => {
1178 data_handle.uid()
1179 }
1180 PrimitiveInstanceKind::ConicGradient { data_handle, .. } => {
1181 data_handle.uid()
1182 }
1183 PrimitiveInstanceKind::TextRun { data_handle, .. } => {
1184 data_handle.uid()
1185 }
1186 PrimitiveInstanceKind::YuvImage { data_handle, .. } => {
1187 data_handle.uid()
1188 }
1189 PrimitiveInstanceKind::BackdropCapture { data_handle, .. } => {
1190 data_handle.uid()
1191 }
1192 PrimitiveInstanceKind::BackdropRender { data_handle, .. } => {
1193 data_handle.uid()
1194 }
1195 PrimitiveInstanceKind::BoxShadow { data_handle, .. } => {
1196 data_handle.uid()
1197 }
1198 }
1199 }
1200}
1201
1202#[cfg_attr(feature = "capture", derive(Serialize))]
1203#[derive(Debug)]
1204pub struct SegmentedInstance {
1205 pub gpu_cache_handle: GpuCacheHandle,
1206 pub segments_range: SegmentsRange,
1207}
1208
1209pub type GlyphKeyStorage = storage::Storage<GlyphKey>;
1210pub type TextRunIndex = storage::Index<TextRunPrimitive>;
1211pub type TextRunStorage = storage::Storage<TextRunPrimitive>;
1212pub type ColorBindingIndex = storage::Index<PropertyBinding<ColorU>>;
1213pub type ColorBindingStorage = storage::Storage<PropertyBinding<ColorU>>;
1214pub type BorderHandleStorage = storage::Storage<RenderTaskId>;
1215pub type SegmentStorage = storage::Storage<BrushSegment>;
1216pub type SegmentsRange = storage::Range<BrushSegment>;
1217pub type SegmentInstanceStorage = storage::Storage<SegmentedInstance>;
1218pub type SegmentInstanceIndex = storage::Index<SegmentedInstance>;
1219pub type ImageInstanceStorage = storage::Storage<ImageInstance>;
1220pub type ImageInstanceIndex = storage::Index<ImageInstance>;
1221pub type GradientTileStorage = storage::Storage<VisibleGradientTile>;
1222pub type GradientTileRange = storage::Range<VisibleGradientTile>;
1223pub type LinearGradientStorage = storage::Storage<LinearGradientPrimitive>;
1224
1225#[cfg_attr(feature = "capture", derive(Serialize))]
1230pub struct PrimitiveScratchBuffer {
1231 pub clip_mask_instances: Vec<ClipMaskKind>,
1234
1235 pub glyph_keys: GlyphKeyStorage,
1238
1239 pub border_cache_handles: BorderHandleStorage,
1242
1243 pub segments: SegmentStorage,
1245
1246 pub segment_instances: SegmentInstanceStorage,
1250
1251 pub gradient_tiles: GradientTileStorage,
1254
1255 pub debug_items: Vec<DebugItem>,
1257
1258 messages: Vec<DebugMessage>,
1260
1261 pub required_sub_graphs: FastHashSet<PictureIndex>,
1263
1264 pub quad_direct_segments: Vec<QuadSegment>,
1266 pub quad_color_segments: Vec<QuadSegment>,
1267 pub quad_indirect_segments: Vec<QuadSegment>,
1268
1269 pub quad_tile_classifier: QuadTileClassifier,
1272}
1273
1274impl Default for PrimitiveScratchBuffer {
1275 fn default() -> Self {
1276 PrimitiveScratchBuffer {
1277 clip_mask_instances: Vec::new(),
1278 glyph_keys: GlyphKeyStorage::new(0),
1279 border_cache_handles: BorderHandleStorage::new(0),
1280 segments: SegmentStorage::new(0),
1281 segment_instances: SegmentInstanceStorage::new(0),
1282 gradient_tiles: GradientTileStorage::new(0),
1283 debug_items: Vec::new(),
1284 messages: Vec::new(),
1285 required_sub_graphs: FastHashSet::default(),
1286 quad_direct_segments: Vec::new(),
1287 quad_color_segments: Vec::new(),
1288 quad_indirect_segments: Vec::new(),
1289 quad_tile_classifier: QuadTileClassifier::new(),
1290 }
1291 }
1292}
1293
1294impl PrimitiveScratchBuffer {
1295 pub fn recycle(&mut self, recycler: &mut Recycler) {
1296 recycler.recycle_vec(&mut self.clip_mask_instances);
1297 self.glyph_keys.recycle(recycler);
1298 self.border_cache_handles.recycle(recycler);
1299 self.segments.recycle(recycler);
1300 self.segment_instances.recycle(recycler);
1301 self.gradient_tiles.recycle(recycler);
1302 recycler.recycle_vec(&mut self.debug_items);
1303 recycler.recycle_vec(&mut self.quad_direct_segments);
1304 recycler.recycle_vec(&mut self.quad_color_segments);
1305 recycler.recycle_vec(&mut self.quad_indirect_segments);
1306 }
1307
1308 pub fn begin_frame(&mut self) {
1309 self.clip_mask_instances.clear();
1313 self.clip_mask_instances.push(ClipMaskKind::None);
1314 self.quad_direct_segments.clear();
1315 self.quad_color_segments.clear();
1316 self.quad_indirect_segments.clear();
1317
1318 self.border_cache_handles.clear();
1319
1320 self.gradient_tiles.clear();
1325
1326 self.required_sub_graphs.clear();
1327
1328 self.debug_items.clear();
1329 }
1330
1331 pub fn end_frame(&mut self) {
1332 const MSGS_TO_RETAIN: usize = 32;
1333 const TIME_TO_RETAIN: u64 = 2000000000;
1334 const LINE_HEIGHT: f32 = 20.0;
1335 const X0: f32 = 32.0;
1336 const Y0: f32 = 32.0;
1337 let now = zeitstempel::now();
1338
1339 let msgs_to_remove = self.messages.len().max(MSGS_TO_RETAIN) - MSGS_TO_RETAIN;
1340 let mut msgs_removed = 0;
1341
1342 self.messages.retain(|msg| {
1343 if msgs_removed < msgs_to_remove {
1344 msgs_removed += 1;
1345 return false;
1346 }
1347
1348 if msg.timestamp + TIME_TO_RETAIN < now {
1349 return false;
1350 }
1351
1352 true
1353 });
1354
1355 let mut y = Y0 + self.messages.len() as f32 * LINE_HEIGHT;
1356 let shadow_offset = 1.0;
1357
1358 for msg in &self.messages {
1359 self.debug_items.push(DebugItem::Text {
1360 position: DevicePoint::new(X0 + shadow_offset, y + shadow_offset),
1361 color: debug_colors::BLACK,
1362 msg: msg.msg.clone(),
1363 });
1364
1365 self.debug_items.push(DebugItem::Text {
1366 position: DevicePoint::new(X0, y),
1367 color: debug_colors::RED,
1368 msg: msg.msg.clone(),
1369 });
1370
1371 y -= LINE_HEIGHT;
1372 }
1373 }
1374
1375 pub fn push_debug_rect_with_stroke_width(
1376 &mut self,
1377 rect: WorldRect,
1378 border: ColorF,
1379 stroke_width: f32
1380 ) {
1381 let top_edge = WorldRect::new(
1382 WorldPoint::new(rect.min.x + stroke_width, rect.min.y),
1383 WorldPoint::new(rect.max.x - stroke_width, rect.min.y + stroke_width)
1384 );
1385 self.push_debug_rect(top_edge * DevicePixelScale::new(1.0), 1, border, border);
1386
1387 let bottom_edge = WorldRect::new(
1388 WorldPoint::new(rect.min.x + stroke_width, rect.max.y - stroke_width),
1389 WorldPoint::new(rect.max.x - stroke_width, rect.max.y)
1390 );
1391 self.push_debug_rect(bottom_edge * DevicePixelScale::new(1.0), 1, border, border);
1392
1393 let right_edge = WorldRect::new(
1394 WorldPoint::new(rect.max.x - stroke_width, rect.min.y),
1395 rect.max
1396 );
1397 self.push_debug_rect(right_edge * DevicePixelScale::new(1.0), 1, border, border);
1398
1399 let left_edge = WorldRect::new(
1400 rect.min,
1401 WorldPoint::new(rect.min.x + stroke_width, rect.max.y)
1402 );
1403 self.push_debug_rect(left_edge * DevicePixelScale::new(1.0), 1, border, border);
1404 }
1405
1406 #[allow(dead_code)]
1407 pub fn push_debug_rect(
1408 &mut self,
1409 rect: DeviceRect,
1410 thickness: i32,
1411 outer_color: ColorF,
1412 inner_color: ColorF,
1413 ) {
1414 self.debug_items.push(DebugItem::Rect {
1415 rect,
1416 outer_color,
1417 inner_color,
1418 thickness,
1419 });
1420 }
1421
1422 #[allow(dead_code)]
1423 pub fn push_debug_string(
1424 &mut self,
1425 position: DevicePoint,
1426 color: ColorF,
1427 msg: String,
1428 ) {
1429 self.debug_items.push(DebugItem::Text {
1430 position,
1431 color,
1432 msg,
1433 });
1434 }
1435
1436 #[allow(dead_code)]
1437 pub fn log(
1438 &mut self,
1439 msg: String,
1440 ) {
1441 self.messages.push(DebugMessage {
1442 msg,
1443 timestamp: zeitstempel::now(),
1444 })
1445 }
1446}
1447
1448#[cfg_attr(feature = "capture", derive(Serialize))]
1449#[cfg_attr(feature = "replay", derive(Deserialize))]
1450#[derive(Clone, Debug)]
1451pub struct PrimitiveStoreStats {
1452 picture_count: usize,
1453 text_run_count: usize,
1454 image_count: usize,
1455 linear_gradient_count: usize,
1456 color_binding_count: usize,
1457}
1458
1459impl PrimitiveStoreStats {
1460 pub fn empty() -> Self {
1461 PrimitiveStoreStats {
1462 picture_count: 0,
1463 text_run_count: 0,
1464 image_count: 0,
1465 linear_gradient_count: 0,
1466 color_binding_count: 0,
1467 }
1468 }
1469}
1470
1471#[cfg_attr(feature = "capture", derive(Serialize))]
1472pub struct PrimitiveStore {
1473 pub pictures: Vec<PicturePrimitive>,
1474 pub text_runs: TextRunStorage,
1475 pub linear_gradients: LinearGradientStorage,
1476
1477 pub images: ImageInstanceStorage,
1481
1482 pub color_bindings: ColorBindingStorage,
1484}
1485
1486impl PrimitiveStore {
1487 pub fn new(stats: &PrimitiveStoreStats) -> PrimitiveStore {
1488 PrimitiveStore {
1489 pictures: Vec::with_capacity(stats.picture_count),
1490 text_runs: TextRunStorage::new(stats.text_run_count),
1491 images: ImageInstanceStorage::new(stats.image_count),
1492 color_bindings: ColorBindingStorage::new(stats.color_binding_count),
1493 linear_gradients: LinearGradientStorage::new(stats.linear_gradient_count),
1494 }
1495 }
1496
1497 pub fn reset(&mut self) {
1498 self.pictures.clear();
1499 self.text_runs.clear();
1500 self.images.clear();
1501 self.color_bindings.clear();
1502 self.linear_gradients.clear();
1503 }
1504
1505 pub fn get_stats(&self) -> PrimitiveStoreStats {
1506 PrimitiveStoreStats {
1507 picture_count: self.pictures.len(),
1508 text_run_count: self.text_runs.len(),
1509 image_count: self.images.len(),
1510 linear_gradient_count: self.linear_gradients.len(),
1511 color_binding_count: self.color_bindings.len(),
1512 }
1513 }
1514
1515 #[allow(unused)]
1516 pub fn print_picture_tree(&self, root: PictureIndex) {
1517 use crate::print_tree::PrintTree;
1518 let mut pt = PrintTree::new("picture tree");
1519 self.pictures[root.0].print(&self.pictures, root, &mut pt);
1520 }
1521}
1522
1523impl Default for PrimitiveStore {
1524 fn default() -> Self {
1525 PrimitiveStore::new(&PrimitiveStoreStats::empty())
1526 }
1527}
1528
1529pub trait InternablePrimitive: intern::Internable<InternData = ()> + Sized {
1532 fn into_key(
1534 self,
1535 info: &LayoutPrimitiveInfo,
1536 ) -> Self::Key;
1537
1538 fn make_instance_kind(
1539 key: Self::Key,
1540 data_handle: intern::Handle<Self>,
1541 prim_store: &mut PrimitiveStore,
1542 ) -> PrimitiveInstanceKind;
1543}
1544
1545
1546#[test]
1547#[cfg(target_pointer_width = "64")]
1548fn test_struct_sizes() {
1549 use std::mem;
1550 assert_eq!(mem::size_of::<PrimitiveInstance>(), 88, "PrimitiveInstance size changed");
1557 assert_eq!(mem::size_of::<PrimitiveInstanceKind>(), 24, "PrimitiveInstanceKind size changed");
1558 assert_eq!(mem::size_of::<PrimitiveTemplate>(), 56, "PrimitiveTemplate size changed");
1559 assert_eq!(mem::size_of::<PrimitiveTemplateKind>(), 28, "PrimitiveTemplateKind size changed");
1560 assert_eq!(mem::size_of::<PrimitiveKey>(), 36, "PrimitiveKey size changed");
1561 assert_eq!(mem::size_of::<PrimitiveKeyKind>(), 16, "PrimitiveKeyKind size changed");
1562}