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 cx.window
405 .layout_engine
406 .compute_layout(root_layout_id, available_space)?;
407 let layout = cx.window.layout_engine.layout(root_layout_id)?;
408
409 root_view.paint(layout, &mut (), &mut frame_state, cx)?;
410 cx.window.root_view = Some(root_view);
411 let scene = cx.window.scene.take();
412
413 cx.run_on_main(view, |_, cx| {
414 cx.window
415 .platform_window
416 .borrow_on_main_thread()
417 .draw(scene);
418 cx.window.dirty = false;
419 })
420 .detach();
421
422 Ok(())
423 })
424 }
425}
426
427impl Context for WindowContext<'_, '_> {
428 type EntityContext<'a, 'w, T: 'static + Send + Sync> = ViewContext<'a, 'w, T>;
429 type Result<T> = T;
430
431 fn entity<T: Send + Sync + 'static>(
432 &mut self,
433 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
434 ) -> Handle<T> {
435 let slot = self.app.entities.reserve();
436 let entity = build_entity(&mut ViewContext::mutable(
437 &mut *self.app,
438 &mut self.window,
439 slot.id,
440 ));
441 self.entities.insert(slot, entity)
442 }
443
444 fn update_entity<T: Send + Sync + 'static, R>(
445 &mut self,
446 handle: &Handle<T>,
447 update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
448 ) -> R {
449 let mut entity = self.entities.lease(handle);
450 let result = update(
451 &mut *entity,
452 &mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.id),
453 );
454 self.entities.end_lease(entity);
455 result
456 }
457}
458
459impl<'a, 'w> std::ops::Deref for WindowContext<'a, 'w> {
460 type Target = AppContext;
461
462 fn deref(&self) -> &Self::Target {
463 &self.app
464 }
465}
466
467impl<'a, 'w> std::ops::DerefMut for WindowContext<'a, 'w> {
468 fn deref_mut(&mut self) -> &mut Self::Target {
469 &mut self.app
470 }
471}
472
473impl BorrowAppContext for WindowContext<'_, '_> {
474 fn app_mut(&mut self) -> &mut AppContext {
475 &mut *self.app
476 }
477}
478
479pub trait BorrowWindow: BorrowAppContext {
480 fn window(&self) -> &Window;
481 fn window_mut(&mut self) -> &mut Window;
482
483 fn with_content_mask<R>(&mut self, mask: ContentMask, f: impl FnOnce(&mut Self) -> R) -> R {
484 let mask = mask.intersect(&self.content_mask());
485 self.window_mut().content_mask_stack.push(mask);
486 let result = f(self);
487 self.window_mut().content_mask_stack.pop();
488 result
489 }
490
491 fn content_mask(&self) -> ContentMask {
492 self.window()
493 .content_mask_stack
494 .last()
495 .cloned()
496 .unwrap_or_else(|| ContentMask {
497 bounds: Bounds {
498 origin: Point::default(),
499 size: self.window().content_size,
500 },
501 })
502 }
503
504 fn rem_size(&self) -> Pixels {
505 self.window().rem_size
506 }
507}
508
509impl BorrowWindow for WindowContext<'_, '_> {
510 fn window(&self) -> &Window {
511 &*self.window
512 }
513
514 fn window_mut(&mut self) -> &mut Window {
515 &mut *self.window
516 }
517}
518
519pub struct ViewContext<'a, 'w, S> {
520 window_cx: WindowContext<'a, 'w>,
521 entity_type: PhantomData<S>,
522 entity_id: EntityId,
523}
524
525impl<S> BorrowAppContext for ViewContext<'_, '_, S> {
526 fn app_mut(&mut self) -> &mut AppContext {
527 &mut *self.window_cx.app
528 }
529
530 fn with_text_style<F, R>(&mut self, style: crate::TextStyleRefinement, f: F) -> R
531 where
532 F: FnOnce(&mut Self) -> R,
533 {
534 self.window_cx.app.push_text_style(style);
535 let result = f(self);
536 self.window_cx.app.pop_text_style();
537 result
538 }
539
540 fn with_state<T: Send + Sync + 'static, F, R>(&mut self, state: T, f: F) -> R
541 where
542 F: FnOnce(&mut Self) -> R,
543 {
544 self.window_cx.app.push_state(state);
545 let result = f(self);
546 self.window_cx.app.pop_state::<T>();
547 result
548 }
549}
550
551impl<S> BorrowWindow for ViewContext<'_, '_, S> {
552 fn window(&self) -> &Window {
553 &self.window_cx.window
554 }
555
556 fn window_mut(&mut self) -> &mut Window {
557 &mut *self.window_cx.window
558 }
559}
560
561impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
562 fn mutable(app: &'a mut AppContext, window: &'w mut Window, entity_id: EntityId) -> Self {
563 Self {
564 window_cx: WindowContext::mutable(app, window),
565 entity_id,
566 entity_type: PhantomData,
567 }
568 }
569
570 pub fn handle(&self) -> WeakHandle<S> {
571 self.entities.weak_handle(self.entity_id)
572 }
573
574 pub fn observe<E: Send + Sync + 'static>(
575 &mut self,
576 handle: &Handle<E>,
577 on_notify: impl Fn(&mut S, Handle<E>, &mut ViewContext<'_, '_, S>) + Send + Sync + 'static,
578 ) {
579 let this = self.handle();
580 let handle = handle.downgrade();
581 let window_handle = self.window.handle;
582 self.app
583 .observers
584 .entry(handle.id)
585 .or_default()
586 .push(Arc::new(move |cx| {
587 cx.update_window(window_handle.id, |cx| {
588 if let Some(handle) = handle.upgrade(cx) {
589 this.update(cx, |this, cx| on_notify(this, handle, cx))
590 .is_ok()
591 } else {
592 false
593 }
594 })
595 .unwrap_or(false)
596 }));
597 }
598
599 pub fn notify(&mut self) {
600 self.window_cx.notify();
601 self.window_cx
602 .app
603 .pending_effects
604 .push_back(Effect::Notify(self.entity_id));
605 }
606
607 pub fn run_on_main<R>(
608 &mut self,
609 view: &mut S,
610 f: impl FnOnce(&mut S, &mut MainThread<ViewContext<'_, '_, S>>) -> R + Send + 'static,
611 ) -> Task<Result<R>>
612 where
613 R: Send + 'static,
614 {
615 if self.executor.is_main_thread() {
616 let cx = unsafe { mem::transmute::<&mut Self, &mut MainThread<Self>>(self) };
617 Task::ready(Ok(f(view, cx)))
618 } else {
619 let handle = self.handle().upgrade(self).unwrap();
620 self.window_cx.run_on_main(move |cx| handle.update(cx, f))
621 }
622 }
623
624 pub fn spawn<Fut, R>(
625 &mut self,
626 f: impl FnOnce(WeakHandle<S>, AsyncWindowContext) -> Fut + Send + 'static,
627 ) -> Task<R>
628 where
629 R: Send + 'static,
630 Fut: Future<Output = R> + Send + 'static,
631 {
632 let handle = self.handle();
633 self.window_cx.spawn(move |_, cx| {
634 let result = f(handle, cx);
635 async move { result.await }
636 })
637 }
638
639 pub(crate) fn erase_state<R>(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R {
640 let entity_id = self.unit_entity.id;
641 let mut cx = ViewContext::mutable(
642 &mut *self.window_cx.app,
643 &mut *self.window_cx.window,
644 entity_id,
645 );
646 f(&mut cx)
647 }
648}
649
650impl<'a, 'w, S> Context for ViewContext<'a, 'w, S> {
651 type EntityContext<'b, 'c, U: 'static + Send + Sync> = ViewContext<'b, 'c, U>;
652 type Result<U> = U;
653
654 fn entity<T2: Send + Sync + 'static>(
655 &mut self,
656 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T2>) -> T2,
657 ) -> Handle<T2> {
658 self.window_cx.entity(build_entity)
659 }
660
661 fn update_entity<U: Send + Sync + 'static, R>(
662 &mut self,
663 handle: &Handle<U>,
664 update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
665 ) -> R {
666 self.window_cx.update_entity(handle, update)
667 }
668}
669
670impl<'a, 'w, S: 'static> std::ops::Deref for ViewContext<'a, 'w, S> {
671 type Target = WindowContext<'a, 'w>;
672
673 fn deref(&self) -> &Self::Target {
674 &self.window_cx
675 }
676}
677
678impl<'a, 'w, S: 'static> std::ops::DerefMut for ViewContext<'a, 'w, S> {
679 fn deref_mut(&mut self) -> &mut Self::Target {
680 &mut self.window_cx
681 }
682}
683
684// #[derive(Clone, Copy, Eq, PartialEq, Hash)]
685slotmap::new_key_type! { pub struct WindowId; }
686
687#[derive(PartialEq, Eq)]
688pub struct WindowHandle<S> {
689 id: WindowId,
690 state_type: PhantomData<S>,
691}
692
693impl<S> Copy for WindowHandle<S> {}
694
695impl<S> Clone for WindowHandle<S> {
696 fn clone(&self) -> Self {
697 WindowHandle {
698 id: self.id,
699 state_type: PhantomData,
700 }
701 }
702}
703
704impl<S> WindowHandle<S> {
705 pub fn new(id: WindowId) -> Self {
706 WindowHandle {
707 id,
708 state_type: PhantomData,
709 }
710 }
711}
712
713impl<S: 'static> Into<AnyWindowHandle> for WindowHandle<S> {
714 fn into(self) -> AnyWindowHandle {
715 AnyWindowHandle {
716 id: self.id,
717 state_type: TypeId::of::<S>(),
718 }
719 }
720}
721
722#[derive(Copy, Clone, PartialEq, Eq)]
723pub struct AnyWindowHandle {
724 pub(crate) id: WindowId,
725 state_type: TypeId,
726}
727
728#[derive(Clone)]
729pub struct Layout {
730 pub order: u32,
731 pub bounds: Bounds<Pixels>,
732}