1use crate::{
2 image_cache::RenderImageParams, px, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
3 BorrowAppContext, Bounds, Context, Corners, DevicePixels, Effect, Element, EntityId, FontId,
4 GlyphId, Handle, Hsla, ImageData, IsZero, LayerId, LayoutId, MainThread, MainThreadOnly,
5 MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Reference,
6 RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene, SharedString, Size, Style,
7 TaffyLayoutEngine, Task, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
8};
9use anyhow::Result;
10use smallvec::SmallVec;
11use std::{any::TypeId, borrow::Cow, future::Future, marker::PhantomData, mem, sync::Arc};
12use util::ResultExt;
13
14pub struct AnyWindow {}
15
16pub struct Window {
17 handle: AnyWindowHandle,
18 platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
19 sprite_atlas: Arc<dyn PlatformAtlas>,
20 rem_size: Pixels,
21 content_size: Size<Pixels>,
22 layout_engine: TaffyLayoutEngine,
23 pub(crate) root_view: Option<AnyView<()>>,
24 mouse_position: Point<Pixels>,
25 current_layer_id: LayerId,
26 content_mask_stack: Vec<ContentMask>,
27 pub(crate) scene: Scene,
28 pub(crate) dirty: bool,
29}
30
31impl Window {
32 pub fn new(
33 handle: AnyWindowHandle,
34 options: WindowOptions,
35 cx: &mut MainThread<AppContext>,
36 ) -> Self {
37 let platform_window = cx.platform().open_window(handle, options);
38 let sprite_atlas = platform_window.sprite_atlas();
39 let mouse_position = platform_window.mouse_position();
40 let content_size = platform_window.content_size();
41 let scale_factor = platform_window.scale_factor();
42 platform_window.on_resize(Box::new({
43 let handle = handle;
44 let cx = cx.to_async();
45 move |content_size, scale_factor| {
46 cx.update_window(handle, |cx| {
47 cx.window.scene = Scene::new(scale_factor);
48 cx.window.content_size = content_size;
49 cx.window.dirty = true;
50 })
51 .log_err();
52 }
53 }));
54
55 let platform_window = MainThreadOnly::new(Arc::new(platform_window), cx.executor.clone());
56
57 Window {
58 handle,
59 platform_window,
60 sprite_atlas,
61 rem_size: px(16.),
62 content_size,
63 layout_engine: TaffyLayoutEngine::new(),
64 root_view: None,
65 mouse_position,
66 current_layer_id: SmallVec::new(),
67 content_mask_stack: Vec::new(),
68 scene: Scene::new(scale_factor),
69 dirty: true,
70 }
71 }
72}
73
74#[derive(Clone, Debug)]
75pub struct ContentMask {
76 pub bounds: Bounds<Pixels>,
77}
78
79impl ContentMask {
80 pub fn scale(&self, factor: f32) -> ScaledContentMask {
81 ScaledContentMask {
82 bounds: self.bounds.scale(factor),
83 }
84 }
85
86 pub fn intersect(&self, other: &Self) -> Self {
87 let bounds = self.bounds.intersect(&other.bounds);
88 ContentMask { bounds }
89 }
90}
91
92#[derive(Clone, Debug, PartialEq, Eq)]
93#[repr(C)]
94pub struct ScaledContentMask {
95 bounds: Bounds<ScaledPixels>,
96}
97
98pub struct WindowContext<'a, 'w> {
99 app: Reference<'a, AppContext>,
100 window: Reference<'w, Window>,
101}
102
103impl<'a, 'w> WindowContext<'a, 'w> {
104 pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window) -> Self {
105 Self {
106 app: Reference::Mutable(app),
107 window: Reference::Mutable(window),
108 }
109 }
110
111 pub fn notify(&mut self) {
112 self.window.dirty = true;
113 }
114
115 pub fn run_on_main<R>(
116 &mut self,
117 f: impl FnOnce(&mut MainThread<WindowContext<'_, '_>>) -> R + Send + 'static,
118 ) -> Task<Result<R>>
119 where
120 R: Send + 'static,
121 {
122 if self.executor.is_main_thread() {
123 Task::ready(Ok(f(unsafe {
124 mem::transmute::<&mut Self, &mut MainThread<Self>>(self)
125 })))
126 } else {
127 let id = self.window.handle.id;
128 self.app.run_on_main(move |cx| cx.update_window(id, f))
129 }
130 }
131
132 pub fn to_async(&self) -> AsyncWindowContext {
133 AsyncWindowContext::new(self.app.to_async(), self.window.handle)
134 }
135
136 pub fn spawn<Fut, R>(
137 &mut self,
138 f: impl FnOnce(AnyWindowHandle, AsyncWindowContext) -> Fut + Send + 'static,
139 ) -> Task<R>
140 where
141 R: Send + 'static,
142 Fut: Future<Output = R> + Send + 'static,
143 {
144 let window = self.window.handle;
145 self.app.spawn(move |app| {
146 let cx = AsyncWindowContext::new(app, window);
147 let future = f(window, cx);
148 async move { future.await }
149 })
150 }
151
152 pub fn request_layout(
153 &mut self,
154 style: Style,
155 children: impl IntoIterator<Item = LayoutId>,
156 ) -> Result<LayoutId> {
157 self.app.layout_id_buffer.clear();
158 self.app.layout_id_buffer.extend(children.into_iter());
159 let rem_size = self.rem_size();
160
161 self.window
162 .layout_engine
163 .request_layout(style, rem_size, &self.app.layout_id_buffer)
164 }
165
166 pub fn request_measured_layout<
167 F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>) -> Size<Pixels> + Send + Sync + 'static,
168 >(
169 &mut self,
170 style: Style,
171 rem_size: Pixels,
172 measure: F,
173 ) -> Result<LayoutId> {
174 self.window
175 .layout_engine
176 .request_measured_layout(style, rem_size, measure)
177 }
178
179 pub fn layout(&mut self, layout_id: LayoutId) -> Result<Layout> {
180 Ok(self
181 .window
182 .layout_engine
183 .layout(layout_id)
184 .map(Into::into)?)
185 }
186
187 pub fn scale_factor(&self) -> f32 {
188 self.window.scene.scale_factor
189 }
190
191 pub fn rem_size(&self) -> Pixels {
192 self.window.rem_size
193 }
194
195 pub fn mouse_position(&self) -> Point<Pixels> {
196 self.window.mouse_position
197 }
198
199 pub fn scene(&mut self) -> &mut Scene {
200 &mut self.window.scene
201 }
202
203 pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
204 self.window.current_layer_id.push(order);
205 let result = f(self);
206 self.window.current_layer_id.pop();
207 result
208 }
209
210 pub fn current_layer_id(&self) -> LayerId {
211 self.window.current_layer_id.clone()
212 }
213
214 pub fn paint_glyph(
215 &mut self,
216 origin: Point<Pixels>,
217 order: u32,
218 font_id: FontId,
219 glyph_id: GlyphId,
220 font_size: Pixels,
221 color: Hsla,
222 ) -> Result<()> {
223 let scale_factor = self.scale_factor();
224 let glyph_origin = origin.scale(scale_factor);
225 let subpixel_variant = Point {
226 x: (glyph_origin.x.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
227 y: (glyph_origin.y.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
228 };
229 let params = RenderGlyphParams {
230 font_id,
231 glyph_id,
232 font_size,
233 subpixel_variant,
234 scale_factor,
235 is_emoji: false,
236 };
237
238 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
239 if !raster_bounds.is_zero() {
240 let layer_id = self.current_layer_id();
241 let tile =
242 self.window
243 .sprite_atlas
244 .get_or_insert_with(¶ms.clone().into(), &mut || {
245 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
246 Ok((size, Cow::Owned(bytes)))
247 })?;
248 let bounds = Bounds {
249 origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
250 size: tile.bounds.size.map(Into::into),
251 };
252 let content_mask = self.content_mask().scale(scale_factor);
253
254 self.window.scene.insert(
255 layer_id,
256 MonochromeSprite {
257 order,
258 bounds,
259 content_mask,
260 color,
261 tile,
262 },
263 );
264 }
265 Ok(())
266 }
267
268 pub fn paint_emoji(
269 &mut self,
270 origin: Point<Pixels>,
271 order: u32,
272 font_id: FontId,
273 glyph_id: GlyphId,
274 font_size: Pixels,
275 ) -> Result<()> {
276 let scale_factor = self.scale_factor();
277 let glyph_origin = origin.scale(scale_factor);
278 let params = RenderGlyphParams {
279 font_id,
280 glyph_id,
281 font_size,
282 // We don't render emojis with subpixel variants.
283 subpixel_variant: Default::default(),
284 scale_factor,
285 is_emoji: true,
286 };
287
288 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
289 if !raster_bounds.is_zero() {
290 let layer_id = self.current_layer_id();
291 let tile =
292 self.window
293 .sprite_atlas
294 .get_or_insert_with(¶ms.clone().into(), &mut || {
295 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
296 Ok((size, Cow::Owned(bytes)))
297 })?;
298 let bounds = Bounds {
299 origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
300 size: tile.bounds.size.map(Into::into),
301 };
302 let content_mask = self.content_mask().scale(scale_factor);
303
304 self.window.scene.insert(
305 layer_id,
306 PolychromeSprite {
307 order,
308 bounds,
309 corner_radii: Default::default(),
310 content_mask,
311 tile,
312 grayscale: false,
313 },
314 );
315 }
316 Ok(())
317 }
318
319 pub fn paint_svg(
320 &mut self,
321 bounds: Bounds<Pixels>,
322 order: u32,
323 path: SharedString,
324 color: Hsla,
325 ) -> Result<()> {
326 let scale_factor = self.scale_factor();
327 let bounds = bounds.scale(scale_factor);
328 // Render the SVG at twice the size to get a higher quality result.
329 let params = RenderSvgParams {
330 path,
331 size: bounds
332 .size
333 .map(|pixels| DevicePixels::from((pixels.0 * 2.).ceil() as i32)),
334 };
335
336 let layer_id = self.current_layer_id();
337 let tile =
338 self.window
339 .sprite_atlas
340 .get_or_insert_with(¶ms.clone().into(), &mut || {
341 let bytes = self.svg_renderer.render(¶ms)?;
342 Ok((params.size, Cow::Owned(bytes)))
343 })?;
344 let content_mask = self.content_mask().scale(scale_factor);
345
346 self.window.scene.insert(
347 layer_id,
348 MonochromeSprite {
349 order,
350 bounds,
351 content_mask,
352 color,
353 tile,
354 },
355 );
356
357 Ok(())
358 }
359
360 pub fn paint_image(
361 &mut self,
362 bounds: Bounds<Pixels>,
363 corner_radii: Corners<Pixels>,
364 order: u32,
365 data: Arc<ImageData>,
366 grayscale: bool,
367 ) -> Result<()> {
368 let scale_factor = self.scale_factor();
369 let bounds = bounds.scale(scale_factor);
370 let params = RenderImageParams { image_id: data.id };
371
372 let layer_id = self.current_layer_id();
373 let tile = self
374 .window
375 .sprite_atlas
376 .get_or_insert_with(¶ms.clone().into(), &mut || {
377 Ok((data.size(), Cow::Borrowed(data.as_bytes())))
378 })?;
379 let content_mask = self.content_mask().scale(scale_factor);
380 let corner_radii = corner_radii.scale(scale_factor);
381
382 self.window.scene.insert(
383 layer_id,
384 PolychromeSprite {
385 order,
386 bounds,
387 content_mask,
388 corner_radii,
389 tile,
390 grayscale,
391 },
392 );
393
394 Ok(())
395 }
396
397 pub(crate) fn draw(&mut self) -> Result<()> {
398 let unit_entity = self.unit_entity.clone();
399 self.update_entity(&unit_entity, |view, cx| {
400 let mut root_view = cx.window.root_view.take().unwrap();
401 let (root_layout_id, mut frame_state) = root_view.layout(&mut (), cx)?;
402 let available_space = cx.window.content_size.map(Into::into);
403
404 let started_at = std::time::Instant::now();
405 cx.window
406 .layout_engine
407 .compute_layout(root_layout_id, available_space)?;
408 println!("compute_layout took {:?}", started_at.elapsed());
409 let layout = cx.window.layout_engine.layout(root_layout_id)?;
410
411 root_view.paint(layout, &mut (), &mut frame_state, cx)?;
412 cx.window.root_view = Some(root_view);
413 let scene = cx.window.scene.take();
414
415 cx.run_on_main(view, |_, cx| {
416 cx.window
417 .platform_window
418 .borrow_on_main_thread()
419 .draw(scene);
420 cx.window.dirty = false;
421 })
422 .detach();
423
424 Ok(())
425 })
426 }
427}
428
429impl Context for WindowContext<'_, '_> {
430 type EntityContext<'a, 'w, T: 'static + Send + Sync> = ViewContext<'a, 'w, T>;
431 type Result<T> = T;
432
433 fn entity<T: Send + Sync + 'static>(
434 &mut self,
435 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
436 ) -> Handle<T> {
437 let slot = self.app.entities.reserve();
438 let entity = build_entity(&mut ViewContext::mutable(
439 &mut *self.app,
440 &mut self.window,
441 slot.id,
442 ));
443 self.entities.insert(slot, entity)
444 }
445
446 fn update_entity<T: Send + Sync + 'static, R>(
447 &mut self,
448 handle: &Handle<T>,
449 update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
450 ) -> R {
451 let mut entity = self.entities.lease(handle);
452 let result = update(
453 &mut *entity,
454 &mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.id),
455 );
456 self.entities.end_lease(entity);
457 result
458 }
459}
460
461impl<'a, 'w> std::ops::Deref for WindowContext<'a, 'w> {
462 type Target = AppContext;
463
464 fn deref(&self) -> &Self::Target {
465 &self.app
466 }
467}
468
469impl<'a, 'w> std::ops::DerefMut for WindowContext<'a, 'w> {
470 fn deref_mut(&mut self) -> &mut Self::Target {
471 &mut self.app
472 }
473}
474
475impl BorrowAppContext for WindowContext<'_, '_> {
476 fn app_mut(&mut self) -> &mut AppContext {
477 &mut *self.app
478 }
479}
480
481pub trait BorrowWindow: BorrowAppContext {
482 fn window(&self) -> &Window;
483 fn window_mut(&mut self) -> &mut Window;
484
485 fn with_content_mask<R>(&mut self, mask: ContentMask, f: impl FnOnce(&mut Self) -> R) -> R {
486 let mask = mask.intersect(&self.content_mask());
487 self.window_mut().content_mask_stack.push(mask);
488 let result = f(self);
489 self.window_mut().content_mask_stack.pop();
490 result
491 }
492
493 fn content_mask(&self) -> ContentMask {
494 self.window()
495 .content_mask_stack
496 .last()
497 .cloned()
498 .unwrap_or_else(|| ContentMask {
499 bounds: Bounds {
500 origin: Point::default(),
501 size: self.window().content_size,
502 },
503 })
504 }
505
506 fn rem_size(&self) -> Pixels {
507 self.window().rem_size
508 }
509}
510
511impl BorrowWindow for WindowContext<'_, '_> {
512 fn window(&self) -> &Window {
513 &*self.window
514 }
515
516 fn window_mut(&mut self) -> &mut Window {
517 &mut *self.window
518 }
519}
520
521pub struct ViewContext<'a, 'w, S> {
522 window_cx: WindowContext<'a, 'w>,
523 entity_type: PhantomData<S>,
524 entity_id: EntityId,
525}
526
527impl<S> BorrowAppContext for ViewContext<'_, '_, S> {
528 fn app_mut(&mut self) -> &mut AppContext {
529 &mut *self.window_cx.app
530 }
531
532 fn with_text_style<F, R>(&mut self, style: crate::TextStyleRefinement, f: F) -> R
533 where
534 F: FnOnce(&mut Self) -> R,
535 {
536 self.window_cx.app.push_text_style(style);
537 let result = f(self);
538 self.window_cx.app.pop_text_style();
539 result
540 }
541
542 fn with_state<T: Send + Sync + 'static, F, R>(&mut self, state: T, f: F) -> R
543 where
544 F: FnOnce(&mut Self) -> R,
545 {
546 self.window_cx.app.push_state(state);
547 let result = f(self);
548 self.window_cx.app.pop_state::<T>();
549 result
550 }
551}
552
553impl<S> BorrowWindow for ViewContext<'_, '_, S> {
554 fn window(&self) -> &Window {
555 &self.window_cx.window
556 }
557
558 fn window_mut(&mut self) -> &mut Window {
559 &mut *self.window_cx.window
560 }
561}
562
563impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
564 fn mutable(app: &'a mut AppContext, window: &'w mut Window, entity_id: EntityId) -> Self {
565 Self {
566 window_cx: WindowContext::mutable(app, window),
567 entity_id,
568 entity_type: PhantomData,
569 }
570 }
571
572 pub fn handle(&self) -> WeakHandle<S> {
573 self.entities.weak_handle(self.entity_id)
574 }
575
576 pub fn observe<E: Send + Sync + 'static>(
577 &mut self,
578 handle: &Handle<E>,
579 on_notify: impl Fn(&mut S, Handle<E>, &mut ViewContext<'_, '_, S>) + Send + Sync + 'static,
580 ) {
581 let this = self.handle();
582 let handle = handle.downgrade();
583 let window_handle = self.window.handle;
584 self.app
585 .observers
586 .entry(handle.id)
587 .or_default()
588 .push(Arc::new(move |cx| {
589 cx.update_window(window_handle.id, |cx| {
590 if let Some(handle) = handle.upgrade(cx) {
591 this.update(cx, |this, cx| on_notify(this, handle, cx))
592 .is_ok()
593 } else {
594 false
595 }
596 })
597 .unwrap_or(false)
598 }));
599 }
600
601 pub fn notify(&mut self) {
602 self.window_cx.notify();
603 self.window_cx
604 .app
605 .pending_effects
606 .push_back(Effect::Notify(self.entity_id));
607 }
608
609 pub fn run_on_main<R>(
610 &mut self,
611 view: &mut S,
612 f: impl FnOnce(&mut S, &mut MainThread<ViewContext<'_, '_, S>>) -> R + Send + 'static,
613 ) -> Task<Result<R>>
614 where
615 R: Send + 'static,
616 {
617 if self.executor.is_main_thread() {
618 let cx = unsafe { mem::transmute::<&mut Self, &mut MainThread<Self>>(self) };
619 Task::ready(Ok(f(view, cx)))
620 } else {
621 let handle = self.handle().upgrade(self).unwrap();
622 self.window_cx.run_on_main(move |cx| handle.update(cx, f))
623 }
624 }
625
626 pub fn spawn<Fut, R>(
627 &mut self,
628 f: impl FnOnce(WeakHandle<S>, AsyncWindowContext) -> Fut + Send + 'static,
629 ) -> Task<R>
630 where
631 R: Send + 'static,
632 Fut: Future<Output = R> + Send + 'static,
633 {
634 let handle = self.handle();
635 self.window_cx.spawn(move |_, cx| {
636 let result = f(handle, cx);
637 async move { result.await }
638 })
639 }
640
641 pub(crate) fn erase_state<R>(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R {
642 let entity_id = self.unit_entity.id;
643 let mut cx = ViewContext::mutable(
644 &mut *self.window_cx.app,
645 &mut *self.window_cx.window,
646 entity_id,
647 );
648 f(&mut cx)
649 }
650}
651
652impl<'a, 'w, S> Context for ViewContext<'a, 'w, S> {
653 type EntityContext<'b, 'c, U: 'static + Send + Sync> = ViewContext<'b, 'c, U>;
654 type Result<U> = U;
655
656 fn entity<T2: Send + Sync + 'static>(
657 &mut self,
658 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T2>) -> T2,
659 ) -> Handle<T2> {
660 self.window_cx.entity(build_entity)
661 }
662
663 fn update_entity<U: Send + Sync + 'static, R>(
664 &mut self,
665 handle: &Handle<U>,
666 update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
667 ) -> R {
668 self.window_cx.update_entity(handle, update)
669 }
670}
671
672impl<'a, 'w, S: 'static> std::ops::Deref for ViewContext<'a, 'w, S> {
673 type Target = WindowContext<'a, 'w>;
674
675 fn deref(&self) -> &Self::Target {
676 &self.window_cx
677 }
678}
679
680impl<'a, 'w, S: 'static> std::ops::DerefMut for ViewContext<'a, 'w, S> {
681 fn deref_mut(&mut self) -> &mut Self::Target {
682 &mut self.window_cx
683 }
684}
685
686// #[derive(Clone, Copy, Eq, PartialEq, Hash)]
687slotmap::new_key_type! { pub struct WindowId; }
688
689#[derive(PartialEq, Eq)]
690pub struct WindowHandle<S> {
691 id: WindowId,
692 state_type: PhantomData<S>,
693}
694
695impl<S> Copy for WindowHandle<S> {}
696
697impl<S> Clone for WindowHandle<S> {
698 fn clone(&self) -> Self {
699 WindowHandle {
700 id: self.id,
701 state_type: PhantomData,
702 }
703 }
704}
705
706impl<S> WindowHandle<S> {
707 pub fn new(id: WindowId) -> Self {
708 WindowHandle {
709 id,
710 state_type: PhantomData,
711 }
712 }
713}
714
715impl<S: 'static> Into<AnyWindowHandle> for WindowHandle<S> {
716 fn into(self) -> AnyWindowHandle {
717 AnyWindowHandle {
718 id: self.id,
719 state_type: TypeId::of::<S>(),
720 }
721 }
722}
723
724#[derive(Copy, Clone, PartialEq, Eq)]
725pub struct AnyWindowHandle {
726 pub(crate) id: WindowId,
727 state_type: TypeId,
728}
729
730#[derive(Clone)]
731pub struct Layout {
732 pub order: u32,
733 pub bounds: Bounds<Pixels>,
734}