use std::rc::Rc;
use std::{any::Any, sync::Arc};
use webrender::api::{
AsyncBlobImageRasterizer, BlobImageHandler, BlobImageParams, BlobImageRequest, BlobImageResult, DocumentId, ExternalImageId,
PipelineId, units::TexelRect,
};
use webrender::{DebugFlags, RenderApi};
use zng_task::channel::{ChannelError, IpcBytes};
use zng_task::parking_lot::Mutex;
use zng_unit::{Factor, PxSize};
use zng_view_api::window::RenderMode;
use zng_view_api::{
Event,
api_extension::{ApiExtensionId, ApiExtensionName, ApiExtensionPayload, ApiExtensions},
};
use crate::display_list::{DisplayExtensionArgs, DisplayExtensionItemArgs, DisplayExtensionUpdateArgs, DisplayListExtension, SpaceAndClip};
pub use crate::px_wr::{PxToWr, WrToPx};
use crate::util::PxToWinit;
pub trait ViewExtension: Send + Any {
fn init(&mut self, args: ViewExtensionInitArgs) {
let _ = args;
}
fn name(&self) -> &ApiExtensionName;
fn command(&mut self, request: ApiExtensionPayload) -> Option<ApiExtensionPayload> {
let _ = request;
None
}
fn window(&mut self) -> Option<Box<dyn WindowExtension>> {
None
}
fn renderer(&mut self) -> Option<Box<dyn RendererExtension>> {
None
}
fn low_memory(&mut self) {}
fn suspended(&mut self) {}
fn resumed(&mut self) {}
}
pub trait WindowExtension: Any {
fn configure(&mut self, args: &mut WindowConfigArgs) {
let _ = args;
}
fn window_inited(&mut self, args: &mut WindowInitedArgs) {
let _ = args;
}
fn is_init_only(&self) -> bool;
fn command(&mut self, args: &mut WindowCommandArgs) -> ApiExtensionPayload {
let _ = args;
ApiExtensionPayload::unknown_extension(ApiExtensionId::INVALID)
}
fn event(&mut self, args: &mut WindowEventArgs) {
let _ = args;
}
fn low_memory(&mut self) {}
fn window_deinited(&mut self, args: &mut WindowDeinitedArgs) {
let _ = args;
}
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
pub trait RendererExtension: Any {
fn configure(&mut self, args: &mut RendererConfigArgs) {
let _ = args;
}
fn renderer_inited(&mut self, args: &mut RendererInitedArgs) {
let _ = args;
}
fn is_init_only(&self) -> bool;
fn command(&mut self, args: &mut RendererCommandArgs) -> ApiExtensionPayload {
let _ = args;
ApiExtensionPayload::unknown_extension(ApiExtensionId::INVALID)
}
fn render_start(&mut self, args: &mut RenderArgs) {
let _ = args;
}
fn render_push(&mut self, args: &mut RenderItemArgs) {
let _ = args;
}
fn render_pop(&mut self, args: &mut RenderItemArgs) {
let _ = args;
}
fn render_end(&mut self, args: &mut RenderArgs) {
let _ = args;
}
fn render_update(&mut self, args: &mut RenderUpdateArgs) {
let _ = args;
}
fn frame_ready(&mut self, args: &mut FrameReadyArgs) {
let _ = args;
}
fn redraw(&mut self, args: &mut RedrawArgs) {
let _ = args;
}
fn low_memory(&mut self) {}
fn renderer_deinited(&mut self, args: &mut RendererDeinitedArgs) {
let _ = args;
}
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
#[non_exhaustive]
pub struct RenderArgs<'a> {
pub frame_id: zng_view_api::window::FrameId,
pub list: &'a mut webrender::api::DisplayListBuilder,
pub sc: &'a mut SpaceAndClip,
pub transaction: &'a mut webrender::Transaction,
pub renderer: &'a mut webrender::Renderer,
pub document_id: DocumentId,
pub api: &'a mut RenderApi,
pub external_images: &'a mut ExternalImages,
}
#[non_exhaustive]
pub struct RenderItemArgs<'a> {
pub extension_id: ApiExtensionId,
pub payload: &'a ApiExtensionPayload,
pub is_reuse: bool,
pub list: &'a mut webrender::api::DisplayListBuilder,
pub sc: &'a mut SpaceAndClip,
pub transaction: &'a mut webrender::Transaction,
pub renderer: &'a mut webrender::Renderer,
pub document_id: DocumentId,
pub api: &'a mut RenderApi,
pub external_images: &'a mut ExternalImages,
}
#[non_exhaustive]
pub struct RenderUpdateArgs<'a> {
pub extension_id: ApiExtensionId,
pub payload: &'a ApiExtensionPayload,
pub new_frame: bool,
pub properties: &'a mut webrender::api::DynamicProperties,
pub transaction: &'a mut webrender::Transaction,
pub renderer: &'a mut webrender::Renderer,
pub document_id: DocumentId,
pub api: &'a mut RenderApi,
pub external_images: &'a mut ExternalImages,
}
#[non_exhaustive]
pub struct FrameReadyArgs {
pub frame_id: zng_view_api::window::FrameId,
pub redraw: bool,
}
#[non_exhaustive]
pub struct RedrawArgs<'a> {
pub scale_factor: Factor,
pub size: PxSize,
pub context: &'a mut dyn OpenGlContext,
}
pub trait BlobExtension: Send + Any {
fn create_blob_rasterizer(&mut self) -> Box<dyn AsyncBlobRasterizer>;
fn create_similar(&self) -> Box<dyn BlobExtension>;
fn prepare_resources(&mut self, args: &mut BlobPrepareArgs) {
let _ = args;
}
fn add(&mut self, args: &BlobAddArgs);
fn update(&mut self, args: &BlobUpdateArgs);
fn delete(&mut self, key: webrender::api::BlobImageKey);
fn delete_font(&mut self, key: webrender::api::FontKey) {
let _ = key;
}
fn delete_font_instance(&mut self, key: webrender::api::FontInstanceKey) {
let _ = key;
}
fn clear_namespace(&mut self, namespace: webrender::api::IdNamespace) {
let _ = namespace;
}
fn enable_multithreading(&mut self, enable: bool);
}
#[non_exhaustive]
pub struct ViewExtensionInitArgs {
pub event_sender: ExtensionEventSender,
}
#[derive(Clone)]
pub struct ExtensionEventSender {
sender: crate::AppEventSender,
id: ApiExtensionId,
}
impl ExtensionEventSender {
pub fn send(&self, payload: ApiExtensionPayload) -> Result<(), ChannelError> {
self.sender.send(crate::AppEvent::Notify(Event::ExtensionEvent(self.id, payload)))
}
}
pub trait AsyncBlobRasterizer: Send + Any {
fn rasterize(&mut self, args: &mut BlobRasterizerArgs);
}
#[non_exhaustive]
pub struct BlobPrepareArgs<'a> {
pub services: &'a dyn webrender::api::BlobImageResources,
pub requests: &'a [BlobImageParams],
}
#[non_exhaustive]
pub struct BlobAddArgs {
pub key: webrender::api::BlobImageKey,
pub data: std::sync::Arc<webrender::api::BlobImageData>,
pub visible_rect: webrender::api::units::DeviceIntRect,
pub tile_size: webrender::api::TileSize,
}
#[non_exhaustive]
pub struct BlobUpdateArgs {
pub key: webrender::api::BlobImageKey,
pub data: std::sync::Arc<webrender::api::BlobImageData>,
pub visible_rect: webrender::api::units::DeviceIntRect,
pub dirty_rect: webrender::api::units::BlobDirtyRect,
}
#[non_exhaustive]
pub struct BlobRasterizerArgs<'a> {
pub requests: &'a [BlobImageParams],
pub low_priority: bool,
pub tile_pool: &'a mut webrender::api::BlobTilePool,
pub responses: &'a mut Vec<(BlobImageRequest, BlobImageResult)>,
}
#[non_exhaustive]
pub struct WindowConfigArgs<'a> {
pub config: Option<&'a ApiExtensionPayload>,
pub window: Option<&'a mut winit::window::WindowAttributes>,
}
#[non_exhaustive]
pub struct RendererConfigArgs<'a> {
pub config: Option<&'a ApiExtensionPayload>,
pub options: &'a mut webrender::WebRenderOptions,
pub blobs: &'a mut Vec<Box<dyn BlobExtension>>,
pub window: Option<&'a winit::window::Window>,
pub context: &'a mut dyn OpenGlContext,
}
#[non_exhaustive]
pub struct RendererInitedArgs<'a> {
pub renderer: &'a mut webrender::Renderer,
pub api_sender: &'a webrender::RenderApiSender,
pub api: &'a mut RenderApi,
pub document_id: DocumentId,
pub pipeline_id: PipelineId,
pub window: Option<&'a winit::window::Window>,
pub context: &'a mut dyn OpenGlContext,
pub external_images: &'a mut ExternalImages,
}
#[derive(Default)]
pub struct ExternalImages {
images: Vec<Arc<crate::image_cache::ImageData>>,
}
impl ExternalImages {
pub fn register_texture(&mut self, uv: TexelRect, texture: gleam::gl::GLuint) -> ExternalImageId {
self.register(crate::image_cache::ImageData::NativeTexture { uv, texture })
}
pub fn register_image(&mut self, size: PxSize, is_opaque: bool, pixels: IpcBytes) -> ExternalImageId {
let expected_len = size.width.0 as usize * size.height.0 as usize;
assert!(
pixels.len() == expected_len || pixels.len() == expected_len * 4,
"pixels must be BGRA8 or A8"
);
self.register(crate::image_cache::ImageData::RawData {
size,
range: 0..pixels.len(),
pixels,
is_opaque,
density: None,
stripes: Mutex::new(Box::new([])),
})
}
pub fn unregister(&mut self, id: ExternalImageId) {
if let Some(i) = self.images.iter().position(|img| ExternalImageId(Arc::as_ptr(img) as u64) == id) {
self.images.swap_remove(i);
}
}
fn register(&mut self, img: crate::image_cache::ImageData) -> ExternalImageId {
let img = Arc::new(img);
let id = ExternalImageId(Arc::as_ptr(&img) as u64);
self.images.push(img);
id
}
}
#[non_exhaustive]
pub struct RendererDeinitedArgs<'a> {
pub document_id: DocumentId,
pub pipeline_id: PipelineId,
pub window: Option<&'a winit::window::Window>,
pub context: &'a mut dyn OpenGlContext,
}
#[non_exhaustive]
pub struct WindowInitedArgs<'a> {
pub window: &'a winit::window::Window,
pub context: &'a mut dyn OpenGlContext,
}
#[non_exhaustive]
pub struct WindowDeinitedArgs<'a> {
pub window: &'a winit::window::Window,
pub context: &'a mut dyn OpenGlContext,
}
#[non_exhaustive]
pub struct WindowCommandArgs<'a> {
pub window: &'a winit::window::Window,
pub context: &'a mut dyn OpenGlContext,
pub request: ApiExtensionPayload,
}
#[non_exhaustive]
pub struct WindowEventArgs<'a> {
pub window: &'a winit::window::Window,
pub context: &'a mut dyn OpenGlContext,
pub event: &'a winit::event::WindowEvent,
}
pub trait OpenGlContext {
fn is_current(&self) -> bool;
fn make_current(&mut self);
fn gl(&self) -> &Rc<dyn gleam::gl::Gl>;
fn render_mode(&self) -> RenderMode;
fn resize(&mut self, size: PxSize);
fn is_software(&self) -> bool;
fn swap_buffers(&mut self);
}
impl OpenGlContext for crate::gl::GlContext {
fn is_current(&self) -> bool {
self.is_current()
}
fn make_current(&mut self) {
self.make_current()
}
fn gl(&self) -> &Rc<dyn gleam::gl::Gl> {
self.gl()
}
fn render_mode(&self) -> RenderMode {
self.render_mode()
}
fn resize(&mut self, size: PxSize) {
self.resize(size.to_winit())
}
fn is_software(&self) -> bool {
self.is_software()
}
fn swap_buffers(&mut self) {
self.swap_buffers()
}
}
#[non_exhaustive]
pub struct RendererCommandArgs<'a> {
pub renderer: &'a mut webrender::Renderer,
pub api: &'a mut RenderApi,
pub document_id: DocumentId,
pub request: ApiExtensionPayload,
pub window: Option<&'a winit::window::Window>,
pub context: &'a mut dyn OpenGlContext,
pub redraw: &'a mut bool,
}
pub struct ViewExtensions {
exts: Vec<Box<dyn ViewExtension>>,
}
impl ViewExtensions {
pub(crate) fn new() -> Self {
Self { exts: vec![] }
}
pub fn register<E: ViewExtension>(&mut self, ext: impl FnOnce(ApiExtensionId) -> E) -> &mut Self {
let id = ApiExtensionId::from_index(self.exts.len());
let ext = ext(id);
assert!(self.id(ext.name()).is_none(), "extension already registered");
self.exts.push(Box::new(ext));
self
}
pub fn id(&self, name: &ApiExtensionName) -> Option<ApiExtensionId> {
self.exts.iter().position(|e| e.name() == name).map(ApiExtensionId::from_index)
}
pub fn command_raw(
&mut self,
name: impl Into<ApiExtensionName>,
handler: impl FnMut(ApiExtensionPayload, ApiExtensionId) -> ApiExtensionPayload + Send + 'static,
) -> &mut Self {
struct CommandExt<F>(ApiExtensionName, ApiExtensionId, F);
impl<F: FnMut(ApiExtensionPayload, ApiExtensionId) -> ApiExtensionPayload + Send + 'static> ViewExtension for CommandExt<F> {
fn name(&self) -> &ApiExtensionName {
&self.0
}
fn command(&mut self, request: ApiExtensionPayload) -> Option<ApiExtensionPayload> {
Some((self.2)(request, self.1))
}
}
self.register(|id| CommandExt(name.into(), id, handler));
self
}
pub fn command<I: serde::de::DeserializeOwned, O: serde::Serialize>(
&mut self,
name: impl Into<ApiExtensionName>,
mut handler: impl FnMut(I, ApiExtensionId) -> O + Send + 'static,
) -> &mut Self {
self.command_raw(name, move |p, id| match p.deserialize::<I>() {
Ok(p) => {
let o = handler(p, id);
ApiExtensionPayload::serialize(&o).unwrap()
}
Err(e) => ApiExtensionPayload::invalid_request(id, e),
})
}
pub fn window<E: WindowExtension>(
&mut self,
name: impl Into<ApiExtensionName>,
new: impl FnMut(ApiExtensionId) -> E + Send + 'static,
) -> &mut Self {
struct WindowExt<F>(ApiExtensionName, ApiExtensionId, F);
impl<E, F> ViewExtension for WindowExt<F>
where
E: WindowExtension,
F: FnMut(ApiExtensionId) -> E + Send + 'static,
{
fn name(&self) -> &ApiExtensionName {
&self.0
}
fn window(&mut self) -> Option<Box<dyn WindowExtension>> {
Some(Box::new((self.2)(self.1)))
}
}
self.register(move |id| WindowExt(name.into(), id, new));
self
}
pub fn renderer<E: RendererExtension>(
&mut self,
name: impl Into<ApiExtensionName>,
new: impl FnMut(ApiExtensionId) -> E + Send + 'static,
) -> &mut Self {
struct RendererExt<F>(ApiExtensionName, ApiExtensionId, F);
impl<E, F> ViewExtension for RendererExt<F>
where
E: RendererExtension,
F: FnMut(ApiExtensionId) -> E + Send + 'static,
{
fn name(&self) -> &ApiExtensionName {
&self.0
}
fn renderer(&mut self) -> Option<Box<dyn RendererExtension>> {
Some(Box::new((self.2)(self.1)))
}
}
self.register(move |id| RendererExt(name.into(), id, new));
self
}
pub fn data(&mut self, name: impl Into<ApiExtensionName>) -> &mut Self {
struct DataExt(ApiExtensionName);
impl ViewExtension for DataExt {
fn name(&self) -> &ApiExtensionName {
&self.0
}
}
self.register(|_| DataExt(name.into()))
}
pub(crate) fn api_extensions(&self) -> ApiExtensions {
let mut r = ApiExtensions::new();
for ext in &self.exts {
r.insert(ext.name().clone()).unwrap();
}
r
}
pub(crate) fn call_command(&mut self, id: ApiExtensionId, request: ApiExtensionPayload) -> ApiExtensionPayload {
let idx = id.index();
if idx >= self.exts.len() {
ApiExtensionPayload::unknown_extension(id)
} else if let Some(r) = self.exts[idx].command(request) {
r
} else {
ApiExtensionPayload::unknown_extension(id)
}
}
pub(crate) fn new_window(&mut self) -> Vec<(ApiExtensionId, Box<dyn WindowExtension>)> {
self.exts
.iter_mut()
.enumerate()
.filter_map(|(i, e)| e.window().map(|e| (ApiExtensionId::from_index(i), e)))
.collect()
}
pub(crate) fn new_renderer(&mut self) -> Vec<(ApiExtensionId, Box<dyn RendererExtension>)> {
self.exts
.iter_mut()
.enumerate()
.filter_map(|(i, e)| e.renderer().map(|e| (ApiExtensionId::from_index(i), e)))
.collect()
}
pub(crate) fn init(&mut self, event_sender: &crate::AppEventSender) {
for (i, ext) in self.exts.iter_mut().enumerate() {
ext.init(ViewExtensionInitArgs {
event_sender: ExtensionEventSender {
sender: event_sender.clone(),
id: ApiExtensionId::from_index(i),
},
});
}
}
pub(crate) fn on_low_memory(&mut self) {
for ext in self.exts.iter_mut() {
ext.low_memory();
}
}
pub(crate) fn suspended(&mut self) {
for ext in self.exts.iter_mut() {
ext.suspended();
}
}
pub(crate) fn resumed(&mut self) {
for ext in self.exts.iter_mut() {
ext.resumed();
}
}
pub fn append(&mut self, mut other: ViewExtensions) {
self.exts.append(&mut other.exts);
}
}
#[cfg(windows)]
pub(crate) struct PreferAngleExt {
pub(crate) prefer_egl: bool,
}
#[cfg(windows)]
impl PreferAngleExt {
pub(crate) fn new(_: ApiExtensionId) -> Self {
Self { prefer_egl: false }
}
}
#[cfg(windows)]
impl WindowExtension for PreferAngleExt {
fn is_init_only(&self) -> bool {
true
}
fn configure(&mut self, args: &mut WindowConfigArgs) {
if let Some(cfg) = args.config {
match cfg.deserialize::<bool>() {
Ok(y) => self.prefer_egl = y,
Err(e) => tracing::error!("invalid arg for 'zng-view.prefer_angle', {e}"),
}
}
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
pub(crate) struct RendererDebugExt {
id: ApiExtensionId,
ui: Option<String>,
}
impl RendererDebugExt {
pub(crate) fn new(id: ApiExtensionId) -> Self {
Self { id, ui: None }
}
}
impl RendererExtension for RendererDebugExt {
fn is_init_only(&self) -> bool {
false
}
fn configure(&mut self, args: &mut RendererConfigArgs) {
if let Some(cfg) = args.config.as_ref().and_then(|c| c.deserialize::<RendererDebug>().ok()) {
args.options.debug_flags = cfg.flags;
self.ui = Some(cfg.profiler_ui);
}
}
fn renderer_inited(&mut self, args: &mut RendererInitedArgs) {
if let Some(ui) = self.ui.take() {
args.renderer.set_profiler_ui(&ui);
}
}
fn command(&mut self, args: &mut RendererCommandArgs) -> ApiExtensionPayload {
match args.request.deserialize::<RendererDebug>() {
Ok(cfg) => {
args.renderer.set_debug_flags(cfg.flags);
args.renderer.set_profiler_ui(&cfg.profiler_ui);
ApiExtensionPayload::empty()
}
Err(e) => ApiExtensionPayload::invalid_request(self.id, e),
}
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}
#[derive(serde::Serialize, serde::Deserialize)]
struct RendererDebug {
pub flags: DebugFlags,
pub profiler_ui: String,
}
pub(crate) struct DisplayListExtAdapter<'a> {
pub extensions: &'a mut Vec<(ApiExtensionId, Box<dyn RendererExtension>)>,
pub transaction: &'a mut webrender::Transaction,
pub renderer: &'a mut webrender::Renderer,
pub document_id: DocumentId,
pub api: &'a mut RenderApi,
pub external_images: &'a mut ExternalImages,
pub frame_id: zng_view_api::window::FrameId,
}
impl DisplayListExtension for DisplayListExtAdapter<'_> {
fn display_list_start(&mut self, args: &mut DisplayExtensionArgs) {
for (_, ext) in self.extensions.iter_mut() {
ext.render_start(&mut RenderArgs {
frame_id: self.frame_id,
list: args.list,
sc: args.sc,
transaction: self.transaction,
renderer: self.renderer,
document_id: self.document_id,
api: self.api,
external_images: self.external_images,
});
}
}
fn push_display_item(&mut self, args: &mut DisplayExtensionItemArgs) {
for (id, ext) in self.extensions.iter_mut() {
if *id == args.extension_id {
ext.render_push(&mut RenderItemArgs {
extension_id: args.extension_id,
payload: args.payload,
is_reuse: args.is_reuse,
list: args.list,
sc: args.sc,
transaction: self.transaction,
renderer: self.renderer,
document_id: self.document_id,
api: self.api,
external_images: self.external_images,
});
break;
}
}
}
fn pop_display_item(&mut self, args: &mut DisplayExtensionItemArgs) {
for (id, ext) in self.extensions.iter_mut() {
if *id == args.extension_id {
ext.render_pop(&mut RenderItemArgs {
extension_id: args.extension_id,
payload: args.payload,
is_reuse: args.is_reuse,
list: args.list,
sc: args.sc,
transaction: self.transaction,
renderer: self.renderer,
document_id: self.document_id,
api: self.api,
external_images: self.external_images,
});
break;
}
}
}
fn display_list_end(&mut self, args: &mut DisplayExtensionArgs) {
for (_, ext) in self.extensions.iter_mut() {
ext.render_end(&mut RenderArgs {
frame_id: self.frame_id,
list: args.list,
sc: args.sc,
transaction: self.transaction,
renderer: self.renderer,
document_id: self.document_id,
api: self.api,
external_images: self.external_images,
});
}
}
fn update(&mut self, args: &mut DisplayExtensionUpdateArgs) {
for (id, ext) in self.extensions.iter_mut() {
if *id == args.extension_id {
let mut r_args = RenderUpdateArgs {
extension_id: args.extension_id,
payload: args.payload,
new_frame: args.new_frame,
properties: args.properties,
document_id: self.document_id,
transaction: self.transaction,
renderer: self.renderer,
api: self.api,
external_images: self.external_images,
};
ext.render_update(&mut r_args);
args.new_frame = r_args.new_frame;
break;
}
}
}
}
pub(crate) struct BlobExtensionsImgHandler(pub Vec<Box<dyn BlobExtension>>);
impl BlobImageHandler for BlobExtensionsImgHandler {
fn create_blob_rasterizer(&mut self) -> Box<dyn AsyncBlobImageRasterizer> {
Box::new(BlockExtensionsImgRasterizer(
self.0.iter_mut().map(|t| t.create_blob_rasterizer()).collect(),
))
}
fn create_similar(&self) -> Box<dyn BlobImageHandler> {
Box::new(Self(self.0.iter().map(|e| e.create_similar()).collect()))
}
fn prepare_resources(&mut self, services: &dyn webrender::api::BlobImageResources, requests: &[BlobImageParams]) {
for ext in self.0.iter_mut() {
ext.prepare_resources(&mut BlobPrepareArgs { services, requests })
}
}
fn add(
&mut self,
key: webrender::api::BlobImageKey,
data: std::sync::Arc<webrender::api::BlobImageData>,
visible_rect: &webrender::api::units::DeviceIntRect,
tile_size: webrender::api::TileSize,
) {
let args = BlobAddArgs {
key,
data,
visible_rect: *visible_rect,
tile_size,
};
for ext in self.0.iter_mut() {
ext.add(&args);
}
}
fn update(
&mut self,
key: webrender::api::BlobImageKey,
data: std::sync::Arc<webrender::api::BlobImageData>,
visible_rect: &webrender::api::units::DeviceIntRect,
dirty_rect: &webrender::api::units::BlobDirtyRect,
) {
let args = BlobUpdateArgs {
key,
data,
visible_rect: *visible_rect,
dirty_rect: *dirty_rect,
};
for ext in self.0.iter_mut() {
ext.update(&args);
}
}
fn delete(&mut self, key: webrender::api::BlobImageKey) {
for ext in self.0.iter_mut() {
ext.delete(key);
}
}
fn delete_font(&mut self, key: webrender::api::FontKey) {
for ext in self.0.iter_mut() {
ext.delete_font(key);
}
}
fn delete_font_instance(&mut self, key: webrender::api::FontInstanceKey) {
for ext in self.0.iter_mut() {
ext.delete_font_instance(key);
}
}
fn clear_namespace(&mut self, namespace: webrender::api::IdNamespace) {
for ext in self.0.iter_mut() {
ext.clear_namespace(namespace);
}
}
fn enable_multithreading(&mut self, enable: bool) {
for ext in self.0.iter_mut() {
ext.enable_multithreading(enable);
}
}
}
struct BlockExtensionsImgRasterizer(Vec<Box<dyn AsyncBlobRasterizer>>);
impl AsyncBlobImageRasterizer for BlockExtensionsImgRasterizer {
fn rasterize(
&mut self,
requests: &[BlobImageParams],
low_priority: bool,
tile_pool: &mut crate::BlobTilePool,
) -> Vec<(BlobImageRequest, BlobImageResult)> {
let mut responses = vec![];
for r in &mut self.0 {
r.rasterize(&mut BlobRasterizerArgs {
requests,
low_priority,
tile_pool,
responses: &mut responses,
})
}
responses
}
}
#[macro_export]
macro_rules! view_process_extension {
($closure:expr) => {
#[used]
#[cfg_attr(
any(
target_os = "none",
target_os = "linux",
target_os = "android",
target_os = "fuchsia",
target_os = "psp"
),
unsafe(link_section = "linkme_VIEW_EXTENSIONS")
)]
#[cfg_attr(
any(target_os = "macos", target_os = "ios", target_os = "tvos"),
unsafe(link_section = "__DATA,__linkmeTbhLJz52,regular,no_dead_strip")
)]
#[cfg_attr(
any(target_os = "uefi", target_os = "windows"),
unsafe(link_section = ".linkme_VIEW_EXTENSIONS$b")
)]
#[cfg_attr(target_os = "illumos", unsafe(link_section = "set_linkme_VIEW_EXTENSIONS"))]
#[cfg_attr(
any(target_os = "freebsd", target_os = "openbsd"),
unsafe(link_section = "linkme_VIEW_EXTENSIONS")
)]
#[doc(hidden)]
static _VIEW_EXTENSIONS: fn(&mut $crate::extensions::ViewExtensions) = _view_extensions;
#[doc(hidden)]
fn _view_extensions(ext: &mut $crate::extensions::ViewExtensions) {
fn view_extensions(
ext: &mut $crate::extensions::ViewExtensions,
handler: impl FnOnce(&mut $crate::extensions::ViewExtensions),
) {
handler(ext)
}
view_extensions(ext, $closure)
}
};
}
#[doc(hidden)]
#[linkme::distributed_slice]
pub static VIEW_EXTENSIONS: [fn(&mut ViewExtensions)];