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            stripes: Mutex::new(Box::new([])),
575        })
576    }
577
578    /// Unregister the image or texture.
579    ///
580    /// The `id` is invalid after this call, using it in a display list is undefined behavior and
581    /// will likely cause access violation or other memory problems.
582    pub fn unregister(&mut self, id: ExternalImageId) {
583        if let Some(i) = self.images.iter().position(|img| ExternalImageId(Arc::as_ptr(img) as u64) == id) {
584            self.images.swap_remove(i);
585        }
586    }
587
588    fn register(&mut self, img: crate::image_cache::ImageData) -> ExternalImageId {
589        let img = Arc::new(img);
590        let id = ExternalImageId(Arc::as_ptr(&img) as u64);
591        self.images.push(img);
592        id
593    }
594}
595
596/// Arguments for [`RendererExtension::renderer_deinited`].
597#[non_exhaustive]
598pub struct RendererDeinitedArgs<'a> {
599    /// The document ID of the main content, already deinited.
600    pub document_id: DocumentId,
601
602    /// The pipeline of the main content, already deinited.
603    pub pipeline_id: PipelineId,
604
605    /// Winit window if the renderer is associated with a headed window.
606    pub window: Option<&'a winit::window::Window>,
607
608    /// OpenGL context.
609    ///
610    /// The context is current and Webrender has already deinited, the context will be dropped
611    /// after all extensions handle deinit.
612    pub context: &'a mut dyn OpenGlContext,
613}
614
615/// Arguments for [`WindowExtension::window_inited`].
616#[non_exhaustive]
617pub struct WindowInitedArgs<'a> {
618    /// Underlying winit window.
619    pub window: &'a winit::window::Window,
620
621    /// OpenGL context connected to the window or headless surface.
622    pub context: &'a mut dyn OpenGlContext,
623}
624
625/// Arguments for [`WindowExtension::window_deinited`].
626#[non_exhaustive]
627pub struct WindowDeinitedArgs<'a> {
628    /// Underlying winit window.
629    pub window: &'a winit::window::Window,
630
631    /// OpenGL context connected to the window or headless surface.
632    pub context: &'a mut dyn OpenGlContext,
633}
634
635/// Arguments for [`WindowExtension::command`].
636#[non_exhaustive]
637pub struct WindowCommandArgs<'a> {
638    /// Underlying winit window.
639    pub window: &'a winit::window::Window,
640
641    /// OpenGL context connected to the window or headless surface.
642    pub context: &'a mut dyn OpenGlContext,
643
644    /// The command request.
645    pub request: ApiExtensionPayload,
646}
647
648/// Arguments for [`WindowExtension::event`].
649#[non_exhaustive]
650pub struct WindowEventArgs<'a> {
651    /// Underlying winit window.
652    pub window: &'a winit::window::Window,
653
654    /// OpenGL context connected to the window or headless surface.
655    pub context: &'a mut dyn OpenGlContext,
656
657    /// The event.
658    pub event: &'a winit::event::WindowEvent,
659}
660
661/// Represents a managed OpenGL context connected to a window or headless surface.
662pub trait OpenGlContext {
663    /// Context is current on the calling thread.
664    fn is_current(&self) -> bool;
665
666    /// Make context current on the calling thread.
667    fn make_current(&mut self);
668
669    /// The context.
670    fn gl(&self) -> &Rc<dyn gleam::gl::Gl>;
671
672    /// Actual render mode used to create the context.
673    fn render_mode(&self) -> RenderMode;
674
675    /// Resize surface.
676    fn resize(&mut self, size: PxSize);
677
678    /// If the context runs on the CPU, not a GPU.
679    fn is_software(&self) -> bool;
680
681    /// Swap buffers if the context is double-buffered.
682    fn swap_buffers(&mut self);
683}
684impl OpenGlContext for crate::gl::GlContext {
685    fn is_current(&self) -> bool {
686        self.is_current()
687    }
688
689    fn make_current(&mut self) {
690        self.make_current()
691    }
692
693    fn gl(&self) -> &Rc<dyn gleam::gl::Gl> {
694        self.gl()
695    }
696
697    fn render_mode(&self) -> RenderMode {
698        self.render_mode()
699    }
700
701    fn resize(&mut self, size: PxSize) {
702        self.resize(size.to_winit())
703    }
704
705    fn is_software(&self) -> bool {
706        self.is_software()
707    }
708
709    fn swap_buffers(&mut self) {
710        self.swap_buffers()
711    }
712}
713
714/// Arguments for [`RendererExtension::command`].
715#[non_exhaustive]
716pub struct RendererCommandArgs<'a> {
717    /// The renderer.
718    pub renderer: &'a mut webrender::Renderer,
719
720    /// The render API used by the window or surface.
721    pub api: &'a mut RenderApi,
722
723    /// The document ID of the main content.
724    pub document_id: DocumentId,
725
726    /// The command request.
727    pub request: ApiExtensionPayload,
728
729    /// Winit window if the renderer is associated with a headed window.
730    pub window: Option<&'a winit::window::Window>,
731
732    /// OpenGL context associated with the renderer.
733    pub context: &'a mut dyn OpenGlContext,
734
735    /// Redraw flag.
736    ///
737    /// If set to `true` the window is guaranteed to redraw the frame.
738    pub redraw: &'a mut bool,
739}
740
741/// View extensions register.
742pub struct ViewExtensions {
743    exts: Vec<Box<dyn ViewExtension>>,
744}
745impl ViewExtensions {
746    /// New empty.
747    pub(crate) fn new() -> Self {
748        Self { exts: vec![] }
749    }
750
751    /// Register an extension with the ID that will be assigned to it.
752    ///
753    /// The ID is useful for error messages.
754    ///
755    /// # Panics
756    ///
757    /// Panics if the name is already registered.
758    pub fn register<E: ViewExtension>(&mut self, ext: impl FnOnce(ApiExtensionId) -> E) -> &mut Self {
759        let id = ApiExtensionId::from_index(self.exts.len());
760        let ext = ext(id);
761        assert!(self.id(ext.name()).is_none(), "extension already registered");
762        self.exts.push(Box::new(ext));
763        self
764    }
765
766    /// Returns the extension ID.
767    pub fn id(&self, name: &ApiExtensionName) -> Option<ApiExtensionId> {
768        self.exts.iter().position(|e| e.name() == name).map(ApiExtensionId::from_index)
769    }
770
771    /// Register a command extension with custom encoded messages.
772    ///
773    /// The `handler` receives the request payload and it's own ID to be used in error messages.
774    pub fn command_raw(
775        &mut self,
776        name: impl Into<ApiExtensionName>,
777        handler: impl FnMut(ApiExtensionPayload, ApiExtensionId) -> ApiExtensionPayload + Send + 'static,
778    ) -> &mut Self {
779        struct CommandExt<F>(ApiExtensionName, ApiExtensionId, F);
780        impl<F: FnMut(ApiExtensionPayload, ApiExtensionId) -> ApiExtensionPayload + Send + 'static> ViewExtension for CommandExt<F> {
781            fn name(&self) -> &ApiExtensionName {
782                &self.0
783            }
784            fn command(&mut self, request: ApiExtensionPayload) -> Option<ApiExtensionPayload> {
785                Some((self.2)(request, self.1))
786            }
787        }
788
789        self.register(|id| CommandExt(name.into(), id, handler));
790        self
791    }
792
793    /// Register a command extension.
794    ///
795    /// The `handler` receives the deserialized request payload and it's own ID to be used in error messages.
796    pub fn command<I: serde::de::DeserializeOwned, O: serde::Serialize>(
797        &mut self,
798        name: impl Into<ApiExtensionName>,
799        mut handler: impl FnMut(I, ApiExtensionId) -> O + Send + 'static,
800    ) -> &mut Self {
801        self.command_raw(name, move |p, id| match p.deserialize::<I>() {
802            Ok(p) => {
803                let o = handler(p, id);
804                ApiExtensionPayload::serialize(&o).unwrap()
805            }
806            Err(e) => ApiExtensionPayload::invalid_request(id, e),
807        })
808    }
809
810    /// Register a window extension with its own ID.
811    pub fn window<E: WindowExtension>(
812        &mut self,
813        name: impl Into<ApiExtensionName>,
814        new: impl FnMut(ApiExtensionId) -> E + Send + 'static,
815    ) -> &mut Self {
816        struct WindowExt<F>(ApiExtensionName, ApiExtensionId, F);
817        impl<E, F> ViewExtension for WindowExt<F>
818        where
819            E: WindowExtension,
820            F: FnMut(ApiExtensionId) -> E + Send + 'static,
821        {
822            fn name(&self) -> &ApiExtensionName {
823                &self.0
824            }
825
826            fn window(&mut self) -> Option<Box<dyn WindowExtension>> {
827                Some(Box::new((self.2)(self.1)))
828            }
829        }
830        self.register(move |id| WindowExt(name.into(), id, new));
831        self
832    }
833
834    /// Register a renderer extension with its own ID.
835    pub fn renderer<E: RendererExtension>(
836        &mut self,
837        name: impl Into<ApiExtensionName>,
838        new: impl FnMut(ApiExtensionId) -> E + Send + 'static,
839    ) -> &mut Self {
840        struct RendererExt<F>(ApiExtensionName, ApiExtensionId, F);
841        impl<E, F> ViewExtension for RendererExt<F>
842        where
843            E: RendererExtension,
844            F: FnMut(ApiExtensionId) -> E + Send + 'static,
845        {
846            fn name(&self) -> &ApiExtensionName {
847                &self.0
848            }
849
850            fn renderer(&mut self) -> Option<Box<dyn RendererExtension>> {
851                Some(Box::new((self.2)(self.1)))
852            }
853        }
854        self.register(move |id| RendererExt(name.into(), id, new));
855        self
856    }
857
858    pub(crate) fn api_extensions(&self) -> ApiExtensions {
859        let mut r = ApiExtensions::new();
860        for ext in &self.exts {
861            r.insert(ext.name().clone()).unwrap();
862        }
863        r
864    }
865
866    pub(crate) fn call_command(&mut self, id: ApiExtensionId, request: ApiExtensionPayload) -> ApiExtensionPayload {
867        let idx = id.index();
868        if idx >= self.exts.len() {
869            ApiExtensionPayload::unknown_extension(id)
870        } else if let Some(r) = self.exts[idx].command(request) {
871            r
872        } else {
873            ApiExtensionPayload::unknown_extension(id)
874        }
875    }
876
877    pub(crate) fn new_window(&mut self) -> Vec<(ApiExtensionId, Box<dyn WindowExtension>)> {
878        self.exts
879            .iter_mut()
880            .enumerate()
881            .filter_map(|(i, e)| e.window().map(|e| (ApiExtensionId::from_index(i), e)))
882            .collect()
883    }
884
885    pub(crate) fn new_renderer(&mut self) -> Vec<(ApiExtensionId, Box<dyn RendererExtension>)> {
886        self.exts
887            .iter_mut()
888            .enumerate()
889            .filter_map(|(i, e)| e.renderer().map(|e| (ApiExtensionId::from_index(i), e)))
890            .collect()
891    }
892
893    pub(crate) fn init(&mut self, event_sender: &crate::AppEventSender) {
894        for (i, ext) in self.exts.iter_mut().enumerate() {
895            ext.init(ViewExtensionInitArgs {
896                event_sender: ExtensionEventSender {
897                    sender: event_sender.clone(),
898                    id: ApiExtensionId::from_index(i),
899                },
900            });
901        }
902    }
903
904    pub(crate) fn on_low_memory(&mut self) {
905        for ext in self.exts.iter_mut() {
906            ext.low_memory();
907        }
908    }
909
910    pub(crate) fn suspended(&mut self) {
911        for ext in self.exts.iter_mut() {
912            ext.suspended();
913        }
914    }
915
916    pub(crate) fn resumed(&mut self) {
917        for ext in self.exts.iter_mut() {
918            ext.resumed();
919        }
920    }
921
922    /// Add `other` to self.
923    pub fn append(&mut self, mut other: ViewExtensions) {
924        self.exts.append(&mut other.exts);
925    }
926}
927
928#[cfg(windows)]
929pub(crate) struct PreferAngleExt {
930    pub(crate) prefer_egl: bool,
931}
932#[cfg(windows)]
933impl PreferAngleExt {
934    pub(crate) fn new(_: ApiExtensionId) -> Self {
935        Self { prefer_egl: false }
936    }
937}
938#[cfg(windows)]
939impl WindowExtension for PreferAngleExt {
940    fn is_init_only(&self) -> bool {
941        true
942    }
943
944    fn configure(&mut self, args: &mut WindowConfigArgs) {
945        if let Some(cfg) = args.config {
946            match cfg.deserialize::<bool>() {
947                Ok(y) => self.prefer_egl = y,
948                Err(e) => tracing::error!("invalid arg for 'zng-view.prefer_angle', {e}"),
949            }
950        }
951    }
952
953    fn as_any(&self) -> &dyn Any {
954        self
955    }
956
957    fn as_any_mut(&mut self) -> &mut dyn Any {
958        self
959    }
960}
961
962/// Sets renderer debug flags.
963///
964/// This is a test case of the extensions API.
965pub(crate) struct RendererDebugExt {
966    id: ApiExtensionId,
967    ui: Option<String>,
968}
969
970impl RendererDebugExt {
971    pub(crate) fn new(id: ApiExtensionId) -> Self {
972        Self { id, ui: None }
973    }
974}
975impl RendererExtension for RendererDebugExt {
976    fn is_init_only(&self) -> bool {
977        false
978    }
979
980    fn configure(&mut self, args: &mut RendererConfigArgs) {
981        if let Some(cfg) = args.config.as_ref().and_then(|c| c.deserialize::<RendererDebug>().ok()) {
982            args.options.debug_flags = cfg.flags;
983            self.ui = Some(cfg.profiler_ui);
984        }
985    }
986
987    fn renderer_inited(&mut self, args: &mut RendererInitedArgs) {
988        if let Some(ui) = self.ui.take() {
989            args.renderer.set_profiler_ui(&ui);
990        }
991    }
992
993    fn command(&mut self, args: &mut RendererCommandArgs) -> ApiExtensionPayload {
994        match args.request.deserialize::<RendererDebug>() {
995            Ok(cfg) => {
996                args.renderer.set_debug_flags(cfg.flags);
997                args.renderer.set_profiler_ui(&cfg.profiler_ui);
998                ApiExtensionPayload::empty()
999            }
1000            Err(e) => ApiExtensionPayload::invalid_request(self.id, e),
1001        }
1002    }
1003
1004    fn as_any(&self) -> &dyn Any {
1005        self
1006    }
1007
1008    fn as_any_mut(&mut self) -> &mut dyn Any {
1009        self
1010    }
1011}
1012
1013/// Webrender renderer debug flags and profiler UI.
1014#[derive(serde::Serialize, serde::Deserialize)]
1015struct RendererDebug {
1016    pub flags: DebugFlags,
1017    pub profiler_ui: String,
1018}
1019
1020pub(crate) struct DisplayListExtAdapter<'a> {
1021    pub extensions: &'a mut Vec<(ApiExtensionId, Box<dyn RendererExtension>)>,
1022    pub transaction: &'a mut webrender::Transaction,
1023    pub renderer: &'a mut webrender::Renderer,
1024    pub document_id: DocumentId,
1025    pub api: &'a mut RenderApi,
1026    pub external_images: &'a mut ExternalImages,
1027    pub frame_id: zng_view_api::window::FrameId,
1028}
1029
1030impl DisplayListExtension for DisplayListExtAdapter<'_> {
1031    fn display_list_start(&mut self, args: &mut DisplayExtensionArgs) {
1032        for (_, ext) in self.extensions.iter_mut() {
1033            ext.render_start(&mut RenderArgs {
1034                frame_id: self.frame_id,
1035                list: args.list,
1036                sc: args.sc,
1037                transaction: self.transaction,
1038                renderer: self.renderer,
1039                document_id: self.document_id,
1040                api: self.api,
1041                external_images: self.external_images,
1042            });
1043        }
1044    }
1045
1046    fn push_display_item(&mut self, args: &mut DisplayExtensionItemArgs) {
1047        for (id, ext) in self.extensions.iter_mut() {
1048            if *id == args.extension_id {
1049                ext.render_push(&mut RenderItemArgs {
1050                    extension_id: args.extension_id,
1051                    payload: args.payload,
1052                    is_reuse: args.is_reuse,
1053                    list: args.list,
1054                    sc: args.sc,
1055                    transaction: self.transaction,
1056                    renderer: self.renderer,
1057                    document_id: self.document_id,
1058                    api: self.api,
1059                    external_images: self.external_images,
1060                });
1061                break;
1062            }
1063        }
1064    }
1065
1066    fn pop_display_item(&mut self, args: &mut DisplayExtensionItemArgs) {
1067        for (id, ext) in self.extensions.iter_mut() {
1068            if *id == args.extension_id {
1069                ext.render_pop(&mut RenderItemArgs {
1070                    extension_id: args.extension_id,
1071                    payload: args.payload,
1072                    is_reuse: args.is_reuse,
1073                    list: args.list,
1074                    sc: args.sc,
1075                    transaction: self.transaction,
1076                    renderer: self.renderer,
1077                    document_id: self.document_id,
1078                    api: self.api,
1079                    external_images: self.external_images,
1080                });
1081                break;
1082            }
1083        }
1084    }
1085
1086    fn display_list_end(&mut self, args: &mut DisplayExtensionArgs) {
1087        for (_, ext) in self.extensions.iter_mut() {
1088            ext.render_end(&mut RenderArgs {
1089                frame_id: self.frame_id,
1090                list: args.list,
1091                sc: args.sc,
1092                transaction: self.transaction,
1093                renderer: self.renderer,
1094                document_id: self.document_id,
1095                api: self.api,
1096                external_images: self.external_images,
1097            });
1098        }
1099    }
1100
1101    fn update(&mut self, args: &mut DisplayExtensionUpdateArgs) {
1102        for (id, ext) in self.extensions.iter_mut() {
1103            if *id == args.extension_id {
1104                let mut r_args = RenderUpdateArgs {
1105                    extension_id: args.extension_id,
1106                    payload: args.payload,
1107                    new_frame: args.new_frame,
1108                    properties: args.properties,
1109                    document_id: self.document_id,
1110                    transaction: self.transaction,
1111                    renderer: self.renderer,
1112                    api: self.api,
1113                    external_images: self.external_images,
1114                };
1115                ext.render_update(&mut r_args);
1116                args.new_frame = r_args.new_frame;
1117                break;
1118            }
1119        }
1120    }
1121}
1122
1123pub(crate) struct BlobExtensionsImgHandler(pub Vec<Box<dyn BlobExtension>>);
1124
1125impl BlobImageHandler for BlobExtensionsImgHandler {
1126    fn create_blob_rasterizer(&mut self) -> Box<dyn AsyncBlobImageRasterizer> {
1127        Box::new(BlockExtensionsImgRasterizer(
1128            self.0.iter_mut().map(|t| t.create_blob_rasterizer()).collect(),
1129        ))
1130    }
1131
1132    fn create_similar(&self) -> Box<dyn BlobImageHandler> {
1133        Box::new(Self(self.0.iter().map(|e| e.create_similar()).collect()))
1134    }
1135
1136    fn prepare_resources(&mut self, services: &dyn webrender::api::BlobImageResources, requests: &[BlobImageParams]) {
1137        for ext in self.0.iter_mut() {
1138            ext.prepare_resources(&mut BlobPrepareArgs { services, requests })
1139        }
1140    }
1141
1142    fn add(
1143        &mut self,
1144        key: webrender::api::BlobImageKey,
1145        data: std::sync::Arc<webrender::api::BlobImageData>,
1146        visible_rect: &webrender::api::units::DeviceIntRect,
1147        tile_size: webrender::api::TileSize,
1148    ) {
1149        let args = BlobAddArgs {
1150            key,
1151            data,
1152            visible_rect: *visible_rect,
1153            tile_size,
1154        };
1155        for ext in self.0.iter_mut() {
1156            ext.add(&args);
1157        }
1158    }
1159
1160    fn update(
1161        &mut self,
1162        key: webrender::api::BlobImageKey,
1163        data: std::sync::Arc<webrender::api::BlobImageData>,
1164        visible_rect: &webrender::api::units::DeviceIntRect,
1165        dirty_rect: &webrender::api::units::BlobDirtyRect,
1166    ) {
1167        let args = BlobUpdateArgs {
1168            key,
1169            data,
1170            visible_rect: *visible_rect,
1171            dirty_rect: *dirty_rect,
1172        };
1173        for ext in self.0.iter_mut() {
1174            ext.update(&args);
1175        }
1176    }
1177
1178    fn delete(&mut self, key: webrender::api::BlobImageKey) {
1179        for ext in self.0.iter_mut() {
1180            ext.delete(key);
1181        }
1182    }
1183
1184    fn delete_font(&mut self, key: webrender::api::FontKey) {
1185        for ext in self.0.iter_mut() {
1186            ext.delete_font(key);
1187        }
1188    }
1189
1190    fn delete_font_instance(&mut self, key: webrender::api::FontInstanceKey) {
1191        for ext in self.0.iter_mut() {
1192            ext.delete_font_instance(key);
1193        }
1194    }
1195
1196    fn clear_namespace(&mut self, namespace: webrender::api::IdNamespace) {
1197        for ext in self.0.iter_mut() {
1198            ext.clear_namespace(namespace);
1199        }
1200    }
1201
1202    fn enable_multithreading(&mut self, enable: bool) {
1203        for ext in self.0.iter_mut() {
1204            ext.enable_multithreading(enable);
1205        }
1206    }
1207}
1208
1209struct BlockExtensionsImgRasterizer(Vec<Box<dyn AsyncBlobRasterizer>>);
1210impl AsyncBlobImageRasterizer for BlockExtensionsImgRasterizer {
1211    fn rasterize(
1212        &mut self,
1213        requests: &[BlobImageParams],
1214        low_priority: bool,
1215        tile_pool: &mut crate::BlobTilePool,
1216    ) -> Vec<(BlobImageRequest, BlobImageResult)> {
1217        let mut responses = vec![];
1218        for r in &mut self.0 {
1219            r.rasterize(&mut BlobRasterizerArgs {
1220                requests,
1221                low_priority,
1222                tile_pool,
1223                responses: &mut responses,
1224            })
1225        }
1226        responses
1227    }
1228}
1229
1230/// Register a `FnOnce(&mut ViewExtensions)` closure to be called on view-process init to inject custom API extensions.
1231///
1232/// See [`ViewExtensions`] for more details.
1233#[macro_export]
1234macro_rules! view_process_extension {
1235    ($closure:expr) => {
1236        // expanded from:
1237        // #[linkme::distributed_slice(VIEW_EXTENSIONS)]
1238        // static _VIEW_EXTENSIONS: fn(&FooArgs) = foo;
1239        // so that users don't need to depend on linkme just to call this macro.
1240        #[used]
1241        #[cfg_attr(
1242            any(
1243                target_os = "none",
1244                target_os = "linux",
1245                target_os = "android",
1246                target_os = "fuchsia",
1247                target_os = "psp"
1248            ),
1249            unsafe(link_section = "linkme_VIEW_EXTENSIONS")
1250        )]
1251        #[cfg_attr(
1252            any(target_os = "macos", target_os = "ios", target_os = "tvos"),
1253            unsafe(link_section = "__DATA,__linkmeTbhLJz52,regular,no_dead_strip")
1254        )]
1255        #[cfg_attr(
1256            any(target_os = "uefi", target_os = "windows"),
1257            unsafe(link_section = ".linkme_VIEW_EXTENSIONS$b")
1258        )]
1259        #[cfg_attr(target_os = "illumos", unsafe(link_section = "set_linkme_VIEW_EXTENSIONS"))]
1260        #[cfg_attr(
1261            any(target_os = "freebsd", target_os = "openbsd"),
1262            unsafe(link_section = "linkme_VIEW_EXTENSIONS")
1263        )]
1264        #[doc(hidden)]
1265        static _VIEW_EXTENSIONS: fn(&mut $crate::extensions::ViewExtensions) = _view_extensions;
1266        #[doc(hidden)]
1267        fn _view_extensions(ext: &mut $crate::extensions::ViewExtensions) {
1268            fn view_extensions(
1269                ext: &mut $crate::extensions::ViewExtensions,
1270                handler: impl FnOnce(&mut $crate::extensions::ViewExtensions),
1271            ) {
1272                handler(ext)
1273            }
1274            view_extensions(ext, $closure)
1275        }
1276    };
1277}
1278
1279#[doc(hidden)]
1280#[linkme::distributed_slice]
1281pub static VIEW_EXTENSIONS: [fn(&mut ViewExtensions)];