window.rs

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