ltk_webkit/wpe/
snapshot.rsuse std::ptr;
use gio::ffi::GAsyncResult;
use glib_sys::{ g_bytes_get_data, g_error_free, gpointer, GError };
use gobject_sys::{ g_object_unref, GObject };
use wpe_webkit_sys::*;
use super::WebView;
use crate::types::Snapshot;
type SnapshotDone = Box<dyn FnOnce( Result<Snapshot, String> )>;
impl WebView
{
pub fn snapshot_document( &self, done: impl FnOnce( Result<Snapshot, String> ) + 'static )
{
let Some( webview ) = self.webview_ptr() else { return done( Err( "no view".to_string() ) ) };
snapshot( webview, WEBKIT_SNAPSHOT_REGION_FULL_DOCUMENT, done );
}
}
pub( super ) fn snapshot( webview: *mut WebKitWebView, region: WebKitSnapshotRegion, done: impl FnOnce( Result<Snapshot, String> ) + 'static )
{
let data = Box::into_raw( Box::new( Box::new( done ) as SnapshotDone ) ) as gpointer;
unsafe
{
webkit_web_view_get_snapshot( webview, region, WEBKIT_SNAPSHOT_OPTIONS_NONE, ptr::null_mut(), Some( on_snapshot ), data );
}
}
unsafe extern "C" fn on_snapshot( source: *mut GObject, result: *mut GAsyncResult, user_data: gpointer )
{
unsafe
{
let done = Box::from_raw( user_data as *mut SnapshotDone );
let mut err: *mut GError = ptr::null_mut();
let image = webkit_web_view_get_snapshot_finish( source as *mut WebKitWebView, result, &mut err );
if image.is_null()
{
let message = super::error_message_or_default( err, "no snapshot" );
if !err.is_null() { g_error_free( err ); }
return ( *done )( Err( message ) );
}
let snapshot = read( image );
g_object_unref( image as *mut GObject );
( *done )( snapshot )
}
}
unsafe fn read( image: *mut WebKitImage ) -> Result<Snapshot, String>
{
unsafe
{
let width = webkit_image_get_width( image ).max( 0 ) as usize;
let height = webkit_image_get_height( image ).max( 0 ) as usize;
let stride = webkit_image_get_stride( image ) as usize;
let bytes = webkit_image_as_bytes( image );
if bytes.is_null() || width == 0 || height == 0 || stride < width * 4 { return Err( "empty snapshot".to_string() ); }
let mut size = 0;
let data = g_bytes_get_data( bytes, &mut size ) as *const u8;
if data.is_null() || size < stride * ( height - 1 ) + width * 4 { return Err( "short snapshot".to_string() ); }
let source = std::slice::from_raw_parts( data, size );
let mut rgba = Vec::with_capacity( width * height * 4 );
for row in 0..height
{
for px in source[ row * stride..row * stride + width * 4 ].chunks_exact( 4 )
{
rgba.extend_from_slice( &[ px[ 2 ], px[ 1 ], px[ 0 ], px[ 3 ] ] );
}
}
Ok( Snapshot { rgba, width: width as u32, height: height as u32 } )
}
}