Skip to content

Commit

Permalink
Merge branch 'feat/windows/sharedbuffer' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
defims committed Dec 7, 2023
2 parents da88810 + a13ab19 commit 5242f41
Show file tree
Hide file tree
Showing 3 changed files with 213 additions and 0 deletions.
145 changes: 145 additions & 0 deletions examples/shared_buffer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright 2020-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

use tao::{
event::{Event, WindowEvent},
event_loop::ControlFlow,
window::WindowBuilder,
};
use wry::WebViewBuilder;

// Currently, only Windows platforms support shared_buffer.
#[cfg(target_os = "windows")]
fn main() -> wry::Result<()> {
use wry::WebViewExtWindows;

enum UserEvent {
InitSharedBuffer,
PingSharedBuffer,
}

let event_loop = tao::event_loop::EventLoopBuilder::<UserEvent>::with_user_event().build();
let proxy = event_loop.create_proxy();
let window = WindowBuilder::new().build(&event_loop).unwrap();

let webview = WebViewBuilder::new(&window)
.with_url("https://tauri.app")?
.with_ipc_handler(move |req: String| match req.as_str() {
"initSharedBuffer" => { let _ = proxy.send_event(UserEvent::InitSharedBuffer); }
"pingSharedBuffer" => { let _ = proxy.send_event(UserEvent::PingSharedBuffer); }
_ => {}
})
.with_initialization_script(r#";(function() {
function writeStringIntoSharedBuffer(string, sharedBuffer, pathPtr) {
const path = new TextEncoder().encode(string)
const pathLen = path.length
const pathArray = new Uint8Array(sharedBuffer, pathPtr, pathLen*8)
for(let i = 0; i < pathLen; i++) {
pathArray[i] = path[i]
}
return [pathPtr, pathLen]
}
const sharedBufferReceivedHandler = e => {
window.chrome.webview.removeEventListener("sharedbufferreceived", sharedBufferReceivedHandler);
alert(JSON.stringify(e.additionalData))
var sharedBuffer = e.getBuffer()
console.log(sharedBuffer)
window.sharedBuffer = sharedBuffer
// JS write
writeStringIntoSharedBuffer("I'm JS.", sharedBuffer, 0)
window.ipc.postMessage('pingSharedBuffer');
}
window.chrome.webview.addEventListener("sharedbufferreceived", sharedBufferReceivedHandler);
window.ipc.postMessage('initSharedBuffer');
})();"#)
.build()?;

// The Webview2 developer tools include a memory inspector, which makes it easy to debug memory issues.
webview.open_devtools();

let mut shared_buffer: Option<webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2SharedBuffer> = None;

event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
*control_flow = ControlFlow::Exit
},

Event::UserEvent(e) => match e {
UserEvent::InitSharedBuffer => {
// Memory obtained through webview2 must be manually managed. Use it with care.
shared_buffer = Some(unsafe { webview.create_shared_buffer(1024) }.unwrap());
if let Some(shared_buffer) = &shared_buffer {
dbg!(shared_buffer);
let _ = unsafe {
webview.post_shared_buffer_to_script(
shared_buffer,
webview2_com::Microsoft::Web::WebView2::Win32::COREWEBVIEW2_SHARED_BUFFER_ACCESS_READ_WRITE,
windows::core::w!(r#"{"jsonkey":"jsonvalue"}"#)
)
};
}
},
UserEvent::PingSharedBuffer => {
if let Some(shared_buffer) = &shared_buffer {
let mut ptr: *mut u8 = &mut 0u8;
let _ = unsafe { shared_buffer.Buffer(&mut ptr) };

// Rust read
let len = 8; // align to 4
let read_string: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(ptr, len) };
let read_string = std::str::from_utf8(&read_string).unwrap();
dbg!(read_string);

// Rust write
let mut vec = String::from("I'm Rust.").into_bytes();
unsafe { std::ptr::copy((&mut vec).as_mut_ptr(), ptr.offset(len as isize), 9) };

let _ = webview.evaluate_script(r#";(function() {
// JS read
alert(
new TextDecoder()
.decode(new Uint8Array(window.sharedBuffer, 8, 9))
)
})()"#);
}
}
},

