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