use crate::prelude::{
WebviewDpr, WebviewSize, WebviewSource, WebviewSurface, update_webview_image,
};
use crate::webview::ui::input::WebviewUiInputPlugin;
use crate::webview::ui::material::WEBVIEW_UI_SHADER_HANDLE;
use bevy::asset::load_internal_asset;
use bevy::prelude::*;
use bevy::ui::UiSystems;
use bevy_cef_core::prelude::RenderTextureMessage;
mod input;
mod material;
pub use material::WebviewUiMaterial;
pub(in crate::webview) struct UiWebviewPlugin;
impl Plugin for UiWebviewPlugin {
fn build(&self, app: &mut App) {
load_internal_asset!(
app,
WEBVIEW_UI_SHADER_HANDLE,
"ui/webview_ui.wgsl",
Shader::from_wgsl
);
if !app.is_plugin_added::<UiPickingPlugin>() {
app.add_plugins(UiPickingPlugin);
}
app.add_plugins((
UiMaterialPlugin::<WebviewUiMaterial>::default(),
WebviewUiInputPlugin,
))
.add_systems(
PostUpdate,
(
render_ui_surface.run_if(on_message::<RenderTextureMessage>),
update_webview_ui_size.after(UiSystems::Layout),
),
);
}
}
pub(crate) fn webview_size_from_computed(
physical_size: Vec2,
inverse_scale_factor: f32,
) -> Option<Vec2> {
let logical = physical_size * inverse_scale_factor;
if logical.x < 1.0 || logical.y < 1.0 {
None
} else {
Some(logical)
}
}
fn render_ui_surface(
mut commands: Commands,
mut er: MessageReader<RenderTextureMessage>,
mut images: ResMut<Assets<Image>>,
mut materials: ResMut<Assets<WebviewUiMaterial>>,
webviews: Query<&MaterialNode<WebviewUiMaterial>>,
) {
for texture in er.read() {
if let Ok(handle) = webviews.get(texture.webview)
&& let Some(material) = materials.get_mut(handle.id())
&& let Some(image) = {
let image_handle = material
.surface
.get_or_insert_with(|| images.add(Image::default()));
commands
.entity(texture.webview)
.insert(WebviewSurface(image_handle.clone()));
images.get_mut(image_handle.id())
}
{
update_webview_image(texture, image);
}
}
}
fn update_webview_ui_size(
mut webviews: Query<
(&ComputedNode, &mut WebviewSize),
(
With<WebviewSource>,
With<MaterialNode<WebviewUiMaterial>>,
Or<(Changed<ComputedNode>, Changed<WebviewDpr>)>,
),
>,
) {
for (computed, mut size) in webviews.iter_mut() {
if let Some(logical) =
webview_size_from_computed(computed.size(), computed.inverse_scale_factor())
{
size.set_if_neq(WebviewSize(logical));
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn converts_physical_to_logical() {
let out = webview_size_from_computed(Vec2::new(1600.0, 1200.0), 0.5);
assert_eq!(out, Some(Vec2::new(800.0, 600.0)));
}
#[test]
fn identity_at_1x() {
let out = webview_size_from_computed(Vec2::new(640.0, 480.0), 1.0);
assert_eq!(out, Some(Vec2::new(640.0, 480.0)));
}
#[test]
fn zero_and_subpixel_return_none() {
assert_eq!(webview_size_from_computed(Vec2::ZERO, 1.0), None);
assert_eq!(webview_size_from_computed(Vec2::new(0.0, 600.0), 1.0), None);
assert_eq!(webview_size_from_computed(Vec2::new(0.5, 0.5), 1.0), None);
}
}