Remove the window parameter from the render() function of all the renderers

This makes for a slimmer API and instead we can create the renderer <-> window association
behind the scenes ourselves,
in set_component.
This commit is contained in:
Simon Hausmann 2023-07-25 15:46:13 +02:00 committed by Simon Hausmann
parent 507428b03e
commit 7d136b6568
14 changed files with 73 additions and 57 deletions

View file

@ -351,11 +351,10 @@ public:
/// ///
/// The stride is the amount of pixels between two lines in the buffer. /// The stride is the amount of pixels between two lines in the buffer.
/// It is must be at least as large as the width of the window. /// It is must be at least as large as the width of the window.
PhysicalRegion render(const Window &window, std::span<slint::Rgb8Pixel> buffer, PhysicalRegion render(std::span<slint::Rgb8Pixel> buffer, std::size_t pixel_stride) const
std::size_t pixel_stride) const
{ {
auto r = cbindgen_private::slint_software_renderer_render_rgb8( auto r = cbindgen_private::slint_software_renderer_render_rgb8(inner, buffer.data(),
inner, &window.window_handle().inner, buffer.data(), buffer.size(), pixel_stride); buffer.size(), pixel_stride);
return PhysicalRegion { r }; return PhysicalRegion { r };
} }
@ -365,12 +364,10 @@ public:
/// ///
/// The stride is the amount of pixels between two lines in the buffer. /// The stride is the amount of pixels between two lines in the buffer.
/// It is must be at least as large as the width of the window. /// It is must be at least as large as the width of the window.
PhysicalRegion render(const Window &window, std::span<Rgb565Pixel> buffer, PhysicalRegion render(std::span<Rgb565Pixel> buffer, std::size_t pixel_stride) const
std::size_t pixel_stride) const
{ {
auto r = cbindgen_private::slint_software_renderer_render_rgb565( auto r = cbindgen_private::slint_software_renderer_render_rgb565(
inner, &window.window_handle().inner, reinterpret_cast<uint16_t *>(buffer.data()), inner, reinterpret_cast<uint16_t *>(buffer.data()), buffer.size(), pixel_stride);
buffer.size(), pixel_stride);
return PhysicalRegion { r }; return PhysicalRegion { r };
} }
}; };
@ -483,10 +480,7 @@ public:
inner = cbindgen_private::slint_skia_renderer_new(window_handle.inner, initial_size); inner = cbindgen_private::slint_skia_renderer_new(window_handle.inner, initial_size);
} }
void render(const Window &window) const void render() const { cbindgen_private::slint_skia_renderer_render(inner); }
{
cbindgen_private::slint_skia_renderer_render(inner, &window.window_handle().inner);
}
void resize(PhysicalSize size) const void resize(PhysicalSize size) const
{ {

View file

@ -281,15 +281,12 @@ pub unsafe extern "C" fn slint_software_renderer_drop(r: SoftwareRendererOpaque)
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_software_renderer_render_rgb8( pub unsafe extern "C" fn slint_software_renderer_render_rgb8(
r: SoftwareRendererOpaque, r: SoftwareRendererOpaque,
window_adapter: *const WindowAdapterRcOpaque,
buffer: *mut Rgb8Pixel, buffer: *mut Rgb8Pixel,
buffer_len: usize, buffer_len: usize,
pixel_stride: usize, pixel_stride: usize,
) -> IntRect { ) -> IntRect {
let buffer = core::slice::from_raw_parts_mut(buffer, buffer_len); let buffer = core::slice::from_raw_parts_mut(buffer, buffer_len);
let renderer = &*(r as *const SoftwareRenderer); let renderer = &*(r as *const SoftwareRenderer);
let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);
renderer.set_window(window_adapter.window());
let r = renderer.render(buffer, pixel_stride); let r = renderer.render(buffer, pixel_stride);
let (orig, size) = (r.bounding_box_origin(), r.bounding_box_size()); let (orig, size) = (r.bounding_box_origin(), r.bounding_box_size());
i_slint_core::graphics::euclid::rect(orig.x, orig.y, size.width as i32, size.height as i32) i_slint_core::graphics::euclid::rect(orig.x, orig.y, size.width as i32, size.height as i32)
@ -298,15 +295,12 @@ pub unsafe extern "C" fn slint_software_renderer_render_rgb8(
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_software_renderer_render_rgb565( pub unsafe extern "C" fn slint_software_renderer_render_rgb565(
r: SoftwareRendererOpaque, r: SoftwareRendererOpaque,
window_adapter: *const WindowAdapterRcOpaque,
buffer: *mut u16, buffer: *mut u16,
buffer_len: usize, buffer_len: usize,
pixel_stride: usize, pixel_stride: usize,
) -> IntRect { ) -> IntRect {
let buffer = core::slice::from_raw_parts_mut(buffer as *mut Rgb565Pixel, buffer_len); let buffer = core::slice::from_raw_parts_mut(buffer as *mut Rgb565Pixel, buffer_len);
let renderer = &*(r as *const SoftwareRenderer); let renderer = &*(r as *const SoftwareRenderer);
let window_adapter = &*(window_adapter as *const Rc<dyn WindowAdapter>);
renderer.set_window(window_adapter.window());
let r = renderer.render(buffer, pixel_stride); let r = renderer.render(buffer, pixel_stride);
let (orig, size) = (r.bounding_box_origin(), r.bounding_box_size()); let (orig, size) = (r.bounding_box_origin(), r.bounding_box_size());
i_slint_core::graphics::euclid::rect(orig.x, orig.y, size.width as i32, size.height as i32) i_slint_core::graphics::euclid::rect(orig.x, orig.y, size.width as i32, size.height as i32)
@ -458,13 +452,9 @@ pub mod skia {
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn slint_skia_renderer_render( pub unsafe extern "C" fn slint_skia_renderer_render(r: SkiaRendererOpaque) {
r: SkiaRendererOpaque,
window: *const WindowAdapterRcOpaque,
) {
let window_adapter = &*(window as *const Rc<dyn WindowAdapter>);
let r = &*(r as *const SkiaRenderer); let r = &*(r as *const SkiaRenderer);
r.render(window_adapter.window()).unwrap(); r.render().unwrap();
} }
#[no_mangle] #[no_mangle]

View file

@ -82,7 +82,7 @@ struct MyWindowAdapter : public slint_platform::WindowAdapter
void render() void render()
{ {
m_renderer->render(window()); m_renderer->render();
if (has_active_animations()) if (has_active_animations())
request_redraw(); request_redraw();
} }

View file

@ -83,7 +83,7 @@ public:
{ {
slint_platform::update_timers_and_animations(); slint_platform::update_timers_and_animations();
m_renderer->render(window()); m_renderer->render();
if (has_active_animations()) { if (has_active_animations()) {
requestUpdate(); requestUpdate();

View file

@ -2016,6 +2016,10 @@ impl i_slint_core::renderer::RendererSealed for QtWindow {
self.cache.component_destroyed(component); self.cache.component_destroyed(component);
Ok(()) Ok(())
} }
fn set_window_adapter(&self, _window_adapter: &Rc<dyn WindowAdapter>) {
// No-op because QtWindow is also the WindowAdapter
}
} }
fn accessible_item(item: Option<ItemRc>) -> Option<ItemRc> { fn accessible_item(item: Option<ItemRc>) -> Option<ItemRc> {

View file

@ -158,6 +158,10 @@ impl RendererSealed for TestingWindow {
fn default_font_size(&self) -> LogicalLength { fn default_font_size(&self) -> LogicalLength {
LogicalLength::new(10.) LogicalLength::new(10.)
} }
fn set_window_adapter(&self, _window_adapter: &Rc<dyn WindowAdapter>) {
// No-op since TestingWindow is also the WindowAdapter
}
} }
/// Initialize the testing backend. /// Initialize the testing backend.

View file

@ -45,8 +45,8 @@ impl super::WinitCompatibleRenderer for GlutinFemtoVGRenderer {
Ok((Self { renderer }, winit_window)) Ok((Self { renderer }, winit_window))
} }
fn render(&self, window: &i_slint_core::api::Window) -> Result<(), PlatformError> { fn render(&self, _window: &i_slint_core::api::Window) -> Result<(), PlatformError> {
self.renderer.render(window) self.renderer.render()
} }
fn as_core_renderer(&self) -> &dyn Renderer { fn as_core_renderer(&self) -> &dyn Renderer {

View file

@ -63,7 +63,7 @@ impl super::WinitCompatibleRenderer for SkiaRenderer {
} }
fn render(&self, window: &i_slint_core::api::Window) -> Result<(), PlatformError> { fn render(&self, window: &i_slint_core::api::Window) -> Result<(), PlatformError> {
self.renderer.render(window) self.renderer.render()
} }
fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer { fn as_core_renderer(&self) -> &dyn i_slint_core::renderer::Renderer {

View file

@ -63,8 +63,6 @@ impl super::WinitCompatibleRenderer for WinitSoftwareRenderer {
) )
})?; })?;
self.renderer.set_window(window);
let mut surface = self.surface.borrow_mut(); let mut surface = self.surface.borrow_mut();
surface surface

View file

@ -2,10 +2,12 @@
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
use alloc::boxed::Box; use alloc::boxed::Box;
use alloc::rc::Rc;
use core::pin::Pin; use core::pin::Pin;
use crate::component::ComponentRef; use crate::component::ComponentRef;
use crate::lengths::{LogicalLength, LogicalPoint, LogicalRect, LogicalSize, ScaleFactor}; use crate::lengths::{LogicalLength, LogicalPoint, LogicalRect, LogicalSize, ScaleFactor};
use crate::window::WindowAdapter;
/// This trait represents a Renderer that can render a slint scene. /// This trait represents a Renderer that can render a slint scene.
/// ///
@ -103,4 +105,6 @@ pub trait RendererSealed {
} }
fn default_font_size(&self) -> LogicalLength; fn default_font_size(&self) -> LogicalLength;
fn set_window_adapter(&self, _window_adapter: &Rc<dyn WindowAdapter>);
} }

View file

@ -121,7 +121,7 @@ pub struct SoftwareRenderer {
/// This is the area which was dirty on the previous frame. /// This is the area which was dirty on the previous frame.
/// Only used if repaint_buffer_type == RepaintBufferType::SwappedBuffers /// Only used if repaint_buffer_type == RepaintBufferType::SwappedBuffers
prev_frame_dirty: Cell<DirtyRegion>, prev_frame_dirty: Cell<DirtyRegion>,
window: RefCell<Option<Weak<dyn crate::window::WindowAdapter>>>, maybe_window_adapter: RefCell<Option<Weak<dyn crate::window::WindowAdapter>>>,
} }
impl SoftwareRenderer { impl SoftwareRenderer {
@ -141,7 +141,7 @@ impl SoftwareRenderer {
window: Weak<dyn crate::window::WindowAdapter>, window: Weak<dyn crate::window::WindowAdapter>,
) -> Self { ) -> Self {
Self { Self {
window: RefCell::new(Some(window.clone())), maybe_window_adapter: RefCell::new(Some(window.clone())),
repaint_buffer_type, repaint_buffer_type,
partial_cache: Default::default(), partial_cache: Default::default(),
force_dirty: Default::default(), force_dirty: Default::default(),
@ -159,7 +159,7 @@ impl SoftwareRenderer {
#[doc(hidden)] #[doc(hidden)]
pub fn new_without_window(repaint_buffer_type: RepaintBufferType) -> Self { pub fn new_without_window(repaint_buffer_type: RepaintBufferType) -> Self {
Self { Self {
window: RefCell::new(None), maybe_window_adapter: RefCell::new(None),
repaint_buffer_type, repaint_buffer_type,
partial_cache: Default::default(), partial_cache: Default::default(),
force_dirty: Default::default(), force_dirty: Default::default(),
@ -168,14 +168,6 @@ impl SoftwareRenderer {
} }
} }
/// Sets the window to be use for future rendering operations. Call this before calling
/// rendering.
#[doc(hidden)]
pub fn set_window(&self, window: &crate::api::Window) {
*self.window.borrow_mut() =
Some(Rc::downgrade(&WindowInner::from_pub(window).window_adapter().clone()));
}
/// Internal function to apply a dirty region depending on the dirty_tracking_policy. /// Internal function to apply a dirty region depending on the dirty_tracking_policy.
/// Returns the region to actually draw. /// Returns the region to actually draw.
fn apply_dirty_region( fn apply_dirty_region(
@ -212,7 +204,7 @@ impl SoftwareRenderer {
/// returns the dirty region for this frame (not including the extra_draw_region) /// returns the dirty region for this frame (not including the extra_draw_region)
pub fn render(&self, buffer: &mut [impl TargetPixel], pixel_stride: usize) -> PhysicalRegion { pub fn render(&self, buffer: &mut [impl TargetPixel], pixel_stride: usize) -> PhysicalRegion {
let window = self let window = self
.window .maybe_window_adapter
.borrow() .borrow()
.as_ref() .as_ref()
.and_then(|w| w.upgrade()) .and_then(|w| w.upgrade())
@ -327,7 +319,7 @@ impl SoftwareRenderer {
/// ``` /// ```
pub fn render_by_line(&self, line_buffer: impl LineBufferProvider) -> PhysicalRegion { pub fn render_by_line(&self, line_buffer: impl LineBufferProvider) -> PhysicalRegion {
let window = self let window = self
.window .maybe_window_adapter
.borrow() .borrow()
.as_ref() .as_ref()
.and_then(|w| w.upgrade()) .and_then(|w| w.upgrade())
@ -532,6 +524,10 @@ impl RendererSealed for SoftwareRenderer {
fn default_font_size(&self) -> LogicalLength { fn default_font_size(&self) -> LogicalLength {
self::fonts::DEFAULT_FONT_SIZE self::fonts::DEFAULT_FONT_SIZE
} }
fn set_window_adapter(&self, window_adapter: &Rc<dyn WindowAdapter>) {
*self.maybe_window_adapter.borrow_mut() = Some(Rc::downgrade(window_adapter));
}
} }
fn render_window_frame_by_line( fn render_window_frame_by_line(
@ -2051,7 +2047,6 @@ impl MinimalSoftwareWindow {
/// Return true if something was redrawn. /// Return true if something was redrawn.
pub fn draw_if_needed(&self, render_callback: impl FnOnce(&SoftwareRenderer)) -> bool { pub fn draw_if_needed(&self, render_callback: impl FnOnce(&SoftwareRenderer)) -> bool {
if self.needs_redraw.replace(false) { if self.needs_redraw.replace(false) {
self.renderer.set_window(&self.window);
render_callback(&self.renderer); render_callback(&self.renderer);
true true
} else { } else {

View file

@ -371,6 +371,7 @@ impl WindowInner {
self.component.replace(ComponentRc::downgrade(component)); self.component.replace(ComponentRc::downgrade(component));
self.pinned_fields.window_properties_tracker.set_dirty(); // component changed, layout constraints for sure must be re-calculated self.pinned_fields.window_properties_tracker.set_dirty(); // component changed, layout constraints for sure must be re-calculated
let window_adapter = self.window_adapter(); let window_adapter = self.window_adapter();
window_adapter.renderer().set_window_adapter(&window_adapter);
{ {
let component = ComponentRc::borrow_pin(component); let component = ComponentRc::borrow_pin(component);
let root_item = component.as_ref().get_item_ref(0); let root_item = component.as_ref().get_item_ref(0);

View file

@ -6,7 +6,7 @@
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::pin::Pin; use std::pin::Pin;
use std::rc::Rc; use std::rc::{Rc, Weak};
use i_slint_common::sharedfontdb; use i_slint_common::sharedfontdb;
use i_slint_core::api::{ use i_slint_core::api::{
@ -20,7 +20,7 @@ use i_slint_core::lengths::{
}; };
use i_slint_core::platform::PlatformError; use i_slint_core::platform::PlatformError;
use i_slint_core::renderer::RendererSealed; use i_slint_core::renderer::RendererSealed;
use i_slint_core::window::WindowInner; use i_slint_core::window::{WindowAdapter, WindowInner};
use i_slint_core::Brush; use i_slint_core::Brush;
type PhysicalLength = euclid::Length<f32, PhysicalPx>; type PhysicalLength = euclid::Length<f32, PhysicalPx>;
@ -71,6 +71,7 @@ unsafe impl OpenGLContextWrapper for WebGLNeedsNoCurrentContext {
/// Use the FemtoVG renderer when implementing a custom Slint platform where you deliver events to /// Use the FemtoVG renderer when implementing a custom Slint platform where you deliver events to
/// Slint and want the scene to be rendered using OpenGL and the FemtoVG renderer. /// Slint and want the scene to be rendered using OpenGL and the FemtoVG renderer.
pub struct FemtoVGRenderer { pub struct FemtoVGRenderer {
maybe_window_adapter: RefCell<Option<Weak<dyn WindowAdapter>>>,
rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>, rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>,
canvas: CanvasRc, canvas: CanvasRc,
graphics_cache: itemrenderer::ItemGraphicsCache, graphics_cache: itemrenderer::ItemGraphicsCache,
@ -135,6 +136,7 @@ impl FemtoVGRenderer {
let canvas = Rc::new(RefCell::new(femtovg_canvas)); let canvas = Rc::new(RefCell::new(femtovg_canvas));
Ok(Self { Ok(Self {
maybe_window_adapter: Default::default(),
rendering_notifier: Default::default(), rendering_notifier: Default::default(),
canvas, canvas,
graphics_cache: Default::default(), graphics_cache: Default::default(),
@ -148,10 +150,7 @@ impl FemtoVGRenderer {
} }
/// Render the scene using OpenGL. This function assumes that the context is current. /// Render the scene using OpenGL. This function assumes that the context is current.
pub fn render( pub fn render(&self) -> Result<(), i_slint_core::platform::PlatformError> {
&self,
window: &i_slint_core::api::Window,
) -> Result<(), i_slint_core::platform::PlatformError> {
self.opengl_context.ensure_current()?; self.opengl_context.ensure_current()?;
if self.rendering_first_time.take() { if self.rendering_first_time.take() {
@ -165,6 +164,8 @@ impl FemtoVGRenderer {
} }
} }
let window_adapter = self.window_adapter()?;
let window = window_adapter.window();
let size = window.size(); let size = window.size();
let width = size.width; let width = size.width;
let height = size.height; let height = size.height;
@ -297,6 +298,14 @@ impl FemtoVGRenderer {
callback(api); callback(api);
Ok(()) Ok(())
} }
fn window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {
self.maybe_window_adapter
.borrow()
.as_ref()
.and_then(|w| w.upgrade())
.ok_or_else(|| format!("Renderer must be associated with component before use").into())
}
} }
impl RendererSealed for FemtoVGRenderer { impl RendererSealed for FemtoVGRenderer {
@ -463,6 +472,10 @@ impl RendererSealed for FemtoVGRenderer {
self.graphics_cache.component_destroyed(component); self.graphics_cache.component_destroyed(component);
Ok(()) Ok(())
} }
fn set_window_adapter(&self, window_adapter: &Rc<dyn WindowAdapter>) {
*self.maybe_window_adapter.borrow_mut() = Some(Rc::downgrade(window_adapter));
}
} }
impl Drop for FemtoVGRenderer { impl Drop for FemtoVGRenderer {

View file

@ -5,7 +5,7 @@
#![doc(html_logo_url = "https://slint.dev/logo/slint-logo-square-light.svg")] #![doc(html_logo_url = "https://slint.dev/logo/slint-logo-square-light.svg")]
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::rc::Rc; use std::rc::{Rc, Weak};
use i_slint_core::api::{ use i_slint_core::api::{
GraphicsAPI, PhysicalSize as PhysicalWindowSize, RenderingNotifier, RenderingState, GraphicsAPI, PhysicalSize as PhysicalWindowSize, RenderingNotifier, RenderingState,
@ -19,7 +19,7 @@ use i_slint_core::lengths::{
LogicalLength, LogicalPoint, LogicalRect, LogicalSize, PhysicalPx, ScaleFactor, LogicalLength, LogicalPoint, LogicalRect, LogicalSize, PhysicalPx, ScaleFactor,
}; };
use i_slint_core::platform::PlatformError; use i_slint_core::platform::PlatformError;
use i_slint_core::window::WindowInner; use i_slint_core::window::{WindowAdapter, WindowInner};
use i_slint_core::Brush; use i_slint_core::Brush;
type PhysicalLength = euclid::Length<f32, PhysicalPx>; type PhysicalLength = euclid::Length<f32, PhysicalPx>;
@ -54,6 +54,7 @@ cfg_if::cfg_if! {
/// Use the SkiaRenderer when implementing a custom Slint platform where you deliver events to /// Use the SkiaRenderer when implementing a custom Slint platform where you deliver events to
/// Slint and want the scene to be rendered using Skia as underlying graphics library. /// Slint and want the scene to be rendered using Skia as underlying graphics library.
pub struct SkiaRenderer { pub struct SkiaRenderer {
maybe_window_adapter: RefCell<Option<Weak<dyn WindowAdapter>>>,
rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>, rendering_notifier: RefCell<Option<Box<dyn RenderingNotifier>>>,
image_cache: ItemCache<Option<skia_safe::Image>>, image_cache: ItemCache<Option<skia_safe::Image>>,
path_cache: ItemCache<Option<(Vector2D<f32, PhysicalPx>, skia_safe::Path)>>, path_cache: ItemCache<Option<(Vector2D<f32, PhysicalPx>, skia_safe::Path)>>,
@ -72,6 +73,7 @@ impl SkiaRenderer {
let surface = DefaultSurface::new(window_handle, display_handle, size)?; let surface = DefaultSurface::new(window_handle, display_handle, size)?;
Ok(Self { Ok(Self {
maybe_window_adapter: Default::default(),
rendering_notifier: Default::default(), rendering_notifier: Default::default(),
image_cache: Default::default(), image_cache: Default::default(),
path_cache: Default::default(), path_cache: Default::default(),
@ -82,10 +84,7 @@ impl SkiaRenderer {
} }
/// Render the scene in the previously associated window. The size parameter must match the size of the window. /// Render the scene in the previously associated window. The size parameter must match the size of the window.
pub fn render( pub fn render(&self) -> Result<(), i_slint_core::platform::PlatformError> {
&self,
window: &i_slint_core::api::Window,
) -> Result<(), i_slint_core::platform::PlatformError> {
if self.rendering_first_time.take() { if self.rendering_first_time.take() {
*self.rendering_metrics_collector.borrow_mut() = *self.rendering_metrics_collector.borrow_mut() =
RenderingMetricsCollector::new(&format!( RenderingMetricsCollector::new(&format!(
@ -100,6 +99,8 @@ impl SkiaRenderer {
} }
} }
let window_adapter = self.window_adapter()?;
let window = window_adapter.window();
let size = window.size(); let size = window.size();
let window_inner = WindowInner::from_pub(window); let window_inner = WindowInner::from_pub(window);
@ -177,6 +178,14 @@ impl SkiaRenderer {
) -> Result<(), i_slint_core::platform::PlatformError> { ) -> Result<(), i_slint_core::platform::PlatformError> {
self.surface.resize_event(size) self.surface.resize_event(size)
} }
fn window_adapter(&self) -> Result<Rc<dyn WindowAdapter>, PlatformError> {
self.maybe_window_adapter
.borrow()
.as_ref()
.and_then(|w| w.upgrade())
.ok_or_else(|| format!("Renderer must be associated with component before use").into())
}
} }
impl i_slint_core::renderer::RendererSealed for SkiaRenderer { impl i_slint_core::renderer::RendererSealed for SkiaRenderer {
@ -333,6 +342,10 @@ impl i_slint_core::renderer::RendererSealed for SkiaRenderer {
self.path_cache.component_destroyed(component); self.path_cache.component_destroyed(component);
Ok(()) Ok(())
} }
fn set_window_adapter(&self, window_adapter: &Rc<dyn WindowAdapter>) {
*self.maybe_window_adapter.borrow_mut() = Some(Rc::downgrade(window_adapter));
}
} }
impl Drop for SkiaRenderer { impl Drop for SkiaRenderer {