_ => (),
}
});
}

// Non-Windows systems do not yet support shared_buffer.
#[cfg(not(target_os = "windows"))]
fn main() -> wry::Result<()> {
let event_loop = tao::event_loop::EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();

let _ = WebViewBuilder::new(&window)
.with_url("https://tauri.app")?
.build()?;

event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;

if let Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} = event
{
*control_flow = ControlFlow::Exit
}
});
}
34 changes: 34 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1411,6 +1411,20 @@ pub trait WebViewExtWindows {
) -> ::windows::core::Result<()>
where
P0: ::windows::core::IntoParam<::windows::core::PCWSTR>;
unsafe fn create_shared_buffer(
&self,
size: u64,
) -> ::windows::core::Result<webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2SharedBuffer>;

unsafe fn post_shared_buffer_to_script<P0, P1>(
&self,
sharedbuffer: P0,
access: webview2_com::Microsoft::Web::WebView2::Win32::COREWEBVIEW2_SHARED_BUFFER_ACCESS,
additionaldataasjson: P1,
) -> ::windows::core::Result<()>
where
P0: ::windows::core::IntoParam<webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2SharedBuffer>,
P1: ::windows::core::IntoParam<::windows::core::PCWSTR>;
}

#[cfg(target_os = "windows")]
Expand All @@ -1435,6 +1449,26 @@ impl WebViewExtWindows for WebView {
{
self.webview.add_host_object_to_script(name, object)
}

unsafe fn create_shared_buffer(
&self,
size: u64,
) -> ::windows::core::Result<webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2SharedBuffer> {
self.webview.create_shared_buffer(size)
}

unsafe fn post_shared_buffer_to_script<P0, P1>(
&self,
sharedbuffer: P0,
access: webview2_com::Microsoft::Web::WebView2::Win32::COREWEBVIEW2_SHARED_BUFFER_ACCESS,
additionaldataasjson: P1,
) -> ::windows::core::Result<()>
where
P0: ::windows::core::IntoParam<webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2SharedBuffer>,
P1: ::windows::core::IntoParam<::windows::core::PCWSTR>,
{
self.webview.post_shared_buffer_to_script(sharedbuffer, access, additionaldataasjson)
}
}

/// Additional methods on `WebView` that are specific to Linux.
Expand Down
34 changes: 34 additions & 0 deletions src/webview2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,40 @@ impl InnerWebView {
}
}
}

pub unsafe fn create_shared_buffer(
&self,
size: u64,
) -> ::windows::core::Result<ICoreWebView2SharedBuffer> {
match self.env.cast::<ICoreWebView2Environment12>() {
Ok(env) => {
env.CreateSharedBuffer(size)
},
Err(error) => {
Err(error)
}
}
}

pub unsafe fn post_shared_buffer_to_script<P0, P1>(
&self,
sharedbuffer: P0,
access: webview2_com::Microsoft::Web::WebView2::Win32::COREWEBVIEW2_SHARED_BUFFER_ACCESS,
additionaldataasjson: P1,
) -> ::windows::core::Result<()>
where
P0: ::windows::core::IntoParam<webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2SharedBuffer>,
P1: ::windows::core::IntoParam<::windows::core::PCWSTR>,
{
match self.webview.cast::<ICoreWebView2_19>() {
Ok(webview) => {
webview.PostSharedBufferToScript(sharedbuffer, access, additionaldataasjson)
},
Err(error) => {
Err(error)
}
}
}
}

unsafe fn prepare_web_request_response(
Expand Down

0 comments on commit 5242f41

Please sign in to comment.