1use std::sync::Arc;
13
14use inset_embedder::{Offset, Size, Surface};
15use inset_foundation::App;
16
17use crate::box_::{BoxConstraints, RenderBox, RenderBoxData};
18use crate::layer::{ErasedLayer, SurfaceLayer};
19use crate::object::{RenderHandle, RenderObject, RenderObjectData};
20use crate::painting_context::PaintingContext;
21
22pub struct RenderSurfaceView {
24 render_object: RenderObjectData,
25 render_box: RenderBoxData,
26 surface: Arc<dyn Surface>,
27}
28
29impl RenderSurfaceView {
30 pub fn new(app: &mut App, surface: Arc<dyn Surface>) -> RenderHandle<RenderSurfaceView> {
31 RenderHandle::new_box(
32 app,
33 RenderSurfaceView {
34 render_object: RenderObjectData::new(),
35 render_box: RenderBoxData::new(),
36 surface,
37 },
38 )
39 }
40
41 pub fn surface(self: RenderHandle<Self>, app: &App) -> &Arc<dyn Surface> {
43 &self.get(app).surface
44 }
45
46 pub fn set_surface(self: RenderHandle<Self>, app: &mut App, surface: Arc<dyn Surface>) {
48 if Arc::ptr_eq(&self.get(app).surface, &surface) {
49 return;
50 }
51 self.get_mut(app).surface = surface;
52 self.mark_needs_paint(app);
53 }
54}
55
56impl RenderObject for RenderSurfaceView {
57 crate::render_object_accessors!();
58
59 fn always_needs_compositing(self: RenderHandle<Self>, _app: &App) -> bool {
60 true
61 }
62
63 fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
64 let size = self.constraints(app).biggest();
65 self.set_size(app, size);
66 }
67
68 fn paint(
71 self: RenderHandle<Self>,
72 app: &mut App,
73 context: &mut PaintingContext,
74 offset: Offset,
75 ) {
76 let surface = Arc::clone(&self.get(app).surface);
77 let layer = SurfaceLayer::new(app, surface, offset & self.size(app));
78 context.add_layer(app, layer.as_layer());
79 }
80}
81
82impl RenderBox for RenderSurfaceView {
83 crate::render_box_accessors!();
84
85 fn compute_dry_layout(
86 self: RenderHandle<Self>,
87 _app: &mut App,
88 constraints: BoxConstraints,
89 ) -> Size {
90 constraints.biggest()
91 }
92
93 fn hit_test_self(self: RenderHandle<Self>, _app: &App, _position: Offset) -> bool {
95 true
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use inset_embedder::test_support::idle_surface;
102 use inset_embedder::{Clip, Matrix4, Mutator, Part, Rect, SceneBuilder};
103 use inset_foundation::{AppCell, Handle};
104
105 use super::*;
106 use crate::layer::{ContainerLayer, OffsetLayer};
107 use crate::object::AnyRenderObject;
108 use crate::pipeline_owner::PipelineOwner;
109
110 const CHILD_OFFSET: Offset = Offset::new(10.0, 5.0);
112
113 struct Parent {
115 render_object: RenderObjectData,
116 render_box: RenderBoxData,
117 child: RenderHandle<RenderSurfaceView>,
118 painting: ChildPainting,
119 }
120
121 #[derive(Clone, Copy)]
123 enum ChildPainting {
124 AtOffset,
126 HalvedUnderAClip,
128 }
129
130 impl RenderObject for Parent {
131 crate::render_object_accessors!();
132
133 fn is_repaint_boundary(self: RenderHandle<Self>, _app: &App) -> bool {
135 true
136 }
137
138 fn perform_layout(self: RenderHandle<Self>, app: &mut App) {
139 let child = self.get(app).child;
140 child.layout(app, BoxConstraints::tight(Size::new(30.0, 20.0)), false);
141 self.set_size(app, Size::new(100.0, 100.0));
142 }
143
144 fn visit_children(
145 self: RenderHandle<Self>,
146 app: &App,
147 visitor: &mut dyn FnMut(AnyRenderObject),
148 ) {
149 visitor(self.get(app).child.as_object());
150 }
151
152 fn paint(
153 self: RenderHandle<Self>,
154 app: &mut App,
155 context: &mut PaintingContext,
156 offset: Offset,
157 ) {
158 let child = self.get(app).child.as_object();
159 match self.get(app).painting {
160 ChildPainting::AtOffset => context.paint_child(app, child, offset + CHILD_OFFSET),
161 ChildPainting::HalvedUnderAClip => {
162 let needs_compositing = self.as_object().needs_compositing(app);
163 context.push_clip_rect(
164 app,
165 needs_compositing,
166 offset,
167 Rect::from_ltwh(0.0, 0.0, 100.0, 10.0),
168 |app, context, offset| {
169 context.push_transform(
170 app,
171 needs_compositing,
172 offset + CHILD_OFFSET,
173 Matrix4::scale(0.5, 0.5),
174 |app, context, offset| context.paint_child(app, child, offset),
175 None,
176 );
177 },
178 Clip::HardEdge,
179 None,
180 );
181 }
182 }
183 }
184 }
185
186 impl RenderBox for Parent {
187 crate::render_box_accessors!();
188 }
189
190 fn scene_of_one_frame(
193 app: &mut App,
194 surface: Arc<dyn Surface>,
195 painting: ChildPainting,
196 ) -> (inset_embedder::Scene, Handle<PipelineOwner>) {
197 let owner = PipelineOwner::new(app, None, None);
198 let child = RenderSurfaceView::new(app, surface);
199 let parent = RenderHandle::new_box(
200 app,
201 Parent {
202 render_object: RenderObjectData::new(),
203 render_box: RenderBoxData::new(),
204 child,
205 painting,
206 },
207 );
208 parent.adopt_child(app, child.as_object());
209 owner.set_root_node(app, Some(parent.as_object()));
210 parent.schedule_initial_layout(app);
211 let root = OffsetLayer::new(app, Offset::ZERO);
212 root.as_layer().attach(app, parent.as_object().id());
213 parent
214 .as_object()
215 .schedule_initial_paint(app, root.as_container_layer());
216 owner.flush_layout(app);
217 owner.flush_compositing_bits(app);
218 owner.flush_paint(app);
219 let scene = root
220 .as_container_layer()
221 .build_scene(app, SceneBuilder::new());
222 (scene, owner)
223 }
224
225 #[test]
226 fn the_box_is_placed_and_nothing_is_painted() {
227 let cell = AppCell::new();
228 let mut app = cell.borrow_mut();
229 let surface = idle_surface();
230 let (scene, _owner) =
231 scene_of_one_frame(&mut app, Arc::clone(&surface), ChildPainting::AtOffset);
232 let slices = inset_embedder::slices(&scene);
233 let [Part::Surface(placement)] = slices.parts() else {
234 panic!("the surface alone: {:?}", slices.parts());
235 };
236 assert!(Arc::ptr_eq(&placement.surface, &surface));
237 let placed = Rect::from_ltwh(10.0, 5.0, 30.0, 20.0);
238 assert_eq!(placement.bounds(), placed);
239 assert_eq!(placement.visible_bounds(), placed);
240 assert!(!slices.paints());
241 }
242
243 #[test]
246 fn a_surface_is_placed_under_the_transform_and_the_clip_above_it() {
247 let cell = AppCell::new();
248 let mut app = cell.borrow_mut();
249 let (scene, _owner) =
250 scene_of_one_frame(&mut app, idle_surface(), ChildPainting::HalvedUnderAClip);
251 let placement = inset_embedder::slices(&scene)
252 .surfaces()
253 .next()
254 .cloned()
255 .expect("placed");
256 assert!(
257 placement
258 .mutators
259 .contains(&Mutator::ClipRect(Rect::from_ltwh(0.0, 0.0, 100.0, 10.0)))
260 );
261 assert_eq!(placement.scale(), 0.5);
262 assert_eq!(placement.bounds(), Rect::from_ltwh(10.0, 5.0, 15.0, 10.0));
263 assert_eq!(
264 placement.visible_bounds(),
265 Rect::from_ltrb(10.0, 5.0, 25.0, 10.0)
266 );
267 }
268}