zng_view/
extensions.rs

1//! Extensions API
2//!
3//! Extensions that run in the view-process, with internal access to things like the raw handle of windows or
4//! direct access to renderers. These extensions are build on top of the view API extensions as a way to customize
5//! the view-process without needing to fork it or re-implement the entire view API from scratch.
6//!
7
8use std::rc::Rc;
9use std::{any::Any, sync::Arc};
10
11use webrender::api::{
12    AsyncBlobImageRasterizer, BlobImageHandler, BlobImageParams, BlobImageRequest, BlobImageResult, DocumentId, ExternalImageId,
13    PipelineId, units::TexelRect,
14};
15use webrender::{DebugFlags, RenderApi};
16use zng_unit::{Factor, PxSize};
17use zng_view_api::window::RenderMode;
18use zng_view_api::{
19    Event,
20    api_extension::{ApiExtensionId, ApiExtensionName, ApiExtensionPayload, ApiExtensions},
21};
22
23use crate::display_list::{DisplayExtensionArgs, DisplayExtensionItemArgs, DisplayExtensionUpdateArgs, DisplayListExtension, SpaceAndClip};
24
25pub use crate::px_wr::{PxToWr, WrToPx};
26use crate::util::PxToWinit;
27
28/// The extension API.
29pub trait ViewExtension: Send + Any {
30    /// Called once at the start of the view-process.
31    fn init(&mut self, args: ViewExtensionInitArgs) {
32        let _ = args;
33    }
34
35    /// Unique name and version of this extension.
36    fn name(&self) -> &ApiExtensionName;
37
38    /// Run the extension as an app level command.
39    fn command(&mut self, request: ApiExtensionPayload) -> Option<ApiExtensionPayload> {
40        let _ = request;
41        None
42    }
43
44    /// Create a [`WindowExtension`] for a new window instance.
45    fn window(&mut self) -> Option<Box<dyn WindowExtension>> {
46        None
47    }
48
49    /// Create a [`RendererExtension`] for a new renderer instance.
50    fn renderer(&mut self) -> Option<Box<dyn RendererExtension>> {
51        None
52    }
53
54    /// System warning low memory, release unused memory, caches.
55    fn low_memory(&mut self) {}
56
57    /// App is being suspended, all graphic resources must be dropped.
58    ///
59    /// Android and iOS apps can be suspended without fully exiting, all graphic resources must be dropped on suspension, and
60    /// any persistent state must be flushed because the app will process will exit if the user does not return to the app.
61    ///
62    /// Note that [`window`] and [`renderer`] resources are managed by the app and will be dropped automatically, this
63    /// callback only needs to drop custom graphic resources.
64    ///
65    /// [`window`]: Self::window
66    /// [`renderer`]: Self::renderer
67    fn suspended(&mut self) {}
68
69    /// App resumed from a suspended state.
70    ///
71    /// Expect [`window`] and [`renderer`] requests to recrate previous instances.
72    ///
73    /// Note that this is not called on init, only after a suspension.
74    ///
75    /// [`window`]: Self::window
76    /// [`renderer`]: Self::renderer
77    fn resumed(&mut self) {}
78}
79
80/// Represents a view extension associated with a headed or headless window instance.
81pub trait WindowExtension: Any {
82    /// Edit attributes for the new window.
83    fn configure(&mut self, args: &mut WindowConfigArgs) {
84        let _ = args;
85    }
86
87    /// Called just after the window is created.
88    fn window_inited(&mut self, args: &mut WindowInitedArgs) {
89        let _ = args;
90    }
91
92    /// If this extension can be dropped after window creation.
93    fn is_init_only(&self) -> bool;
94
95    /// Called when a command request is made for the extension and window (window ID).
96    fn command(&mut self, args: &mut WindowCommandArgs) -> ApiExtensionPayload {
97        let _ = args;
98        ApiExtensionPayload::unknown_extension(ApiExtensionId::INVALID)
99    }
100
101    /// Called when the window receives an event.
102    fn event(&mut self, args: &mut WindowEventArgs) {
103        let _ = args;
104    }
105
106    /// System warning low memory, release unused memory, caches.
107    fn low_memory(&mut self) {}
108
109    /// Called just after the window closes.
110    fn window_deinited(&mut self, args: &mut WindowDeinitedArgs) {
111        let _ = args;
112    }
113
114    /// Cast to `&dyn Any`.
115    fn as_any(&self) -> &dyn Any;
116
117    /// Cast to `&mut dyn Any`.
118    fn as_any_mut(&mut self) -> &mut dyn Any;
119}
120
121/// Represents a view extension associated with a renderer instance.
122pub trait RendererExtension: Any {
123    /// Edit options for the new renderer.
124    fn configure(&mut self, args: &mut RendererConfigArgs) {
125        let _ = args;
126    }
127
128    /// Called just after the renderer is created.
129    fn renderer_inited(&mut self, args: &mut RendererInitedArgs) {
130        let _ = args;
131    }
132
133    /// If this extension can be dropped after render creation.
134    fn is_init_only(&self) -> bool;
135
136    /// Called when a command request is made for the extension and renderer (window ID).
137    fn command(&mut self, args: &mut RendererCommandArgs) -> ApiExtensionPayload {
138        let _ = args;
139        ApiExtensionPayload::unknown_extension(ApiExtensionId::INVALID)
140    }
141
142    /// Called when a new display list begins building.
143    fn render_start(&mut self, args: &mut RenderArgs) {
144        let _ = args;
145    }
146
147    /// Called when a display item push for the extension is found.
148    fn render_push(&mut self, args: &mut RenderItemArgs) {
149        let _ = args;
150    }
151
152    /// Called when a display item pop for the extension is found.
153    fn render_pop(&mut self, args: &mut RenderItemArgs) {
154        let _ = args;
155    }
156
157    /// Called when a new display list finishes building.
158    ///
159    /// The list will be send to the renderer for asynchronous rendering.
160    fn render_end(&mut self, args: &mut RenderArgs) {
161        let _ = args;
162    }
163
164    /// Called when a render-update for the extension is found.
165    fn render_update(&mut self, args: &mut RenderUpdateArgs) {
166        let _ = args;
167    }
168
169    /// Called when Webrender finishes rendering a frame and it is ready for redraw.
170    fn frame_ready(&mut self, args: &mut FrameReadyArgs) {
171        let _ = args;
172    }
173
174    /// Called every time the window or surface redraws, after Webrender has redraw.
175    fn redraw(&mut self, args: &mut RedrawArgs) {
176        let _ = args;
177    }
178
179    /// System warning low memory, release unused memory, caches.
180    fn low_memory(&mut self) {}
181
182    /// Called just before the renderer is destroyed.
183    fn renderer_deinited(&mut self, args: &mut RendererDeinitedArgs) {
184        let _ = args;
185    }
186
187    /// Cast to `&dyn Any`.
188    fn as_any(&self) -> &dyn Any;
189
190    /// Cast to `&mut dyn Any`.
191    fn as_any_mut(&mut self) -> &mut dyn Any;
192}
193
194/// Arguments for [`RendererExtension::render_start`] and [`RendererExtension::render_end`].
195#[non_exhaustive]
196pub struct RenderArgs<'a> {
197    /// Id of the new frame.
198    pub frame_id: zng_view_api::window::FrameId,
199
200    /// The webrender display list.
201    pub list: &'a mut webrender::api::DisplayListBuilder,
202    /// Space and clip tracker.
203    pub sc: &'a mut SpaceAndClip,
204
205    /// The transaction that will send the display list.
206    pub transaction: &'a mut webrender::Transaction,
207
208    /// The window or surface renderer.
209    pub renderer: &'a mut webrender::Renderer,
210    /// The window or surface render API.
211    pub api: &'a mut RenderApi,
212    /// External images registry for the `renderer`.
213    pub external_images: &'a mut ExternalImages,
214}
215
216/// Arguments for [`RendererExtension::render_push`] and [`RendererExtension::render_pop`].
217#[non_exhaustive]
218pub struct RenderItemArgs<'a> {
219    /// Extension index.
220    pub extension_id: ApiExtensionId,
221    /// Push payload, is empty for pop.
222    pub payload: &'a ApiExtensionPayload,
223    /// If the display item is reused.
224    ///
225    /// If `true` the payload is the same as received before any updates, the updated
226    /// values must be applied to value deserialized from the payload.
227    pub is_reuse: bool,
228
229    /// The webrender display list.
230    pub list: &'a mut webrender::api::DisplayListBuilder,
231    /// Space and clip tracker.
232    pub sc: &'a mut SpaceAndClip,
233
234    /// The transaction that will send the display list.
235    pub transaction: &'a mut webrender::Transaction,
236
237    /// The window or surface renderer.
238    pub renderer: &'a mut webrender::Renderer,
239    /// The window or surface render API.
240    pub api: &'a mut RenderApi,
241    /// External images registry for the `renderer`.
242    pub external_images: &'a mut ExternalImages,
243}
244
245/// Arguments for [`RendererExtension::render_update`].
246#[non_exhaustive]
247pub struct RenderUpdateArgs<'a> {
248    /// Extension index.
249    pub extension_id: ApiExtensionId,
250    /// Update payload.
251    pub payload: &'a ApiExtensionPayload,
252
253    /// Set to `true` to rebuild the display list.
254    ///
255    /// The list will be rebuild using the last full payload received, the extension
256    /// must patch in any subsequent updates onto this value.
257    pub new_frame: bool,
258
259    /// Webrender binding updates.
260    ///
261    /// If no other extension and update handlers request a new frame these properties
262    /// will be send to Webrender to update the current frame.
263    pub properties: &'a mut webrender::api::DynamicProperties,
264
265    /// The transaction that will send the properties update.
266    pub transaction: &'a mut webrender::Transaction,
267
268    /// The window or surface renderer.
269    pub renderer: &'a mut webrender::Renderer,
270    /// The window or surface render API.
271    pub api: &'a mut RenderApi,
272    /// External images registry for the `renderer`.
273    pub external_images: &'a mut ExternalImages,
274}
275
276/// Arguments for [`RendererExtension::frame_ready`].
277#[non_exhaustive]
278pub struct FrameReadyArgs {
279    /// Frame that finished rendering and is ready to redraw.
280    pub frame_id: zng_view_api::window::FrameId,
281    /// If a screen redraw is requested.
282    ///
283    /// This is `true` if Webrender requested recomposite after rendering the frame, or an
284    /// extension set it to `true`. Don't set this to `false`.
285    pub redraw: bool,
286}
287
288/// Arguments for [`RendererExtension::redraw`].
289#[non_exhaustive]
290pub struct RedrawArgs<'a> {
291    /// Scale factor of the screen or window.
292    pub scale_factor: Factor,
293
294    /// Current size of the surface or window content.
295    pub size: PxSize,
296
297    /// OpenGL context used by the renderer.
298    ///
299    /// The context is current, and Webrender has already redraw.
300    pub context: &'a mut dyn OpenGlContext,
301}
302
303/// Represents a Webrender blob handler that can coexist with other blob handlers on the same renderer.
304///
305/// This API is very similar to Webrender's `BlobImageHandler`, the only difference is that implementers
306/// are expected to detect and ignore requests targeting other blob extensions as multiple extensions may
307/// implement blob renderers.
308///
309/// See [`RendererConfigArgs::blobs`] for more details.
310pub trait BlobExtension: Send + Any {
311    /// Creates a snapshot of the current state of blob images in the handler.
312    fn create_blob_rasterizer(&mut self) -> Box<dyn AsyncBlobRasterizer>;
313
314    /// New blob extension instance of the same type.
315    fn create_similar(&self) -> Box<dyn BlobExtension>;
316
317    /// Prepare resources that are not bundled in with the encoded request commands.
318    ///
319    /// The extension must ignore requests not addressing it.
320    fn prepare_resources(&mut self, args: &mut BlobPrepareArgs) {
321        let _ = args;
322    }
323
324    /// Register a blob image if the request addresses this extension.
325    fn add(&mut self, args: &BlobAddArgs);
326    /// Update a blob image if the request addresses this extension.
327    fn update(&mut self, args: &BlobUpdateArgs);
328
329    /// Remove a blob image if the key was generated by this extension.
330    fn delete(&mut self, key: webrender::api::BlobImageKey);
331
332    /// Cleanup any prepared resource for the font.
333    fn delete_font(&mut self, key: webrender::api::FontKey) {
334        let _ = key;
335    }
336
337    /// Cleanup any prepared resource for the font instance.
338    fn delete_font_instance(&mut self, key: webrender::api::FontInstanceKey) {
339        let _ = key;
340    }
341
342    /// Cleanup any state related with the namespace.
343    fn clear_namespace(&mut self, namespace: webrender::api::IdNamespace) {
344        let _ = namespace;
345    }
346
347    /// Sets if multi-threading is allowed.
348    ///
349    /// The default is `true`, this method is only called on init if multithreading is disabled.
350    fn enable_multithreading(&mut self, enable: bool);
351}
352
353/// Arguments for [`ViewExtension::init`].
354#[non_exhaustive]
355pub struct ViewExtensionInitArgs {
356    /// Sender of [`Event::ExtensionEvent`] events.
357    pub event_sender: ExtensionEventSender,
358}
359
360/// Sender of [`Event::ExtensionEvent`] events.
361///
362/// Available in [`ViewExtensionInitArgs`].
363#[derive(Clone)]
364pub struct ExtensionEventSender {
365    sender: crate::AppEventSender,
366    id: ApiExtensionId,
367}
368impl ExtensionEventSender {
369    /// Send the event `payload`.
370    pub fn send(&self, payload: ApiExtensionPayload) -> Result<(), zng_view_api::ipc::ViewChannelError> {
371        self.sender.send(crate::AppEvent::Notify(Event::ExtensionEvent(self.id, payload)))
372    }
373}
374
375/// Snapshot of a [`BlobExtension`] that can render/copy pixels.
376pub trait AsyncBlobRasterizer: Send + Any {
377    /// Rasterize the requests addressed for this rasterizer.
378    ///
379    /// Note that all requests (for all rasterizers) is shared here, the rasterizer must
380    /// find their own requests and push responses in the `args`.
381    fn rasterize(&mut self, args: &mut BlobRasterizerArgs);
382}
383
384/// Arguments for [`BlobExtension::prepare_resources`].
385#[non_exhaustive]
386pub struct BlobPrepareArgs<'a> {
387    /// Webrender services.
388    pub services: &'a dyn webrender::api::BlobImageResources,
389    /// Requests targeting any of the blob extensions. Each extension must
390    /// inspect the requests to find the ones targeting it.
391    pub requests: &'a [BlobImageParams],
392}
393
394/// Arguments for [`BlobExtension::add`].
395#[non_exhaustive]
396pub struct BlobAddArgs {
397    /// Blob key.
398    ///
399    /// Blob extension must ignore this request if it did not generate this key.
400    pub key: webrender::api::BlobImageKey,
401    /// Encoded data.
402    pub data: std::sync::Arc<webrender::api::BlobImageData>,
403
404    /// Webrender value.
405    pub visible_rect: webrender::api::units::DeviceIntRect,
406    /// Webrender value.
407    pub tile_size: webrender::api::TileSize,
408}
409
410/// Arguments for [`BlobExtension::update`].
411#[non_exhaustive]
412pub struct BlobUpdateArgs {
413    /// Blob key.
414    ///
415    /// Blob extension must ignore this request if it did not generate this key.
416    pub key: webrender::api::BlobImageKey,
417    /// Encoded data.
418    pub data: std::sync::Arc<webrender::api::BlobImageData>,
419    /// Webrender value.
420    pub visible_rect: webrender::api::units::DeviceIntRect,
421    /// Webrender value.
422    pub dirty_rect: webrender::api::units::BlobDirtyRect,
423}
424
425/// Arguments for [`AsyncBlobRasterizer::rasterize`].
426#[non_exhaustive]
427pub struct BlobRasterizerArgs<'a> {
428    /// Rasterization requests for all rasterizers.
429    ///
430    /// The rasterizer must inspect the requests to find the ones targeting it.
431    pub requests: &'a [BlobImageParams],
432    /// Rasterization request can be schedules in a way that minimizes the risk of
433    /// high priority work being enqueued behind it.
434    pub low_priority: bool,
435
436    /// A pool of blob tile buffers to mitigate the overhead of allocating and deallocating blob tiles.
437    pub tile_pool: &'a mut webrender::api::BlobTilePool,
438
439    /// Rasterization responses.
440    ///
441    /// Note that `requests` and `responses` are shared by all blob rasterizers, each rasterizer
442    /// must inspect the requests and push responses here.
443    pub responses: &'a mut Vec<(BlobImageRequest, BlobImageResult)>,
444}
445
446/// Arguments for [`WindowExtension::configure`]
447#[non_exhaustive]
448pub struct WindowConfigArgs<'a> {
449    /// Config payload send with the window creation request addressed to this extension.
450    ///
451    /// Note that this extension will participate in the renderer creation even if there is no config for it.
452    pub config: Option<&'a ApiExtensionPayload>,
453
454    /// Window attributes that will be used to build the headed window.
455    pub window: Option<&'a mut winit::window::WindowAttributes>,
456}
457
458/// Arguments for [`RendererExtension::configure`]
459#[non_exhaustive]
460pub struct RendererConfigArgs<'a> {
461    /// Config payload send with the renderer creation request addressed to this extension.
462    ///
463    /// Note that this extension will participate in the renderer creation even if there is no config for it.
464    pub config: Option<&'a ApiExtensionPayload>,
465
466    /// Webrender options.
467    ///
468    /// Note that this config is modified by the window and other extensions. Some options
469    /// must not be set by extensions:
470    ///
471    /// * `workers` will be already set by the window, blob rasterizers may clone and use these threads.
472    /// * `blob_image_handler` will be set by the window to an object that aggregates
473    ///   all extension blob image handlers. Add your own blob handler to `blobs` instead.
474    pub options: &'a mut webrender::WebRenderOptions,
475
476    /// Blob extensions.
477    ///
478    /// Use this API instead of `blob_image_handler` in options to support multiple blob handlers.
479    pub blobs: &'a mut Vec<Box<dyn BlobExtension>>,
480
481    /// Winit window if the renderer is associated with a headed window.
482    pub window: Option<&'a winit::window::Window>,
483
484    /// OpenGL context that will be used by the new renderer.
485    pub context: &'a mut dyn OpenGlContext,
486}
487
488/// Arguments for [`RendererExtension::renderer_inited`].
489#[non_exhaustive]
490pub struct RendererInitedArgs<'a> {
491    /// The new renderer.
492    ///
493    /// Note that some renderer config is set by the window and must not be set by extensions:
494    ///
495    /// * `set_external_image_handler` will be set by the window to the image cache, you can use `external_images` to
496    ///   register external images and textures.
497    pub renderer: &'a mut webrender::Renderer,
498
499    /// The API sender connected with the new renderer.
500    pub api_sender: &'a webrender::RenderApiSender,
501
502    /// The API used by the window or surface.
503    pub api: &'a mut RenderApi,
504
505    /// The document ID of the main content.
506    pub document_id: DocumentId,
507
508    /// The pipeline of the main content.
509    pub pipeline_id: PipelineId,
510
511    /// Winit window if the renderer is associated with a headed window.
512    pub window: Option<&'a winit::window::Window>,
513
514    /// OpenGL context used by the new renderer.
515    ///
516    /// The context is new and current, only Webrender and previous extensions have interacted with it.
517    pub context: &'a mut dyn OpenGlContext,
518
519    /// External images registry for the `renderer`.
520    pub external_images: &'a mut ExternalImages,
521}
522
523/// Tracks extension external images for a renderer.
524#[derive(Default)]
525pub struct ExternalImages {
526    images: Vec<Arc<crate::image_cache::ImageData>>,
527}
528impl ExternalImages {
529    /// Register an OpenGL texture.
530    ///
531    /// Returns an `ExternalImageId` that can be used in display lists.
532    ///
533    /// The id is only valid in the same renderer, and the `texture` must be generated by the same
534    /// GL API used by the renderer. Note that you must manage the `texture` lifetime, [`unregister`]
535    /// only releases the external image entry.
536    ///
537    /// [`unregister`]: Self::unregister
538    pub fn register_texture(&mut self, uv: TexelRect, texture: gleam::gl::GLuint) -> ExternalImageId {
539        self.register(crate::image_cache::ImageData::NativeTexture { uv, texture })
540    }
541
542    /// Register a loaded image.
543    ///
544    /// Returns an `ExternalImageId` that can be used in display lists.
545    ///
546    /// The `pixels` are held in memory until [`unregister`] or the window is closed.
547    ///
548    /// [`unregister`]: Self::unregister
549    pub fn register_image(&mut self, descriptor: webrender::api::ImageDescriptor, pixels: zng_view_api::ipc::IpcBytes) -> ExternalImageId {
550        self.register(crate::image_cache::ImageData::RawData {
551            size: descriptor.size.cast().cast_unit(), // not used
552            pixels,
553            descriptor,
554            density: None,
555        })
556    }
557
558    /// Unregister the image or texture.
559    ///
560    /// The `id` is invalid after this call, using it in a display list is undefined behavior and
561    /// will likely cause access violation or other memory problems.
562    pub fn unregister(&mut self, id: ExternalImageId) {
563        if let Some(i) = self.images.iter().position(|img| ExternalImageId(Arc::as_ptr(img) as u64) == id) {
564            self.images.swap_remove(i);
565        }
566    }
567
568    fn register(&mut self, img: crate::image_cache::ImageData) -> ExternalImageId {
569        let img = Arc::new(img);
570        let id = ExternalImageId(Arc::as_ptr(&img) as u64);
571        self.images.push(img);
572        id
573    }
574}
575
576/// Arguments for [`RendererExtension::renderer_deinited`].
577#[non_exhaustive]
578pub struct RendererDeinitedArgs<'a> {
579    /// The document ID of the main content, already deinited.
580    pub document_id: DocumentId,
581
582    /// The pipeline of the main content, already deinited.
583    pub pipeline_id: PipelineId,
584
585    /// Winit window if the renderer is associated with a headed window.
586    pub window: Option<&'a winit::window::Window>,
587
588    /// OpenGL context.
589    ///
590    /// The context is current and Webrender has already deinited, the context will be dropped
591    /// after all extensions handle deinit.
592    pub context: &'a mut dyn OpenGlContext,
593}
594
595/// Arguments for [`WindowExtension::window_inited`].
596#[non_exhaustive]
597pub struct WindowInitedArgs<'a> {
598    /// Underlying winit window.
599    pub window: &'a winit::window::Window,
600
601    /// OpenGL context connected to the window or headless surface.
602    pub context: &'a mut dyn OpenGlContext,
603}
604
605/// Arguments for [`WindowExtension::window_deinited`].
606#[non_exhaustive]
607pub struct WindowDeinitedArgs<'a> {
608    /// Underlying winit window.
609    pub window: &'a winit::window::Window,
610
611    /// OpenGL context connected to the window or headless surface.
612    pub context: &'a mut dyn OpenGlContext,
613}
614
615/// Arguments for [`WindowExtension::command`].
616#[non_exhaustive]
617pub struct WindowCommandArgs<'a> {
618    /// Underlying winit window.
619    pub window: &'a winit::window::Window,
620
621    /// OpenGL context connected to the window or headless surface.
622    pub context: &'a mut dyn OpenGlContext,
623
624    /// The command request.
625    pub request: ApiExtensionPayload,
626}
627
628/// Arguments for [`WindowExtension::event`].
629#[non_exhaustive]
630pub struct WindowEventArgs<'a> {
631    /// Underlying winit window.
632    pub window: &'a winit::window::Window,
633
634    /// OpenGL context connected to the window or headless surface.
635    pub context: &'a mut dyn OpenGlContext,
636
637    /// The event.
638    pub event: &'a winit::event::WindowEvent,
639}
640
641/// Represents a managed OpenGL context connected to a window or headless surface.
642pub trait OpenGlContext {
643    /// Context is current on the calling thread.
644    fn is_current(&self) -> bool;
645
646    /// Make context current on the calling thread.
647    fn make_current(&mut self);
648
649    /// The context.
650    fn gl(&self) -> &Rc<dyn gleam::gl::Gl>;
651
652    /// Actual render mode used to create the context.
653    fn render_mode(&self) -> RenderMode;
654
655    /// Resize surface.
656    fn resize(&mut self, size: PxSize);
657
658    /// If the context runs on the CPU, not a GPU.
659    fn is_software(&self) -> bool;
660
661    /// Swap buffers if the context is double-buffered.
662    fn swap_buffers(&mut self);
663}
664impl OpenGlContext for crate::gl::GlContext {
665    fn is_current(&self) -> bool {
666        self.is_current()
667    }
668
669    fn make_current(&mut self) {
670        self.make_current()
671    }
672
673    fn gl(&self) -> &Rc<dyn gleam::gl::Gl> {
674        self.gl()
675    }
676
677    fn render_mode(&self) -> RenderMode {
678        self.render_mode()
679    }
680
681    fn resize(&mut self, size: PxSize) {
682        self.resize(size.to_winit())
683    }
684
685    fn is_software(&self) -> bool {
686        self.is_software()
687    }
688
689    fn swap_buffers(&mut self) {
690        self.swap_buffers()
691    }
692}
693
694/// Arguments for [`RendererExtension::command`].
695#[non_exhaustive]
696pub struct RendererCommandArgs<'a> {
697    /// The renderer.
698    pub renderer: &'a mut webrender::Renderer,
699
700    /// The render API used by the window or surface.
701    pub api: &'a mut RenderApi,
702
703    /// The command request.
704    pub request: ApiExtensionPayload,
705
706    /// Winit window if the renderer is associated with a headed window.
707    pub window: Option<&'a winit::window::Window>,
708
709    /// OpenGL context associated with the renderer.
710    pub context: &'a mut dyn OpenGlContext,
711
712    /// Redraw flag.
713    ///
714    /// If set to `true` the window is guaranteed to redraw the frame.
715    pub redraw: &'a mut bool,
716}
717
718/// View extensions register.
719pub struct ViewExtensions {
720    exts: Vec<Box<dyn ViewExtension>>,
721}
722impl ViewExtensions {
723    /// New empty.
724    pub(crate) fn new() -> Self {
725        Self { exts: vec![] }
726    }
727
728    /// Register an extension with the ID that will be assigned to it.
729    ///
730    /// The ID is useful for error messages.
731    ///
732    /// # Panics
733    ///
734    /// Panics if the name is already registered.
735    pub fn register<E: ViewExtension>(&mut self, ext: impl FnOnce(ApiExtensionId) -> E) -> &mut Self {
736        let id = ApiExtensionId::from_index(self.exts.len());
737        let ext = ext(id);
738        assert!(self.id(ext.name()).is_none(), "extension already registered");
739        self.exts.push(Box::new(ext));
740        self
741    }
742
743    /// Returns the extension ID.
744    pub fn id(&self, name: &ApiExtensionName) -> Option<ApiExtensionId> {
745        self.exts.iter().position(|e| e.name() == name).map(ApiExtensionId::from_index)
746    }
747
748    /// Register a command extension with custom encoded messages.
749    ///
750    /// The `handler` receives the request payload and it's own ID to be used in error messages.
751    pub fn command_raw(
752        &mut self,
753        name: impl Into<ApiExtensionName>,
754        handler: impl FnMut(ApiExtensionPayload, ApiExtensionId) -> ApiExtensionPayload + Send + 'static,
755    ) -> &mut Self {
756        struct CommandExt<F>(ApiExtensionName, ApiExtensionId, F);
757        impl<F: FnMut(ApiExtensionPayload, ApiExtensionId) -> ApiExtensionPayload + Send + 'static> ViewExtension for CommandExt<F> {
758            fn name(&self) -> &ApiExtensionName {
759                &self.0
760            }
761            fn command(&mut self, request: ApiExtensionPayload) -> Option<ApiExtensionPayload> {
762                Some((self.2)(request, self.1))
763            }
764        }
765
766        self.register(|id| CommandExt(name.into(), id, handler));
767        self
768    }
769
770    /// Register a command extension.
771    ///
772    /// The `handler` receives the deserialized request payload and it's own ID to be used in error messages.
773    pub fn command<I: serde::de::DeserializeOwned, O: serde::Serialize>(
774        &mut self,
775        name: impl Into<ApiExtensionName>,
776        mut handler: impl FnMut(I, ApiExtensionId) -> O + Send + 'static,
777    ) -> &mut Self {
778        self.command_raw(name, move |p, id| match p.deserialize::<I>() {
779            Ok(p) => {
780                let o = handler(p, id);
781                ApiExtensionPayload::serialize(&o).unwrap()
782            }
783            Err(e) => ApiExtensionPayload::invalid_request(id, e),
784        })
785    }
786
787    /// Register a window extension with its own ID.
788    pub fn window<E: WindowExtension>(
789        &mut self,
790        name: impl Into<ApiExtensionName>,
791        new: impl FnMut(ApiExtensionId) -> E + Send + 'static,
792    ) -> &mut Self {
793        struct WindowExt<F>(ApiExtensionName, ApiExtensionId, F);
794        impl<E, F> ViewExtension for WindowExt<F>
795        where
796            E: WindowExtension,
797            F: FnMut(ApiExtensionId) -> E + Send + 'static,
798        {
799            fn name(&self) -> &ApiExtensionName {
800                &self.0
801            }
802
803            fn window(&mut self) -> Option<Box<dyn WindowExtension>> {
804                Some(Box::new((self.2)(self.1)))
805            }
806        }
807        self.register(move |id| WindowExt(name.into(), id, new));
808        self
809    }
810
811    /// Register a renderer extension with its own ID.
812    pub fn renderer<E: RendererExtension>(
813        &mut self,
814        name: impl Into<ApiExtensionName>,
815        new: impl FnMut(ApiExtensionId) -> E + Send + 'static,
816    ) -> &mut Self {
817        struct RendererExt<F>(ApiExtensionName, ApiExtensionId, F);
818        impl<E, F> ViewExtension for RendererExt<F>
819        where
820            E: RendererExtension,
821            F: FnMut(ApiExtensionId) -> E + Send + 'static,
822        {
823            fn name(&self) -> &ApiExtensionName {
824                &self.0
825            }
826
827            fn renderer(&mut self) -> Option<Box<dyn RendererExtension>> {
828                Some(Box::new((self.2)(self.1)))
829            }
830        }
831        self.register(move |id| RendererExt(name.into(), id, new));
832        self
833    }
834
835    pub(crate) fn api_extensions(&self) -> ApiExtensions {
836        let mut r = ApiExtensions::new();
837        for ext in &self.exts {
838            r.insert(ext.name().clone()).unwrap();
839        }
840        r
841    }
842
843    pub(crate) fn call_command(&mut self, id: ApiExtensionId, request: ApiExtensionPayload) -> ApiExtensionPayload {
844        let idx = id.index();
845        if idx >= self.exts.len() {
846            ApiExtensionPayload::unknown_extension(id)
847        } else if let Some(r) = self.exts[idx].command(request) {
848            r
849        } else {
850            ApiExtensionPayload::unknown_extension(id)
851        }
852    }
853
854    pub(crate) fn new_window(&mut self) -> Vec<(ApiExtensionId, Box<dyn WindowExtension>)> {
855        self.exts
856            .iter_mut()
857            .enumerate()
858            .filter_map(|(i, e)| e.window().map(|e| (ApiExtensionId::from_index(i), e)))
859            .collect()
860    }
861
862    pub(crate) fn new_renderer(&mut self) -> Vec<(ApiExtensionId, Box<dyn RendererExtension>)> {
863        self.exts
864            .iter_mut()
865            .enumerate()
866            .filter_map(|(i, e)| e.renderer().map(|e| (ApiExtensionId::from_index(i), e)))
867            .collect()
868    }
869
870    pub(crate) fn init(&mut self, event_sender: &crate::AppEventSender) {
871        for (i, ext) in self.exts.iter_mut().enumerate() {
872            ext.init(ViewExtensionInitArgs {
873                event_sender: ExtensionEventSender {
874                    sender: event_sender.clone(),
875                    id: ApiExtensionId::from_index(i),
876                },
877            });
878        }
879    }
880
881    pub(crate) fn on_low_memory(&mut self) {
882        for ext in self.exts.iter_mut() {
883            ext.low_memory();
884        }
885    }
886
887    pub(crate) fn suspended(&mut self) {
888        for ext in self.exts.iter_mut() {
889            ext.suspended();
890        }
891    }
892
893    pub(crate) fn resumed(&mut self) {
894        for ext in self.exts.iter_mut() {
895            ext.resumed();
896        }
897    }
898
899    /// Add `other` to self.
900    pub fn append(&mut self, mut other: ViewExtensions) {
901        self.exts.append(&mut other.exts);
902    }
903}
904
905#[cfg(windows)]
906pub(crate) struct PreferAngleExt {
907    pub(crate) prefer_egl: bool,
908}
909#[cfg(windows)]
910impl PreferAngleExt {
911    pub(crate) fn new(_: ApiExtensionId) -> Self {
912        Self { prefer_egl: false }
913    }
914}
915#[cfg(windows)]
916impl WindowExtension for PreferAngleExt {
917    fn is_init_only(&self) -> bool {
918        true
919    }
920
921    fn configure(&mut self, args: &mut WindowConfigArgs) {
922        if let Some(cfg) = args.config {
923            match cfg.deserialize::<bool>() {
924                Ok(y) => self.prefer_egl = y,
925                Err(e) => tracing::error!("invalid arg for 'zng-view.prefer_angle', {e}"),
926            }
927        }
928    }
929
930    fn as_any(&self) -> &dyn Any {
931        self
932    }
933
934    fn as_any_mut(&mut self) -> &mut dyn Any {
935        self
936    }
937}
938
939/// Sets renderer debug flags.
940///
941/// This is a test case of the extensions API.
942pub(crate) struct RendererDebugExt {
943    id: ApiExtensionId,
944    ui: Option<String>,
945}
946
947impl RendererDebugExt {
948    pub(crate) fn new(id: ApiExtensionId) -> Self {
949        Self { id, ui: None }
950    }
951}
952impl RendererExtension for RendererDebugExt {
953    fn is_init_only(&self) -> bool {
954        false
955    }
956
957    fn configure(&mut self, args: &mut RendererConfigArgs) {
958        if let Some(cfg) = args.config.as_ref().and_then(|c| c.deserialize::<RendererDebug>().ok()) {
959            args.options.debug_flags = cfg.flags;
960            self.ui = Some(cfg.profiler_ui);
961        }
962    }
963
964    fn renderer_inited(&mut self, args: &mut RendererInitedArgs) {
965        if let Some(ui) = self.ui.take() {
966            args.renderer.set_profiler_ui(&ui);
967        }
968    }
969
970    fn command(&mut self, args: &mut RendererCommandArgs) -> ApiExtensionPayload {
971        match args.request.deserialize::<RendererDebug>() {
972            Ok(cfg) => {
973                args.renderer.set_debug_flags(cfg.flags);
974                args.renderer.set_profiler_ui(&cfg.profiler_ui);
975                ApiExtensionPayload::empty()
976            }
977            Err(e) => ApiExtensionPayload::invalid_request(self.id, e),
978        }
979    }
980
981    fn as_any(&self) -> &dyn Any {
982        self
983    }
984
985    fn as_any_mut(&mut self) -> &mut dyn Any {
986        self
987    }
988}
989
990/// Webrender renderer debug flags and profiler UI.
991#[derive(serde::Serialize, serde::Deserialize)]
992struct RendererDebug {
993    pub flags: DebugFlags,
994    pub profiler_ui: String,
995}
996
997pub(crate) struct DisplayListExtAdapter<'a> {
998    pub extensions: &'a mut Vec<(ApiExtensionId, Box<dyn RendererExtension>)>,
999    pub transaction: &'a mut webrender::Transaction,
1000    pub renderer: &'a mut webrender::Renderer,
1001    pub api: &'a mut RenderApi,
1002    pub external_images: &'a mut ExternalImages,
1003    pub frame_id: zng_view_api::window::FrameId,
1004}
1005
1006impl DisplayListExtension for DisplayListExtAdapter<'_> {
1007    fn display_list_start(&mut self, args: &mut DisplayExtensionArgs) {
1008        for (_, ext) in self.extensions.iter_mut() {
1009            ext.render_start(&mut RenderArgs {
1010                frame_id: self.frame_id,
1011                list: args.list,
1012                sc: args.sc,
1013                transaction: self.transaction,
1014                renderer: self.renderer,
1015                api: self.api,
1016                external_images: self.external_images,
1017            });
1018        }
1019    }
1020
1021    fn push_display_item(&mut self, args: &mut DisplayExtensionItemArgs) {
1022        for (id, ext) in self.extensions.iter_mut() {
1023            if *id == args.extension_id {
1024                ext.render_push(&mut RenderItemArgs {
1025                    extension_id: args.extension_id,
1026                    payload: args.payload,
1027                    is_reuse: args.is_reuse,
1028                    list: args.list,
1029                    sc: args.sc,
1030                    transaction: self.transaction,
1031                    renderer: self.renderer,
1032                    api: self.api,
1033                    external_images: self.external_images,
1034                });
1035                break;
1036            }
1037        }
1038    }
1039
1040    fn pop_display_item(&mut self, args: &mut DisplayExtensionItemArgs) {
1041        for (id, ext) in self.extensions.iter_mut() {
1042            if *id == args.extension_id {
1043                ext.render_pop(&mut RenderItemArgs {
1044                    extension_id: args.extension_id,
1045                    payload: args.payload,
1046                    is_reuse: args.is_reuse,
1047                    list: args.list,
1048                    sc: args.sc,
1049                    transaction: self.transaction,
1050                    renderer: self.renderer,
1051                    api: self.api,
1052                    external_images: self.external_images,
1053                });
1054                break;
1055            }
1056        }
1057    }
1058
1059    fn display_list_end(&mut self, args: &mut DisplayExtensionArgs) {
1060        for (_, ext) in self.extensions.iter_mut() {
1061            ext.render_end(&mut RenderArgs {
1062                frame_id: self.frame_id,
1063                list: args.list,
1064                sc: args.sc,
1065                transaction: self.transaction,
1066                renderer: self.renderer,
1067                api: self.api,
1068                external_images: self.external_images,
1069            });
1070        }
1071    }
1072
1073    fn update(&mut self, args: &mut DisplayExtensionUpdateArgs) {
1074        for (id, ext) in self.extensions.iter_mut() {
1075            if *id == args.extension_id {
1076                let mut r_args = RenderUpdateArgs {
1077                    extension_id: args.extension_id,
1078                    payload: args.payload,
1079                    new_frame: args.new_frame,
1080                    properties: args.properties,
1081                    transaction: self.transaction,
1082                    renderer: self.renderer,
1083                    api: self.api,
1084                    external_images: self.external_images,
1085                };
1086                ext.render_update(&mut r_args);
1087                args.new_frame = r_args.new_frame;
1088                break;
1089            }
1090        }
1091    }
1092}
1093
1094pub(crate) struct BlobExtensionsImgHandler(pub Vec<Box<dyn BlobExtension>>);
1095
1096impl BlobImageHandler for BlobExtensionsImgHandler {
1097    fn create_blob_rasterizer(&mut self) -> Box<dyn AsyncBlobImageRasterizer> {
1098        Box::new(BlockExtensionsImgRasterizer(
1099            self.0.iter_mut().map(|t| t.create_blob_rasterizer()).collect(),
1100        ))
1101    }
1102
1103    fn create_similar(&self) -> Box<dyn BlobImageHandler> {
1104        Box::new(Self(self.0.iter().map(|e| e.create_similar()).collect()))
1105    }
1106
1107    fn prepare_resources(&mut self, services: &dyn webrender::api::BlobImageResources, requests: &[BlobImageParams]) {
1108        for ext in self.0.iter_mut() {
1109            ext.prepare_resources(&mut BlobPrepareArgs { services, requests })
1110        }
1111    }
1112
1113    fn add(
1114        &mut self,
1115        key: webrender::api::BlobImageKey,
1116        data: std::sync::Arc<webrender::api::BlobImageData>,
1117        visible_rect: &webrender::api::units::DeviceIntRect,
1118        tile_size: webrender::api::TileSize,
1119    ) {
1120        let args = BlobAddArgs {
1121            key,
1122            data,
1123            visible_rect: *visible_rect,
1124            tile_size,
1125        };
1126        for ext in self.0.iter_mut() {
1127            ext.add(&args);
1128        }
1129    }
1130
1131    fn update(
1132        &mut self,
1133        key: webrender::api::BlobImageKey,
1134        data: std::sync::Arc<webrender::api::BlobImageData>,
1135        visible_rect: &webrender::api::units::DeviceIntRect,
1136        dirty_rect: &webrender::api::units::BlobDirtyRect,
1137    ) {
1138        let args = BlobUpdateArgs {
1139            key,
1140            data,
1141            visible_rect: *visible_rect,
1142            dirty_rect: *dirty_rect,
1143        };
1144        for ext in self.0.iter_mut() {
1145            ext.update(&args);
1146        }
1147    }
1148
1149    fn delete(&mut self, key: webrender::api::BlobImageKey) {
1150        for ext in self.0.iter_mut() {
1151            ext.delete(key);
1152        }
1153    }
1154
1155    fn delete_font(&mut self, key: webrender::api::FontKey) {
1156        for ext in self.0.iter_mut() {
1157            ext.delete_font(key);
1158        }
1159    }
1160
1161    fn delete_font_instance(&mut self, key: webrender::api::FontInstanceKey) {
1162        for ext in self.0.iter_mut() {
1163            ext.delete_font_instance(key);
1164        }
1165    }
1166
1167    fn clear_namespace(&mut self, namespace: webrender::api::IdNamespace) {
1168        for ext in self.0.iter_mut() {
1169            ext.clear_namespace(namespace);
1170        }
1171    }
1172
1173    fn enable_multithreading(&mut self, enable: bool) {
1174        for ext in self.0.iter_mut() {
1175            ext.enable_multithreading(enable);
1176        }
1177    }
1178}
1179
1180struct BlockExtensionsImgRasterizer(Vec<Box<dyn AsyncBlobRasterizer>>);
1181impl AsyncBlobImageRasterizer for BlockExtensionsImgRasterizer {
1182    fn rasterize(
1183        &mut self,
1184        requests: &[BlobImageParams],
1185        low_priority: bool,
1186        tile_pool: &mut crate::BlobTilePool,
1187    ) -> Vec<(BlobImageRequest, BlobImageResult)> {
1188        let mut responses = vec![];
1189        for r in &mut self.0 {
1190            r.rasterize(&mut BlobRasterizerArgs {
1191                requests,
1192                low_priority,
1193                tile_pool,
1194                responses: &mut responses,
1195            })
1196        }
1197        responses
1198    }
1199}
1200
1201/// Register a `FnOnce(&mut ViewExtensions)` closure to be called on view-process init to inject custom API extensions.
1202///
1203/// See [`ViewExtensions`] for more details.
1204#[macro_export]
1205macro_rules! view_process_extension {
1206    ($closure:expr) => {
1207        // expanded from:
1208        // #[linkme::distributed_slice(VIEW_EXTENSIONS)]
1209        // static _VIEW_EXTENSIONS: fn(&FooArgs) = foo;
1210        // so that users don't need to depend on linkme just to call this macro.
1211        #[used]
1212        #[cfg_attr(
1213            any(
1214                target_os = "none",
1215                target_os = "linux",
1216                target_os = "android",
1217                target_os = "fuchsia",
1218                target_os = "psp"
1219            ),
1220            unsafe(link_section = "linkme_VIEW_EXTENSIONS")
1221        )]
1222        #[cfg_attr(
1223            any(target_os = "macos", target_os = "ios", target_os = "tvos"),
1224            unsafe(link_section = "__DATA,__linkmeTbhLJz52,regular,no_dead_strip")
1225        )]
1226        #[cfg_attr(
1227            any(target_os = "uefi", target_os = "windows"),
1228            unsafe(link_section = ".linkme_VIEW_EXTENSIONS$b")
1229        )]
1230        #[cfg_attr(target_os = "illumos", unsafe(link_section = "set_linkme_VIEW_EXTENSIONS"))]
1231        #[cfg_attr(
1232            any(target_os = "freebsd", target_os = "openbsd"),
1233            unsafe(link_section = "linkme_VIEW_EXTENSIONS")
1234        )]
1235        #[doc(hidden)]
1236        static _VIEW_EXTENSIONS: fn(&mut $crate::extensions::ViewExtensions) = _view_extensions;
1237        #[doc(hidden)]
1238        fn _view_extensions(ext: &mut $crate::extensions::ViewExtensions) {
1239            fn view_extensions(
1240                ext: &mut $crate::extensions::ViewExtensions,
1241                handler: impl FnOnce(&mut $crate::extensions::ViewExtensions),
1242            ) {
1243                handler(ext)
1244            }
1245            view_extensions(ext, $closure)
1246        }
1247    };
1248}
1249
1250#[doc(hidden)]
1251#[linkme::distributed_slice]
1252pub static VIEW_EXTENSIONS: [fn(&mut ViewExtensions)];