Skip to main content

inset_rendering/
relayout_when_system_fonts_change.rs

1//! Flutter counterpart: `rendering/object.dart` (`RelayoutWhenSystemFontsChangeMixin`).
2
3use std::time::Duration;
4
5use inset_foundation::{App, Handle, Listenable, Listener};
6use inset_painting::PaintingBinding;
7use inset_scheduler::{FrameCallback, SchedulerBinding};
8
9use crate::object::{RenderHandle, RenderObject};
10
11/// Flutter's `RelayoutWhenSystemFontsChangeMixin` fields.
12#[derive(Debug, Default)]
13pub struct RelayoutWhenSystemFontsChangeData {
14    has_pending_system_fonts_did_change_callback: bool,
15}
16
17impl RelayoutWhenSystemFontsChangeData {
18    /// No pending system-fonts callback.
19    pub const fn new() -> RelayoutWhenSystemFontsChangeData {
20        RelayoutWhenSystemFontsChangeData {
21            has_pending_system_fonts_did_change_callback: false,
22        }
23    }
24}
25
26/// Mixin for a [`RenderObject`] that relayouts when system fonts change.
27///
28/// System fonts can change when the OS installs or removes a font. Use this mixin if the
29/// render object uses `TextPainter` or `Paragraph` to correctly update the text when it
30/// happens.
31pub trait RelayoutWhenSystemFontsChangeMixin: RenderObject {
32    /// Mixin field access.
33    fn relayout_when_system_fonts_change_data(
34        self: RenderHandle<Self>,
35        app: &App,
36    ) -> &RelayoutWhenSystemFontsChangeData;
37
38    /// See [`relayout_when_system_fonts_change_data`](Self::relayout_when_system_fonts_change_data).
39    fn relayout_when_system_fonts_change_data_mut(
40        self: RenderHandle<Self>,
41        app: &mut App,
42    ) -> &mut RelayoutWhenSystemFontsChangeData;
43
44    /// A callback that is called when system fonts have changed.
45    ///
46    /// The framework defers the invocation of the callback to the
47    /// `SchedulerPhase::TransientCallbacks` phase to ensure that the render object's text
48    /// layout is still valid when user interactions are in progress (which usually take
49    /// place during the idle phase).
50    ///
51    /// By default, `markNeedsLayout` is called on the render object implementing this mixin.
52    ///
53    /// Subclass should override this method to clear any extra cache that depend on
54    /// font-related metrics.
55    fn system_fonts_did_change(self: RenderHandle<Self>, app: &mut App) {
56        self.as_render_object(app).mark_needs_layout(app);
57    }
58
59    /// Flutter's `attach` override body after `super.attach`.
60    fn attach_system_fonts(self: RenderHandle<Self>, app: &mut App) {
61        debug_assert!(
62            !self
63                .relayout_when_system_fonts_change_data(app)
64                .has_pending_system_fonts_did_change_callback
65        );
66        PaintingBinding::instance(app)
67            .system_fonts(app)
68            .add_listener(app, self.system_fonts_listener());
69    }
70
71    /// Flutter's `detach` override body before `super.detach`.
72    fn detach_system_fonts(self: RenderHandle<Self>, app: &mut App) {
73        debug_assert!(
74            !self
75                .relayout_when_system_fonts_change_data(app)
76                .has_pending_system_fonts_did_change_callback
77        );
78        PaintingBinding::instance(app)
79            .system_fonts(app)
80            .remove_listener(app, &self.system_fonts_listener());
81    }
82
83    fn system_fonts_listener(self: RenderHandle<Self>) -> Listener {
84        Listener::handle_method(self.handle(), schedule_system_fonts_update::<Self>)
85    }
86
87    fn schedule_system_fonts_update(self: RenderHandle<Self>, app: &mut App) {
88        if self
89            .relayout_when_system_fonts_change_data(app)
90            .has_pending_system_fonts_did_change_callback
91        {
92            return;
93        }
94        self.relayout_when_system_fonts_change_data_mut(app)
95            .has_pending_system_fonts_did_change_callback = true;
96        SchedulerBinding::schedule_frame_callback(
97            app,
98            FrameCallback::handle_method(self.handle(), run_system_fonts_update::<Self>),
99            None,
100            false,
101            true,
102        );
103    }
104}
105
106fn schedule_system_fonts_update<T: RelayoutWhenSystemFontsChangeMixin>(
107    this: Handle<T>,
108    app: &mut App,
109) {
110    RenderHandle::from_handle(this).schedule_system_fonts_update(app);
111}
112
113fn run_system_fonts_update<T: RelayoutWhenSystemFontsChangeMixin>(
114    this: Handle<T>,
115    app: &mut App,
116    _time_stamp: Duration,
117) {
118    let this = RenderHandle::from_handle(this);
119    if app.is_disposed(this.handle()) {
120        return;
121    }
122    debug_assert!(
123        this.relayout_when_system_fonts_change_data(app)
124            .has_pending_system_fonts_did_change_callback
125    );
126    this.relayout_when_system_fonts_change_data_mut(app)
127        .has_pending_system_fonts_did_change_callback = false;
128    if this.as_render_object(app).attached(app) {
129        RelayoutWhenSystemFontsChangeMixin::system_fonts_did_change(this, app);
130    }
131}