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