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            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}