window.rs

  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(&params)?;
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(&params.clone().into(), &mut || {
245                        let (size, bytes) = self.text_system().rasterize_glyph(&params)?;
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(&params)?;
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(&params.clone().into(), &mut || {
295                        let (size, bytes) = self.text_system().rasterize_glyph(&params)?;
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(&params.clone().into(), &mut || {
341                    let bytes = self.svg_renderer.render(&params)?;
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(&params.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}