2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <tizen-web-engine-chromium.h>
21 #include <Ecore_Evas.h>
23 #include <Elementary.h>
25 #include <EWebKit_internal.h>
26 #include <EWebKit_product.h>
28 #include <dali/devel-api/common/stage.h>
29 #include <dali/integration-api/debug.h>
30 #include <dali/integration-api/adaptor-framework/adaptor.h>
39 class WebViewContainerClientPair {
41 WebViewContainerClientPair( WebViewContainerClient* client, Evas_Object* webView )
47 WebViewContainerClient* mClient;
48 Evas_Object* mWebView;
51 class WebEngineManager {
53 // A class for managing multiple WebViews
56 static WebEngineManager& Get()
58 static WebEngineManager instance;
63 WebEngineManager(WebEngineManager const&) = delete;
65 void operator=(WebEngineManager const&) = delete;
67 Ecore_Evas* GetWindow()
72 void AddContainerClient( WebViewContainerClient* client, Evas_Object* webView )
74 mContainerClients.push_back( WebViewContainerClientPair( client, webView ) );
77 void RemoveContainerClient( Evas_Object* webView )
79 for( auto it = mContainerClients.begin(); it != mContainerClients.end(); )
81 if( (*it).mWebView == webView )
83 mContainerClients.erase( it );
89 WebViewContainerClient* FindContainerClient( Evas_Object* o )
91 for( auto& webViewClient : mContainerClients )
93 if( webViewClient.mWebView == o )
95 return webViewClient.mClient;
106 mWindow = ecore_evas_new( "wayland_egl", 0, 0, 1, 1, 0 );
110 std::vector< WebViewContainerClientPair > mContainerClients;
113 class WebViewContainerForDali
116 WebViewContainerForDali( WebViewContainerClient& client, int width, int height )
120 mCookieAcceptancePolicy( EWK_COOKIE_ACCEPT_POLICY_NO_THIRD_PARTY )
124 WebEngineManager::Get().AddContainerClient( &mClient, mWebView );
127 ~WebViewContainerForDali()
129 WebEngineManager::Get().RemoveContainerClient( mWebView );
131 evas_object_del( mWebView );
136 Ecore_Wl2_Window* win = AnyCast< Ecore_Wl2_Window* >( Adaptor::Get().GetNativeWindowHandle() );
137 Ewk_Context* context = ewk_context_default_get();
138 ewk_context_max_refresh_rate_set( context, 60 );
139 mWebView = ewk_view_add( ecore_evas_get( WebEngineManager::Get().GetWindow() ) );
140 ewk_view_offscreen_rendering_enabled_set( mWebView, true );
141 ewk_view_ime_window_set( mWebView, win );
143 evas_object_smart_callback_add( mWebView, "offscreen,frame,rendered",
144 &WebViewContainerForDali::OnFrameRendered,
146 evas_object_smart_callback_add( mWebView, "load,started",
147 &WebViewContainerForDali::OnLoadStarted,
149 evas_object_smart_callback_add( mWebView, "load,finished",
150 &WebViewContainerForDali::OnLoadFinished,
152 evas_object_smart_callback_add( mWebView, "load,error",
153 &WebViewContainerForDali::OnLoadError,
155 evas_object_smart_callback_add( mWebView, "console,message",
156 &WebViewContainerForDali::OnConsoleMessage,
159 evas_object_resize( mWebView, mWidth, mHeight );
160 evas_object_show( mWebView );
163 void LoadUrl( const std::string& url )
165 ewk_view_url_set( mWebView, url.c_str() );
166 ewk_view_focus_set( mWebView, true );
169 void LoadHtml( const std::string& html )
171 ewk_view_html_string_load( mWebView, html.c_str(), 0, 0 );
176 return std::string( ewk_view_url_get( mWebView ) );
181 ewk_view_reload( mWebView );
186 ewk_view_stop( mWebView );
191 ewk_view_suspend( mWebView );
196 ewk_view_resume( mWebView );
201 ewk_view_back( mWebView );
206 ewk_view_forward( mWebView );
211 return ewk_view_back_possible( mWebView );
216 return ewk_view_forward_possible( mWebView );
219 void EvaluateJavaScript( size_t key, const std::string& script )
221 ewk_view_script_execute( mWebView, script.c_str(), OnEvaluateJavaScript, (void*)key );
224 void AddJavaScriptMessageHandler( const std::string& exposedObjectName )
226 // |jsFunctionName| is fixed as "postMessage" so we don't use this.
227 ewk_view_javascript_message_handler_add( mWebView, &WebViewContainerForDali::OnJavaScriptMessage, exposedObjectName.c_str() );
232 ewk_view_back_forward_list_clear( mWebView );
237 ewk_context_cache_clear( ewk_view_context_get( mWebView ) );
242 ewk_cookie_manager_cookies_clear( ewk_context_cookie_manager_get( ewk_view_context_get( mWebView ) ) );
245 Ewk_Cache_Model GetCacheModel()
247 return ewk_context_cache_model_get( ewk_view_context_get( mWebView ) );
250 void SetCacheModel( Ewk_Cache_Model cacheModel )
252 ewk_context_cache_model_set( ewk_view_context_get( mWebView ), cacheModel );
255 Ewk_Cookie_Accept_Policy GetCookieAcceptPolicy()
257 return mCookieAcceptancePolicy;
260 void SetCookieAcceptPolicy( Ewk_Cookie_Accept_Policy policy )
262 ewk_cookie_manager_accept_policy_set( ewk_context_cookie_manager_get( ewk_view_context_get( mWebView ) ), policy );
263 mCookieAcceptancePolicy = policy;
266 const std::string& GetUserAgent()
268 mUserAgent = std::string( ewk_view_user_agent_get( mWebView ) );
272 void SetUserAgent( const std::string& userAgent )
274 ewk_view_user_agent_set( mWebView, userAgent.c_str() );
277 bool IsJavaScriptEnabled()
279 return ewk_settings_javascript_enabled_get( ewk_view_settings_get( mWebView ) );
282 void EnableJavaScript( bool enabled )
284 ewk_settings_javascript_enabled_set( ewk_view_settings_get( mWebView ), enabled );
287 bool AreImagesAutomaticallyLoaded()
289 return ewk_settings_loads_images_automatically_get( ewk_view_settings_get( mWebView ) );
292 void LoadImagesAutomatically( bool automatic )
294 ewk_settings_loads_images_automatically_set( ewk_view_settings_get( mWebView ), automatic );
297 const std::string& GetDefaultTextEncodingName()
299 mDefaultTextEncodingName = std::string( ewk_settings_default_text_encoding_name_get( ewk_view_settings_get( mWebView ) ) );
300 return mDefaultTextEncodingName;
303 void SetDefaultTextEncodingName( const std::string& defaultTextEncodingName )
305 ewk_settings_default_text_encoding_name_set( ewk_view_settings_get( mWebView ), defaultTextEncodingName.c_str() );
308 int GetDefaultFontSize()
310 return ewk_settings_default_font_size_get( ewk_view_settings_get( mWebView ) );
313 void SetDefaultFontSize( int defaultFontSize )
315 ewk_settings_default_font_size_set( ewk_view_settings_get( mWebView ), defaultFontSize );
318 void SetSize( int width, int height )
322 evas_object_resize( mWebView, mWidth, mHeight );
325 bool SendTouchEvent( const TouchEvent& touch )
327 Ewk_Touch_Event_Type type = EWK_TOUCH_START;
328 Evas_Touch_Point_State state = EVAS_TOUCH_POINT_DOWN;
329 switch ( touch.GetState( 0 ) )
331 case PointState::DOWN:
333 type = EWK_TOUCH_START;
334 state = EVAS_TOUCH_POINT_DOWN;
339 type = EWK_TOUCH_END;
340 state = EVAS_TOUCH_POINT_UP;
343 case PointState::MOTION:
345 type = EWK_TOUCH_MOVE;
346 state = EVAS_TOUCH_POINT_MOVE;
349 case PointState::INTERRUPTED:
351 type = EWK_TOUCH_CANCEL;
352 state = EVAS_TOUCH_POINT_CANCEL;
361 Eina_List* pointList = 0;
362 Ewk_Touch_Point* point = new Ewk_Touch_Point;
364 point->x = touch.GetLocalPosition( 0 ).x;
365 point->y = touch.GetLocalPosition( 0 ).y;
366 point->state = state;
367 pointList = eina_list_append( pointList, point );
369 ewk_view_feed_touch_event( mWebView, type, pointList, 0 );
370 eina_list_free( pointList );
374 bool SendKeyEvent( const Dali::KeyEvent& keyEvent )
376 void* evasKeyEvent = 0;
377 if( keyEvent.GetState() == Dali::KeyEvent::Down )
379 Evas_Event_Key_Down downEvent;
380 memset( &downEvent, 0, sizeof(Evas_Event_Key_Down) );
381 downEvent.key = keyEvent.GetKeyName().c_str();
382 downEvent.string = keyEvent.GetKeyString().c_str();
383 evasKeyEvent = static_cast<void*>(&downEvent);
384 ewk_view_send_key_event( mWebView, evasKeyEvent, true );
388 Evas_Event_Key_Up upEvent;
389 memset(&upEvent, 0, sizeof(Evas_Event_Key_Up));
390 upEvent.key = keyEvent.GetKeyName().c_str();
391 upEvent.string = keyEvent.GetKeyString().c_str();
392 evasKeyEvent = static_cast<void*>(&upEvent);
393 ewk_view_send_key_event( mWebView, evasKeyEvent, false );
399 static void OnFrameRendered( void* data, Evas_Object*, void* buffer )
401 auto client = static_cast<WebViewContainerClient*>(data);
402 client->UpdateImage( static_cast<tbm_surface_h>(buffer) );
405 static void OnLoadStarted( void* data, Evas_Object*, void* )
407 auto client = static_cast<WebViewContainerClient*>(data);
408 client->LoadStarted();
411 static void OnLoadFinished( void* data, Evas_Object*, void* )
413 auto client = static_cast<WebViewContainerClient*>(data);
414 client->LoadFinished();
417 static void OnLoadError( void* data, Evas_Object*, void* rawError )
419 auto client = static_cast<WebViewContainerClient*>(data);
420 Ewk_Error* error = static_cast< Ewk_Error* >( rawError );
422 client->LoadError( ewk_error_url_get( error ), ewk_error_code_get( error ) );
425 static void OnConsoleMessage( void*, Evas_Object*, void* eventInfo )
427 Ewk_Console_Message* message = (Ewk_Console_Message*)eventInfo;
428 DALI_LOG_RELEASE_INFO( "console message:%s: %d: %d: %s",
429 ewk_console_message_source_get( message ),
430 ewk_console_message_line_get( message ),
431 ewk_console_message_level_get( message ),
432 ewk_console_message_text_get( message ) );
435 static void OnEvaluateJavaScript( Evas_Object* o, const char* result, void* data )
437 auto client = WebEngineManager::Get().FindContainerClient( o );
440 client->RunJavaScriptEvaluationResultHandler( (size_t)data, result );
444 static void OnJavaScriptMessage( Evas_Object* o, Ewk_Script_Message message )
446 auto client = WebEngineManager::Get().FindContainerClient( o );
449 client->RunJavaScriptMessageHandler( message.name, static_cast<char*>( message.body ) );
454 Evas_Object* mWebView;
455 WebViewContainerClient& mClient;
460 Ewk_Cookie_Accept_Policy mCookieAcceptancePolicy;
461 std::string mUserAgent;
462 std::string mDefaultTextEncodingName;
465 class TBMSurfaceSourceInitializer
468 explicit TBMSurfaceSourceInitializer( NativeImageSourcePtr& imageSrc,
469 int width, int height )
471 mSurface = tbm_surface_create( width, height, TBM_FORMAT_ARGB8888 );
474 DALI_LOG_ERROR( "Failed to create tbm surface." );
477 Any tbmSource( mSurface );
478 imageSrc = NativeImageSource::New( tbmSource );
479 Any emptySource( 0 );
480 imageSrc->SetSource( emptySource );
483 ~TBMSurfaceSourceInitializer()
487 if( tbm_surface_destroy( mSurface ) != TBM_SURFACE_ERROR_NONE )
489 DALI_LOG_ERROR( "Failed to destroy tbm surface." );
494 tbm_surface_h mSurface;
497 TizenWebEngineChromium::TizenWebEngineChromium()
498 : mWebViewContainer( 0 )
499 , mJavaScriptEvaluationCount( 0 )
503 TizenWebEngineChromium::~TizenWebEngineChromium()
508 void TizenWebEngineChromium::Create( int width, int height,
509 const std::string& locale,
510 const std::string& timezoneID )
513 new WebViewContainerForDali( *this, width, height );
514 TBMSurfaceSourceInitializer initializer( mDaliImageSrc, width, height );
517 void TizenWebEngineChromium::Destroy()
519 if (mWebViewContainer)
521 mJavaScriptEvaluationResultHandlers.clear();
522 mJavaScriptMessageHandlers.clear();
524 delete mWebViewContainer;
525 mWebViewContainer = 0;
529 void TizenWebEngineChromium::LoadUrl( const std::string& path )
531 if( mWebViewContainer )
533 mWebViewContainer->LoadUrl( path );
537 NativeImageInterfacePtr TizenWebEngineChromium::GetNativeImageSource()
539 return mDaliImageSrc;
542 const std::string& TizenWebEngineChromium::GetUrl()
544 if( mWebViewContainer )
546 mUrl = mWebViewContainer->GetUrl();
551 void TizenWebEngineChromium::LoadHTMLString( const std::string& string )
553 if( mWebViewContainer )
555 mWebViewContainer->LoadHtml( string );
559 void TizenWebEngineChromium::Reload()
561 if( mWebViewContainer )
563 mWebViewContainer->Reload();
567 void TizenWebEngineChromium::StopLoading()
569 if( mWebViewContainer )
571 mWebViewContainer->StopLoading();
575 void TizenWebEngineChromium::Suspend()
577 if( mWebViewContainer )
579 mWebViewContainer->Suspend();
583 void TizenWebEngineChromium::Resume()
585 if( mWebViewContainer )
587 mWebViewContainer->Resume();
591 bool TizenWebEngineChromium::CanGoForward()
593 if( mWebViewContainer )
595 return mWebViewContainer->CanGoForward();
600 void TizenWebEngineChromium::GoForward()
602 if( mWebViewContainer )
604 mWebViewContainer->GoForward();
608 bool TizenWebEngineChromium::CanGoBack()
610 if( mWebViewContainer )
612 return mWebViewContainer->CanGoBack();
617 void TizenWebEngineChromium::GoBack()
619 if( mWebViewContainer )
621 mWebViewContainer->GoBack();
625 void TizenWebEngineChromium::EvaluateJavaScript( const std::string& script, std::function< void( const std::string& ) > resultHandler )
627 if( mWebViewContainer )
629 bool badAlloc = false;
633 mJavaScriptEvaluationResultHandlers.emplace( mJavaScriptEvaluationCount, resultHandler );
635 catch( std::bad_alloc &e )
638 DALI_LOG_ERROR( "Too many ongoing JavaScript evaluations." );
643 mWebViewContainer->EvaluateJavaScript( mJavaScriptEvaluationCount++, script );
648 void TizenWebEngineChromium::AddJavaScriptMessageHandler( const std::string& exposedObjectName, std::function< void( const std::string& ) > handler )
650 if( mWebViewContainer )
652 if( mJavaScriptMessageHandlers.emplace( exposedObjectName, handler ).second )
654 mWebViewContainer->AddJavaScriptMessageHandler( exposedObjectName );
658 DALI_LOG_ERROR( "Callback for (%s) already exists.", exposedObjectName.c_str() );
663 void TizenWebEngineChromium::ClearHistory()
665 if( mWebViewContainer )
667 mWebViewContainer->ClearHistory();
671 void TizenWebEngineChromium::ClearCache()
673 if( mWebViewContainer )
675 mWebViewContainer->ClearCache();
679 void TizenWebEngineChromium::ClearCookies()
681 if( mWebViewContainer )
683 mWebViewContainer->ClearCookies();
687 Dali::WebEnginePlugin::CacheModel TizenWebEngineChromium::GetCacheModel() const
689 if( mWebViewContainer )
691 return static_cast< Dali::WebEnginePlugin::CacheModel >( mWebViewContainer->GetCacheModel() );
693 return Dali::WebEnginePlugin::CacheModel::DOCUMENT_VIEWER;
696 void TizenWebEngineChromium::SetCacheModel( Dali::WebEnginePlugin::CacheModel cacheModel )
698 if( mWebViewContainer )
700 return mWebViewContainer->SetCacheModel( static_cast< Ewk_Cache_Model >( cacheModel ) );
704 Dali::WebEnginePlugin::CookieAcceptPolicy TizenWebEngineChromium::GetCookieAcceptPolicy() const
706 if( mWebViewContainer )
708 return static_cast< Dali::WebEnginePlugin::CookieAcceptPolicy >( mWebViewContainer->GetCookieAcceptPolicy() );
710 return Dali::WebEnginePlugin::CookieAcceptPolicy::NO_THIRD_PARTY;
713 void TizenWebEngineChromium::SetCookieAcceptPolicy( Dali::WebEnginePlugin::CookieAcceptPolicy policy )
715 if( mWebViewContainer )
717 mWebViewContainer->SetCookieAcceptPolicy( static_cast< Ewk_Cookie_Accept_Policy >( policy ) );
721 const std::string kEmpty;
723 const std::string& TizenWebEngineChromium::GetUserAgent() const
725 if( mWebViewContainer )
727 return mWebViewContainer->GetUserAgent();
732 void TizenWebEngineChromium::SetUserAgent( const std::string& userAgent )
734 if( mWebViewContainer )
736 mWebViewContainer->SetUserAgent( userAgent );
740 bool TizenWebEngineChromium::IsJavaScriptEnabled() const
742 if( mWebViewContainer )
744 return mWebViewContainer->IsJavaScriptEnabled();
749 void TizenWebEngineChromium::EnableJavaScript( bool enabled )
751 if( mWebViewContainer )
753 mWebViewContainer->EnableJavaScript( enabled );
757 bool TizenWebEngineChromium::AreImagesAutomaticallyLoaded() const
759 if( mWebViewContainer )
761 return mWebViewContainer->AreImagesAutomaticallyLoaded();
766 void TizenWebEngineChromium::LoadImagesAutomatically( bool automatic )
768 if( mWebViewContainer )
770 mWebViewContainer->LoadImagesAutomatically( automatic );
774 const std::string& TizenWebEngineChromium::GetDefaultTextEncodingName() const
776 if( mWebViewContainer )
778 return mWebViewContainer->GetDefaultTextEncodingName();
783 void TizenWebEngineChromium::SetDefaultTextEncodingName( const std::string& defaultTextEncodingName )
785 if( mWebViewContainer )
787 mWebViewContainer->SetDefaultTextEncodingName( defaultTextEncodingName );
791 int TizenWebEngineChromium::GetDefaultFontSize() const
793 if( mWebViewContainer )
795 return mWebViewContainer->AreImagesAutomaticallyLoaded();
800 void TizenWebEngineChromium::SetDefaultFontSize( int defaultFontSize )
802 if( mWebViewContainer )
804 mWebViewContainer->SetDefaultFontSize( defaultFontSize );
808 void TizenWebEngineChromium::SetSize( int width, int height )
810 if( mWebViewContainer )
812 mWebViewContainer->SetSize( width, height );
816 bool TizenWebEngineChromium::SendTouchEvent( const Dali::TouchEvent& touch )
818 if( mWebViewContainer )
820 return mWebViewContainer->SendTouchEvent( touch );
825 bool TizenWebEngineChromium::SendKeyEvent( const Dali::KeyEvent& event )
827 if( mWebViewContainer )
829 return mWebViewContainer->SendKeyEvent( event );
834 Dali::WebEnginePlugin::WebEnginePageLoadSignalType& TizenWebEngineChromium::PageLoadStartedSignal()
836 return mLoadStartedSignal;
839 Dali::WebEnginePlugin::WebEnginePageLoadSignalType& TizenWebEngineChromium::PageLoadFinishedSignal()
841 return mLoadFinishedSignal;
844 Dali::WebEnginePlugin::WebEnginePageLoadErrorSignalType& TizenWebEngineChromium::PageLoadErrorSignal()
846 return mLoadErrorSignal;
849 // WebViewContainerClient Interface
850 void TizenWebEngineChromium::UpdateImage( tbm_surface_h buffer )
857 Any source( buffer );
858 mDaliImageSrc->SetSource( source );
859 Dali::Stage::GetCurrent().KeepRendering( 0.0f );
862 void TizenWebEngineChromium::LoadStarted()
864 DALI_LOG_RELEASE_INFO( "#LoadStarted : %s\n", GetUrl().c_str() );
865 mLoadStartedSignal.Emit( GetUrl() );
868 void TizenWebEngineChromium::LoadFinished()
870 DALI_LOG_RELEASE_INFO( "#LoadFinished : %s\n", GetUrl().c_str() );
871 mLoadFinishedSignal.Emit( GetUrl() );
874 void TizenWebEngineChromium::LoadError( const char* url, int errorCode )
876 std::string stdUrl( url );
877 mLoadErrorSignal.Emit( stdUrl, errorCode );
880 void TizenWebEngineChromium::RunJavaScriptEvaluationResultHandler( size_t key, const char* result )
882 auto handler = mJavaScriptEvaluationResultHandlers.find( key );
883 if( handler == mJavaScriptEvaluationResultHandlers.end() )
888 if( handler->second )
890 std::string stored( result );
891 handler->second( stored );
894 mJavaScriptEvaluationResultHandlers.erase( handler );
897 void TizenWebEngineChromium::RunJavaScriptMessageHandler( const std::string& objectName, const std::string& message )
899 auto handler = mJavaScriptMessageHandlers.find( objectName );
900 if( handler == mJavaScriptMessageHandlers.end() )
905 handler->second( message );
907 } // namespace Plugin
911 extern "C" DALI_EXPORT_API Dali::WebEnginePlugin* CreateWebEnginePlugin()
913 return new Dali::Plugin::TizenWebEngineChromium();
916 extern "C" DALI_EXPORT_API void DestroyWebEnginePlugin( Dali::WebEnginePlugin* plugin )