Skip to main content

gpui/
view.rs

1use crate::{
2    AnyElement, AnyEntity, AnyWeakEntity, App, Bounds, ContentMask, Context, Dependencies, Element,
3    ElementId, Entity, EntityId, GlobalElementId, InspectorElementId, IntoElement, LayoutId,
4    Modifiers, PaintIndex, Pixels, Point, PrepaintStateIndex, Render, RenderOnce,
5    ResolvedDirection, Style, StyleRefinement, TextStyle, UnicodeBidi, WeakEntity,
6    scene::ReplaySummary,
7    taffy::LayoutIsland,
8    window::{InputReads, a11y::A11yRecording},
9};
10use crate::{Empty, Window};
11use anyhow::Result;
12use refineable::Refineable;
13use std::{
14    any::{TypeId, type_name},
15    fmt,
16    ops::Range,
17};
18
19/// A type-erased handle to a view.
20///
21/// It pairs an [`Entity`] with its render function, so a field or collection can hold views of
22/// different types. Convert an entity with `AnyView::from` or `.into()`, and recover its type with
23/// [`AnyView::downcast`]. An `AnyView` can be a child wherever a view is accepted. Two `AnyView`s
24/// compare equal when they refer to the same entity.
25///
26/// # Example
27///
28/// ```
29/// use gpui::{AnyView, Context, Render, TestApp, Window, div, prelude::*};
30///
31/// struct First;
32/// struct Second;
33///
34/// impl Render for First {
35///     fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
36///         div().child("First")
37///     }
38/// }
39///
40/// impl Render for Second {
41///     fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
42///         div().child("Second")
43///     }
44/// }
45///
46/// let mut app = TestApp::new();
47/// let (first, second) = app.update(|cx| (cx.new(|_| First), cx.new(|_| Second)));
48/// let views: Vec<AnyView> = vec![first.into(), second.into()];
49///
50/// assert!(views[0].clone().downcast::<First>().is_ok());
51/// assert!(views[1].clone().downcast::<First>().is_err());
52/// ```
53#[derive(Clone, Debug)]
54pub struct AnyView {
55    entity: AnyEntity,
56    render: fn(&AnyView, &mut Window, &mut App) -> AnyElement,
57    view_type_name: &'static str,
58}
59
60impl<V: Render> From<Entity<V>> for AnyView {
61    fn from(value: Entity<V>) -> Self {
62        AnyView {
63            entity: value.into_any(),
64            render: any_view::render::<V>,
65            view_type_name: type_name::<V>(),
66        }
67    }
68}
69
70impl AnyView {
71    /// Returns this view as an element with a fixed root layout style.
72    ///
73    /// GPUI can reuse the rendered subtree while the view's entity, tracked entity and global
74    /// reads, and layout environment remain unchanged. Reads made by nested views and deferred
75    /// prepaint or paint work are tracked too. A notification to a tracked entity, a tracked
76    /// global revision change, or [`Window::refresh`] causes the view to rebuild. Changes to
77    /// bounds or inherited layout and paint state can also require fresh output.
78    ///
79    /// `style` sets the retained root's layout style. Pass the entity directly as a child when it
80    /// should keep its natural layout. See [`Entity::cached`] and
81    /// [retained view rendering](crate::_documentation::concepts::retained_rendering).
82    pub fn cached(self, style: StyleRefinement) -> ViewElement<AnyView> {
83        self.into_element().cached(style)
84    }
85
86    /// Returns a weak handle to this view. The weak handle doesn't keep the view alive.
87    ///
88    /// Call [`AnyWeakView::upgrade`] on it to get an `AnyView` back, or `None` once the view has
89    /// been dropped.
90    pub fn downgrade(&self) -> AnyWeakView {
91        AnyWeakView {
92            entity: self.entity.downgrade(),
93            render: self.render,
94            view_type_name: self.view_type_name,
95        }
96    }
97
98    /// Converts this handle into an [`Entity`] of type `T`.
99    ///
100    /// Returns `Err` with the unchanged `AnyView` when the view isn't a `T`.
101    pub fn downcast<T: 'static>(self) -> Result<Entity<T>, Self> {
102        match self.entity.downcast() {
103            Ok(entity) => Ok(entity),
104            Err(entity) => Err(Self {
105                entity,
106                render: self.render,
107                view_type_name: self.view_type_name,
108            }),
109        }
110    }
111
112    /// Returns the [`TypeId`] of the view's type.
113    pub fn entity_type(&self) -> TypeId {
114        self.entity.entity_type
115    }
116
117    /// Returns the [`EntityId`] of the entity that backs this view.
118    pub fn entity_id(&self) -> EntityId {
119        self.entity.entity_id()
120    }
121}
122
123impl PartialEq for AnyView {
124    fn eq(&self, other: &Self) -> bool {
125        self.entity == other.entity
126    }
127}
128
129impl Eq for AnyView {}
130
131/// `AnyView` is the type-erased [`View`]. Its render is a function pointer rather than a
132/// concrete type, so it takes part in the reactive graph like any other view, with the same
133/// identity as its entity.
134impl View for AnyView {
135    fn entity_id(&self) -> Option<EntityId> {
136        Some(self.entity.entity_id())
137    }
138
139    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
140        (self.render)(&self, window, cx)
141    }
142}
143
144impl<V: 'static + Render> IntoElement for Entity<V> {
145    type Element = ViewElement<Entity<V>>;
146
147    fn into_element(self) -> Self::Element {
148        ViewElement::with_type_name(self, type_name::<V>())
149    }
150
151    #[inline(never)]
152    fn into_any_element(self) -> AnyElement {
153        self.into_element().into_any()
154    }
155}
156
157impl IntoElement for AnyView {
158    type Element = ViewElement<AnyView>;
159
160    fn into_element(self) -> Self::Element {
161        let view_type_name = self.view_type_name;
162        ViewElement::with_type_name(self, view_type_name)
163    }
164}
165
166/// A weak, type-erased handle to a view.
167///
168/// It does not keep the view alive. Create one with [`AnyView::downgrade`] or convert a
169/// [`WeakEntity`].
170pub struct AnyWeakView {
171    entity: AnyWeakEntity,
172    render: fn(&AnyView, &mut Window, &mut App) -> AnyElement,
173    view_type_name: &'static str,
174}
175
176impl AnyWeakView {
177    /// Returns a strong [`AnyView`] if the view is still alive, or `None` if it has been dropped.
178    pub fn upgrade(&self) -> Option<AnyView> {
179        let entity = self.entity.upgrade()?;
180        Some(AnyView {
181            entity,
182            render: self.render,
183            view_type_name: self.view_type_name,
184        })
185    }
186}
187
188impl<V: 'static + Render> From<WeakEntity<V>> for AnyWeakView {
189    fn from(view: WeakEntity<V>) -> Self {
190        AnyWeakView {
191            entity: view.into(),
192            render: any_view::render::<V>,
193            view_type_name: type_name::<V>(),
194        }
195    }
196}
197
198impl PartialEq for AnyWeakView {
199    fn eq(&self, other: &Self) -> bool {
200        self.entity == other.entity
201    }
202}
203
204impl std::fmt::Debug for AnyWeakView {
205    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206        f.debug_struct("AnyWeakView")
207            .field("entity_id", &self.entity.entity_id)
208            .finish_non_exhaustive()
209    }
210}
211
212mod any_view {
213    use crate::{AnyElement, AnyView, App, IntoElement, Render, Window};
214
215    pub(crate) fn render<V: 'static + Render>(
216        view: &AnyView,
217        window: &mut Window,
218        cx: &mut App,
219    ) -> AnyElement {
220        let view = view.clone().downcast::<V>().unwrap();
221        // Record the view's Render type name so the accessibility debug dump can
222        // attribute nodes to the view that produced them.
223        #[cfg(debug_assertions)]
224        window
225            .a11y
226            .view_type_names
227            .insert(view.entity_id(), std::any::type_name::<V>());
228        view.update(cx, |view, cx| {
229            #[cfg(all(
230                feature = "hot-patching",
231                debug_assertions,
232                not(target_family = "wasm")
233            ))]
234            let element = subsecond::HotFn::current(V::render).call((view, window, cx));
235            #[cfg(not(all(
236                feature = "hot-patching",
237                debug_assertions,
238                not(target_family = "wasm")
239            )))]
240            let element = view.render(window, cx);
241            element.into_any_element()
242        })
243    }
244}
245
246/// A value that renders into elements and may carry an entity identity.
247///
248/// Every [`Entity`] of a [`Render`] type is a `View`, and so is every [`RenderOnce`] component.
249/// Implement `View` directly when a component needs both props from its parent and an entity
250/// identity. Otherwise, use [`Render`] for an entity-backed view or [`RenderOnce`] for a stateless
251/// component.
252///
253/// When [`View::entity_id`] returns `Some`, that entity is the view's identity. GPUI gives the
254/// view its own space for element ids, so state inside it can't collide with its siblings. A
255/// [`Context::notify`] on that entity redraws only this view's subtree. When it returns `None`,
256/// the view is stateless. GPUI scopes it under its type name, and it has no entity to notify.
257pub trait View: 'static + Sized {
258    /// Returns the entity that identifies this view, or `None` for a stateless view.
259    ///
260    /// A view that holds its entity as a field returns the entity's id here. The id becomes the
261    /// view's [`ElementId`]. Two views backed by the same entity must not be siblings under one
262    /// parent, because their element state would collide. Nesting is fine, since the parent's
263    /// path keeps the ids apart.
264    fn entity_id(&self) -> Option<EntityId>;
265
266    /// Renders this view into elements. Takes `self` by value, so the view is used up.
267    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement;
268}
269
270/// A stateless component (`RenderOnce`) is a [`View`] with no entity identity.
271impl<T: RenderOnce> View for T {
272    fn entity_id(&self) -> Option<EntityId> {
273        None
274    }
275
276    #[inline]
277    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
278        #[cfg(all(
279            feature = "hot-patching",
280            debug_assertions,
281            not(target_family = "wasm")
282        ))]
283        let element = subsecond::HotFn::current(<T as RenderOnce>::render).call((self, window, cx));
284        #[cfg(not(all(
285            feature = "hot-patching",
286            debug_assertions,
287            not(target_family = "wasm")
288        )))]
289        let element = RenderOnce::render(self, window, cx);
290        element
291    }
292}
293
294/// An entity that renders itself (`Render`) is a [`View`] keyed by its own id.
295impl<T: Render> View for Entity<T> {
296    fn entity_id(&self) -> Option<EntityId> {
297        Some(Entity::entity_id(self))
298    }
299
300    #[inline]
301    fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
302        self.update(cx, |this, cx| {
303            #[cfg(all(
304                feature = "hot-patching",
305                debug_assertions,
306                not(target_family = "wasm")
307            ))]
308            let element = subsecond::HotFn::current(T::render).call((this, window, cx));
309            #[cfg(not(all(
310                feature = "hot-patching",
311                debug_assertions,
312                not(target_family = "wasm")
313            )))]
314            let element = Render::render(this, window, cx);
315            element.into_any_element()
316        })
317    }
318}
319
320impl<T: Render> Entity<T> {
321    /// Returns this entity as an element laid out at a fixed root style.
322    ///
323    /// An entity passed directly as a child already keeps its output while nothing it read has
324    /// changed, and sizes itself from its content. Use `cached` when the parent should decide the
325    /// view's root style instead: the view is laid out at `style`, and its content is laid out
326    /// within the bounds that style produces. See
327    /// [retained rendering](crate::_documentation::concepts::retained_rendering).
328    #[track_caller]
329    pub fn cached(self, style: StyleRefinement) -> ViewElement<Entity<T>> {
330        ViewElement::with_type_name(self, type_name::<T>()).cached(style)
331    }
332}
333
334/// The element that draws a [`View`].
335///
336/// It wraps the view and runs it through the three element phases. Its id is the view's entity
337/// when the view has one. You rarely name this type: entities, [`AnyView`] and derived components
338/// all convert into it. Create one with [`ViewElement::new`].
339#[doc(hidden)]
340pub struct ViewElement<V: View> {
341    view: Option<V>,
342    entity_id: Option<EntityId>,
343    retention: Retention,
344    #[cfg(feature = "profiler")]
345    view_type_name: &'static str,
346    #[cfg(debug_assertions)]
347    source: &'static core::panic::Location<'static>,
348}
349
350enum Retention {
351    /// Rendered every frame, because the view may hold properties its parent passed in.
352    None,
353    /// Kept while nothing it read changed, sized by its content.
354    Natural,
355    /// Kept while nothing it read changed, laid out at a fixed root style.
356    Fixed(StyleRefinement),
357}
358
359impl<V: View> ViewElement<V> {
360    /// Wraps `view` as an element. The element takes the view's entity id, if it has one.
361    ///
362    /// A view wrapped this way renders every frame, since its parent may hand it new
363    /// properties without notifying its entity. Entities and [`AnyView`]s placed as children
364    /// directly keep their output between frames instead.
365    #[track_caller]
366    pub fn new(view: V) -> Self {
367        let mut element = Self::with_type_name(view, type_name::<V>());
368        element.retention = Retention::None;
369        element
370    }
371
372    /// Wraps a view whose draw time profiling attributes to `view_type_name`,
373    /// such as an entity's type rather than [`Entity`]'s.
374    #[track_caller]
375    #[cfg_attr(not(feature = "profiler"), expect(unused_variables))]
376    pub(crate) fn with_type_name(view: V, view_type_name: &'static str) -> Self {
377        let entity_id = view.entity_id();
378        ViewElement {
379            entity_id,
380            retention: if entity_id.is_some() {
381                Retention::Natural
382            } else {
383                Retention::None
384            },
385            #[cfg(feature = "profiler")]
386            view_type_name,
387            view: Some(view),
388            #[cfg(debug_assertions)]
389            source: core::panic::Location::caller(),
390        }
391    }
392
393    /// Lays this view out at `style` instead of sizing it by its content.
394    ///
395    /// Crate-private on purpose: keeping output is only sound for entity-backed views, where
396    /// [`Context::notify`] is the contract that busts it. Reach this through [`Entity::cached`]
397    /// or [`AnyView::cached`].
398    pub(crate) fn cached(mut self, style: StyleRefinement) -> Self {
399        debug_assert!(self.entity_id.is_some(), "only entity views can be cached");
400        self.retention = Retention::Fixed(style);
401        self
402    }
403
404    fn render(&mut self, window: &mut Window, cx: &mut App) -> AnyElement {
405        render_view(self.view.take().unwrap(), window, cx)
406    }
407}
408
409impl<V: View> IntoElement for ViewElement<V> {
410    type Element = Self;
411
412    fn into_element(self) -> Self::Element {
413        self
414    }
415}
416
417/// What a kept view carries between frames: its layout island, what it read, and where its
418/// output went in the last frame.
419pub(crate) struct ViewState {
420    island: LayoutIsland,
421    layout: Option<LayoutKey>,
422    dependencies: Dependencies,
423    /// The pointer and modifiers when the view last drew, if it read them.
424    input: Option<InputSnapshot>,
425    output: Option<ViewOutput>,
426    /// The element state its last render used, such as [`Window::use_keyed_state`], which is kept
427    /// alive while the view is reused.
428    render_states: Vec<(GlobalElementId, TypeId)>,
429}
430
431/// What the view's layout depends on beyond its own state.
432#[derive(PartialEq)]
433struct LayoutKey {
434    text_style: TextStyle,
435    rem_size: Pixels,
436    scale_factor: f32,
437}
438
439/// Where the view is drawn. Output recorded under one key can only be reused under an equal key.
440#[derive(PartialEq)]
441struct OutputKey {
442    bounds: Bounds<Pixels>,
443    content_mask: ContentMask<Pixels>,
444    direction: ResolvedDirection,
445    unicode_bidi: UnicodeBidi,
446}
447
448/// The window input a view read while drawing, and what it was then.
449pub(crate) struct InputSnapshot {
450    reads: InputReads,
451    mouse_position: Point<Pixels>,
452    modifiers: Modifiers,
453    modality: crate::window::InputModality,
454}
455
456impl InputSnapshot {
457    fn new(reads: InputReads, window: &Window) -> Self {
458        Self {
459            reads,
460            mouse_position: window.mouse_position,
461            modifiers: window.modifiers,
462            modality: window.last_input_modality,
463        }
464    }
465
466    fn still_valid(&self, window: &Window) -> bool {
467        (!self.reads.contains(InputReads::POINTER) || self.mouse_position == window.mouse_position)
468            && (!self.reads.contains(InputReads::MODIFIERS) || self.modifiers == window.modifiers)
469            && (!self.reads.contains(InputReads::MODALITY)
470                || self.modality == window.last_input_modality)
471    }
472}
473
474struct ViewOutput {
475    key: OutputKey,
476    prepaint: Range<PrepaintStateIndex>,
477    paint: Range<PaintIndex>,
478    /// Whether `paint` belongs to the same frame as `prepaint`.
479    painted: bool,
480    /// The draw these ranges index into.
481    frame: u64,
482    /// The accessibility nodes drawn with it, if the tree was being built.
483    a11y: Option<A11yRecording>,
484    /// What replaying `paint` needs, kept after its first replay.
485    replay: Option<ReplaySummary>,
486}
487
488impl ViewOutput {
489    /// Whether this output has everything the current frame needs.
490    fn complete(&self, window: &Window) -> bool {
491        self.a11y.is_some() || !window.a11y.is_active()
492    }
493}
494
495impl ViewState {
496    /// Moves this view's prepaint range along with a replayed range of its parent, drawn in
497    /// `frame`. Output that wasn't drawn inside that range, in the previous frame, is dropped.
498    pub(crate) fn rebase_prepaint(
499        &mut self,
500        source: &Range<PrepaintStateIndex>,
501        destination: &PrepaintStateIndex,
502        frame: u64,
503    ) {
504        if let Some(output) = &mut self.output {
505            if output.painted
506                && output.frame + 1 == frame
507                && PrepaintStateIndex::within(&output.prepaint, source)
508            {
509                output.prepaint = output.prepaint.start.rebased(source, destination)
510                    ..output.prepaint.end.rebased(source, destination);
511                output.frame = frame;
512                output.painted = false;
513            } else {
514                self.output = None;
515            }
516        }
517    }
518
519    /// Moves this view's paint range along with a replayed range of its parent, drawn in `frame`.
520    pub(crate) fn rebase_paint(
521        &mut self,
522        source: &Range<PaintIndex>,
523        destination: &PaintIndex,
524        frame: u64,
525    ) {
526        if let Some(output) = &mut self.output {
527            if output.frame == frame && PaintIndex::within(&output.paint, source) {
528                output.paint = output.paint.start.rebased(source, destination)
529                    ..output.paint.end.rebased(source, destination);
530                output.painted = true;
531            } else {
532                self.output = None;
533            }
534        }
535    }
536
537    fn reusable(&self, entity_id: EntityId, layout: &LayoutKey, window: &Window, cx: &App) -> bool {
538        self.layout.as_ref() == Some(layout)
539            && !window.refreshing
540            && !window.dirty_views.contains(&entity_id)
541            && !cx.dependencies_changed(&self.dependencies, &window.dirty_views)
542            && self
543                .input
544                .as_ref()
545                .is_none_or(|input| input.still_valid(window))
546            && !window.is_inspector_picking(cx)
547            && self
548                .output
549                .as_ref()
550                .is_none_or(|output| output.complete(window))
551    }
552}
553
554#[inline]
555fn render_view<V: View>(view: V, window: &mut Window, cx: &mut App) -> AnyElement {
556    view.render(window, cx).into_any_element()
557}
558
559impl<V: View> Element for ViewElement<V> {
560    type RequestLayoutState = Option<AnyElement>;
561    type PrepaintState = Option<AnyElement>;
562
563    fn id(&self) -> Option<ElementId> {
564        self.entity_id.map(ElementId::View)
565    }
566
567    fn source_location(&self) -> Option<&'static core::panic::Location<'static>> {
568        #[cfg(debug_assertions)]
569        return Some(self.source);
570
571        #[cfg(not(debug_assertions))]
572        return None;
573    }
574
575    fn request_layout(
576        &mut self,
577        global_id: Option<&GlobalElementId>,
578        _inspector_id: Option<&InspectorElementId>,
579        window: &mut Window,
580        cx: &mut App,
581    ) -> (LayoutId, Option<AnyElement>) {
582        #[cfg(feature = "profiler")]
583        let start = window.window_profiler.begin_view();
584        let result = match (self.entity_id, &self.retention) {
585            (None, _) => window.with_id(ElementId::Name(type_name::<V>().into()), |window| {
586                let mut element = self.render(window, cx);
587                (element.request_layout(window, cx), Some(element))
588            }),
589            (Some(entity_id), Retention::None) => window.with_rendered_view(entity_id, |window| {
590                let mut element = self.render(window, cx);
591                (element.request_layout(window, cx), Some(element))
592            }),
593            (Some(entity_id), _) => window.with_rendered_view(entity_id, |window| {
594                window.with_element_state::<ViewState, _>(global_id.unwrap(), |state, window| {
595                    let mut state = state.unwrap_or_else(|| ViewState {
596                        island: window.create_layout_island(),
597                        layout: None,
598                        dependencies: Dependencies::default(),
599                        input: None,
600                        output: None,
601                        render_states: Vec::new(),
602                    });
603                    let layout = LayoutKey {
604                        text_style: window.text_style(),
605                        rem_size: window.rem_size(),
606                        scale_factor: window.scale_factor(),
607                    };
608                    let element = if state.reusable(entity_id, &layout, window, cx) {
609                        cx.replay_dependencies(&state.dependencies);
610                        window.keep_element_states(&state.render_states);
611                        None
612                    } else {
613                        state.layout = Some(layout);
614                        state.output = None;
615                        Some(self.render_into_island(&mut state, window, cx))
616                    };
617                    let island = state.island.id();
618                    let layout_id = match &self.retention {
619                        Retention::Fixed(style) => {
620                            let mut root_style = Style::default();
621                            root_style.refine(style);
622                            let layout_id = window.request_layout(root_style, None, cx);
623                            window.anchor_layout_island(island, layout_id);
624                            // The parent can't see the content through a fixed node, so it gets
625                            // the direction the content would contribute to an `Auto` ancestor.
626                            let direction = window.layout_island_direction_contribution(island);
627                            window.set_layout_auto_direction_hint(layout_id, direction);
628                            layout_id
629                        }
630                        _ => window.request_layout_island(island),
631                    };
632                    ((layout_id, element), state)
633                })
634            }),
635        };
636        #[cfg(feature = "profiler")]
637        window.window_profiler.end_view(
638            start,
639            self.view_type_name,
640            crate::profiler::ViewPhase::RequestLayout,
641        );
642        result
643    }
644
645    fn prepaint(
646        &mut self,
647        global_id: Option<&GlobalElementId>,
648        _inspector_id: Option<&InspectorElementId>,
649        bounds: Bounds<Pixels>,
650        element: &mut Option<AnyElement>,
651        window: &mut Window,
652        cx: &mut App,
653    ) -> Option<AnyElement> {
654        #[cfg(feature = "profiler")]
655        let start = window.window_profiler.begin_view();
656        let result = match (self.entity_id, &self.retention) {
657            (None, _) => window.with_id(ElementId::Name(type_name::<V>().into()), |window| {
658                let mut element = element.take().unwrap();
659                element.prepaint(window, cx);
660                Some(element)
661            }),
662            (Some(entity_id), Retention::None) => {
663                window.set_view_id(entity_id);
664                window.with_rendered_view(entity_id, |window| {
665                    let mut element = element.take().unwrap();
666                    element.prepaint(window, cx);
667                    Some(element)
668                })
669            }
670            (Some(entity_id), retention) => {
671                let fixed = matches!(retention, Retention::Fixed(_));
672                window.set_view_id(entity_id);
673                window.with_rendered_view(entity_id, |window| {
674                    window.with_element_state::<ViewState, _>(
675                        global_id.unwrap(),
676                        |state, window| {
677                            let mut state = state.unwrap();
678                            let key = OutputKey {
679                                bounds,
680                                content_mask: window.content_mask(),
681                                direction: window.resolved_direction(),
682                                unicode_bidi: window.resolved_unicode_bidi(),
683                            };
684                            let mut element = element.take();
685                            if element.is_none()
686                                && let Some(output) = state.output.as_mut()
687                                && output.painted
688                                && output.frame + 1 == window.frame_number
689                                && output.key == key
690                                && output.complete(window)
691                            {
692                                let start = window.prepaint_index();
693                                window.reuse_prepaint(output.prepaint.clone());
694                                if let Some(a11y) =
695                                    output.a11y.as_ref().filter(|_| window.a11y.is_active())
696                                {
697                                    window.a11y.replay(a11y);
698                                }
699                                output.prepaint = start..window.prepaint_index();
700                                output.frame = window.frame_number;
701                                output.painted = false;
702                                return (None, state);
703                            }
704
705                            // Drawn somewhere new: render again into the island, which keeps the
706                            // size its anchor was given this frame.
707                            let rendered_now = element.is_none();
708                            let mut element = match element.take() {
709                                Some(element) => element,
710                                None => self.render_into_island(&mut state, window, cx),
711                            };
712                            if fixed || rendered_now {
713                                window.layout_island(state.island.id(), bounds.size, cx);
714                            }
715                            let start = window.prepaint_index();
716                            let a11y = window.a11y.is_active().then(|| window.a11y.mark());
717                            let (_, dependencies) = record(&mut state, window, cx, |window, cx| {
718                                element.prepaint(window, cx)
719                            });
720                            state.dependencies.extend(dependencies);
721                            state.output = Some(ViewOutput {
722                                key,
723                                prepaint: start..window.prepaint_index(),
724                                paint: PaintIndex::default()..PaintIndex::default(),
725                                painted: false,
726                                frame: window.frame_number,
727                                a11y: a11y.map(|mark| window.a11y.record(mark)),
728                                replay: None,
729                            });
730                            (Some(element), state)
731                        },
732                    )
733                })
734            }
735        };
736        #[cfg(feature = "profiler")]
737        window.window_profiler.end_view(
738            start,
739            self.view_type_name,
740            crate::profiler::ViewPhase::Prepaint,
741        );
742        result
743    }
744
745    fn paint(
746        &mut self,
747        global_id: Option<&GlobalElementId>,
748        _inspector_id: Option<&InspectorElementId>,
749        _bounds: Bounds<Pixels>,
750        _request_layout: &mut Option<AnyElement>,
751        element: &mut Option<AnyElement>,
752        window: &mut Window,
753        cx: &mut App,
754    ) {
755        #[cfg(feature = "profiler")]
756        let start = window.window_profiler.begin_view();
757        match (self.entity_id, &self.retention) {
758            (None, _) => window.with_id(ElementId::Name(type_name::<V>().into()), |window| {
759                element.as_mut().unwrap().paint(window, cx);
760            }),
761            (Some(entity_id), Retention::None) => window.with_rendered_view(entity_id, |window| {
762                element.as_mut().unwrap().paint(window, cx);
763            }),
764            (Some(entity_id), _) => window.with_rendered_view(entity_id, |window| {
765                window.with_element_state::<ViewState, _>(global_id.unwrap(), |state, window| {
766                    let mut state = state.unwrap();
767                    let start = window.paint_index();
768                    match element {
769                        Some(element) => {
770                            let ((), dependencies) =
771                                record(&mut state, window, cx, |window, cx| {
772                                    element.paint(window, cx)
773                                });
774                            state.dependencies.extend(dependencies);
775                        }
776                        None => {
777                            let output = state.output.as_mut().unwrap();
778                            window.reuse_paint(output.paint.clone(), &mut output.replay);
779                        }
780                    }
781                    let output = state.output.as_mut().unwrap();
782                    output.paint = start..window.paint_index();
783                    output.painted = true;
784                    ((), state)
785                })
786            }),
787        }
788        #[cfg(feature = "profiler")]
789        window.window_profiler.end_view(
790            start,
791            self.view_type_name,
792            crate::profiler::ViewPhase::Paint,
793        );
794    }
795}
796
797impl<V: View> ViewElement<V> {
798    /// Renders the view into its island and requests its layout there, recording what it read.
799    fn render_into_island(
800        &mut self,
801        state: &mut ViewState,
802        window: &mut Window,
803        cx: &mut App,
804    ) -> AnyElement {
805        let island = state.island.id();
806        state.input = None;
807        state.dependencies = Dependencies::default();
808        let states_start = window.element_states_mark();
809        let view = self.view.take().unwrap();
810        let (element, dependencies) = record(state, window, cx, |window, cx| {
811            window.with_layout_island(island, |window| {
812                let mut element = render_view(view, window, cx);
813                let root = element.request_layout(window, cx);
814                (element, root)
815            })
816        });
817        let (element, root) = element;
818        window.set_layout_island_root(island, root);
819        state.dependencies = dependencies;
820        state.render_states = window.element_states_since(states_start);
821        element
822    }
823}
824
825/// Runs `f`, returning what it read and noting whether it read the pointer or modifiers.
826fn record<R>(
827    state: &mut ViewState,
828    window: &mut Window,
829    cx: &mut App,
830    f: impl FnOnce(&mut Window, &mut App) -> R,
831) -> (R, Dependencies) {
832    let outer_reads = window.input_reads.replace(InputReads::empty());
833    let result = cx.record_dependencies(|cx| f(window, cx));
834    let reads = window.input_reads.get();
835    window.input_reads.set(outer_reads | reads);
836    if !reads.is_empty() {
837        let previous = state
838            .input
839            .take()
840            .map_or(InputReads::empty(), |input| input.reads);
841        state.input = Some(InputSnapshot::new(previous | reads, window));
842    }
843    result
844}
845
846/// A view that renders nothing.
847///
848/// Its `render` returns [`Empty`]. Use it as a placeholder view, for example as the root of a
849/// window that has no content yet.
850pub struct EmptyView;
851
852impl Render for EmptyView {
853    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
854        Empty
855    }
856}