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}
97
98#[derive(Debug, Copy, Clone, PartialEq)]
99#[cfg_attr(feature = "capture", derive(Serialize))]
100pub struct ClipTaskIndex(pub u32);
101
102impl ClipTaskIndex {
103 pub const INVALID: ClipTaskIndex = ClipTaskIndex(0);
104}
105
106#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, MallocSizeOf, Ord, PartialOrd)]
107#[cfg_attr(feature = "capture", derive(Serialize))]
108#[cfg_attr(feature = "replay", derive(Deserialize))]
109pub struct PictureIndex(pub usize);
110
111impl PictureIndex {
112 pub const INVALID: PictureIndex = PictureIndex(!0);
113}
114
115#[cfg_attr(feature = "capture", derive(Serialize))]
116#[cfg_attr(feature = "replay", derive(Deserialize))]
117#[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
118pub struct RectangleKey {
119 pub x0: f32,
120 pub y0: f32,
121 pub x1: f32,
122 pub y1: f32,
123}
124
125impl RectangleKey {
126 pub fn intersects(&self, other: &Self) -> bool {
127 self.x0 < other.x1
128 && other.x0 < self.x1
129 && self.y0 < other.y1
130 && other.y0 < self.y1
131 }
132}
133
134impl Eq for RectangleKey {}
135
136impl hash::Hash for RectangleKey {
137 fn hash<H: hash::Hasher>(&self, state: &mut H) {
138 self.x0.to_bits().hash(state);
139 self.y0.to_bits().hash(state);
140 self.x1.to_bits().hash(state);
141 self.y1.to_bits().hash(state);
142 }
143}
144
145impl From<RectangleKey> for LayoutRect {
146 fn from(key: RectangleKey) -> LayoutRect {
147 LayoutRect {
148 min: LayoutPoint::new(key.x0, key.y0),
149 max: LayoutPoint::new(key.x1, key.y1),
150 }
151 }
152}
153
154impl From<RectangleKey> for WorldRect {
155 fn from(key: RectangleKey) -> WorldRect {
156 WorldRect {
157 min: WorldPoint::new(key.x0, key.y0),
158 max: WorldPoint::new(key.x1, key.y1),
159 }
160 }
161}
162
163impl From<LayoutRect> for RectangleKey {
164 fn from(rect: LayoutRect) -> RectangleKey {
165 RectangleKey {
166 x0: rect.min.x,
167 y0: rect.min.y,
168 x1: rect.max.x,
169 y1: rect.max.y,
170 }
171 }
172}
173
174impl From<PictureRect> for RectangleKey {
175 fn from(rect: PictureRect) -> RectangleKey {
176 RectangleKey {
177 x0: rect.min.x,
178 y0: rect.min.y,
179 x1: rect.max.x,
180 y1: rect.max.y,
181 }
182 }
183}
184
185impl From<WorldRect> for RectangleKey {
186 fn from(rect: WorldRect) -> RectangleKey {
187 RectangleKey {
188 x0: rect.min.x,
189 y0: rect.min.y,
190 x1: rect.max.x,
191 y1: rect.max.y,
192 }
193 }
194}
195
196#[cfg_attr(feature = "capture", derive(Serialize))]
201#[cfg_attr(feature = "replay", derive(Deserialize))]
202#[derive(Copy, Debug, Clone, Hash, MallocSizeOf, PartialEq)]
203pub struct PolygonKey {
204 pub point_count: u8,
205 pub points: [PointKey; POLYGON_CLIP_VERTEX_MAX],
206 pub fill_rule: FillRule,
207}
208
209impl PolygonKey {
210 pub fn new(
211 points_layout: &Vec<LayoutPoint>,
212 fill_rule: FillRule,
213 ) -> Self {
214 let mut points: [PointKey; POLYGON_CLIP_VERTEX_MAX] = [PointKey { x: 0.0, y: 0.0}; POLYGON_CLIP_VERTEX_MAX];
219
220 let mut point_count: u8 = 0;
221 for (src, dest) in points_layout.iter().zip(points.iter_mut()) {
222 *dest = (*src as LayoutPoint).into();
223 point_count = point_count + 1;
224 }
225
226 PolygonKey {
227 point_count,
228 points,
229 fill_rule,
230 }
231 }
232}
233
234impl Eq for PolygonKey {}
235
236#[cfg_attr(feature = "capture", derive(Serialize))]
238#[cfg_attr(feature = "replay", derive(Deserialize))]
239#[derive(Debug, Clone, MallocSizeOf, PartialEq)]
240pub struct SideOffsetsKey {
241 pub top: f32,
242 pub right: f32,
243 pub bottom: f32,
244 pub left: f32,
245}
246
247impl Eq for SideOffsetsKey {}
248
249impl hash::Hash for SideOffsetsKey {
250 fn hash<H: hash::Hasher>(&self, state: &mut H) {
251 self.top.to_bits().hash(state);
252 self.right.to_bits().hash(state);
253 self.bottom.to_bits().hash(state);
254 self.left.to_bits().hash(state);
255 }
256}
257
258impl From<SideOffsetsKey> for LayoutSideOffsets {
259 fn from(key: SideOffsetsKey) -> LayoutSideOffsets {
260 LayoutSideOffsets::new(
261 key.top,
262 key.right,
263 key.bottom,
264 key.left,
265 )
266 }
267}
268
269impl<U> From<SideOffsets2D<f32, U>> for SideOffsetsKey {
270 fn from(offsets: SideOffsets2D<f32, U>) -> SideOffsetsKey {
271 SideOffsetsKey {
272 top: offsets.top,
273 right: offsets.right,
274 bottom: offsets.bottom,
275 left: offsets.left,
276 }
277 }
278}
279
280#[cfg_attr(feature = "capture", derive(Serialize))]
282#[cfg_attr(feature = "replay", derive(Deserialize))]
283#[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
284pub struct SizeKey {
285 w: f32,
286 h: f32,
287}
288
289impl Eq for SizeKey {}
290
291impl hash::Hash for SizeKey {
292 fn hash<H: hash::Hasher>(&self, state: &mut H) {
293 self.w.to_bits().hash(state);
294 self.h.to_bits().hash(state);
295 }
296}
297
298impl From<SizeKey> for LayoutSize {
299 fn from(key: SizeKey) -> LayoutSize {
300 LayoutSize::new(key.w, key.h)
301 }
302}
303
304impl<U> From<Size2D<f32, U>> for SizeKey {
305 fn from(size: Size2D<f32, U>) -> SizeKey {
306 SizeKey {
307 w: size.width,
308 h: size.height,
309 }
310 }
311}
312
313#[cfg_attr(feature = "capture", derive(Serialize))]
315#[cfg_attr(feature = "replay", derive(Deserialize))]
316#[derive(Copy, Debug, Clone, MallocSizeOf, PartialEq)]
317pub struct VectorKey {
318 pub x: f32,
319 pub y: f32,
320}
321
322impl Eq for VectorKey {}
323
324impl hash::Hash for VectorKey {
325 fn hash<H: hash::Hasher>(&self, state: &mut H) {
326 self.x.to_bits().hash(state);
327 self.y.to_bits().hash(state);
328 }
329}
330
331impl From<VectorKey> for LayoutVector2D {
332 fn from(key: VectorKey) -> LayoutVector2D {
333 LayoutVector2D::new(key.x, key.y)
334 }
335}
336
337impl From<VectorKey> for WorldVector2D {
338 fn from(key: VectorKey) -> WorldVector2D {
339 WorldVector2D::new(key.x, key.y)
340 }
341}
342
343impl From<LayoutVector2D> for VectorKey {
344 fn from(vec: LayoutVector2D) -> VectorKey {
345 VectorKey {
346 x: vec.x,
347 y: vec.y,
348 }
349 }
350}
351
352impl From<WorldVector2D> for VectorKey {
353 fn from(vec: WorldVector2D) -> VectorKey {
354 VectorKey {
355 x: vec.x,
356 y: vec.y,
357 }
358 }
359}
360
361#[cfg_attr(feature = "capture", derive(Serialize))]
363#[cfg_attr(feature = "replay", derive(Deserialize))]
364#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)]
365pub struct PointKey {
366 pub x: f32,
367 pub y: f32,
368}
369
370impl Eq for PointKey {}
371
372impl hash::Hash for PointKey {
373 fn hash<H: hash::Hasher>(&self, state: &mut H) {
374 self.x.to_bits().hash(state);
375 self.y.to_bits().hash(state);
376 }
377}
378
379impl From<PointKey> for LayoutPoint {
380 fn from(key: PointKey) -> LayoutPoint {
381 LayoutPoint::new(key.x, key.y)
382 }
383}
384
385impl From<LayoutPoint> for PointKey {
386 fn from(p: LayoutPoint) -> PointKey {
387 PointKey {
388 x: p.x,
389 y: p.y,
390 }
391 }
392}
393
394impl From<PicturePoint> for PointKey {
395 fn from(p: PicturePoint) -> PointKey {
396 PointKey {
397 x: p.x,
398 y: p.y,
399 }
400 }
401}
402
403impl From<WorldPoint> for PointKey {
404 fn from(p: WorldPoint) -> PointKey {
405 PointKey {
406 x: p.x,
407 y: p.y,
408 }
409 }
410}
411
412#[cfg_attr(feature = "capture", derive(Serialize))]
414#[cfg_attr(feature = "replay", derive(Deserialize))]
415#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)]
416pub struct FloatKey(f32);
417
418impl Eq for FloatKey {}
419
420impl hash::Hash for FloatKey {
421 fn hash<H: hash::Hasher>(&self, state: &mut H) {
422 self.0.to_bits().hash(state);
423 }
424}
425
426
427#[cfg_attr(feature = "capture", derive(Serialize))]
428#[cfg_attr(feature = "replay", derive(Deserialize))]
429#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
430pub struct PrimKeyCommonData {
431 pub flags: PrimitiveFlags,
432 pub prim_rect: RectangleKey,
433}
434
435impl From<&LayoutPrimitiveInfo> for PrimKeyCommonData {
436 fn from(info: &LayoutPrimitiveInfo) -> Self {
437 PrimKeyCommonData {
438 flags: info.flags,
439 prim_rect: info.rect.into(),
440 }
441 }
442}
443
444#[cfg_attr(feature = "capture", derive(Serialize))]
445#[cfg_attr(feature = "replay", derive(Deserialize))]
446#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
447pub struct PrimKey<T: MallocSizeOf> {
448 pub common: PrimKeyCommonData,
449 pub kind: T,
450}
451
452#[cfg_attr(feature = "capture", derive(Serialize))]
453#[cfg_attr(feature = "replay", derive(Deserialize))]
454#[derive(Debug, Clone, Eq, MallocSizeOf, PartialEq, Hash)]
455pub struct PrimitiveKey {
456 pub common: PrimKeyCommonData,
457 pub kind: PrimitiveKeyKind,
458}
459
460impl PrimitiveKey {
461 pub fn new(
462 info: &LayoutPrimitiveInfo,
463 kind: PrimitiveKeyKind,
464 ) -> Self {
465 PrimitiveKey {
466 common: info.into(),
467 kind,
468 }
469 }
470}
471
472impl intern::InternDebug for PrimitiveKey {}
473
474#[cfg_attr(feature = "capture", derive(Serialize))]
477#[cfg_attr(feature = "replay", derive(Deserialize))]
478#[derive(MallocSizeOf)]
479pub enum PrimitiveTemplateKind {
480 Rectangle {
481 color: PropertyBinding<ColorF>,
482 },
483 Clear,
484}
485
486impl PrimitiveTemplateKind {
487 pub fn write_prim_gpu_blocks(
489 &self,
490 request: &mut GpuDataRequest,
491 scene_properties: &SceneProperties,
492 ) {
493 match *self {
494 PrimitiveTemplateKind::Clear => {
495 request.push(PremultipliedColorF::BLACK);
497 }
498 PrimitiveTemplateKind::Rectangle { ref color, .. } => {
499 request.push(scene_properties.resolve_color(color).premultiplied())
500 }
501 }
502 }
503}
504
505impl From<PrimitiveKeyKind> for PrimitiveTemplateKind {
509 fn from(kind: PrimitiveKeyKind) -> Self {
510 match kind {
511 PrimitiveKeyKind::Clear => {
512 PrimitiveTemplateKind::Clear
513 }
514 PrimitiveKeyKind::Rectangle { color, .. } => {
515 PrimitiveTemplateKind::Rectangle {
516 color: color.into(),
517 }
518 }
519 }
520 }
521}
522
523#[cfg_attr(feature = "capture", derive(Serialize))]
524#[cfg_attr(feature = "replay", derive(Deserialize))]
525#[derive(MallocSizeOf)]
526#[derive(Debug)]
527pub struct PrimTemplateCommonData {
528 pub flags: PrimitiveFlags,
529 pub may_need_repetition: bool,
530 pub prim_rect: LayoutRect,
531 pub opacity: PrimitiveOpacity,
532 pub gpu_cache_handle: GpuCacheHandle,
537 pub edge_aa_mask: EdgeAaSegmentMask,
543}
544
545impl PrimTemplateCommonData {
546 pub fn with_key_common(common: PrimKeyCommonData) -> Self {
547 PrimTemplateCommonData {
548 flags: common.flags,
549 may_need_repetition: true,
550 prim_rect: common.prim_rect.into(),
551 gpu_cache_handle: GpuCacheHandle::new(),
552 opacity: PrimitiveOpacity::translucent(),
553 edge_aa_mask: EdgeAaSegmentMask::all(),
554 }
555 }
556}
557
558#[cfg_attr(feature = "capture", derive(Serialize))]
559#[cfg_attr(feature = "replay", derive(Deserialize))]
560#[derive(MallocSizeOf)]
561pub struct PrimTemplate<T> {
562 pub common: PrimTemplateCommonData,
563 pub kind: T,
564}
565
566#[cfg_attr(feature = "capture", derive(Serialize))]
567#[cfg_attr(feature = "replay", derive(Deserialize))]
568#[derive(MallocSizeOf)]
569pub struct PrimitiveTemplate {
570 pub common: PrimTemplateCommonData,
571 pub kind: PrimitiveTemplateKind,
572}
573
574impl PatternBuilder for PrimitiveTemplate {
575 fn build(
576 &self,
577 _sub_rect: Option<DeviceRect>,
578 ctx: &PatternBuilderContext,
579 _state: &mut PatternBuilderState,
580 ) -> crate::pattern::Pattern {
581 match self.kind {
582 PrimitiveTemplateKind::Clear => Pattern::clear(),
583 PrimitiveTemplateKind::Rectangle { ref color, .. } => {
584 let color = ctx.scene_properties.resolve_color(color);
585 Pattern::color(color)
586 }
587 }
588 }
589
590 fn get_base_color(
591 &self,
592 ctx: &PatternBuilderContext,
593 ) -> ColorF {
594 match self.kind {
595 PrimitiveTemplateKind::Clear => ColorF::BLACK,
596 PrimitiveTemplateKind::Rectangle { ref color, .. } => {
597 ctx.scene_properties.resolve_color(color)
598 }
599 }
600 }
601
602 fn use_shared_pattern(
603 &self,
604 ) -> bool {
605 true
606 }
607}
608
609impl ops::Deref for PrimitiveTemplate {
610 type Target = PrimTemplateCommonData;
611 fn deref(&self) -> &Self::Target {
612 &self.common
613 }
614}
615
616impl ops::DerefMut for PrimitiveTemplate {
617 fn deref_mut(&mut self) -> &mut Self::Target {
618 &mut self.common
619 }
620}
621
622impl From<PrimitiveKey> for PrimitiveTemplate {
623 fn from(item: PrimitiveKey) -> Self {
624 PrimitiveTemplate {
625 common: PrimTemplateCommonData::with_key_common(item.common),
626 kind: item.kind.into(),
627 }
628 }
629}
630
631impl PrimitiveTemplate {
632 pub fn update(
637 &mut self,
638 frame_state: &mut FrameBuildingState,
639 scene_properties: &SceneProperties,
640 ) {
641 if let Some(mut request) = frame_state.gpu_cache.request(&mut self.common.gpu_cache_handle) {
642 self.kind.write_prim_gpu_blocks(&mut request, scene_properties);
643 }
644
645 self.opacity = match self.kind {
646 PrimitiveTemplateKind::Clear => {
647 PrimitiveOpacity::translucent()
648 }
649 PrimitiveTemplateKind::Rectangle { ref color, .. } => {
650 PrimitiveOpacity::from_alpha(scene_properties.resolve_color(color).a)
651 }
652 };
653 }
654}
655
656type PrimitiveDataHandle = intern::Handle<PrimitiveKeyKind>;
657
658impl intern::Internable for PrimitiveKeyKind {
659 type Key = PrimitiveKey;
660 type StoreData = PrimitiveTemplate;
661 type InternData = ();
662 const PROFILE_COUNTER: usize = crate::profiler::INTERNED_PRIMITIVES;
663}
664
665impl InternablePrimitive for PrimitiveKeyKind {
666 fn into_key(
667 self,
668 info: &LayoutPrimitiveInfo,
669 ) -> PrimitiveKey {
670 PrimitiveKey::new(info, self)
671 }
672
673 fn make_instance_kind(
674 key: PrimitiveKey,
675 data_handle: PrimitiveDataHandle,
676 prim_store: &mut PrimitiveStore,
677 ) -> PrimitiveInstanceKind {
678 match key.kind {
679 PrimitiveKeyKind::Clear => {
680 PrimitiveInstanceKind::Clear {
681 data_handle
682 }
683 }
684 PrimitiveKeyKind::Rectangle { color, .. } => {
685 let color_binding_index = match color {
686 PropertyBinding::Binding(..) => {
687 prim_store.color_bindings.push(color)
688 }
689 PropertyBinding::Value(..) => ColorBindingIndex::INVALID,
690 };
691 PrimitiveInstanceKind::Rectangle {
692 data_handle,
693 segment_instance_index: SegmentInstanceIndex::INVALID,
694 color_binding_index,
695 use_legacy_path: false,
696 }
697 }
698 }
699 }
700}
701
702#[derive(Debug, MallocSizeOf)]
703#[cfg_attr(feature = "capture", derive(Serialize))]
704#[cfg_attr(feature = "replay", derive(Deserialize))]
705pub struct VisibleMaskImageTile {
706 pub tile_offset: TileOffset,
707 pub tile_rect: LayoutRect,
708 pub task_id: RenderTaskId,
709}
710
711#[derive(Debug)]
712#[cfg_attr(feature = "capture", derive(Serialize))]
713pub struct VisibleGradientTile {
714 pub handle: GpuCacheHandle,
715 pub local_rect: LayoutRect,
716 pub local_clip_rect: LayoutRect,
717}
718
719#[cfg_attr(feature = "capture", derive(Serialize))]
722#[cfg_attr(feature = "replay", derive(Deserialize))]
723#[derive(Debug, MallocSizeOf)]
724pub struct BorderSegmentInfo {
725 pub local_task_size: LayoutSize,
726 pub cache_key: BorderSegmentCacheKey,
727}
728
729#[cfg_attr(feature = "capture", derive(Serialize))]
731#[derive(Debug, Clone)]
732pub enum ClipMaskKind {
733 Mask(RenderTaskId),
735 None,
737 Clipped,
739}
740
741#[cfg_attr(feature = "capture", derive(Serialize))]
742#[cfg_attr(feature = "replay", derive(Deserialize))]
743#[derive(Debug, Clone, MallocSizeOf)]
744pub struct BrushSegment {
745 pub local_rect: LayoutRect,
746 pub may_need_clip_mask: bool,
747 pub edge_flags: EdgeAaSegmentMask,
748 pub extra_data: [f32; 4],
749 pub brush_flags: BrushFlags,
750}
751
752impl BrushSegment {
753 pub fn new(
754 local_rect: LayoutRect,
755 may_need_clip_mask: bool,
756 edge_flags: EdgeAaSegmentMask,
757 extra_data: [f32; 4],
758 brush_flags: BrushFlags,
759 ) -> Self {
760 Self {
761 local_rect,
762 may_need_clip_mask,
763 edge_flags,
764 extra_data,
765 brush_flags,
766 }
767 }
768}
769
770#[derive(Debug, Clone)]
771#[repr(C)]
772#[cfg_attr(feature = "capture", derive(Serialize))]
773#[cfg_attr(feature = "replay", derive(Deserialize))]
774struct ClipRect {
775 rect: LayoutRect,
776 mode: f32,
777}
778
779#[derive(Debug, Clone)]
780#[repr(C)]
781#[cfg_attr(feature = "capture", derive(Serialize))]
782#[cfg_attr(feature = "replay", derive(Deserialize))]
783struct ClipCorner {
784 rect: LayoutRect,
785 outer_radius_x: f32,
786 outer_radius_y: f32,
787 inner_radius_x: f32,
788 inner_radius_y: f32,
789}
790
791impl ClipCorner {
792 fn uniform(rect: LayoutRect, outer_radius: f32, inner_radius: f32) -> ClipCorner {
793 ClipCorner {
794 rect,
795 outer_radius_x: outer_radius,
796 outer_radius_y: outer_radius,
797 inner_radius_x: inner_radius,
798 inner_radius_y: inner_radius,
799 }
800 }
801}
802
803#[derive(Debug, Clone)]
804#[repr(C)]
805#[cfg_attr(feature = "capture", derive(Serialize))]
806#[cfg_attr(feature = "replay", derive(Deserialize))]
807pub struct ClipData {
808 rect: ClipRect,
809 top_left: ClipCorner,
810 top_right: ClipCorner,
811 bottom_left: ClipCorner,
812 bottom_right: ClipCorner,
813}
814
815impl ClipData {
816 pub fn rounded_rect(size: LayoutSize, radii: &BorderRadius, mode: ClipMode) -> ClipData {
817 let rect = LayoutRect::from_size(size);
822
823 ClipData {
824 rect: ClipRect {
825 rect,
826 mode: mode as u32 as f32,
827 },
828 top_left: ClipCorner {
829 rect: LayoutRect::from_origin_and_size(
830 LayoutPoint::new(rect.min.x, rect.min.y),
831 LayoutSize::new(radii.top_left.width, radii.top_left.height),
832 ),
833 outer_radius_x: radii.top_left.width,
834 outer_radius_y: radii.top_left.height,
835 inner_radius_x: 0.0,
836 inner_radius_y: 0.0,
837 },
838 top_right: ClipCorner {
839 rect: LayoutRect::from_origin_and_size(
840 LayoutPoint::new(
841 rect.max.x - radii.top_right.width,
842 rect.min.y,
843 ),
844 LayoutSize::new(radii.top_right.width, radii.top_right.height),
845 ),
846 outer_radius_x: radii.top_right.width,
847 outer_radius_y: radii.top_right.height,
848 inner_radius_x: 0.0,
849 inner_radius_y: 0.0,
850 },
851 bottom_left: ClipCorner {
852 rect: LayoutRect::from_origin_and_size(
853 LayoutPoint::new(
854 rect.min.x,
855 rect.max.y - radii.bottom_left.height,
856 ),
857 LayoutSize::new(radii.bottom_left.width, radii.bottom_left.height),
858 ),
859 outer_radius_x: radii.bottom_left.width,
860 outer_radius_y: radii.bottom_left.height,
861 inner_radius_x: 0.0,
862 inner_radius_y: 0.0,
863 },
864 bottom_right: ClipCorner {
865 rect: LayoutRect::from_origin_and_size(
866 LayoutPoint::new(
867 rect.max.x - radii.bottom_right.width,
868 rect.max.y - radii.bottom_right.height,
869 ),
870 LayoutSize::new(radii.bottom_right.width, radii.bottom_right.height),
871 ),
872 outer_radius_x: radii.bottom_right.width,
873 outer_radius_y: radii.bottom_right.height,
874 inner_radius_x: 0.0,
875 inner_radius_y: 0.0,
876 },
877 }
878 }
879
880 pub fn uniform(size: LayoutSize, radius: f32, mode: ClipMode) -> ClipData {
881 let rect = LayoutRect::from_size(size);
886
887 ClipData {
888 rect: ClipRect {
889 rect,
890 mode: mode as u32 as f32,
891 },
892 top_left: ClipCorner::uniform(
893 LayoutRect::from_origin_and_size(
894 LayoutPoint::new(rect.min.x, rect.min.y),
895 LayoutSize::new(radius, radius),
896 ),
897 radius,
898 0.0,
899 ),
900 top_right: ClipCorner::uniform(
901 LayoutRect::from_origin_and_size(
902 LayoutPoint::new(rect.max.x - radius, rect.min.y),
903 LayoutSize::new(radius, radius),
904 ),
905 radius,
906 0.0,
907 ),
908 bottom_left: ClipCorner::uniform(
909 LayoutRect::from_origin_and_size(
910 LayoutPoint::new(rect.min.x, rect.max.y - radius),
911 LayoutSize::new(radius, radius),
912 ),
913 radius,
914 0.0,
915 ),
916 bottom_right: ClipCorner::uniform(
917 LayoutRect::from_origin_and_size(
918 LayoutPoint::new(
919 rect.max.x - radius,
920 rect.max.y - radius,
921 ),
922 LayoutSize::new(radius, radius),
923 ),
924 radius,
925 0.0,
926 ),
927 }
928 }
929}
930
931#[derive(Debug, Clone, PartialEq, Eq, Hash, MallocSizeOf)]
934#[cfg_attr(feature = "capture", derive(Serialize))]
935#[cfg_attr(feature = "replay", derive(Deserialize))]
936pub struct NinePatchDescriptor {
937 pub width: i32,
938 pub height: i32,
939 pub slice: DeviceIntSideOffsets,
940 pub fill: bool,
941 pub repeat_horizontal: RepeatMode,
942 pub repeat_vertical: RepeatMode,
943 pub widths: SideOffsetsKey,
944}
945
946impl IsVisible for PrimitiveKeyKind {
947 fn is_visible(&self) -> bool {
955 match *self {
956 PrimitiveKeyKind::Clear => {
957 true
958 }
959 PrimitiveKeyKind::Rectangle { ref color, .. } => {
960 match *color {
961 PropertyBinding::Value(value) => value.a > 0,
962 PropertyBinding::Binding(..) => true,
963 }
964 }
965 }
966 }
967}
968
969impl CreateShadow for PrimitiveKeyKind {
970 fn create_shadow(
974 &self,
975 shadow: &Shadow,
976 _: bool,
977 _: RasterSpace,
978 ) -> PrimitiveKeyKind {
979 match *self {
980 PrimitiveKeyKind::Rectangle { .. } => {
981 PrimitiveKeyKind::Rectangle {
982 color: PropertyBinding::Value(shadow.color.into()),
983 }
984 }
985 PrimitiveKeyKind::Clear => {
986 panic!("bug: this prim is not supported in shadow contexts");
987 }
988 }
989 }
990}
991
992#[derive(Debug)]
993#[cfg_attr(feature = "capture", derive(Serialize))]
994pub enum PrimitiveInstanceKind {
995 Picture {
997 data_handle: PictureDataHandle,
999 pic_index: PictureIndex,
1000 },
1001 TextRun {
1003 data_handle: TextRunDataHandle,
1005 run_index: TextRunIndex,
1007 },
1008 LineDecoration {
1011 data_handle: LineDecorationDataHandle,
1013 render_task: Option<RenderTaskId>,
1022 },
1023 NormalBorder {
1024 data_handle: NormalBorderDataHandle,
1026 render_task_ids: storage::Range<RenderTaskId>,
1027 },
1028 ImageBorder {
1029 data_handle: ImageBorderDataHandle,
1031 },
1032 Rectangle {
1033 data_handle: PrimitiveDataHandle,
1035 segment_instance_index: SegmentInstanceIndex,
1036 color_binding_index: ColorBindingIndex,
1037 use_legacy_path: bool,
1038 },
1039 YuvImage {
1040 data_handle: YuvImageDataHandle,
1042 segment_instance_index: SegmentInstanceIndex,
1043 compositor_surface_kind: CompositorSurfaceKind,
1044 },
1045 Image {
1046 data_handle: ImageDataHandle,
1048 image_instance_index: ImageInstanceIndex,
1049 compositor_surface_kind: CompositorSurfaceKind,
1050 },
1051 LinearGradient {
1054 data_handle: LinearGradientDataHandle,
1056 visible_tiles_range: GradientTileRange,
1057 },
1058 CachedLinearGradient {
1061 data_handle: LinearGradientDataHandle,
1063 visible_tiles_range: GradientTileRange,
1064 },
1065 RadialGradient {
1066 data_handle: RadialGradientDataHandle,
1068 visible_tiles_range: GradientTileRange,
1069 cached: bool,
1070 },
1071 ConicGradient {
1072 data_handle: ConicGradientDataHandle,
1074 visible_tiles_range: GradientTileRange,
1075 cached: bool,
1076 },
1077 Clear {
1079 data_handle: PrimitiveDataHandle,
1081 },
1082 BackdropCapture {
1084 data_handle: BackdropCaptureDataHandle,
1085 },
1086 BackdropRender {
1087 data_handle: BackdropRenderDataHandle,
1088 pic_index: PictureIndex,
1089 },
1090 BoxShadow {
1091 data_handle: BoxShadowDataHandle,
1092 },
1093}
1094
1095impl PrimitiveInstanceKind {
1096 pub fn as_pic(&self) -> PictureIndex {
1097 match self {
1098 PrimitiveInstanceKind::Picture { pic_index, .. } => *pic_index,
1099 _ => panic!("bug: as_pic called on a prim that is not a picture"),
1100 }
1101 }
1102}
1103
1104#[derive(Debug, Copy, Clone)]
1105#[cfg_attr(feature = "capture", derive(Serialize))]
1106#[cfg_attr(feature = "replay", derive(Deserialize))]
1107pub struct PrimitiveInstanceIndex(pub u32);
1108
1109#[derive(Debug)]
1110#[cfg_attr(feature = "capture", derive(Serialize))]
1111pub struct PrimitiveInstance {
1112 pub kind: PrimitiveInstanceKind,
1117
1118 pub clip_leaf_id: ClipLeafId,
1120
1121 pub vis: PrimitiveVisibility,
1125}
1126
1127impl PrimitiveInstance {
1128 pub fn new(
1129 kind: PrimitiveInstanceKind,
1130 clip_leaf_id: ClipLeafId,
1131 ) -> Self {
1132 PrimitiveInstance {
1133 kind,
1134 vis: PrimitiveVisibility::new(),
1135 clip_leaf_id,
1136 }
1137 }
1138
1139 pub fn reset(&mut self) {
1141 self.vis.reset();
1142 }
1143
1144 pub fn clear_visibility(&mut self) {
1145 self.vis.reset();
1146 }
1147
1148 pub fn uid(&self) -> intern::ItemUid {
1149 match &self.kind {
1150 PrimitiveInstanceKind::Clear { data_handle, .. } |
1151 PrimitiveInstanceKind::Rectangle { data_handle, .. } => {
1152 data_handle.uid()
1153 }
1154 PrimitiveInstanceKind::Image { data_handle, .. } => {
1155 data_handle.uid()
1156 }
1157 PrimitiveInstanceKind::ImageBorder { data_handle, .. } => {
1158 data_handle.uid()
1159 }
1160 PrimitiveInstanceKind::LineDecoration { data_handle, .. } => {
1161 data_handle.uid()
1162 }
1163 PrimitiveInstanceKind::LinearGradient { data_handle, .. } => {
1164 data_handle.uid()
1165 }
1166 PrimitiveInstanceKind::CachedLinearGradient { data_handle, .. } => {
1167 data_handle.uid()
1168 }
1169 PrimitiveInstanceKind::NormalBorder { data_handle, .. } => {
1170 data_handle.uid()
1171 }
1172 PrimitiveInstanceKind::Picture { data_handle, .. } => {
1173 data_handle.uid()
1174 }
1175 PrimitiveInstanceKind::RadialGradient { data_handle, .. } => {
1176 data_handle.uid()
1177 }
1178 PrimitiveInstanceKind::ConicGradient { data_handle, .. } => {
1179 data_handle.uid()
1180 }
1181 PrimitiveInstanceKind::TextRun { data_handle, .. } => {
1182 data_handle.uid()
1183 }
1184 PrimitiveInstanceKind::YuvImage { data_handle, .. } => {
1185 data_handle.uid()
1186 }
1187 PrimitiveInstanceKind::BackdropCapture { data_handle, .. } => {
1188 data_handle.uid()
1189 }
1190 PrimitiveInstanceKind::BackdropRender { data_handle, .. } => {
1191 data_handle.uid()
1192 }
1193 PrimitiveInstanceKind::BoxShadow { data_handle, .. } => {
1194 data_handle.uid()
1195 }
1196 }
1197 }
1198}
1199
1200#[cfg_attr(feature = "capture", derive(Serialize))]
1201#[derive(Debug)]
1202pub struct SegmentedInstance {
1203 pub gpu_cache_handle: GpuCacheHandle,
1204 pub segments_range: SegmentsRange,
1205}
1206
1207pub type GlyphKeyStorage = storage::Storage<GlyphKey>;
1208pub type TextRunIndex = storage::Index<TextRunPrimitive>;
1209pub type TextRunStorage = storage::Storage<TextRunPrimitive>;
1210pub type ColorBindingIndex = storage::Index<PropertyBinding<ColorU>>;
1211pub type ColorBindingStorage = storage::Storage<PropertyBinding<ColorU>>;
1212pub type BorderHandleStorage = storage::Storage<RenderTaskId>;
1213pub type SegmentStorage = storage::Storage<BrushSegment>;
1214pub type SegmentsRange = storage::Range<BrushSegment>;
1215pub type SegmentInstanceStorage = storage::Storage<SegmentedInstance>;
1216pub type SegmentInstanceIndex = storage::Index<SegmentedInstance>;
1217pub type ImageInstanceStorage = storage::Storage<ImageInstance>;
1218pub type ImageInstanceIndex = storage::Index<ImageInstance>;
1219pub type GradientTileStorage = storage::Storage<VisibleGradientTile>;
1220pub type GradientTileRange = storage::Range<VisibleGradientTile>;
1221pub type LinearGradientStorage = storage::Storage<LinearGradientPrimitive>;
1222
1223#[cfg_attr(feature = "capture", derive(Serialize))]
1228pub struct PrimitiveScratchBuffer {
1229 pub clip_mask_instances: Vec<ClipMaskKind>,
1232
1233 pub glyph_keys: GlyphKeyStorage,
1236
1237 pub border_cache_handles: BorderHandleStorage,
1240
1241 pub segments: SegmentStorage,
1243
1244 pub segment_instances: SegmentInstanceStorage,
1248
1249 pub gradient_tiles: GradientTileStorage,
1252
1253 pub debug_items: Vec<DebugItem>,
1255
1256 messages: Vec<DebugMessage>,
1258
1259 pub required_sub_graphs: FastHashSet<PictureIndex>,
1261
1262 pub quad_direct_segments: Vec<QuadSegment>,
1264 pub quad_color_segments: Vec<QuadSegment>,
1265 pub quad_indirect_segments: Vec<QuadSegment>,
1266
1267 pub quad_tile_classifier: QuadTileClassifier,
1270}
1271
1272impl Default for PrimitiveScratchBuffer {
1273 fn default() -> Self {
1274 PrimitiveScratchBuffer {
1275 clip_mask_instances: Vec::new(),
1276 glyph_keys: GlyphKeyStorage::new(0),
1277 border_cache_handles: BorderHandleStorage::new(0),
1278 segments: SegmentStorage::new(0),
1279 segment_instances: SegmentInstanceStorage::new(0),
1280 gradient_tiles: GradientTileStorage::new(0),
1281 debug_items: Vec::new(),
1282 messages: Vec::new(),
1283 required_sub_graphs: FastHashSet::default(),
1284 quad_direct_segments: Vec::new(),
1285 quad_color_segments: Vec::new(),
1286 quad_indirect_segments: Vec::new(),
1287 quad_tile_classifier: QuadTileClassifier::new(),
1288 }
1289 }
1290}
1291
1292impl PrimitiveScratchBuffer {
1293 pub fn recycle(&mut self, recycler: &mut Recycler) {
1294 recycler.recycle_vec(&mut self.clip_mask_instances);
1295 self.glyph_keys.recycle(recycler);
1296 self.border_cache_handles.recycle(recycler);
1297 self.segments.recycle(recycler);
1298 self.segment_instances.recycle(recycler);
1299 self.gradient_tiles.recycle(recycler);
1300 recycler.recycle_vec(&mut self.debug_items);
1301 recycler.recycle_vec(&mut self.quad_direct_segments);
1302 recycler.recycle_vec(&mut self.quad_color_segments);
1303 recycler.recycle_vec(&mut self.quad_indirect_segments);
1304 }
1305
1306 pub fn begin_frame(&mut self) {
1307 self.clip_mask_instances.clear();
1311 self.clip_mask_instances.push(ClipMaskKind::None);
1312 self.quad_direct_segments.clear();
1313 self.quad_color_segments.clear();
1314 self.quad_indirect_segments.clear();
1315
1316 self.border_cache_handles.clear();
1317
1318 self.gradient_tiles.clear();
1323
1324 self.required_sub_graphs.clear();
1325
1326 self.debug_items.clear();
1327 }
1328
1329 pub fn end_frame(&mut self) {
1330 const MSGS_TO_RETAIN: usize = 32;
1331 const TIME_TO_RETAIN: u64 = 2000000000;
1332 const LINE_HEIGHT: f32 = 20.0;
1333 const X0: f32 = 32.0;
1334 const Y0: f32 = 32.0;
1335 let now = api::precise_time_ns();
1336
1337 let msgs_to_remove = self.messages.len().max(MSGS_TO_RETAIN) - MSGS_TO_RETAIN;
1338 let mut msgs_removed = 0;
1339
1340 self.messages.retain(|msg| {
1341 if msgs_removed < msgs_to_remove {
1342 msgs_removed += 1;
1343 return false;
1344 }
1345
1346 if msg.timestamp + TIME_TO_RETAIN < now {
1347 return false;
1348 }
1349
1350 true
1351 });
1352
1353 let mut y = Y0 + self.messages.len() as f32 * LINE_HEIGHT;
1354 let shadow_offset = 1.0;
1355
1356 for msg in &self.messages {
1357 self.debug_items.push(DebugItem::Text {
1358 position: DevicePoint::new(X0 + shadow_offset, y + shadow_offset),
1359 color: debug_colors::BLACK,
1360 msg: msg.msg.clone(),
1361 });
1362
1363 self.debug_items.push(DebugItem::Text {
1364 position: DevicePoint::new(X0, y),
1365 color: debug_colors::RED,
1366 msg: msg.msg.clone(),
1367 });
1368
1369 y -= LINE_HEIGHT;
1370 }
1371 }
1372
1373 pub fn push_debug_rect_with_stroke_width(
1374 &mut self,
1375 rect: WorldRect,
1376 border: ColorF,
1377 stroke_width: f32
1378 ) {
1379 let top_edge = WorldRect::new(
1380 WorldPoint::new(rect.min.x + stroke_width, rect.min.y),
1381 WorldPoint::new(rect.max.x - stroke_width, rect.min.y + stroke_width)
1382 );
1383 self.push_debug_rect(top_edge * DevicePixelScale::new(1.0), 1, border, border);
1384
1385 let bottom_edge = WorldRect::new(
1386 WorldPoint::new(rect.min.x + stroke_width, rect.max.y - stroke_width),
1387 WorldPoint::new(rect.max.x - stroke_width, rect.max.y)
1388 );
1389 self.push_debug_rect(bottom_edge * DevicePixelScale::new(1.0), 1, border, border);
1390
1391 let right_edge = WorldRect::new(
1392 WorldPoint::new(rect.max.x - stroke_width, rect.min.y),
1393 rect.max
1394 );
1395 self.push_debug_rect(right_edge * DevicePixelScale::new(1.0), 1, border, border);
1396
1397 let left_edge = WorldRect::new(
1398 rect.min,
1399 WorldPoint::new(rect.min.x + stroke_width, rect.max.y)
1400 );
1401 self.push_debug_rect(left_edge * DevicePixelScale::new(1.0), 1, border, border);
1402 }
1403
1404 #[allow(dead_code)]
1405 pub fn push_debug_rect(
1406 &mut self,
1407 rect: DeviceRect,
1408 thickness: i32,
1409 outer_color: ColorF,
1410 inner_color: ColorF,
1411 ) {
1412 self.debug_items.push(DebugItem::Rect {
1413 rect,
1414 outer_color,
1415 inner_color,
1416 thickness,
1417 });
1418 }
1419
1420 #[allow(dead_code)]
1421 pub fn push_debug_string(
1422 &mut self,
1423 position: DevicePoint,
1424 color: ColorF,
1425 msg: String,
1426 ) {
1427 self.debug_items.push(DebugItem::Text {
1428 position,
1429 color,
1430 msg,
1431 });
1432 }
1433
1434 #[allow(dead_code)]
1435 pub fn log(
1436 &mut self,
1437 msg: String,
1438 ) {
1439 self.messages.push(DebugMessage {
1440 msg,
1441 timestamp: api::precise_time_ns(),
1442 })
1443 }
1444}
1445
1446#[cfg_attr(feature = "capture", derive(Serialize))]
1447#[cfg_attr(feature = "replay", derive(Deserialize))]
1448#[derive(Clone, Debug)]
1449pub struct PrimitiveStoreStats {
1450 picture_count: usize,
1451 text_run_count: usize,
1452 image_count: usize,
1453 linear_gradient_count: usize,
1454 color_binding_count: usize,
1455}
1456
1457impl PrimitiveStoreStats {
1458 pub fn empty() -> Self {
1459 PrimitiveStoreStats {
1460 picture_count: 0,
1461 text_run_count: 0,
1462 image_count: 0,
1463 linear_gradient_count: 0,
1464 color_binding_count: 0,
1465 }
1466 }
1467}
1468
1469#[cfg_attr(feature = "capture", derive(Serialize))]
1470pub struct PrimitiveStore {
1471 pub pictures: Vec<PicturePrimitive>,
1472 pub text_runs: TextRunStorage,
1473 pub linear_gradients: LinearGradientStorage,
1474
1475 pub images: ImageInstanceStorage,
1479
1480 pub color_bindings: ColorBindingStorage,
1482}
1483
1484impl PrimitiveStore {
1485 pub fn new(stats: &PrimitiveStoreStats) -> PrimitiveStore {
1486 PrimitiveStore {
1487 pictures: Vec::with_capacity(stats.picture_count),
1488 text_runs: TextRunStorage::new(stats.text_run_count),
1489 images: ImageInstanceStorage::new(stats.image_count),
1490 color_bindings: ColorBindingStorage::new(stats.color_binding_count),
1491 linear_gradients: LinearGradientStorage::new(stats.linear_gradient_count),
1492 }
1493 }
1494
1495 pub fn reset(&mut self) {
1496 self.pictures.clear();
1497 self.text_runs.clear();
1498 self.images.clear();
1499 self.color_bindings.clear();
1500 self.linear_gradients.clear();
1501 }
1502
1503 pub fn get_stats(&self) -> PrimitiveStoreStats {
1504 PrimitiveStoreStats {
1505 picture_count: self.pictures.len(),
1506 text_run_count: self.text_runs.len(),
1507 image_count: self.images.len(),
1508 linear_gradient_count: self.linear_gradients.len(),
1509 color_binding_count: self.color_bindings.len(),
1510 }
1511 }
1512
1513 #[allow(unused)]
1514 pub fn print_picture_tree(&self, root: PictureIndex) {
1515 use crate::print_tree::PrintTree;
1516 let mut pt = PrintTree::new("picture tree");
1517 self.pictures[root.0].print(&self.pictures, root, &mut pt);
1518 }
1519}
1520
1521impl Default for PrimitiveStore {
1522 fn default() -> Self {
1523 PrimitiveStore::new(&PrimitiveStoreStats::empty())
1524 }
1525}
1526
1527pub trait InternablePrimitive: intern::Internable<InternData = ()> + Sized {
1530 fn into_key(
1532 self,
1533 info: &LayoutPrimitiveInfo,
1534 ) -> Self::Key;
1535
1536 fn make_instance_kind(
1537 key: Self::Key,
1538 data_handle: intern::Handle<Self>,
1539 prim_store: &mut PrimitiveStore,
1540 ) -> PrimitiveInstanceKind;
1541}
1542
1543
1544#[test]
1545#[cfg(target_pointer_width = "64")]
1546fn test_struct_sizes() {
1547 use std::mem;
1548 assert_eq!(mem::size_of::<PrimitiveInstance>(), 88, "PrimitiveInstance size changed");
1555 assert_eq!(mem::size_of::<PrimitiveInstanceKind>(), 24, "PrimitiveInstanceKind size changed");
1556 assert_eq!(mem::size_of::<PrimitiveTemplate>(), 56, "PrimitiveTemplate size changed");
1557 assert_eq!(mem::size_of::<PrimitiveTemplateKind>(), 28, "PrimitiveTemplateKind size changed");
1558 assert_eq!(mem::size_of::<PrimitiveKey>(), 36, "PrimitiveKey size changed");
1559 assert_eq!(mem::size_of::<PrimitiveKeyKind>(), 16, "PrimitiveKeyKind size changed");
1560}