mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Refactor save_output_image into own file so it can be reused in
servoshell and other embedders and let OHOS accept -x and -o flag. Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
This commit is contained in:
parent
56c0ad8420
commit
676feadee9
6 changed files with 75 additions and 33 deletions
|
@ -7,15 +7,14 @@ use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use euclid::{Point2D, Vector2D};
|
use euclid::Vector2D;
|
||||||
use image::{DynamicImage, ImageFormat};
|
|
||||||
use keyboard_types::{Key, KeyboardEvent, Modifiers, ShortcutMatcher};
|
use keyboard_types::{Key, KeyboardEvent, Modifiers, ShortcutMatcher};
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use servo::base::id::WebViewId;
|
use servo::base::id::WebViewId;
|
||||||
use servo::config::pref;
|
use servo::config::pref;
|
||||||
use servo::ipc_channel::ipc::IpcSender;
|
use servo::ipc_channel::ipc::IpcSender;
|
||||||
use servo::webrender_api::ScrollLocation;
|
use servo::webrender_api::ScrollLocation;
|
||||||
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
|
use servo::webrender_api::units::{DeviceIntPoint, DeviceIntSize};
|
||||||
use servo::{
|
use servo::{
|
||||||
AllowOrDenyRequest, AuthenticationRequest, FilterPattern, FormControl, GamepadHapticEffectType,
|
AllowOrDenyRequest, AuthenticationRequest, FilterPattern, FormControl, GamepadHapticEffectType,
|
||||||
LoadStatus, PermissionRequest, Servo, ServoDelegate, ServoError, SimpleDialog, TouchEventType,
|
LoadStatus, PermissionRequest, Servo, ServoDelegate, ServoError, SimpleDialog, TouchEventType,
|
||||||
|
@ -28,6 +27,7 @@ use super::dialog::Dialog;
|
||||||
use super::gamepad::GamepadSupport;
|
use super::gamepad::GamepadSupport;
|
||||||
use super::keyutils::CMD_OR_CONTROL;
|
use super::keyutils::CMD_OR_CONTROL;
|
||||||
use super::window_trait::{LINE_HEIGHT, WindowPortsMethods};
|
use super::window_trait::{LINE_HEIGHT, WindowPortsMethods};
|
||||||
|
use crate::output_image::save_output_image_if_necessary;
|
||||||
use crate::prefs::ServoShellPreferences;
|
use crate::prefs::ServoShellPreferences;
|
||||||
|
|
||||||
pub(crate) enum AppState {
|
pub(crate) enum AppState {
|
||||||
|
@ -140,31 +140,6 @@ impl RunningAppState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn save_output_image_if_necessary(&self) {
|
|
||||||
let Some(output_path) = self.servoshell_preferences.output_image_path.as_ref() else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let inner = self.inner();
|
|
||||||
let size = inner.window.rendering_context().size2d().to_i32();
|
|
||||||
let viewport_rect = DeviceIntRect::from_origin_and_size(Point2D::origin(), size);
|
|
||||||
let Some(image) = inner
|
|
||||||
.window
|
|
||||||
.rendering_context()
|
|
||||||
.read_to_image(viewport_rect)
|
|
||||||
else {
|
|
||||||
error!("Failed to read output image.");
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let image_format = ImageFormat::from_path(output_path).unwrap_or(ImageFormat::Png);
|
|
||||||
if let Err(error) =
|
|
||||||
DynamicImage::ImageRgba8(image).save_with_format(output_path, image_format)
|
|
||||||
{
|
|
||||||
error!("Failed to save {output_path}: {error}.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Repaint the Servo view is necessary, returning true if anything was actually
|
/// Repaint the Servo view is necessary, returning true if anything was actually
|
||||||
/// painted or false otherwise. Something may not be painted if Servo is waiting
|
/// painted or false otherwise. Something may not be painted if Servo is waiting
|
||||||
/// for a stable image to paint.
|
/// for a stable image to paint.
|
||||||
|
@ -179,9 +154,10 @@ impl RunningAppState {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This needs to be done before presenting(), because `ReneringContext::read_to_image` reads
|
save_output_image_if_necessary(
|
||||||
// from the back buffer.
|
&self.servoshell_preferences,
|
||||||
self.save_output_image_if_necessary();
|
&self.inner().window.rendering_context(),
|
||||||
|
);
|
||||||
|
|
||||||
let mut inner_mut = self.inner_mut();
|
let mut inner_mut = self.inner_mut();
|
||||||
inner_mut.window.rendering_context().present();
|
inner_mut.window.rendering_context().present();
|
||||||
|
|
|
@ -25,6 +25,7 @@ use servo::{
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::egl::host_trait::HostTrait;
|
use crate::egl::host_trait::HostTrait;
|
||||||
|
use crate::output_image::save_output_image_if_necessary;
|
||||||
use crate::prefs::ServoShellPreferences;
|
use crate::prefs::ServoShellPreferences;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -718,8 +719,14 @@ impl RunningAppState {
|
||||||
pub fn present_if_needed(&self) {
|
pub fn present_if_needed(&self) {
|
||||||
if self.inner().need_present {
|
if self.inner().need_present {
|
||||||
self.inner_mut().need_present = false;
|
self.inner_mut().need_present = false;
|
||||||
self.active_webview().paint();
|
if !self.active_webview().paint() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
save_output_image_if_necessary(&self.servoshell_preferences, &self.rendering_context);
|
||||||
self.rendering_context.present();
|
self.rendering_context.present();
|
||||||
|
if self.servoshell_preferences.exit_after_stable_image {
|
||||||
|
self.request_shutdown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,6 +123,8 @@ const PROMPT_QUEUE_SIZE: usize = 4;
|
||||||
static SET_URL_BAR_CB: OnceLock<
|
static SET_URL_BAR_CB: OnceLock<
|
||||||
ThreadsafeFunction<String, (), String, false, false, UPDATE_URL_QUEUE_SIZE>,
|
ThreadsafeFunction<String, (), String, false, false, UPDATE_URL_QUEUE_SIZE>,
|
||||||
> = OnceLock::new();
|
> = OnceLock::new();
|
||||||
|
static TERMINATE_CALLBACK: OnceLock<ThreadsafeFunction<(), (), (), false, false, 1>> =
|
||||||
|
OnceLock::new();
|
||||||
static PROMPT_TOAST: OnceLock<
|
static PROMPT_TOAST: OnceLock<
|
||||||
ThreadsafeFunction<String, (), String, false, false, PROMPT_QUEUE_SIZE>,
|
ThreadsafeFunction<String, (), String, false, false, PROMPT_QUEUE_SIZE>,
|
||||||
> = OnceLock::new();
|
> = OnceLock::new();
|
||||||
|
@ -601,6 +603,15 @@ pub fn register_url_callback(callback: Function<String, ()>) -> napi_ohos::Resul
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[napi(js_name = "registerTerminateCallback")]
|
||||||
|
pub fn register_terminate_callback(callback: Function<(), ()>) -> napi_ohos::Result<()> {
|
||||||
|
let tsfn_builder = callback.build_threadsafe_function();
|
||||||
|
let function = tsfn_builder.max_queue_size::<1>().build()?;
|
||||||
|
TERMINATE_CALLBACK
|
||||||
|
.set(function)
|
||||||
|
.map_err(|_| napi_ohos::Error::from_reason("Failed to set terminate function"))
|
||||||
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub fn register_prompt_toast_callback(callback: Function<String, ()>) -> napi_ohos::Result<()> {
|
pub fn register_prompt_toast_callback(callback: Function<String, ()>) -> napi_ohos::Result<()> {
|
||||||
debug!("register_prompt_toast_callback called!");
|
debug!("register_prompt_toast_callback called!");
|
||||||
|
@ -850,7 +861,13 @@ impl HostTrait for HostCallbacks {
|
||||||
// todo: should we tell the vsync thread that it should perform updates?
|
// todo: should we tell the vsync thread that it should perform updates?
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_shutdown_complete(&self) {}
|
fn on_shutdown_complete(&self) {
|
||||||
|
if let Some(terminate_fn) = TERMINATE_CALLBACK.get() {
|
||||||
|
terminate_fn.call((), ThreadsafeFunctionCallMode::Blocking);
|
||||||
|
} else {
|
||||||
|
error!("Could not shut down despite servo shutting down");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Shows the Inputmethod
|
/// Shows the Inputmethod
|
||||||
///
|
///
|
||||||
|
|
|
@ -15,6 +15,7 @@ mod crash_handler;
|
||||||
pub(crate) mod desktop;
|
pub(crate) mod desktop;
|
||||||
#[cfg(any(target_os = "android", target_env = "ohos"))]
|
#[cfg(any(target_os = "android", target_env = "ohos"))]
|
||||||
mod egl;
|
mod egl;
|
||||||
|
mod output_image;
|
||||||
#[cfg(not(any(target_os = "android", target_env = "ohos")))]
|
#[cfg(not(any(target_os = "android", target_env = "ohos")))]
|
||||||
mod panic_hook;
|
mod panic_hook;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
39
ports/servoshell/output_image.rs
Normal file
39
ports/servoshell/output_image.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use euclid::Point2D;
|
||||||
|
use image::{DynamicImage, ImageFormat};
|
||||||
|
use log::error;
|
||||||
|
use servo::RenderingContext;
|
||||||
|
use servo::webrender_api::units::DeviceIntRect;
|
||||||
|
|
||||||
|
use crate::prefs::ServoShellPreferences;
|
||||||
|
|
||||||
|
// This needs to be done before presenting(), because `ReneringContext::read_to_image` reads
|
||||||
|
// from the back buffer.
|
||||||
|
pub(crate) fn save_output_image_if_necessary<T>(
|
||||||
|
prefs: &ServoShellPreferences,
|
||||||
|
rendering_context: &Rc<T>,
|
||||||
|
) where
|
||||||
|
T: RenderingContext + ?Sized,
|
||||||
|
{
|
||||||
|
let Some(output_path) = prefs.output_image_path.as_ref() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let size = rendering_context.size2d().to_i32();
|
||||||
|
let viewport_rect = DeviceIntRect::from_origin_and_size(Point2D::origin(), size);
|
||||||
|
let Some(image) = rendering_context.read_to_image(viewport_rect) else {
|
||||||
|
error!("Failed to read output image.");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let image_format = ImageFormat::from_path(output_path).unwrap_or(ImageFormat::Png);
|
||||||
|
if let Err(error) = DynamicImage::ImageRgba8(image).save_with_format(output_path, image_format)
|
||||||
|
{
|
||||||
|
error!("Failed to save {output_path}: {error}.");
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ interface ServoXComponentInterface {
|
||||||
goBack(): void;
|
goBack(): void;
|
||||||
goForward(): void;
|
goForward(): void;
|
||||||
registerURLcallback(callback: (url: string) => void): void;
|
registerURLcallback(callback: (url: string) => void): void;
|
||||||
|
registerTerminateCallback(callback: () => void): void;
|
||||||
registerPromptToastCallback(callback: (msg: string) => void): void
|
registerPromptToastCallback(callback: (msg: string) => void): void
|
||||||
initServo(options: InitOpts): void;
|
initServo(options: InitOpts): void;
|
||||||
}
|
}
|
||||||
|
@ -130,6 +131,7 @@ struct Index {
|
||||||
console.info('New URL from native: ', new_url)
|
console.info('New URL from native: ', new_url)
|
||||||
this.urlToLoad = new_url
|
this.urlToLoad = new_url
|
||||||
})
|
})
|
||||||
|
this.xComponentContext.registerTerminateCallback(() => { this.context?.terminateSelf(); })
|
||||||
this.xComponentContext.registerPromptToastCallback(prompt_toast)
|
this.xComponentContext.registerPromptToastCallback(prompt_toast)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue