2020-06-17 12:31:42 -03:00
/*
* Copyright ( c ) 2020 , Andreas Kling < kling @ serenityos . org >
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* 1. Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer .
*
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " AS IS "
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL
* DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
2020-08-17 11:20:47 -03:00
# include "OutOfProcessWebView.h"
2020-06-17 12:31:42 -03:00
# include "WebContentClient.h"
2021-01-30 17:57:16 -03:00
# include <AK/String.h>
# include <AK/URLParser.h>
2021-02-20 08:05:18 -03:00
# include <LibGUI/InputBox.h>
2020-09-12 06:56:13 -03:00
# include <LibGUI/MessageBox.h>
2020-06-17 12:31:42 -03:00
# include <LibGUI/Painter.h>
2020-07-04 18:19:32 -03:00
# include <LibGUI/ScrollBar.h>
2020-07-06 18:32:12 -03:00
# include <LibGUI/Window.h>
2020-12-28 20:44:58 -03:00
# include <LibGfx/Palette.h>
2020-06-17 12:31:42 -03:00
# include <LibGfx/SystemTheme.h>
2020-10-08 17:11:32 -03:00
REGISTER_WIDGET ( Web , OutOfProcessWebView )
2020-08-24 08:03:18 -03:00
namespace Web {
2020-08-17 11:20:47 -03:00
OutOfProcessWebView : : OutOfProcessWebView ( )
2020-06-17 12:31:42 -03:00
{
2020-07-06 17:02:38 -03:00
set_should_hide_unnecessary_scrollbars ( true ) ;
2020-10-30 06:58:27 -03:00
set_focus_policy ( GUI : : FocusPolicy : : StrongFocus ) ;
2021-01-30 14:20:40 -03:00
create_client ( ) ;
2020-06-17 12:31:42 -03:00
}
2020-08-17 11:20:47 -03:00
OutOfProcessWebView : : ~ OutOfProcessWebView ( )
2020-06-17 12:31:42 -03:00
{
}
2021-02-22 07:07:40 -03:00
void OutOfProcessWebView : : handle_web_content_process_crash ( )
{
create_client ( ) ;
2021-02-23 16:42:32 -03:00
VERIFY ( m_client_state . client ) ;
2021-02-22 07:07:40 -03:00
// Don't keep a stale backup bitmap around.
m_backup_bitmap = nullptr ;
handle_resize ( ) ;
StringBuilder builder ;
builder . append ( " <html><head><title>Crashed: " ) ;
builder . append ( escape_html_entities ( m_url . to_string ( ) ) ) ;
builder . append ( " </title></head><body> " ) ;
builder . append ( " <h1>Web page crashed " ) ;
if ( ! m_url . host ( ) . is_empty ( ) ) {
builder . appendff ( " on {} " , escape_html_entities ( m_url . host ( ) ) ) ;
}
builder . append ( " </h1> " ) ;
builder . appendff ( " The web page <a href= \" {} \" >{}</a> has crashed.<br><br>You can reload the page to try again. " , escape_html_entities ( m_url . to_string_encoded ( ) ) , escape_html_entities ( m_url . to_string ( ) ) ) ;
builder . append ( " </body></html> " ) ;
load_html ( builder . to_string ( ) , m_url ) ;
}
2021-01-30 14:20:40 -03:00
void OutOfProcessWebView : : create_client ( )
{
m_client_state = { } ;
m_client_state . client = WebContentClient : : construct ( * this ) ;
m_client_state . client - > on_web_content_process_crash = [ this ] {
2021-02-22 07:07:40 -03:00
deferred_invoke ( [ this ] {
handle_web_content_process_crash ( ) ;
} ) ;
2021-01-30 14:20:40 -03:00
} ;
client ( ) . post_message ( Messages : : WebContentServer : : UpdateSystemTheme ( Gfx : : current_system_theme_buffer ( ) ) ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : load ( const URL & url )
2020-06-17 12:31:42 -03:00
{
2020-07-06 16:46:37 -03:00
m_url = url ;
2020-06-17 12:31:42 -03:00
client ( ) . post_message ( Messages : : WebContentServer : : LoadURL ( url ) ) ;
}
2020-10-08 17:11:01 -03:00
void OutOfProcessWebView : : load_html ( const StringView & html , const URL & url )
{
m_url = url ;
client ( ) . post_message ( Messages : : WebContentServer : : LoadHTML ( html , url ) ) ;
}
2020-10-08 17:58:00 -03:00
void OutOfProcessWebView : : load_empty_document ( )
{
m_url = { } ;
client ( ) . post_message ( Messages : : WebContentServer : : LoadHTML ( " " , { } ) ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : paint_event ( GUI : : PaintEvent & event )
2020-06-17 12:31:42 -03:00
{
2020-07-05 07:45:56 -03:00
GUI : : ScrollableWidget : : paint_event ( event ) ;
2020-07-04 18:27:36 -03:00
2020-11-08 12:07:57 -03:00
// If the available size is empty, we don't have a front or back bitmap to draw.
if ( available_size ( ) . is_empty ( ) )
return ;
2020-06-17 12:31:42 -03:00
GUI : : Painter painter ( * this ) ;
painter . add_clip_rect ( event . rect ( ) ) ;
2020-12-28 20:44:58 -03:00
2021-02-09 18:07:36 -03:00
if ( auto * bitmap = m_client_state . has_usable_bitmap ? m_client_state . front_bitmap . ptr ( ) : m_backup_bitmap . ptr ( ) ) {
painter . add_clip_rect ( frame_inner_rect ( ) ) ;
painter . translate ( frame_thickness ( ) , frame_thickness ( ) ) ;
painter . blit ( { 0 , 0 } , * bitmap , bitmap - > rect ( ) ) ;
2020-12-28 20:44:58 -03:00
return ;
}
2021-02-09 18:07:36 -03:00
painter . fill_rect ( frame_inner_rect ( ) , palette ( ) . base ( ) ) ;
2020-06-17 12:31:42 -03:00
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : resize_event ( GUI : : ResizeEvent & event )
2020-06-17 12:31:42 -03:00
{
2020-07-05 07:45:56 -03:00
GUI : : ScrollableWidget : : resize_event ( event ) ;
2021-01-30 14:20:40 -03:00
handle_resize ( ) ;
}
2020-07-05 07:45:56 -03:00
2021-01-30 14:20:40 -03:00
void OutOfProcessWebView : : handle_resize ( )
{
2020-11-08 12:07:57 -03:00
client ( ) . post_message ( Messages : : WebContentServer : : SetViewportRect ( Gfx : : IntRect ( { horizontal_scrollbar ( ) . value ( ) , vertical_scrollbar ( ) . value ( ) } , available_size ( ) ) ) ) ;
2021-02-09 18:07:36 -03:00
if ( m_client_state . has_usable_bitmap ) {
// NOTE: We keep the outgoing front bitmap as a backup so we have something to paint until we get a new one.
m_backup_bitmap = m_client_state . front_bitmap ;
}
2021-01-30 14:20:40 -03:00
if ( m_client_state . front_bitmap ) {
m_client_state . front_bitmap = nullptr ;
client ( ) . post_message ( Messages : : WebContentServer : : RemoveBackingStore ( m_client_state . front_bitmap_id ) ) ;
2021-01-16 19:15:32 -03:00
}
2021-01-30 14:20:40 -03:00
if ( m_client_state . back_bitmap ) {
m_client_state . back_bitmap = nullptr ;
client ( ) . post_message ( Messages : : WebContentServer : : RemoveBackingStore ( m_client_state . back_bitmap_id ) ) ;
2021-01-16 19:15:32 -03:00
}
2021-01-30 14:20:40 -03:00
m_client_state . front_bitmap_id = - 1 ;
m_client_state . back_bitmap_id = - 1 ;
m_client_state . has_usable_bitmap = false ;
2020-11-08 10:53:36 -03:00
2020-11-08 12:07:57 -03:00
if ( available_size ( ) . is_empty ( ) )
return ;
2021-01-02 12:25:10 -03:00
if ( auto new_bitmap = Gfx : : Bitmap : : create_shareable ( Gfx : : BitmapFormat : : RGB32 , available_size ( ) ) ) {
2021-01-30 14:20:40 -03:00
m_client_state . front_bitmap = move ( new_bitmap ) ;
m_client_state . front_bitmap_id = m_client_state . next_bitmap_id + + ;
client ( ) . post_message ( Messages : : WebContentServer : : AddBackingStore ( m_client_state . front_bitmap_id , m_client_state . front_bitmap - > to_shareable_bitmap ( ) ) ) ;
2020-11-08 10:53:36 -03:00
}
2021-01-02 12:25:10 -03:00
if ( auto new_bitmap = Gfx : : Bitmap : : create_shareable ( Gfx : : BitmapFormat : : RGB32 , available_size ( ) ) ) {
2021-01-30 14:20:40 -03:00
m_client_state . back_bitmap = move ( new_bitmap ) ;
m_client_state . back_bitmap_id = m_client_state . next_bitmap_id + + ;
client ( ) . post_message ( Messages : : WebContentServer : : AddBackingStore ( m_client_state . back_bitmap_id , m_client_state . back_bitmap - > to_shareable_bitmap ( ) ) ) ;
2020-11-08 10:53:36 -03:00
}
2020-07-05 11:31:50 -03:00
2020-07-04 18:19:32 -03:00
request_repaint ( ) ;
2020-06-17 12:31:42 -03:00
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : keydown_event ( GUI : : KeyEvent & event )
2020-08-03 14:58:59 -03:00
{
client ( ) . post_message ( Messages : : WebContentServer : : KeyDown ( event . key ( ) , event . modifiers ( ) , event . code_point ( ) ) ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : mousedown_event ( GUI : : MouseEvent & event )
2020-06-17 13:05:08 -03:00
{
2020-07-04 18:23:36 -03:00
client ( ) . post_message ( Messages : : WebContentServer : : MouseDown ( to_content_position ( event . position ( ) ) , event . button ( ) , event . buttons ( ) , event . modifiers ( ) ) ) ;
2020-06-17 13:05:08 -03:00
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : mouseup_event ( GUI : : MouseEvent & event )
2020-06-17 13:05:08 -03:00
{
2020-07-04 18:23:36 -03:00
client ( ) . post_message ( Messages : : WebContentServer : : MouseUp ( to_content_position ( event . position ( ) ) , event . button ( ) , event . buttons ( ) , event . modifiers ( ) ) ) ;
2020-06-17 13:05:08 -03:00
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : mousemove_event ( GUI : : MouseEvent & event )
2020-06-17 13:05:08 -03:00
{
2020-07-04 18:23:36 -03:00
client ( ) . post_message ( Messages : : WebContentServer : : MouseMove ( to_content_position ( event . position ( ) ) , event . button ( ) , event . buttons ( ) , event . modifiers ( ) ) ) ;
2020-06-17 13:05:08 -03:00
}
2021-02-22 15:45:41 -03:00
void OutOfProcessWebView : : mousewheel_event ( GUI : : MouseEvent & event )
{
client ( ) . post_message ( Messages : : WebContentServer : : MouseWheel ( to_content_position ( event . position ( ) ) , event . button ( ) , event . buttons ( ) , event . modifiers ( ) , event . wheel_delta ( ) ) ) ;
}
2020-10-08 18:13:54 -03:00
void OutOfProcessWebView : : theme_change_event ( GUI : : ThemeChangeEvent & event )
{
GUI : : ScrollableWidget : : theme_change_event ( event ) ;
2021-01-16 13:20:53 -03:00
client ( ) . post_message ( Messages : : WebContentServer : : UpdateSystemTheme ( Gfx : : current_system_theme_buffer ( ) ) ) ;
2020-10-08 18:13:54 -03:00
request_repaint ( ) ;
}
2021-01-16 19:15:32 -03:00
void OutOfProcessWebView : : notify_server_did_paint ( Badge < WebContentClient > , i32 bitmap_id )
2020-06-17 12:31:42 -03:00
{
2021-01-30 14:20:40 -03:00
if ( m_client_state . back_bitmap_id = = bitmap_id ) {
m_client_state . has_usable_bitmap = true ;
swap ( m_client_state . back_bitmap , m_client_state . front_bitmap ) ;
swap ( m_client_state . back_bitmap_id , m_client_state . front_bitmap_id ) ;
2021-02-09 18:07:36 -03:00
// We don't need the backup bitmap anymore, so drop it.
m_backup_bitmap = nullptr ;
2020-06-17 12:31:42 -03:00
update ( ) ;
2020-07-05 11:31:50 -03:00
}
2020-06-17 12:31:42 -03:00
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : notify_server_did_invalidate_content_rect ( Badge < WebContentClient > , [[maybe_unused]] const Gfx : : IntRect & content_rect )
2020-06-17 13:00:18 -03:00
{
2020-07-04 15:57:57 -03:00
request_repaint ( ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : notify_server_did_change_selection ( Badge < WebContentClient > )
2020-07-04 15:57:57 -03:00
{
request_repaint ( ) ;
}
2021-02-27 18:12:12 -03:00
void OutOfProcessWebView : : notify_server_did_request_cursor_change ( Badge < WebContentClient > , Gfx : : StandardCursor cursor )
{
set_override_cursor ( cursor ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : notify_server_did_layout ( Badge < WebContentClient > , const Gfx : : IntSize & content_size )
2020-07-04 18:19:32 -03:00
{
set_content_size ( content_size ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : notify_server_did_change_title ( Badge < WebContentClient > , const String & title )
2020-07-04 18:40:17 -03:00
{
if ( on_title_change )
on_title_change ( title ) ;
}
2021-03-01 18:39:07 -03:00
void OutOfProcessWebView : : notify_server_did_request_scroll ( Badge < WebContentClient > , int wheel_delta )
{
vertical_scrollbar ( ) . set_value ( vertical_scrollbar ( ) . value ( ) + wheel_delta * 20 ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : notify_server_did_request_scroll_into_view ( Badge < WebContentClient > , const Gfx : : IntRect & rect )
2020-07-05 10:43:43 -03:00
{
scroll_into_view ( rect , true , true ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : notify_server_did_hover_link ( Badge < WebContentClient > , const URL & url )
2020-07-05 11:59:20 -03:00
{
if ( on_link_hover )
on_link_hover ( url ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : notify_server_did_unhover_link ( Badge < WebContentClient > )
2020-07-05 11:59:20 -03:00
{
2020-09-11 09:28:05 -03:00
set_override_cursor ( Gfx : : StandardCursor : : None ) ;
2020-07-05 11:59:20 -03:00
if ( on_link_hover )
on_link_hover ( { } ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : notify_server_did_click_link ( Badge < WebContentClient > , const URL & url , const String & target , unsigned int modifiers )
2020-07-06 15:01:46 -03:00
{
if ( on_link_click )
on_link_click ( url , target , modifiers ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : notify_server_did_middle_click_link ( Badge < WebContentClient > , const URL & url , const String & target , unsigned int modifiers )
2020-07-06 15:01:46 -03:00
{
if ( on_link_middle_click )
on_link_middle_click ( url , target , modifiers ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : notify_server_did_start_loading ( Badge < WebContentClient > , const URL & url )
2020-07-06 16:58:16 -03:00
{
if ( on_load_start )
on_load_start ( url ) ;
}
2020-12-08 17:44:42 -03:00
void OutOfProcessWebView : : notify_server_did_finish_loading ( Badge < WebContentClient > , const URL & url )
{
if ( on_load_finish )
on_load_finish ( url ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : notify_server_did_request_context_menu ( Badge < WebContentClient > , const Gfx : : IntPoint & content_position )
2020-07-07 07:24:29 -03:00
{
if ( on_context_menu_request )
on_context_menu_request ( screen_relative_rect ( ) . location ( ) . translated ( to_widget_position ( content_position ) ) ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : notify_server_did_request_link_context_menu ( Badge < WebContentClient > , const Gfx : : IntPoint & content_position , const URL & url , const String & , unsigned )
2020-07-07 07:24:29 -03:00
{
if ( on_link_context_menu_request )
on_link_context_menu_request ( url , screen_relative_rect ( ) . location ( ) . translated ( to_widget_position ( content_position ) ) ) ;
}
2020-09-12 06:56:13 -03:00
void OutOfProcessWebView : : notify_server_did_request_alert ( Badge < WebContentClient > , const String & message )
{
GUI : : MessageBox : : show ( window ( ) , message , " Alert " , GUI : : MessageBox : : Type : : Information ) ;
}
2021-02-10 04:48:28 -03:00
bool OutOfProcessWebView : : notify_server_did_request_confirm ( Badge < WebContentClient > , const String & message )
{
auto confirm_result = GUI : : MessageBox : : show ( window ( ) , message , " Confirm " , GUI : : MessageBox : : Type : : Warning , GUI : : MessageBox : : InputType : : OKCancel ) ;
return confirm_result = = GUI : : Dialog : : ExecResult : : ExecOK ;
}
2021-02-20 08:05:18 -03:00
String OutOfProcessWebView : : notify_server_did_request_prompt ( Badge < WebContentClient > , const String & message , const String & default_ )
{
String response { default_ } ;
if ( GUI : : InputBox : : show ( window ( ) , response , message , " Prompt " ) = = GUI : : InputBox : : ExecOK )
return response ;
return { } ;
}
2021-02-23 09:17:23 -03:00
void OutOfProcessWebView : : notify_server_did_get_source ( const URL & url , const String & source )
{
if ( on_get_source )
on_get_source ( url , source ) ;
}
2021-02-28 00:47:14 -03:00
void OutOfProcessWebView : : notify_server_did_js_console_output ( const String & method , const String & line )
{
if ( on_js_console_output )
on_js_console_output ( method , line ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : did_scroll ( )
2020-07-04 18:19:32 -03:00
{
2020-07-05 07:45:56 -03:00
client ( ) . post_message ( Messages : : WebContentServer : : SetViewportRect ( visible_content_rect ( ) ) ) ;
2020-07-04 18:19:32 -03:00
request_repaint ( ) ;
}
2020-08-17 11:20:47 -03:00
void OutOfProcessWebView : : request_repaint ( )
2020-07-04 15:57:57 -03:00
{
2020-10-24 07:28:38 -03:00
// If this widget was instantiated but not yet added to a window,
// it won't have a back bitmap yet, so we can just skip repaint requests.
2021-01-30 14:20:40 -03:00
if ( ! m_client_state . back_bitmap )
2020-10-24 07:28:38 -03:00
return ;
2021-01-30 14:20:40 -03:00
client ( ) . post_message ( Messages : : WebContentServer : : Paint ( m_client_state . back_bitmap - > rect ( ) . translated ( horizontal_scrollbar ( ) . value ( ) , vertical_scrollbar ( ) . value ( ) ) , m_client_state . back_bitmap_id ) ) ;
2020-06-17 13:00:18 -03:00
}
2020-08-17 11:20:47 -03:00
WebContentClient & OutOfProcessWebView : : client ( )
2020-06-17 12:31:42 -03:00
{
2021-02-23 16:42:32 -03:00
VERIFY ( m_client_state . client ) ;
2021-01-30 14:20:40 -03:00
return * m_client_state . client ;
2020-06-17 12:31:42 -03:00
}
2020-08-24 08:03:18 -03:00
2021-01-31 05:06:25 -03:00
void OutOfProcessWebView : : debug_request ( const String & request , const String & argument )
{
client ( ) . post_message ( Messages : : WebContentServer : : DebugRequest ( request , argument ) ) ;
}
2021-02-23 09:17:23 -03:00
void OutOfProcessWebView : : get_source ( )
{
client ( ) . post_message ( Messages : : WebContentServer : : GetSource ( ) ) ;
}
2021-02-28 00:47:14 -03:00
void OutOfProcessWebView : : js_console_initialize ( )
{
client ( ) . post_message ( Messages : : WebContentServer : : JSConsoleInitialize ( ) ) ;
}
void OutOfProcessWebView : : js_console_input ( const String & js_source )
{
client ( ) . post_message ( Messages : : WebContentServer : : JSConsoleInput ( js_source ) ) ;
}
2020-08-24 08:03:18 -03:00
}