From 95deac36e6f4258836ac9d2ccbe68c5090443397 Mon Sep 17 00:00:00 2001 From: Chandan Padhi Date: Mon, 6 Mar 2023 21:16:53 +0530 Subject: [PATCH 01/16] Clear browser frame only if a valid texture is available This commit adds a check in EvasObjectImagePixelsGetCallback to ensure that browser frame is cleared only if a valid texture is available from NotifySwap. This helps in fixing the blink issue while navigating through hyperlinks on a page. Change-Id: I95854ec6c6e39f515b44ef673d17ed87c58059f4 Signed-off-by: Chandan Padhi --- .../content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc index 8b1e6ef..a0b37908 100644 --- a/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc +++ b/tizen_src/chromium_impl/content/browser/renderer_host/rwhv_aura_offscreen_helper_efl.cc @@ -570,11 +570,13 @@ void RWHVAuraOffscreenHelperEfl::EvasObjectImagePixelsGetCallback( Evas_Object* obj) { RWHVAuraOffscreenHelperEfl* rwhv_helper = reinterpret_cast(data); + if (!rwhv_helper->texture_id_) + return; + rwhv_helper->MakeCurrent(); rwhv_helper->ClearBrowserFrame(); rwhv_helper->ClearCurrent(); - if (rwhv_helper->texture_id_) - rwhv_helper->PaintTextureToSurface(rwhv_helper->texture_id_); + rwhv_helper->PaintTextureToSurface(rwhv_helper->texture_id_); } void RWHVAuraOffscreenHelperEfl::NotifySwap(const uint32_t texture_id) { -- 2.7.4 From e80d00960edb8f6c52b72b7c3f821237b779e324 Mon Sep 17 00:00:00 2001 From: Venugopal S M Date: Tue, 7 Mar 2023 18:32:57 +0530 Subject: [PATCH 02/16] fixup! [M108 Migration] Support builds for aarch64 and emulator Remove clang check in "BufferObserverImpl". Change-Id: Iebdbf7e5743fcbbf5badf5bcfbc2ac1b1206c19b Signed-off-by: Venugopal S M --- .../chromium_impl/media/filters/esplusplayer_buffer_observer_impl.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tizen_src/chromium_impl/media/filters/esplusplayer_buffer_observer_impl.cc b/tizen_src/chromium_impl/media/filters/esplusplayer_buffer_observer_impl.cc index b6852a5..4eb5b0d 100644 --- a/tizen_src/chromium_impl/media/filters/esplusplayer_buffer_observer_impl.cc +++ b/tizen_src/chromium_impl/media/filters/esplusplayer_buffer_observer_impl.cc @@ -101,14 +101,10 @@ void BufferObserverImpl::ResetBufferStatus() { int BufferObserverImpl::SetMediaStreamStatusCallback( esplusplayer_handle player, esplusplayer_stream_type stream_type) { -#if BUILDFLAG(IS_CLANG) const BufferStatusCallbacks callbacks = { BufferObserverImpl::OnBufferedSizeChanged, BufferObserverImpl::OnBufferedTimeChanged}; return SetBufferStatusCallbacks(player, stream_type, callbacks); -#endif - LOG(ERROR)<<" Disabled due to build break related to gcc"; - return 1; } BufferStatus BufferObserverImpl::GetAudioStatus() const { -- 2.7.4 From eeec861d3a8e2e9d7f666124092d21324507c652 Mon Sep 17 00:00:00 2001 From: Ayush Kumar Date: Mon, 27 Feb 2023 14:04:15 +0530 Subject: [PATCH 03/16] [M108 Migration] Segregate ContextMenuControllerEfl into a base class 1. Split ContextMenuControllerEfl into two parts, one of which will be recycled by WRTJS as well 2. Removed redundant and extra headers and cleaned up the code a bit 3. Modified/Removed functions from ContextMenuController which are no longer needed in m108 Reference: 1. https://review.tizen.org/gerrit/282571 2. https://review.tizen.org/gerrit/284343 Change-Id: Ifc9730734bea5a0bf530b553bd00a90e0f39f136 Signed-off-by: Ayush Kumar --- .../browser/web_contents/web_contents_view_aura.h | 8 + .../chromium_impl/content/browser/browser_efl.gni | 2 + .../context_menu/context_menu_controller_base.cc | 641 +++++++++++++++++++++ .../context_menu/context_menu_controller_base.h | 145 +++++ tizen_src/ewk/efl_integration/BUILD.gn | 1 + .../efl_integration/context_menu_controller_efl.cc | 598 +------------------ .../efl_integration/context_menu_controller_efl.h | 112 +--- .../private/ewk_context_menu_item_private.h | 28 + .../private/ewk_context_menu_private.h | 19 +- 9 files changed, 859 insertions(+), 695 deletions(-) create mode 100644 tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.cc create mode 100644 tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.h create mode 100644 tizen_src/ewk/efl_integration/private/ewk_context_menu_item_private.h diff --git a/content/browser/web_contents/web_contents_view_aura.h b/content/browser/web_contents/web_contents_view_aura.h index db0945e..7e4abc8 100644 --- a/content/browser/web_contents/web_contents_view_aura.h +++ b/content/browser/web_contents/web_contents_view_aura.h @@ -86,6 +86,10 @@ class CONTENT_EXPORT WebContentsViewAura } #endif +#if BUILDFLAG(IS_TIZEN) + int GetOrientation() { return orientation_; } +#endif + private: // Just the metadata from DropTargetEvent that's safe and cheap to copy to // help locate drop events in the callback. @@ -412,6 +416,10 @@ class CONTENT_EXPORT WebContentsViewAura std::unique_ptr wcva_helper_; #endif +#if BUILDFLAG(IS_TIZEN) + int orientation_ = 0; +#endif + base::WeakPtrFactory weak_ptr_factory_{this}; }; diff --git a/tizen_src/chromium_impl/content/browser/browser_efl.gni b/tizen_src/chromium_impl/content/browser/browser_efl.gni index 0830e10..03a1545 100644 --- a/tizen_src/chromium_impl/content/browser/browser_efl.gni +++ b/tizen_src/chromium_impl/content/browser/browser_efl.gni @@ -75,6 +75,8 @@ if (enable_wrt_js) { # Source ############################################################################## external_content_browser_efl_sources = [ + "//tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.cc", + "//tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.h", "//tizen_src/chromium_impl/content/browser/date_time_chooser_efl.cc", "//tizen_src/chromium_impl/content/browser/date_time_chooser_efl.h", "//tizen_src/chromium_impl/content/browser/input_picker/input_picker_base.cc", diff --git a/tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.cc b/tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.cc new file mode 100644 index 0000000..a740b9c --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.cc @@ -0,0 +1,641 @@ +// Copyright 2022 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "context_menu_controller_base.h" + +#include + +#include "content/browser/renderer_host/render_widget_host_view_aura.h" +#include "content/browser/web_contents/web_contents_impl.h" +#include "content/browser/web_contents/web_contents_view_aura.h" +#include "tizen_src/chromium_impl/tizen/system_info.h" +#include "tizen_src/ewk/efl_integration/private/ewk_context_menu_item_private.h" +#include "ui/display/screen.h" +#include "ui/gfx/geometry/dip_util.h" +#include "ui/gfx/geometry/rect.h" + +#if BUILDFLAG(IS_TIZEN) +#include +#include +#endif + +namespace content { + +namespace { +// The height of the selection menu. +static const int kMenuHeight = 64; + +// Popup will be restored after kRestoreTime if it is dismissed unexpectedly. +static const float kRestoreTime = 0.5f; + +const int kMinHeightVertical = 840; +const int kMinHeightHorizontal = 420; +} // namespace + +int ContextMenuControllerBase::_popup_item_height = 96; +std::vector + ContextMenuControllerBase::_context_menu_listdata; + +ContextMenuControllerBase::ContextMenuControllerBase(WebContents& web_contents) + : web_contents_(web_contents) { + native_view_ = + static_cast(&web_contents_)->GetEflNativeView(); +} + +ContextMenuControllerBase::~ContextMenuControllerBase() { + _context_menu_listdata.clear(); + DeletePopup(); +} + +void ContextMenuControllerBase::Move(int x, int y) { + if (popup_ && is_text_selection_) + evas_object_move(popup_, x, y); +} + +bool ContextMenuControllerBase::CreateContextMenu( + const ContextMenuParams& params) { + is_text_selection_ = false; + Eina_List* ittr; + void* data; + EINA_LIST_FOREACH(menu_items_, ittr, data) { + _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*>(data); + ContextMenuItemEfl* context_item = item->GetMenuItem(); + switch (context_item->GetContextMenuOption()) { + case EWK_CONTEXT_MENU_ITEM_TAG_COPY: + case EWK_CONTEXT_MENU_ITEM_TAG_SELECT_ALL: + case EWK_CONTEXT_MENU_ITEM_TAG_SELECT_WORD: + case EWK_CONTEXT_MENU_ITEM_TAG_PASTE: + is_text_selection_ = true; + break; + default: + break; + } + } + + if (is_text_selection_) { + popup_ = elm_ctxpopup_add(native_view_); +#if BUILDFLAG(IS_TIZEN) + elm_ctxpopup_horizontal_set(popup_, EINA_TRUE); +#endif + elm_object_tree_focus_allow_set(popup_, false); + } else { + top_widget_ = + elm_object_top_widget_get(elm_object_parent_widget_get(evas_object())); + evas_object_data_set(top_widget_, "ContextMenuContollerEfl", this); + popup_ = elm_popup_add(top_widget_); + + if (IsMobileProfile()) + elm_popup_align_set(popup_, ELM_NOTIFY_ALIGN_FILL, 1.0); + else + elm_popup_align_set(popup_, 0.5, 0.5); + } + + if (!popup_) + return false; + + if (!IsMobileProfile()) + evas_object_smart_member_add(popup_, evas_object()); + + elm_object_tree_focus_allow_set(popup_, EINA_FALSE); + + evas_object_data_set(popup_, "ContextMenuContollerEfl", this); + + _context_menu_listdata.clear(); + if (is_text_selection_) { + EINA_LIST_FOREACH(menu_items_, ittr, data) { + _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*>(data); + ContextMenuItemEfl* context_item = item->GetMenuItem(); + Elm_Object_Item* appended_item = 0; + + if (!context_item->Title().empty()) { + appended_item = elm_ctxpopup_item_append( + popup_, context_item->Title().c_str(), 0, + ContextMenuItemSelectedCallback, context_item); + } else { + appended_item = elm_ctxpopup_item_append( + popup_, 0, 0, ContextMenuItemSelectedCallback, context_item); + } + + if (appended_item) + _context_menu_listdata.push_back(*context_item); + } +#if BUILDFLAG(IS_TIZEN) + // Workaround + // Need to set "copypaste" style, to let moving handles + // when ctxpopup is visible + // http://107.108.218.239/bugzilla/show_bug.cgi?id=11613 + elm_object_style_set(popup_, "copypaste"); +#endif + + evas_object_size_hint_weight_set(popup_, EVAS_HINT_EXPAND, + EVAS_HINT_EXPAND); + evas_object_size_hint_max_set(popup_, -1, _popup_item_height); + evas_object_size_hint_min_set(popup_, 0, _popup_item_height); + } else { + std::string selected_link(params_.link_url.spec()); + if (!selected_link.empty()) { + if (base::StartsWith(selected_link, std::string("mailto:"), + base::CompareCase::INSENSITIVE_ASCII) || + base::StartsWith(selected_link, std::string("tel:"), + base::CompareCase::INSENSITIVE_ASCII)) { + size_t current_pos = 0; + size_t next_delimiter = 0; + // Remove the First part and Extract actual URL or title + // (mailto:abc@d.com?id=345 ==> abc@d.com?id=345) + if ((next_delimiter = selected_link.find(":", current_pos)) != + std::string::npos) { + current_pos = next_delimiter + 1; + } + + std::string last_part = selected_link.substr(current_pos); + std::string core_part = selected_link.substr(current_pos); + current_pos = 0; + next_delimiter = 0; + // Trim the core by removing ? at the end (abc@d.com?id=345 ==> + // abc@d.com) + if ((next_delimiter = core_part.find("?", current_pos)) != + std::string::npos) { + last_part = + core_part.substr(current_pos, next_delimiter - current_pos); + } + } else { + elm_object_part_text_set(popup_, "title,text", selected_link.c_str()); + } + } else { + std::string selected_image(params_.src_url.spec()); + if (!selected_image.empty()) + elm_object_part_text_set(popup_, "title,text", selected_image.c_str()); + } + + evas_object_size_hint_weight_set(popup_, EVAS_HINT_EXPAND, + EVAS_HINT_EXPAND); + + list_ = elm_list_add(popup_); + elm_list_mode_set(list_, ELM_LIST_EXPAND); + evas_object_data_set(list_, "ContextMenuContollerEfl", this); + + Eina_List* ittr; + void* data; + EINA_LIST_FOREACH(menu_items_, ittr, data) { + _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*>(data); + ContextMenuItemEfl* context_item = item->GetMenuItem(); + if (!context_item->Title().empty()) { + Elm_Object_Item* appended_item = elm_list_item_append( + list_, context_item->Title().c_str(), NULL, NULL, + ContextMenuItemSelectedCallback, context_item); + + if (appended_item) + _context_menu_listdata.push_back(*context_item); + } + } + + ContextMenuPopupListResize(); + + evas_object_show(list_); + elm_object_content_set(popup_, list_); + evas_object_event_callback_add(popup_, EVAS_CALLBACK_RESIZE, + ContextMenuPopupResize, this); + } + + if (_context_menu_listdata.empty()) { + DeletePopup(); + return false; + } + return true; +} + +// static +void ContextMenuControllerBase::ContextMenuHWBackKey(void* data, + Evas_Object* obj, + void* event_info) { + auto menu_controller = static_cast(data); + if (menu_controller) { + auto selection_controller = menu_controller->GetSelectionController(); + if (selection_controller) + selection_controller->ToggleCaretAfterSelection(); + + menu_controller->HideContextMenu(); + evas_object_data_del(obj, "ContextEfl"); + } +} + +// static +Eina_Bool ContextMenuControllerBase::RestoreTimerCallback(void* data) { + auto* menu_controller = static_cast(data); + if (!menu_controller) + return ECORE_CALLBACK_CANCEL; + + auto selection_controller = menu_controller->GetSelectionController(); + + if (menu_controller->popup_ && selection_controller && + selection_controller->GetSelectionStatus() && + !selection_controller->IsCaretMode()) { + evas_object_show(menu_controller->popup_); + } + + menu_controller->restore_timer_ = nullptr; + + return ECORE_CALLBACK_CANCEL; +} + +// static +void ContextMenuControllerBase::ContextMenuCancelCallback(void* data, + Evas_Object* obj, + void* event_info) { + ContextMenuControllerBase* menu_controller = + static_cast( + evas_object_data_get(obj, "ContextMenuContollerEfl")); + if (!menu_controller) + return; + + RenderWidgetHostViewAura* rwhva = menu_controller->rwhva(); + if (!rwhva) + return; + + // context_menu is dismissed when we touch outside of popup. + // It is policy of elm_ctxpopup by EFL team. + // But according to wcs TC(21~23) context_menu should be displayed, + // when touchevent is consumed. So we should show context_menu again when + // touchevent is consumed. + if (rwhva->offscreen_helper()->IsTouchstartConsumed() || + rwhva->offscreen_helper()->IsTouchendConsumed()) { + evas_object_show(menu_controller->popup_); + return; + } + + // TODO: If |elm_ctxpopup_auto_hide_disabled_set| is works properly, + // We should remove this timer. + // Bug: http://suprem.sec.samsung.net/jira/browse/TNEXT-67 + menu_controller->restore_timer_ = + ecore_timer_add(kRestoreTime, RestoreTimerCallback, menu_controller); +} + +// static +void ContextMenuControllerBase::ContextMenuItemSelectedCallback( + void* data, + Evas_Object* obj, + void* event_info) { + Evas_Object* pop_up = obj; + ContextMenuControllerBase* menu_controller = + static_cast( + evas_object_data_get(pop_up, "ContextMenuContollerEfl")); + + if (menu_controller) { + ContextMenuItemEfl* selected_menu_item = + static_cast(data); + if (selected_menu_item) + menu_controller->MenuItemSelected(selected_menu_item); + } +} + +void ContextMenuControllerBase::RequestSelectionRect() const { + CHECK(rwhva()); + rwhva()->host()->RequestSelectionRect(); +} + +gfx::Point ContextMenuControllerBase::CalculateSelectionMenuPosition( + const gfx::Rect& selection_rect) { + auto* selection_controller = GetSelectionController(); + if (!selection_controller) + return gfx::Point(); + + auto visible_viewport_rect = selection_controller->GetVisibleViewportRect(); + auto forbidden_rect = + selection_controller->GetForbiddenRegionRect(selection_rect); + + gfx::Point position; + // Selection menu should always be placed at the centre of visible selection + // area horizontally. + position.set_x(forbidden_rect.CenterPoint().x()); + // If possible, selection menu should always be placed above forbidden + // region. + + if (forbidden_rect.y() > visible_viewport_rect.y() + kMenuHeight) { + // If possible, selection menu should always be placed above forbidden + // region. + position.set_y(forbidden_rect.y()); + } else if (forbidden_rect.bottom() + kMenuHeight < + visible_viewport_rect.bottom()) { + // If there is no sufficient space above, we're trying to place selection + // menu below forbidden region. + position.set_y(forbidden_rect.bottom() + kMenuHeight); + } else { + // If there is no sufficient space above and below, selection menu will be + // shown at the centre of visible selection area vertically. + position.set_y(forbidden_rect.CenterPoint().y()); + } + + return position; +} + +void ContextMenuControllerBase::OnSelectionRectReceived( + gfx::Rect selection_rect) { + auto controller = GetSelectionController(); + + if (IsMobileProfile() && (context_menu_status_ != INPROGRESS)) + return; + + if (!popup_ || !rwhva() || !controller) + return; + + float device_scale = + display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(); + gfx::Rect selection_rect_dip = gfx::ToEnclosingRect( + ConvertRectToPixels(gfx::Rect(selection_rect), device_scale)); + + // Consider a webview offset. + selection_rect_dip.Offset( + rwhva()->offscreen_helper()->GetViewBoundsInPix().OffsetFromOrigin()); + + auto visible_viewport_rect = controller->GetVisibleViewportRect(); + + // In case of the caret mode selection_rect is empty + if (!controller->IsCaretMode() && + gfx::IntersectRects(visible_viewport_rect, selection_rect_dip) + .IsEmpty()) { + return; + } + + gfx::Point selection_menu_position = + CalculateSelectionMenuPosition(selection_rect_dip); + if (!visible_viewport_rect.Contains(selection_menu_position)) + return; + + evas_object_smart_callback_add(popup_, "dismissed", ContextMenuCancelCallback, + this); + + if (IsMobileProfile()) + elm_ctxpopup_auto_hide_disabled_set(popup_, EINA_TRUE); + +#if BUILDFLAG(IS_TIZEN) + eext_object_event_callback_add(popup_, EEXT_CALLBACK_BACK, + ContextMenuHWBackKey, this); +#endif + evas_object_move(popup_, selection_menu_position.x(), + selection_menu_position.y()); + + controller->ContextMenuStatusVisible(); + + evas_object_show(popup_); + evas_object_raise(popup_); + if (IsMobileProfile()) + context_menu_status_ = VISIBLE; +} + +bool ContextMenuControllerBase::ShowContextMenu() { + if (!popup_) + return false; + + if (IsMobileProfile()) + context_menu_status_ = INPROGRESS; + + if (is_text_selection_) { + // Selection menu will be shown in OnSelectionRectReceived after receiving + // selection rectangle form the renderer. + RequestSelectionRect(); + } else { + evas_object_smart_callback_add(popup_, "block,clicked", + BlockClickedCallback, this); +#if BUILDFLAG(IS_TIZEN) + eext_object_event_callback_add(popup_, EEXT_CALLBACK_BACK, + ContextMenuHWBackKey, this); + eext_object_event_callback_add(popup_, EEXT_CALLBACK_MORE, + ContextMenuHWBackKey, this); +#endif + evas_object_show(popup_); + evas_object_raise(popup_); + if (IsMobileProfile()) + context_menu_status_ = VISIBLE; + } + return true; +} + +void ContextMenuControllerBase::HideSelectionHandle() { + auto* controller = GetSelectionController(); + if (controller) + controller->HideHandles(); +} + +void ContextMenuControllerBase::ClearSelection() { + auto controller = GetSelectionController(); + if (controller) + controller->ClearSelection(); +} + +void ContextMenuControllerBase::RequestShowSelectionHandleAndContextMenu( + bool trigger_selection_change) { + auto* controller = GetSelectionController(); + if (controller) { + controller->SetSelectionStatus(true); + controller->SetWaitsForRendererSelectionChanges( + SelectionControllerEfl::Reason::RequestedByContextMenu); + if (trigger_selection_change) + controller->TriggerOnSelectionChange(); + } +} + +#if BUILDFLAG(IS_TIZEN) +static void destroy_app_handle(app_control_h* handle) { + std::ignore = app_control_destroy(*handle); +} + +void ContextMenuControllerBase::LaunchShareApp(const std::string& text) { + app_control_h handle = nullptr; + int error_code = app_control_create(&handle); + if (error_code < 0 || !handle) { + LOG(ERROR) << __PRETTY_FUNCTION__ + << " : Failed to create share service. Error code: " + << error_code; + return; + } + + std::unique_ptr handle_ptr( + &handle, destroy_app_handle); + + error_code = + app_control_set_operation(handle, APP_CONTROL_OPERATION_SHARE_TEXT); + if (error_code < 0) { + LOG(ERROR) << __PRETTY_FUNCTION__ + << ": Failed to set share text operation. Error code: " + << error_code; + return; + } + + error_code = + app_control_add_extra_data(handle, APP_CONTROL_DATA_TEXT, text.c_str()); + if (error_code < 0) { + LOG(ERROR) << __PRETTY_FUNCTION__ + << ": Failed to add data for share application. Error code: " + << error_code; + return; + } + + error_code = app_control_send_launch_request(handle, nullptr, nullptr); + if (error_code < 0) { + LOG(ERROR) << __PRETTY_FUNCTION__ + << ": Failed to send launch request for share application. " + << "Error code: " << error_code; + return; + } +} +#endif + +// static +void ContextMenuControllerBase::ContextMenuPopupResize(void* data, + Evas* e, + Evas_Object* obj, + void* event_info) { + auto* thiz = static_cast(data); + if (thiz) + thiz->ContextMenuPopupListResize(); +} + +// static +void ContextMenuControllerBase::BlockClickedCallback(void* data, + Evas_Object*, + void*) { + ContextMenuControllerBase* menu_controller = + static_cast(data); + if (!menu_controller) + return; + + menu_controller->HideContextMenu(); +} + +void ContextMenuControllerBase::ContextMenuPopupListResize() { + if (!IsMobileProfile()) + return; + + int orientation = GetOrientation(); + if ((orientation == 90 || orientation == 270) && + _context_menu_listdata.size() > 3) + evas_object_size_hint_min_set(list_, 0, kMinHeightHorizontal); + else if ((orientation == 0 || orientation == 180) && + _context_menu_listdata.size() > 7) + evas_object_size_hint_min_set(list_, 0, kMinHeightVertical); + else + evas_object_size_hint_min_set( + list_, 0, _context_menu_listdata.size() * _popup_item_height); + + evas_object_show(list_); +} + +void ContextMenuControllerBase::HideContextMenu() { + if (IsMobileProfile() && + (context_menu_status_ == HIDDEN || context_menu_status_ == NONE)) + return; + + if (is_text_selection_) { + SelectionControllerEfl* controller = GetSelectionController(); + if (controller) + controller->ContextMenuStatusHidden(); + } + + if (popup_) { + if (IsMobileProfile()) { + evas_object_hide(popup_); + } else { + evas_object_event_callback_del(popup_, EVAS_CALLBACK_RESIZE, + ContextMenuPopupResize); + evas_object_del(popup_); + popup_ = nullptr; + } + } + + if (restore_timer_) { + ecore_timer_del(restore_timer_); + restore_timer_ = nullptr; + } + + if (IsMobileProfile()) { + context_menu_status_ = HIDDEN; + } else if (menu_items_) { + void* data; + EINA_LIST_FREE(menu_items_, data) { + _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*>(data); + delete item; + } + menu_items_ = nullptr; + } +} + +void ContextMenuControllerBase::Resize(const gfx::Rect& webview_rect) { + if (!popup_) + return; + + if (IsMobileProfile() && context_menu_status_ != VISIBLE) + return; + + if (is_text_selection_) { + RequestSelectionRect(); + } else { + evas_object_resize(popup_, webview_rect.width(), webview_rect.height()); + } +} + +void ContextMenuControllerBase::DeletePopup() { + if (top_widget_) + evas_object_data_set(top_widget_, "ContextMenuContollerEfl", 0); + + if (is_text_selection_) { + SelectionControllerEfl* controller = GetSelectionController(); + if (controller) + controller->ContextMenuStatusHidden(); + } + + if (popup_) { + evas_object_data_set(popup_, "ContextMenuContollerEfl", 0); + if (!IsMobileProfile()) + evas_object_smart_member_del(popup_); + evas_object_del(popup_); + popup_ = nullptr; + list_ = nullptr; + } + + if (menu_items_) { + void* data; + EINA_LIST_FREE(menu_items_, data) { + _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*>(data); + delete item; + } + menu_items_ = nullptr; + } + if (IsMobileProfile()) + context_menu_status_ = NONE; +} + +RenderWidgetHostViewAura* ContextMenuControllerBase::rwhva() const { + return static_cast( + web_contents_.GetRenderWidgetHostView()); +} + +WebContentsViewAura* ContextMenuControllerBase::GetWebContentsViewAura() const { + WebContentsImpl* wc = static_cast(&web_contents_); + return static_cast(wc->GetView()); +} + +int ContextMenuControllerBase::GetOrientation() { +#if BUILDFLAG(IS_TIZEN) + return GetWebContentsViewAura()->GetOrientation(); +#else + return 0; +#endif +} + +SelectionControllerEfl* ContextMenuControllerBase::GetSelectionController() { + RenderViewHost* render_view_host = web_contents_.GetRenderViewHost(); + RenderWidgetHostViewAura* view = static_cast( + render_view_host->GetWidget()->GetView()); + return view ? view->offscreen_helper()->GetSelectionController() : 0; +} + +const char* ContextMenuControllerBase::GetSelectedText() { + if (!rwhva()) + return ""; + + std::string selected_text = base::UTF16ToUTF8(rwhva()->GetSelectedText()); + return selected_text.c_str(); +} + +} // namespace content diff --git a/tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.h b/tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.h new file mode 100644 index 0000000..b8d427e --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/context_menu/context_menu_controller_base.h @@ -0,0 +1,145 @@ +// Copyright 2022 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef context_menu_controller_base_h +#define context_menu_controller_base_h + +#include +#include + +#include "content/public/browser/context_menu_params.h" +#include "content/public/browser/web_contents.h" +#include "tizen_src/ewk/efl_integration/public/ewk_context_menu_internal.h" + +namespace gfx { +class Rect; +} + +namespace content { +class RenderWidgetHostViewAura; +class SelectionControllerEfl; +class WebContents; +class WebContentsViewAura; + +class ContextMenuItemEfl { + public: + ContextMenuItemEfl(Ewk_Context_Menu_Item_Type item, + Ewk_Context_Menu_Item_Tag option, + const std::string& title, + const std::string& image_url = std::string(), + const std::string& link_url = std::string(), + const std::string& icon_path = std::string()) + : menu_type_(item), + menu_option_(option), + title_(title), + is_enabled_(true), + image_url_(image_url), + link_url_(link_url), + icon_path_(icon_path) {} + + ~ContextMenuItemEfl() {} + + const std::string& Title() const { return title_; } + void SetTitle(const std::string& title) { title_ = title; } + + bool IsEnabled() const { return is_enabled_; } + void SetEnabled(bool status) { is_enabled_ = status; } + Ewk_Context_Menu_Item_Tag GetContextMenuOption() const { + return menu_option_; + } + Ewk_Context_Menu_Item_Type GetContextMenuOptionType() const { + return menu_type_; + } + const std::string& LinkURL() const { return link_url_; } + const std::string& ImageURL() const { return image_url_; } + const std::string& IconPath() const { return icon_path_; } + + private: + Ewk_Context_Menu_Item_Type menu_type_; + Ewk_Context_Menu_Item_Tag menu_option_; + std::string title_; + bool is_enabled_; + std::string image_url_; + std::string link_url_; + std::string icon_path_; +}; + +class ContextMenuControllerBase { + public: + ContextMenuControllerBase(WebContents& web_contents); + virtual ~ContextMenuControllerBase(); + + ContextMenuControllerBase(const ContextMenuControllerBase&) = delete; + ContextMenuControllerBase& operator=(const ContextMenuControllerBase&) = + delete; + + static void ContextMenuCancelCallback(void* data, + Evas_Object* obj, + void* event_info); + static void ContextMenuItemSelectedCallback(void* data, + Evas_Object* obj, + void* event_info); + static void ContextMenuHWBackKey(void* data, + Evas_Object* obj, + void* event_info); + + void Move(int x, int y); + void HideContextMenu(); + + void RequestSelectionRect() const; + void OnSelectionRectReceived(gfx::Rect selection_rect); + gfx::Point CalculateSelectionMenuPosition(const gfx::Rect& selection_rect); + + virtual void Resize(const gfx::Rect& webview_rect); + virtual void MenuItemSelected(ContextMenuItemEfl* menu_item) = 0; + + protected: + bool CreateContextMenu(const ContextMenuParams& params); + bool ShowContextMenu(); + void HideSelectionHandle(); + void ClearSelection(); + void RequestShowSelectionHandleAndContextMenu( + bool trigger_selection_change = false); +#if BUILDFLAG(IS_TIZEN) + void LaunchShareApp(const std::string& text); +#endif + RenderWidgetHostViewAura* rwhva() const; + SelectionControllerEfl* GetSelectionController(); + + Eina_List* menu_items_ = nullptr; + ContextMenuParams params_; + WebContents& web_contents_; + bool is_text_selection_ = false; + + private: + virtual Evas_Object* evas_object() = 0; + + enum ContextMenuStatusTag { NONE = 0, HIDDEN, INPROGRESS, VISIBLE }; + static void ContextMenuPopupResize(void* data, + Evas* e, + Evas_Object* obj, + void* event_info); + static void BlockClickedCallback(void*, Evas_Object*, void*); + void ContextMenuPopupListResize(); + static Eina_Bool RestoreTimerCallback(void* data); + + void DeletePopup(); + int GetOrientation(); + virtual const char* GetSelectedText(); + WebContentsViewAura* GetWebContentsViewAura() const; + + static std::vector _context_menu_listdata; + static int _popup_item_height; + + Evas_Object* native_view_; + Evas_Object* top_widget_ = nullptr; + Evas_Object* popup_ = nullptr; + Evas_Object* list_ = nullptr; + Ecore_Timer* restore_timer_ = nullptr; + ContextMenuStatusTag context_menu_status_ = NONE; +}; + +} // namespace content + +#endif // context_menu_controller_base_h diff --git a/tizen_src/ewk/efl_integration/BUILD.gn b/tizen_src/ewk/efl_integration/BUILD.gn index eacbd7d..33fac56 100755 --- a/tizen_src/ewk/efl_integration/BUILD.gn +++ b/tizen_src/ewk/efl_integration/BUILD.gn @@ -392,6 +392,7 @@ shared_library("chromium-ewk") { "private/ewk_console_message_private.h", "private/ewk_context_form_autofill_profile_private.cc", "private/ewk_context_form_autofill_profile_private.h", + "private/ewk_context_menu_item_private.h", "private/ewk_context_menu_private.h", "private/ewk_context_private.cc", "private/ewk_context_private.h", diff --git a/tizen_src/ewk/efl_integration/context_menu_controller_efl.cc b/tizen_src/ewk/efl_integration/context_menu_controller_efl.cc index 838a328..b8e0ae2 100644 --- a/tizen_src/ewk/efl_integration/context_menu_controller_efl.cc +++ b/tizen_src/ewk/efl_integration/context_menu_controller_efl.cc @@ -2,9 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include -#include -#include +#include "context_menu_controller_efl.h" #include "base/files/file_path.h" #include "base/files/file_util.h" @@ -12,67 +10,41 @@ #include "base/strings/escape.h" #include "base/strings/utf_string_conversions.h" #include "browser_context_efl.h" -#include "common/web_contents_utils.h" #include "content/browser/renderer_host/render_widget_host_view_aura.h" #include "content/browser/selection/selection_controller_efl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/common/paths_efl.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/download_manager.h" -#include "content/public/browser/navigation_entry.h" -#include "content/public/browser/render_process_host.h" -#include "context_menu_controller_efl.h" +#include "content/public/browser/render_view_host.h" #include "eweb_view.h" #include "net/base/filename_util.h" -#include "net/traffic_annotation/network_traffic_annotation.h" #include "private/ewk_context_menu_private.h" #include "public/ewk_context_menu_product.h" #include "third_party/blink/public/mojom/context_menu/context_menu.mojom.h" #include "tizen/system_info.h" -#include "ui/base/clipboard/clipboard.h" #include "ui/base/clipboard/clipboard_helper_efl.h" -#include "ui/display/screen.h" #include "ui/gfx/geometry/dip_util.h" -#include "ui/gfx/geometry/rect.h" #if BUILDFLAG(IS_TIZEN) #include -#include -#include #endif using blink::mojom::ContextMenuDataMediaType; -using web_contents_utils::WebViewFromWebContents; namespace { -#define VERTICAL true -#define HORIZONTAL false - -// The height of the selection menu. -static const int kMenuHeight = 64; - -// Popup will be restored after kRestoreTime if it is dismissed unexpectedly. -static const float kRestoreTime = 0.5f; - -const int kMinHeightVertical = 840; -const int kMinHeightHorizontal = 420; - const std::string kWebSearchLink("https://www.google.com/search?q="); const char* const kEditCommandUnselect = "Unselect"; const char* const kDefaultImageExtension = "jpg"; -} +} // namespace namespace content { -int ContextMenuControllerEfl::_popup_item_height = 96; -std::vector ContextMenuControllerEfl::_context_menu_listdata; - ContextMenuControllerEfl::ContextMenuControllerEfl(EWebView* wv, WebContents& web_contents) - : webview_(wv), web_contents_(web_contents), weak_ptr_factory_(this) { - native_view_ = - static_cast(&web_contents_)->GetEflNativeView(); -} + : ContextMenuControllerBase(web_contents), + webview_(wv), + weak_ptr_factory_(this) {} ContextMenuControllerEfl::~ContextMenuControllerEfl() { for (std::set::iterator it = @@ -85,8 +57,14 @@ ContextMenuControllerEfl::~ContextMenuControllerEfl() { it != disk_download_items_.end(); ++it) { (*it)->RemoveObserver(this); } - _context_menu_listdata.clear(); - DeletePopup(); +} + +// ContextMenuControllerBase override methods +Evas_Object* ContextMenuControllerEfl::evas_object() { + return webview_->evas_object(); +} +const char* ContextMenuControllerEfl::GetSelectedText() { + return webview_->CacheSelectedText(); } bool ContextMenuControllerEfl::PopulateAndShowContextMenu(const ContextMenuParams ¶ms) { @@ -119,11 +97,6 @@ bool ContextMenuControllerEfl::PopulateAndShowContextMenu(const ContextMenuParam return ShowContextMenu(); } -void ContextMenuControllerEfl::Move(int x, int y) { - if (popup_ && is_text_selection_) - evas_object_move(popup_, x, y); -} - void ContextMenuControllerEfl::AddItemToProposedList(Ewk_Context_Menu_Item_Type item, Ewk_Context_Menu_Item_Tag option, const std::string& title, @@ -302,384 +275,6 @@ void ContextMenuControllerEfl::GetProposedContextMenu() { } } -bool ContextMenuControllerEfl::CreateContextMenu( - const ContextMenuParams& params) { - is_text_selection_ = false; - Eina_List* ittr; - void* data; - EINA_LIST_FOREACH(menu_items_, ittr, data) { - _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*> (data); - ContextMenuItemEfl* context_item = item->GetMenuItem(); - switch (context_item->GetContextMenuOption()) { - case EWK_CONTEXT_MENU_ITEM_TAG_COPY: - case EWK_CONTEXT_MENU_ITEM_TAG_SELECT_ALL: - case EWK_CONTEXT_MENU_ITEM_TAG_SELECT_WORD: - case EWK_CONTEXT_MENU_ITEM_TAG_PASTE: - is_text_selection_ = true; - break; - default: - break; - } - } - - if (is_text_selection_) { - popup_ = elm_ctxpopup_add(native_view_); -#if BUILDFLAG(IS_TIZEN) - elm_ctxpopup_horizontal_set(popup_, EINA_TRUE); -#endif - elm_object_tree_focus_allow_set(popup_, false); - } else { - top_widget_ = elm_object_top_widget_get( - elm_object_parent_widget_get(webview_->evas_object())); - evas_object_data_set(top_widget_, "ContextMenuContollerEfl", this); - popup_ = elm_popup_add(top_widget_); - - if (IsMobileProfile()) - elm_popup_align_set(popup_, ELM_NOTIFY_ALIGN_FILL, 1.0); - else - elm_popup_align_set(popup_, 0.5, 0.5); - } - - if (!popup_) - return false; - - if (!IsMobileProfile()) - evas_object_smart_member_add(popup_, webview_->evas_object()); - - elm_object_tree_focus_allow_set(popup_, EINA_FALSE); - - evas_object_data_set(popup_, "ContextMenuContollerEfl", this); - - _context_menu_listdata.clear(); - if (is_text_selection_) { - EINA_LIST_FOREACH(menu_items_, ittr, data) { - _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*> (data); - ContextMenuItemEfl* context_item = item->GetMenuItem(); - Elm_Object_Item* appended_item = 0; - - if (!context_item->Title().empty()) { - appended_item = elm_ctxpopup_item_append(popup_, - context_item->Title().c_str(), 0, ContextMenuItemSelectedCallback, - context_item); - } else { - appended_item = elm_ctxpopup_item_append(popup_, 0, 0, - ContextMenuItemSelectedCallback, - context_item); - } - - if (appended_item) - _context_menu_listdata.push_back(*context_item); - } -#if BUILDFLAG(IS_TIZEN) - // Workaround - // Need to set "copypaste" style, to let moving handles - // when ctxpopup is visible - // http://107.108.218.239/bugzilla/show_bug.cgi?id=11613 - elm_object_style_set(popup_, "copypaste"); -#endif - - evas_object_size_hint_weight_set(popup_, EVAS_HINT_EXPAND, - EVAS_HINT_EXPAND); - evas_object_size_hint_max_set(popup_, -1, _popup_item_height); - evas_object_size_hint_min_set(popup_, 0, _popup_item_height); - } else { - std::string selected_link(params_.link_url.spec()); - if (!selected_link.empty()) { - if (base::StartsWith(selected_link, std::string("mailto:"), - base::CompareCase::INSENSITIVE_ASCII) || - base::StartsWith(selected_link, std::string("tel:"), - base::CompareCase::INSENSITIVE_ASCII)) { - size_t current_pos = 0; - size_t next_delimiter = 0; - // Remove the First part and Extract actual URL or title - // (mailto:abc@d.com?id=345 ==> abc@d.com?id=345) - if ((next_delimiter = selected_link.find(":", current_pos)) != - std::string::npos) { - current_pos = next_delimiter + 1; - } - - std::string last_part = selected_link.substr(current_pos); - std::string core_part = selected_link.substr(current_pos); - current_pos = 0; - next_delimiter = 0; - // Trim the core by removing ? at the end (abc@d.com?id=345 ==> - // abc@d.com) - if ((next_delimiter = core_part.find("?", current_pos)) != - std::string::npos) { - last_part = - core_part.substr(current_pos, next_delimiter - current_pos); - } - } else { - elm_object_part_text_set(popup_, "title,text", selected_link.c_str()); - } - } else { - std::string selected_image(params_.src_url.spec()); - if (!selected_image.empty()) - elm_object_part_text_set(popup_, "title,text", selected_image.c_str()); - } - - evas_object_size_hint_weight_set(popup_, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); - - list_ = elm_list_add(popup_); - elm_list_mode_set(list_, ELM_LIST_EXPAND); - evas_object_data_set(list_, "ContextMenuContollerEfl", this); - - Eina_List* ittr; - void* data; - EINA_LIST_FOREACH(menu_items_, ittr, data) { - _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*> (data); - ContextMenuItemEfl* context_item = item->GetMenuItem(); - if (!context_item->Title().empty()) { - Elm_Object_Item* appended_item = elm_list_item_append( - list_, context_item->Title().c_str(), NULL, NULL, - ContextMenuItemSelectedCallback, context_item); - - if (appended_item) - _context_menu_listdata.push_back(*context_item); - } - } - - ContextMenuPopupListResize(); - - evas_object_show(list_); - elm_object_content_set(popup_, list_); - evas_object_event_callback_add(popup_, EVAS_CALLBACK_RESIZE, - ContextMenuPopupResize, this); - } - - if (_context_menu_listdata.empty()) { - DeletePopup(); - return false; - } - return true; -} - -void ContextMenuControllerEfl::ContextMenuHWBackKey(void* data, Evas_Object* obj, - void* event_info) { - auto menu_controller = static_cast(data); - if (menu_controller) { - auto selection_controller = - menu_controller->webview_->GetSelectionController(); - - if (selection_controller) - selection_controller->ToggleCaretAfterSelection(); - - menu_controller->HideContextMenu(); - evas_object_data_del(obj, "ContextEfl"); - } -} - -// static -Eina_Bool ContextMenuControllerEfl::RestoreTimerCallback(void* data) { - auto* menu_controller = static_cast(data); - if (!menu_controller) - return ECORE_CALLBACK_CANCEL; - - auto selection_controller = - menu_controller->webview_->GetSelectionController(); - - if (menu_controller->popup_ && selection_controller && - selection_controller->GetSelectionStatus() && - !selection_controller->IsCaretMode()) { - evas_object_show(menu_controller->popup_); - } - - menu_controller->restore_timer_ = nullptr; - - return ECORE_CALLBACK_CANCEL; -} - -void ContextMenuControllerEfl::ContextMenuCancelCallback(void* data, Evas_Object* obj, - void* event_info) { - ContextMenuControllerEfl* menu_controller = - static_cast( - evas_object_data_get(obj, "ContextMenuContollerEfl")); - if (!menu_controller) - return; - - RenderWidgetHostViewAura* rwhva = static_cast( - menu_controller->web_contents_.GetRenderWidgetHostView()); - if (!rwhva) - return; - - // context_menu is dismissed when we touch outside of popup. - // It is policy of elm_ctxpopup by EFL team. - // But according to wcs TC(21~23) context_menu should be displayed, - // when touchevent is consumed. So we should show context_menu again when - // touchevent is consumed. - if (rwhva->offscreen_helper()->IsTouchstartConsumed() || - rwhva->offscreen_helper()->IsTouchendConsumed()) { - evas_object_show(menu_controller->popup_); - return; - } - - // TODO: If |elm_ctxpopup_auto_hide_disabled_set| is works properly, - // We should remove this timer. - // Bug: http://suprem.sec.samsung.net/jira/browse/TNEXT-67 - menu_controller->restore_timer_ = - ecore_timer_add(kRestoreTime, RestoreTimerCallback, menu_controller); -} - -void ContextMenuControllerEfl::ContextMenuItemSelectedCallback(void* data, - Evas_Object* obj, void* event_info) { - Evas_Object* pop_up = obj; - ContextMenuControllerEfl* menu_controller = - static_cast - (evas_object_data_get(pop_up, "ContextMenuContollerEfl")); - - if (menu_controller) { - ContextMenuItemEfl* selected_menu_item = static_cast(data); - if (selected_menu_item) - menu_controller->MenuItemSelected(selected_menu_item); - } -} - -void ContextMenuControllerEfl::RequestSelectionRect() const { - auto rwhva = static_cast( - web_contents_.GetRenderWidgetHostView()); - CHECK(rwhva); - rwhva->host()->RequestSelectionRect(); -} - -gfx::Point ContextMenuControllerEfl::CalculateSelectionMenuPosition( - const gfx::Rect& selection_rect) { - auto* selection_controller = webview_->GetSelectionController(); - if (!selection_controller) - return gfx::Point(); - - auto visible_viewport_rect = selection_controller->GetVisibleViewportRect(); - auto forbidden_rect = - selection_controller->GetForbiddenRegionRect(selection_rect); - gfx::Point position; - // Selection menu should always be placed at the centre of visible selection - // area horizontally. - position.set_x(forbidden_rect.CenterPoint().x()); - - if (forbidden_rect.y() > visible_viewport_rect.y() + kMenuHeight) { - // If possible, selection menu should always be placed above forbidden - // region. - position.set_y(forbidden_rect.y()); - } else if (forbidden_rect.bottom() + kMenuHeight < - visible_viewport_rect.bottom()) { - // If there is no sufficient space above, we're trying to place selection - // menu below forbidden region. - position.set_y(forbidden_rect.bottom() + kMenuHeight); - } else { - // If there is no sufficient space above and below, selection menu will be - // shown at the centre of visible selection area vertically. - position.set_y(forbidden_rect.CenterPoint().y()); - } - - return position; -} - -void ContextMenuControllerEfl::OnSelectionRectReceived( - gfx::Rect selection_rect) { - auto rwhva = static_cast( - web_contents_.GetRenderWidgetHostView()); - auto controller = webview_->GetSelectionController(); - - if (IsMobileProfile() && (context_menu_status_ != INPROGRESS)) - return; - if (!popup_ || !rwhva || !controller) - return; - - float device_scale = - display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(); - gfx::Rect selection_rect_dip = gfx::ToEnclosingRect( - ConvertRectToPixels(gfx::Rect(selection_rect), device_scale)); - - // Consider a webview offset. - selection_rect_dip.Offset( - rwhva->offscreen_helper()->GetViewBoundsInPix().OffsetFromOrigin()); - - auto visible_viewport_rect = controller->GetVisibleViewportRect(); - - // In case of the caret mode selection_rect is empty - if (!webview_->GetSelectionController()->IsCaretMode() && - gfx::IntersectRects(visible_viewport_rect, selection_rect_dip) - .IsEmpty()) { - return; - } - - gfx::Point selection_menu_position = - CalculateSelectionMenuPosition(selection_rect_dip); - if (!visible_viewport_rect.Contains(selection_menu_position)) - return; - - evas_object_smart_callback_add(popup_, "dismissed", ContextMenuCancelCallback, - this); - - if (IsMobileProfile()) - elm_ctxpopup_auto_hide_disabled_set(popup_, EINA_TRUE); - -#if BUILDFLAG(IS_TIZEN) - eext_object_event_callback_add(popup_, EEXT_CALLBACK_BACK, - ContextMenuHWBackKey, this); -#endif - evas_object_move(popup_, selection_menu_position.x(), - selection_menu_position.y()); - - controller->ContextMenuStatusVisible(); - - evas_object_show(popup_); - evas_object_raise(popup_); - if (IsMobileProfile()) - context_menu_status_ = VISIBLE; -} - -bool ContextMenuControllerEfl::ShowContextMenu() { - if (!popup_) - return false; - - if (IsMobileProfile()) - context_menu_status_ = INPROGRESS; - - if (is_text_selection_) { - // Selection menu will be shown in OnSelectionRectReceived after receiving - // selection rectangle form the renderer. - RequestSelectionRect(); - } else { - evas_object_smart_callback_add(popup_, "block,clicked", - BlockClickedCallback, this); - -#if BUILDFLAG(IS_TIZEN) - eext_object_event_callback_add(popup_, EEXT_CALLBACK_BACK, ContextMenuHWBackKey, this); - eext_object_event_callback_add(popup_, EEXT_CALLBACK_MORE, - ContextMenuHWBackKey, this); -#endif - evas_object_show(popup_); - evas_object_raise(popup_); - if (IsMobileProfile()) - context_menu_status_ = VISIBLE; - } - return true; -} - -void ContextMenuControllerEfl::HideSelectionHandle() { - SelectionControllerEfl* controller = webview_->GetSelectionController(); - if (controller) - controller->HideHandles(); -} - -void ContextMenuControllerEfl::ClearSelection() { - auto controller = webview_->GetSelectionController(); - if (controller) - controller->ClearSelection(); -} - -void ContextMenuControllerEfl::RequestShowSelectionHandleAndContextMenu( - bool trigger_selection_change) { - SelectionControllerEfl* controller = webview_->GetSelectionController(); - if (controller) { - controller->SetSelectionStatus(true); - controller->SetWaitsForRendererSelectionChanges( - SelectionControllerEfl::Reason::RequestedByContextMenu); - if (trigger_selection_change) - controller->TriggerOnSelectionChange(); - } -} - void ContextMenuControllerEfl::OnClipboardDownload( download::DownloadItem* item, download::DownloadInterruptReason interrupt_reason) { @@ -813,10 +408,6 @@ void ContextMenuControllerEfl::OpenURL( } #if BUILDFLAG(IS_TIZEN) -static void destroy_app_handle(app_control_h* handle) { - std::ignore = app_control_destroy(*handle); -} - void ContextMenuControllerEfl::LaunchBrowserWithWebSearch( const std::string& text) { app_control_h app_control; @@ -834,86 +425,8 @@ void ContextMenuControllerEfl::LaunchBrowserWithWebSearch( app_control_destroy(app_control); } - -void ContextMenuControllerEfl::LaunchShareApp(const std::string& text) { - app_control_h handle = nullptr; - int error_code = app_control_create(&handle); - if (error_code < 0 || !handle) { - LOG(ERROR) << __PRETTY_FUNCTION__ - << " : Failed to create share service. Error code: " - << error_code; - return; - } - - std::unique_ptr handle_ptr( - &handle, destroy_app_handle); - - error_code = - app_control_set_operation(handle, APP_CONTROL_OPERATION_SHARE_TEXT); - if (error_code < 0) { - LOG(ERROR) << __PRETTY_FUNCTION__ - << ": Failed to set share text operation. Error code: " - << error_code; - return; - } - - error_code = - app_control_add_extra_data(handle, APP_CONTROL_DATA_TEXT, text.c_str()); - if (error_code < 0) { - LOG(ERROR) << __PRETTY_FUNCTION__ - << ": Failed to add data for share application. Error code: " - << error_code; - return; - } - - error_code = app_control_send_launch_request(handle, nullptr, nullptr); - if (error_code < 0) { - LOG(ERROR) << __PRETTY_FUNCTION__ - << ": Failed to send launch request for share application. " - << "Error code: " << error_code; - return; - } -} #endif -void ContextMenuControllerEfl::ContextMenuPopupResize(void* data, - Evas* e, - Evas_Object* obj, - void* event_info) { - auto thiz = static_cast(data); - if (thiz) - thiz->ContextMenuPopupListResize(); -} - -void ContextMenuControllerEfl::BlockClickedCallback(void* data, Evas_Object*, void*) -{ - ContextMenuControllerEfl* menu_controller = static_cast(data); - - if (!menu_controller) - return; - - menu_controller->HideContextMenu(); -} - -void ContextMenuControllerEfl::ContextMenuPopupListResize() { - if (!IsMobileProfile()) - return; - - int orientation = webview_->GetOrientation(); - if ((orientation == 90 || orientation == 270) && - _context_menu_listdata.size() > 3) { - evas_object_size_hint_min_set(list_, 0, kMinHeightHorizontal); - } else if ((orientation == 0 || orientation == 180) && - _context_menu_listdata.size() > 7) { - evas_object_size_hint_min_set(list_, 0, kMinHeightVertical); - } else { - evas_object_size_hint_min_set( - list_, 0, _context_menu_listdata.size() * _popup_item_height); - } - - evas_object_show(list_); -} - void ContextMenuControllerEfl::CustomMenuItemSelected(ContextMenuItemEfl* menu_item) { _Ewk_Context_Menu_Item item(new ContextMenuItemEfl(menu_item->GetContextMenuOptionType(), menu_item->GetContextMenuOption(), @@ -926,10 +439,7 @@ void ContextMenuControllerEfl::CustomMenuItemSelected(ContextMenuItemEfl* menu_i void ContextMenuControllerEfl::MenuItemSelected(ContextMenuItemEfl* menu_item) { - if (!menu_item) - return; - - if (!webview_) + if (!menu_item || !webview_) return; HideContextMenu(); @@ -1135,41 +645,6 @@ void ContextMenuControllerEfl::MenuItemSelected(ContextMenuItemEfl* menu_item) } } -void ContextMenuControllerEfl::HideContextMenu() { - if (IsMobileProfile() && - (context_menu_status_ == HIDDEN || context_menu_status_ == NONE)) - return; - - if (is_text_selection_) { - SelectionControllerEfl* controller = webview_->GetSelectionController(); - if (controller) - controller->ContextMenuStatusHidden(); - } - - if (popup_) { - evas_object_event_callback_del(popup_, EVAS_CALLBACK_RESIZE, - ContextMenuPopupResize); - evas_object_del(popup_); - popup_ = nullptr; - } - - if (restore_timer_) { - ecore_timer_del(restore_timer_); - restore_timer_ = nullptr; - } - - if (IsMobileProfile()) { - context_menu_status_ = HIDDEN; - } else if (menu_items_) { - void* data; - EINA_LIST_FREE(menu_items_, data) { - _Ewk_Context_Menu_Item* item = static_cast<_Ewk_Context_Menu_Item*>(data); - delete item; - } - menu_items_ = nullptr; - } -} - void ContextMenuControllerEfl::Resize(const gfx::Rect& webview_rect) { if (save_fail_dialog_) save_fail_dialog_->SetPopupSize(webview_rect.width(), @@ -1178,47 +653,6 @@ void ContextMenuControllerEfl::Resize(const gfx::Rect& webview_rect) { file_saved_dialog_->SetPopupSize(webview_rect.width(), webview_rect.height()); - if (!popup_) - return; - - if (IsMobileProfile() && context_menu_status_ != VISIBLE) - return; - - if (is_text_selection_) { - RequestSelectionRect(); - } else { - evas_object_resize(popup_, webview_rect.width(), webview_rect.height()); - } -} - -void ContextMenuControllerEfl::DeletePopup() { - if (top_widget_) - evas_object_data_set(top_widget_, "ContextMenuContollerEfl", 0); - - if (is_text_selection_) { - SelectionControllerEfl* controller = webview_->GetSelectionController(); - if (controller) - controller->ContextMenuStatusHidden(); - } - - if (popup_) { - evas_object_data_set(popup_, "ContextMenuContollerEfl", 0); - if (!IsMobileProfile()) - evas_object_smart_member_del(popup_); - evas_object_del(popup_); - popup_ = nullptr; - list_ = nullptr; - } - - if (menu_items_) { - void* data; - EINA_LIST_FREE(menu_items_, data) { - _Ewk_Context_Menu_Item *item = static_cast<_Ewk_Context_Menu_Item*> (data); - delete item; - } - menu_items_ = nullptr; - } - if (IsMobileProfile()) - context_menu_status_ = NONE; + ContextMenuControllerBase::Resize(webview_rect); } } diff --git a/tizen_src/ewk/efl_integration/context_menu_controller_efl.h b/tizen_src/ewk/efl_integration/context_menu_controller_efl.h index 1c898d2..cab9536 100644 --- a/tizen_src/ewk/efl_integration/context_menu_controller_efl.h +++ b/tizen_src/ewk/efl_integration/context_menu_controller_efl.h @@ -2,111 +2,50 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef context_menu_controller_h -#define context_menu_controller_h +#ifndef context_menu_controller_efl_h +#define context_menu_controller_efl_h + +#include "content/browser/context_menu/context_menu_controller_base.h" -#include #include #include "base/memory/weak_ptr.h" #include "browser/javascript_modal_dialog_efl.h" #include "components/download/public/common/download_item.h" #include "components/download/public/common/download_url_parameters.h" -#include "content/public/browser/context_menu_params.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/web_contents.h" -#include "public/ewk_context_menu_internal.h" +#include "ui/base/window_open_disposition.h" class EWebView; -namespace gfx { -class Rect; -} - namespace content { -class ContextMenuItemEfl { +class ContextMenuControllerEfl : public ContextMenuControllerBase, + public download::DownloadItem::Observer { public: - ContextMenuItemEfl(Ewk_Context_Menu_Item_Type item, - Ewk_Context_Menu_Item_Tag option, - const std::string& title, - const std::string& image_url = std::string(), - const std::string& link_url = std::string(), - const std::string& icon_path = std::string()) - : menu_type_(item) - , menu_option_(option) - , title_(title) - , is_enabled_(true) - , image_url_(image_url) - , link_url_(link_url) - , icon_path_(icon_path) { - } - - ~ContextMenuItemEfl() { } - - const std::string& Title() const { return title_; } - void SetTitle(const std::string& title) { title_ = title; } - - bool IsEnabled() const { return is_enabled_; } - void SetEnabled(bool status) { is_enabled_ = status; } - Ewk_Context_Menu_Item_Tag GetContextMenuOption() const { return menu_option_; } - Ewk_Context_Menu_Item_Type GetContextMenuOptionType() const { return menu_type_; } - const std::string& LinkURL() const { return link_url_; } - const std::string& ImageURL() const { return image_url_; } - const std::string& IconPath() const { return icon_path_; } - - private: - Ewk_Context_Menu_Item_Type menu_type_; - Ewk_Context_Menu_Item_Tag menu_option_; - std::string title_; - bool is_enabled_; - std::string image_url_; - std::string link_url_; - std::string icon_path_; -}; - -class ContextMenuControllerEfl : public download::DownloadItem::Observer { - public: - static void ContextMenuCancelCallback(void* data, Evas_Object* obj, void* event_info); - static void ContextMenuItemSelectedCallback(void* data, Evas_Object* obj, void* event_info); - static void ContextMenuHWBackKey(void* data, Evas_Object* obj, void* event_info); - ContextMenuControllerEfl(EWebView* wv, WebContents& web_contents); ~ContextMenuControllerEfl(); + ContextMenuControllerEfl(const ContextMenuControllerEfl&) = delete; + ContextMenuControllerEfl& operator=(const ContextMenuControllerEfl&) = delete; + bool PopulateAndShowContextMenu(const ContextMenuParams& params); - void Move(int x, int y); - void MenuItemSelected(ContextMenuItemEfl* menu_item); - void HideContextMenu(); + void MenuItemSelected(ContextMenuItemEfl* menu_item) override; gfx::Point GetContextMenuShowPos() const { return context_menu_show_pos_; }; - void Resize(const gfx::Rect& webview_rect); - - void RequestSelectionRect() const; - void OnSelectionRectReceived(gfx::Rect selection_rect); - gfx::Point CalculateSelectionMenuPosition(const gfx::Rect& selection_rect); + void Resize(const gfx::Rect& webview_rect) override; private: - static void ContextMenuPopupResize(void* data, - Evas* e, - Evas_Object* obj, - void* event_info); - enum ContextMenuStatusTag { NONE = 0, HIDDEN, INPROGRESS, VISIBLE }; - static void BlockClickedCallback(void*, Evas_Object*, void*); - void ContextMenuPopupListResize(); + // ContextMenuControllerBase + Evas_Object* evas_object() override; + const char* GetSelectedText() override; + void CustomMenuItemSelected(ContextMenuItemEfl*); void GetProposedContextMenu(); - bool CreateContextMenu(const ContextMenuParams& params); - bool ShowContextMenu(); void AddItemToProposedList(Ewk_Context_Menu_Item_Type item, Ewk_Context_Menu_Item_Tag option, const std::string& title, const std::string& image_url = std::string(), const std::string& link_url = std::string(), const std::string& icon_path = std::string()); - void HideSelectionHandle(); - void ClearSelection(); - void RequestShowSelectionHandleAndContextMenu( - bool trigger_selection_change = false); virtual void OnDownloadUpdated(download::DownloadItem* download) override; void OnClipboardDownload(download::DownloadItem* item, download::DownloadInterruptReason interrupt_reason); @@ -121,34 +60,17 @@ class ContextMenuControllerEfl : public download::DownloadItem::Observer { void OpenURL(const GURL url, const WindowOpenDisposition disposition); #if BUILDFLAG(IS_TIZEN) void LaunchBrowserWithWebSearch(const std::string& text); - void LaunchShareApp(const std::string& text); #endif - void DeletePopup(); - - static Eina_Bool RestoreTimerCallback(void* data); - static std::vector _context_menu_listdata; - static int _popup_item_height; - static bool _context_menu_resized; EWebView* webview_; - Evas_Object* native_view_; - Evas_Object* top_widget_ = nullptr; - Evas_Object* popup_ = nullptr; - Evas_Object* list_ = nullptr; - Eina_List* menu_items_ = nullptr; - ContextMenuParams params_; - WebContents& web_contents_; gfx::Point context_menu_show_pos_; - bool is_text_selection_ = false; std::set clipboard_download_items_; std::set disk_download_items_; std::unique_ptr file_saved_dialog_; std::unique_ptr save_fail_dialog_; - Ecore_Timer* restore_timer_ = nullptr; - ContextMenuStatusTag context_menu_status_ = NONE; base::WeakPtrFactory weak_ptr_factory_; }; } // namespace -#endif // context_menu_controller_h +#endif // context_menu_controller_efl_h diff --git a/tizen_src/ewk/efl_integration/private/ewk_context_menu_item_private.h b/tizen_src/ewk/efl_integration/private/ewk_context_menu_item_private.h new file mode 100644 index 0000000..f2f548a --- /dev/null +++ b/tizen_src/ewk/efl_integration/private/ewk_context_menu_item_private.h @@ -0,0 +1,28 @@ +// Copyright 2022 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef ewk_context_menu_item_private_h +#define ewk_context_menu_item_private_h + +namespace content { +class ContextMenuItemEfl; +} + +class _Ewk_Context_Menu_Item { + public: + _Ewk_Context_Menu_Item(content::ContextMenuItemEfl* menu_item) + : menu_item_(menu_item) {} + + ~_Ewk_Context_Menu_Item() { delete menu_item_; } + + _Ewk_Context_Menu_Item(const _Ewk_Context_Menu_Item&) = delete; + _Ewk_Context_Menu_Item& operator=(const _Ewk_Context_Menu_Item&) = delete; + + content::ContextMenuItemEfl* GetMenuItem() const { return menu_item_; } + + private: + content::ContextMenuItemEfl* menu_item_; +}; + +#endif // ewk_context_menu_private_h diff --git a/tizen_src/ewk/efl_integration/private/ewk_context_menu_private.h b/tizen_src/ewk/efl_integration/private/ewk_context_menu_private.h index ed5778b3..216b29d 100644 --- a/tizen_src/ewk/efl_integration/private/ewk_context_menu_private.h +++ b/tizen_src/ewk/efl_integration/private/ewk_context_menu_private.h @@ -9,24 +9,7 @@ #include #include "context_menu_controller_efl.h" - -class _Ewk_Context_Menu_Item { - public: - _Ewk_Context_Menu_Item(content::ContextMenuItemEfl* menu_item) - : menu_item_(menu_item) { - } - - ~_Ewk_Context_Menu_Item() { - delete menu_item_; - } - - content::ContextMenuItemEfl* GetMenuItem() const { - return menu_item_; - } - private: - content::ContextMenuItemEfl* menu_item_; -}; - +#include "ewk_context_menu_item_private.h" // Wrapper for context_menu_controller items class _Ewk_Context_Menu { -- 2.7.4 From 6a4bf28a017ac772f74ce626c32b8b40cf2121f7 Mon Sep 17 00:00:00 2001 From: jiangyuwei Date: Tue, 7 Mar 2023 17:02:13 +0800 Subject: [PATCH 04/16] [M108 Migration][VD] Implement Multi port RWI RWI server can use easily to debug application. Multi port RWI can let 3 applications debug at the same time. Normal RWI server should start when WebContents init. For RELEASE_MODE shuold use ewk_view_inspector_server_start to start RWI server. Reference: - https://review.tizen.org/gerrit/279379/ - https://review.tizen.org/gerrit/281862/ Change-Id: I9dd2be6d0d59c390bb271d004e67b9add29df546 Signed-off-by: jiangyuwei --- content/browser/BUILD.gn | 1 + content/browser/devtools/devtools_http_handler.cc | 45 ++- content/browser/devtools/devtools_http_handler.h | 8 + .../browser/devtools/devtools_video_consumer.cc | 9 +- content/browser/web_contents/web_contents_impl.cc | 5 + .../public/browser/devtools_manager_delegate.cc | 5 + content/public/browser/devtools_manager_delegate.h | 6 +- content/public/browser/javascript_dialog_manager.h | 4 + .../chromium_impl/content/browser/browser_efl.gni | 2 + .../browser/inspector/devtools_util_manager.cc | 172 ++++++++++++ .../browser/inspector/devtools_util_manager.h | 40 +++ tizen_src/ewk/efl_integration/BUILD.gn | 6 + .../browser/javascript_dialog_manager_efl.cc | 9 + .../browser/javascript_dialog_manager_efl.h | 3 + .../ewk/efl_integration/browser_main_parts_efl.cc | 4 +- .../efl_integration/common/content_client_efl.cc | 2 +- .../efl_integration/content_browser_client_efl.cc | 8 +- .../efl_integration/content_browser_client_efl.h | 2 + .../efl_integration/content_main_delegate_efl.cc | 40 ++- .../efl_integration/content_main_delegate_efl.h | 15 +- .../ewk/efl_integration/devtools_delegate_efl.cc | 113 ++------ .../ewk/efl_integration/devtools_delegate_efl.h | 21 +- .../ewk/efl_integration/devtools_port_manager.cc | 304 +++++++++++++++++++++ .../ewk/efl_integration/devtools_port_manager.h | 62 +++++ tizen_src/ewk/efl_integration/devtools_port_msg.cc | 67 +++++ tizen_src/ewk/efl_integration/devtools_port_msg.h | 14 + .../efl_integration/devtools_port_shared_memory.cc | 137 ++++++++++ .../efl_integration/devtools_port_shared_memory.h | 64 +++++ tizen_src/ewk/efl_integration/eweb_context.cc | 40 ++- tizen_src/ewk/efl_integration/eweb_context.h | 5 + tizen_src/ewk/efl_integration/eweb_view.cc | 69 +++++ tizen_src/ewk/efl_integration/eweb_view.h | 20 ++ .../efl_integration/web_contents_delegate_efl.cc | 42 +++ .../efl_integration/web_contents_delegate_efl.h | 1 + .../efl_integration/web_contents_observer_efl.cc | 14 +- wrt/src/browser/api/tv/wrt_api_tv_extension.cc | 11 +- wrt/src/browser/api/wrt_api_web_runtime.cc | 7 +- wrt/src/browser/wrt_devtools_manager_delegate.cc | 4 +- wrt/src/browser/wrt_devtools_manager_delegate.h | 2 +- 39 files changed, 1236 insertions(+), 147 deletions(-) create mode 100644 tizen_src/chromium_impl/content/browser/inspector/devtools_util_manager.cc create mode 100644 tizen_src/chromium_impl/content/browser/inspector/devtools_util_manager.h create mode 100644 tizen_src/ewk/efl_integration/devtools_port_manager.cc create mode 100644 tizen_src/ewk/efl_integration/devtools_port_manager.h create mode 100644 tizen_src/ewk/efl_integration/devtools_port_msg.cc create mode 100644 tizen_src/ewk/efl_integration/devtools_port_msg.h create mode 100644 tizen_src/ewk/efl_integration/devtools_port_shared_memory.cc create mode 100644 tizen_src/ewk/efl_integration/devtools_port_shared_memory.h diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index cb36b60..d3c3c0c 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn @@ -59,6 +59,7 @@ source_set("browser") { frameworks = [] ldflags = [] + include_dirs = [ "//tizen_src/ewk/efl_integration/" ] if (use_efl) { configs += external_content_browser_efl_configs } diff --git a/content/browser/devtools/devtools_http_handler.cc b/content/browser/devtools/devtools_http_handler.cc index 286e99d..cb0697e 100644 --- a/content/browser/devtools/devtools_http_handler.cc +++ b/content/browser/devtools/devtools_http_handler.cc @@ -143,6 +143,10 @@ class ServerWrapper : net::HttpServer::Delegate { void Send500(int connection_id, const std::string& message); void Close(int connection_id); +#if BUILDFLAG(IS_TIZEN_TV) + base::WeakPtr GetHttpHandle() { return handler_; } +#endif + ~ServerWrapper() override {} private: @@ -220,10 +224,25 @@ void TerminateOnUI(std::unique_ptr thread, std::unique_ptr server_wrapper, std::unique_ptr socket_factory) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (server_wrapper) +#if BUILDFLAG(IS_TIZEN_TV) + base::WeakPtr handler; +#endif + if (server_wrapper) { +#if BUILDFLAG(IS_TIZEN_TV) + handler = server_wrapper->GetHttpHandle(); +#endif thread->task_runner()->DeleteSoon(FROM_HERE, std::move(server_wrapper)); - if (socket_factory) + } + if (socket_factory) { thread->task_runner()->DeleteSoon(FROM_HERE, std::move(socket_factory)); +#if BUILDFLAG(IS_TIZEN_TV) + if (handler) { + thread->task_runner()->PostTask( + FROM_HERE, + base::BindOnce(&DevToolsHttpHandler::ReleasePort, handler)); + } +#endif + } if (thread) { base::ThreadPool::PostTask( FROM_HERE, @@ -438,7 +457,15 @@ void ServerWrapper::OnHttpRequest(int connection_id, } server_->SetSendBufferSize(connection_id, kSendBufferSizeForDevTools); - +#if BUILDFLAG(IS_TIZEN_TV) + if (info.path.find("/closeport") == 0) { + // close first listened port + GetUIThreadTaskRunner({})->PostTask( + FROM_HERE, base::BindOnce(&DevToolsHttpHandler::OnTerminateSocket, + handler_, connection_id)); + return; + } +#endif if (base::StartsWith(info.path, "/json", base::CompareCase::SENSITIVE)) { GetUIThreadTaskRunner({})->PostTask( FROM_HERE, base::BindOnce(&DevToolsHttpHandler::OnJsonRequest, handler_, @@ -547,6 +574,18 @@ static bool ParseJsonPath( return true; } +#if BUILDFLAG(IS_TIZEN_TV) +void DevToolsHttpHandler::OnTerminateSocket(int connection_id) { + server_wrapper_->Send200(connection_id, "OK", "text/html"); + TerminateOnUI(std::move(thread_), std::move(server_wrapper_), + std::move(socket_factory_)); +} + +void DevToolsHttpHandler::ReleasePort() { + delegate_->ReleasePort(); +} +#endif + // These values are persisted to logs. Entries should not be renumbered and // numeric values should never be reused. enum class DevToolsMutatingHttpActionVerb { diff --git a/content/browser/devtools/devtools_http_handler.h b/content/browser/devtools/devtools_http_handler.h index 04a4905..cd8710e 100644 --- a/content/browser/devtools/devtools_http_handler.h +++ b/content/browser/devtools/devtools_http_handler.h @@ -56,6 +56,10 @@ class DevToolsHttpHandler { ~DevToolsHttpHandler(); +#if BUILDFLAG(IS_TIZEN_TV) + void ReleasePort(); +#endif + private: friend class ServerWrapper; friend void ServerStartedOnUI( @@ -65,6 +69,10 @@ class DevToolsHttpHandler { DevToolsSocketFactory* socket_factory, std::unique_ptr ip_address); +#if BUILDFLAG(IS_TIZEN_TV) + void OnTerminateSocket(int connection_id); +#endif + void OnJsonRequest(int connection_id, const net::HttpServerRequestInfo& info); void RespondToJsonList(int connection_id, diff --git a/content/browser/devtools/devtools_video_consumer.cc b/content/browser/devtools/devtools_video_consumer.cc index a803636..835d7b7 100644 --- a/content/browser/devtools/devtools_video_consumer.cc +++ b/content/browser/devtools/devtools_video_consumer.cc @@ -11,6 +11,7 @@ #include "cc/paint/skia_paint_canvas.h" #include "components/viz/common/surfaces/subtree_capture_id.h" #include "components/viz/host/host_frame_sink_manager.h" +#include "components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h" #include "content/browser/compositor/surface_utils.h" #include "media/base/limits.h" #include "media/capture/mojom/video_capture_buffer.mojom.h" @@ -35,7 +36,10 @@ constexpr media::VideoPixelFormat kDefaultPixelFormat = // Creates a ClientFrameSinkVideoCapturer via HostFrameSinkManager. std::unique_ptr CreateCapturer() { - return GetHostFrameSinkManager()->CreateVideoCapturer(); + if (GetHostFrameSinkManager()) + return GetHostFrameSinkManager()->CreateVideoCapturer(); + else + return nullptr; } } // namespace @@ -115,7 +119,8 @@ void DevToolsVideoConsumer::SetFormat(media::VideoPixelFormat format) { void DevToolsVideoConsumer::InnerStartCapture( std::unique_ptr capturer) { capturer_ = std::move(capturer); - + if (!capturer_) + return; // Give |capturer_| the capture parameters. capturer_->SetMinCapturePeriod(min_capture_period_); capturer_->SetMinSizeChangePeriod(kDefaultMinPeriod); diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index b8dbef7..5a50360 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc @@ -8438,6 +8438,11 @@ void WebContentsImpl::OnDialogClosed(int render_process_id, for (auto* handler : page_handlers) handler->DidCloseJavaScriptDialog(success, user_input); +#if BUILDFLAG(IS_TIZEN_TV) + if (dialog_manager_) + dialog_manager_->OnDialogClosed(this); +#endif + is_showing_javascript_dialog_ = false; is_showing_before_unload_dialog_ = false; } diff --git a/content/public/browser/devtools_manager_delegate.cc b/content/public/browser/devtools_manager_delegate.cc index 70900b1..30d31f5 100644 --- a/content/public/browser/devtools_manager_delegate.cc +++ b/content/public/browser/devtools_manager_delegate.cc @@ -70,6 +70,11 @@ std::string DevToolsManagerDelegate::GetDiscoveryPageHTML() { return std::string(); } +std::string DevToolsManagerDelegate::GetFrontendResource( + const std::string& path) { + return std::string(); +} + bool DevToolsManagerDelegate::HasBundledFrontendResources() { return false; } diff --git a/content/public/browser/devtools_manager_delegate.h b/content/public/browser/devtools_manager_delegate.h index cdd9888..facfa79 100644 --- a/content/public/browser/devtools_manager_delegate.h +++ b/content/public/browser/devtools_manager_delegate.h @@ -75,7 +75,7 @@ class CONTENT_EXPORT DevToolsManagerDelegate { // Should return discovery page HTML that should list available tabs // and provide attach links. virtual std::string GetDiscoveryPageHTML(); - + virtual std::string GetFrontendResource(const std::string& path); // Returns whether frontend resources are bundled within the binary. virtual bool HasBundledFrontendResources(); @@ -89,6 +89,10 @@ class CONTENT_EXPORT DevToolsManagerDelegate { virtual bool IsBrowserTargetDiscoverable(); virtual ~DevToolsManagerDelegate(); + +#if BUILDFLAG(IS_TIZEN_TV) + virtual void ReleasePort() {} +#endif }; } // namespace content diff --git a/content/public/browser/javascript_dialog_manager.h b/content/public/browser/javascript_dialog_manager.h index bb0abaf..7449c64 100644 --- a/content/public/browser/javascript_dialog_manager.h +++ b/content/public/browser/javascript_dialog_manager.h @@ -55,6 +55,10 @@ class CONTENT_EXPORT JavaScriptDialogManager { virtual void CancelDialogs(WebContents* web_contents, bool reset_state) = 0; +#if BUILDFLAG(IS_TIZEN_TV) + virtual void OnDialogClosed(WebContents* web_contents) {} +#endif + virtual ~JavaScriptDialogManager() {} }; diff --git a/tizen_src/chromium_impl/content/browser/browser_efl.gni b/tizen_src/chromium_impl/content/browser/browser_efl.gni index 03a1545..158df51 100644 --- a/tizen_src/chromium_impl/content/browser/browser_efl.gni +++ b/tizen_src/chromium_impl/content/browser/browser_efl.gni @@ -118,6 +118,8 @@ external_content_browser_efl_sources = [ "//tizen_src/chromium_impl/content/browser/web_contents/web_drag_dest_efl.h", "//tizen_src/chromium_impl/content/browser/web_contents/web_drag_source_efl.cc", "//tizen_src/chromium_impl/content/browser/web_contents/web_drag_source_efl.h", + "//tizen_src/chromium_impl/content/browser/inspector/devtools_util_manager.cc", + "//tizen_src/chromium_impl/content/browser/inspector/devtools_util_manager.h", ] external_content_browser_efl_sources += [ diff --git a/tizen_src/chromium_impl/content/browser/inspector/devtools_util_manager.cc b/tizen_src/chromium_impl/content/browser/inspector/devtools_util_manager.cc new file mode 100644 index 0000000..9211312 --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/inspector/devtools_util_manager.cc @@ -0,0 +1,172 @@ +// Copyright 2020 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "devtools_util_manager.h" + +#include "base/command_line.h" +#include "base/strings/string_number_conversions.h" +#include "content/public/browser/devtools_agent_host.h" +#include "content/public/browser/devtools_frontend_host.h" +#include "content/public/browser/devtools_socket_factory.h" +#include "content/public/common/content_switches.h" +#include "net/base/net_errors.h" +#include "net/socket/tcp_server_socket.h" +#include "third_party/zlib/google/compression_utils.h" + +#if BUILDFLAG(IS_TIZEN_TV) +#include "devtools_port_manager.h" +#endif + +using content::DevToolsAgentHost; + +namespace content { + +// Copy of internal class implementation from +// content/shell/browser/shell_devtools_delegate.cc + +const int kBackLog = 10; + +class TCPServerSocketFactory : public content::DevToolsSocketFactory { + public: + TCPServerSocketFactory(const std::string& address, uint16_t port) + : server_socket_(nullptr), address_(address), port_(port) {} + TCPServerSocketFactory(std::unique_ptr server_socket) + : server_socket_(server_socket.release()), port_(0) {} + + private: + std::unique_ptr CreateForHttpServer() override { + if (server_socket_) + return std::unique_ptr(server_socket_); + std::unique_ptr socket( + new net::TCPServerSocket(nullptr, net::NetLogSource())); + if (socket->ListenWithAddressAndPort(address_, port_, kBackLog) != net::OK) + return std::unique_ptr(); + + return socket; + } + + std::unique_ptr CreateForTethering( + std::string* out_name) override { + return nullptr; + } + + net::ServerSocket* server_socket_; + std::string address_; + uint16_t port_; +}; + +// static +uint16_t DevToolsUtilManager::port_ = 0; + +DevToolsUtilManager::DevToolsUtilManager() = default; +DevToolsUtilManager::~DevToolsUtilManager() = default; + +DevToolsUtilManager* DevToolsUtilManager::GetInstance() { + static DevToolsUtilManager instance; + return &instance; +} + +int DevToolsUtilManager::StartDebugServer(int port) { + if (port_ > 0) + return port_; + + // It's a hacky way to early detected if port is available. The problem is + // that the only thing we can do after checking is hope that noone will take + // the port until it's initialized on IO thread again. The best approach would + // be creating async callbacks that would inform when inspector server started + // and on which port. + static std::string addr = "0.0.0.0"; + std::unique_ptr sock( + new net::TCPServerSocket(nullptr, net::NetLogSource())); + + const base::CommandLine* const command_line = + base::CommandLine::ForCurrentProcess(); + // See if the user specified a port on the command line (useful for + // automation). If not, use an ephemeral port by specifying 0. + if (!port && command_line->HasSwitch(switches::kRemoteDebuggingPort)) { + int temp_port = 0; + std::string port_str = + command_line->GetSwitchValueASCII(switches::kRemoteDebuggingPort); + if (base::StringToInt(port_str, &temp_port) && temp_port >= 0 && + temp_port < 65535) { + port = temp_port; + } else { + LOG(WARNING) << "Invalid http debugger port number " << temp_port; + } + } + + // why backlog is 1? + if (sock->ListenWithAddressAndPort(addr, port, 1) != net::OK) { + port_ = 0; +#if BUILDFLAG(IS_TIZEN_TV) + ReleasePort(); +#endif + return port_; + } + + net::IPEndPoint givenIp; + sock->GetLocalAddress(&givenIp); + port_ = givenIp.port(); + LOG(INFO) << "Devtool port:" << port_; + + std::unique_ptr factory( + new TCPServerSocketFactory(std::move(sock))); + DevToolsAgentHost::StartRemoteDebuggingServer( + std::move(factory), base::FilePath(), base::FilePath()); + + return port_; +} + +bool DevToolsUtilManager::StopDebugServer() { + if (port_ == 0) + return false; + port_ = 0; + DevToolsAgentHost::StopRemoteDebuggingServer(); + return true; +} + +unsigned int DevToolsUtilManager::InspectorServerStart(int port) { + InspectorServerStop(); +#if BUILDFLAG(IS_TIZEN_TV) + devtools_http_handler::DevToolsPortManager* port_manager = + devtools_http_handler::DevToolsPortManager::GetInstance(); + if (!port && (port_manager && port_manager->ProcessCompare())) { + if (port_manager->GetValidPort(port)) + port_manager->SetPort(port); + } +#endif + return StartDebugServer(port); +} + +bool DevToolsUtilManager::InspectorServerStop() { + if (!StopDebugServer()) + return false; +#if BUILDFLAG(IS_TIZEN_TV) + ReleasePort(); +#endif + return true; +} + +std::string DevToolsUtilManager::GetFrontendResource(const std::string& path) { + const std::string data = + content::DevToolsFrontendHost::GetFrontendResource(path); + // Detect gzip resource with the gzip magic number(1f 8b) in header + if (data.length() > 2 && data[0] == '\x1F' && data[1] == '\x8B') { + std::string uncompressed_data; + + if (compression::GzipUncompress(data, &uncompressed_data)) + return uncompressed_data; + LOG(ERROR) << "Failed to uncompress " << path; + } + return data; +} + +#if BUILDFLAG(IS_TIZEN_TV) +void DevToolsUtilManager::ReleasePort() { + if (devtools_http_handler::DevToolsPortManager::GetInstance()) + devtools_http_handler::DevToolsPortManager::GetInstance()->ReleasePort(); +} +#endif + +} // namespace content diff --git a/tizen_src/chromium_impl/content/browser/inspector/devtools_util_manager.h b/tizen_src/chromium_impl/content/browser/inspector/devtools_util_manager.h new file mode 100644 index 0000000..77e9f52 --- /dev/null +++ b/tizen_src/chromium_impl/content/browser/inspector/devtools_util_manager.h @@ -0,0 +1,40 @@ +// Copyright 2020 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVTOOLS_UTIL_MANAGER_H_ +#define DEVTOOLS_UTIL_MANAGER_H_ + +#include +#include "build/buildflag.h" +#include "build/build_config.h" + +namespace content { + +class DevToolsUtilManager { + public: + DevToolsUtilManager(); + virtual ~DevToolsUtilManager(); + + static DevToolsUtilManager* GetInstance(); + + unsigned int InspectorServerStart(int port = 0); + bool InspectorServerStop(); + + std::string GetFrontendResource(const std::string& path); + +#if BUILDFLAG(IS_TIZEN_TV) + static uint16_t GetPort() { return port_; } + void ReleasePort(); +#endif + + private: + int StartDebugServer(int port); + bool StopDebugServer(); + + static uint16_t port_; +}; + +} // namespace content + +#endif // DEVTOOLS_UTIL_MANAGER_H_ diff --git a/tizen_src/ewk/efl_integration/BUILD.gn b/tizen_src/ewk/efl_integration/BUILD.gn index 33fac56..87210fc 100755 --- a/tizen_src/ewk/efl_integration/BUILD.gn +++ b/tizen_src/ewk/efl_integration/BUILD.gn @@ -650,6 +650,12 @@ shared_library("chromium-ewk") { "wrt/hbbtv_widget.h", "wrt/hbbtv_widget_host.cc", "wrt/hbbtv_widget_host.h", + "devtools_port_manager.cc", + "devtools_port_manager.h", + "devtools_port_msg.cc", + "devtools_port_msg.h", + "devtools_port_shared_memory.cc", + "devtools_port_shared_memory.h", ] } diff --git a/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.cc b/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.cc index 3a5b308..6b00fc3 100644 --- a/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.cc +++ b/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.cc @@ -112,6 +112,15 @@ void JavaScriptDialogManagerEfl::SetPopupSize(int width, int height) { dialog_->SetPopupSize(width, height); } +#if BUILDFLAG(IS_TIZEN_TV) +void JavaScriptDialogManagerEfl::OnDialogClosed( + content::WebContents* web_contents) { + EWebView* wv = WebViewFromWebContents(web_contents); + if (wv) + wv->OnDialogClosed(); +} +#endif + void JavaScriptDialogManagerEfl::RunBeforeUnloadDialog( content::WebContents* web_contents, content::RenderFrameHost* render_frame_host, diff --git a/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.h b/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.h index 9524650..b37f81e 100644 --- a/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.h +++ b/tizen_src/ewk/efl_integration/browser/javascript_dialog_manager_efl.h @@ -52,6 +52,9 @@ class JavaScriptDialogManagerEfl : public content::JavaScriptDialogManager { void* user_data); void ExecuteDialogClosedCallBack(bool result, const std::string prompt_data); void SetPopupSize(int width, int height); +#if BUILDFLAG(IS_TIZEN_TV) + void OnDialogClosed(content::WebContents* web_contents) override; +#endif void SetBeforeUnloadConfirmPanelCallback( Ewk_View_Before_Unload_Confirm_Panel_Callback callback, void* user_data); diff --git a/tizen_src/ewk/efl_integration/browser_main_parts_efl.cc b/tizen_src/ewk/efl_integration/browser_main_parts_efl.cc index a95d634..892d028 100644 --- a/tizen_src/ewk/efl_integration/browser_main_parts_efl.cc +++ b/tizen_src/ewk/efl_integration/browser_main_parts_efl.cc @@ -9,6 +9,7 @@ #include "base/base_switches.h" #include "base/command_line.h" +#include "content/browser/inspector/devtools_util_manager.h" #include "content/public/common/content_switches.h" #include "content/public/common/result_codes.h" @@ -32,8 +33,7 @@ int BrowserMainPartsEfl::PreMainMessageLoopRun() { } void BrowserMainPartsEfl::PostMainMessageLoopRun() { - if (devtools_delegate_) - devtools_delegate_->Stop(); + DevToolsUtilManager::GetInstance()->InspectorServerStop(); } } // namespace diff --git a/tizen_src/ewk/efl_integration/common/content_client_efl.cc b/tizen_src/ewk/efl_integration/common/content_client_efl.cc index ddf0186..7dd5a2d 100644 --- a/tizen_src/ewk/efl_integration/common/content_client_efl.cc +++ b/tizen_src/ewk/efl_integration/common/content_client_efl.cc @@ -5,8 +5,8 @@ #include "common/content_client_efl.h" #include "ipc/ipc_message.h" -#include "ui/base/resource/resource_bundle.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" std::u16string ContentClientEfl::GetLocalizedString(int message_id) { // TODO(boliu): Used only by WebKit, so only bundle those resources for diff --git a/tizen_src/ewk/efl_integration/content_browser_client_efl.cc b/tizen_src/ewk/efl_integration/content_browser_client_efl.cc index e40da0e..58b9c64 100644 --- a/tizen_src/ewk/efl_integration/content_browser_client_efl.cc +++ b/tizen_src/ewk/efl_integration/content_browser_client_efl.cc @@ -443,10 +443,12 @@ void ContentBrowserClientEfl::RenderProcessWillLaunch( host->AddFilter(new RenderMessageFilterEfl(host->GetID())); } -content::DevToolsManagerDelegate* -ContentBrowserClientEfl::GetDevToolsManagerDelegate() { - return new DevToolsManagerDelegateEfl(); +/* LCOV_EXCL_START */ +std::unique_ptr +ContentBrowserClientEfl::CreateDevToolsManagerDelegate() { + return std::make_unique(); } +/* LCOV_EXCL_STOP */ std::string ContentBrowserClientEfl::GetApplicationLocale() { char* local_default = setlocale(LC_CTYPE, 0); diff --git a/tizen_src/ewk/efl_integration/content_browser_client_efl.h b/tizen_src/ewk/efl_integration/content_browser_client_efl.h index d783485..5c480fc 100644 --- a/tizen_src/ewk/efl_integration/content_browser_client_efl.h +++ b/tizen_src/ewk/efl_integration/content_browser_client_efl.h @@ -110,6 +110,8 @@ class ContentBrowserClientEfl : public ContentBrowserClient { blink::web_pref::WebPreferences* prefs); void RenderProcessWillLaunch(RenderProcessHost* host) override; DevToolsManagerDelegate* GetDevToolsManagerDelegate(); + std::unique_ptr + CreateDevToolsManagerDelegate() override; std::string GetApplicationLocale() override; std::unique_ptr GetWebContentsViewDelegate( WebContents* web_contents) override; diff --git a/tizen_src/ewk/efl_integration/content_main_delegate_efl.cc b/tizen_src/ewk/efl_integration/content_main_delegate_efl.cc index 8ee2f48..d69d015 100644 --- a/tizen_src/ewk/efl_integration/content_main_delegate_efl.cc +++ b/tizen_src/ewk/efl_integration/content_main_delegate_efl.cc @@ -15,7 +15,10 @@ #include "content_browser_client_efl.h" #include "renderer/content_renderer_client_efl.h" #include "ui/base/resource/resource_bundle.h" - +#if BUILDFLAG(IS_TIZEN_TV) +#include "content/public/browser/render_process_host.h" +#include "devtools_port_manager.h" +#endif namespace content { namespace { @@ -65,6 +68,13 @@ void InitializeDiskCacheDir() { } } // namespace +ContentMainDelegateEfl::ContentMainDelegateEfl() { +#if BUILDFLAG(IS_TIZEN_TV) + enableInspector_ = false; +#endif +} + + void ContentMainDelegateEfl::PreSandboxStartupBrowser() { LocaleEfl::Initialize(); base::PathService::Override(base::FILE_EXE, base::FilePath(SubProcessPath())); @@ -118,4 +128,32 @@ ContentBrowserClient* ContentMainDelegateEfl::GetContentBrowserClient() const { return browser_client_.get(); } +#if BUILDFLAG(IS_TIZEN_TV) +void ContentMainDelegateEfl::ProcessExiting(const std::string& process_type) { + if (!enableInspector_) + return; + + if (process_type.empty() && + devtools_http_handler::DevToolsPortManager::GetInstance()) // browser + devtools_http_handler::DevToolsPortManager::GetInstance()->ReleasePort(); +} + +void ContentMainDelegateEfl::SetInspectorStatus(bool enable) { + enableInspector_ = enable; +} + +bool ContentMainDelegateEfl::GetInspectorStatus() { + return enableInspector_; +} + +ContentMainDelegateEfl::~ContentMainDelegateEfl() { + if (content::RenderProcessHost::run_renderer_in_process()) { + LOG(INFO) << "ContentMainDelegateEfl[" << (void*)this + << "]::~ContentMainDelegateEfl, set ContentClient to nullptr"; + content::SetContentClient(nullptr); + } +} +#endif + + } // namespace content diff --git a/tizen_src/ewk/efl_integration/content_main_delegate_efl.h b/tizen_src/ewk/efl_integration/content_main_delegate_efl.h index 470710f..f7697ea 100644 --- a/tizen_src/ewk/efl_integration/content_main_delegate_efl.h +++ b/tizen_src/ewk/efl_integration/content_main_delegate_efl.h @@ -17,8 +17,10 @@ namespace content { class ContentMainDelegateEfl : public ContentMainDelegate { public: - ContentMainDelegateEfl() = default; - ~ContentMainDelegateEfl() override = default; + ContentMainDelegateEfl(); +#if BUILDFLAG(IS_TIZEN_TV) + ~ContentMainDelegateEfl() override; +#endif ContentMainDelegateEfl(const ContentMainDelegateEfl&) = delete; ContentMainDelegateEfl& operator=(const ContentMainDelegateEfl&) = delete; @@ -31,12 +33,21 @@ class ContentMainDelegateEfl ContentBrowserClient* GetContentBrowserClient() const; +#if BUILDFLAG(IS_TIZEN_TV) + void ProcessExiting(const std::string& process_type) override; + void SetInspectorStatus(bool enable); + bool GetInspectorStatus(); +#endif + private: void PreSandboxStartupBrowser(); std::unique_ptr browser_client_; std::unique_ptr renderer_client_; ContentClientEfl content_client_; +#if BUILDFLAG(IS_TIZEN_TV) + bool enableInspector_; +#endif }; } diff --git a/tizen_src/ewk/efl_integration/devtools_delegate_efl.cc b/tizen_src/ewk/efl_integration/devtools_delegate_efl.cc index 3b76a9d..dc20abd 100644 --- a/tizen_src/ewk/efl_integration/devtools_delegate_efl.cc +++ b/tizen_src/ewk/efl_integration/devtools_delegate_efl.cc @@ -19,6 +19,7 @@ #include "common/version_info.h" #include "content/browser/devtools/devtools_http_handler.h" #include "content/browser/devtools/grit/devtools_resources.h" +#include "content/browser/inspector/devtools_util_manager.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_frontend_host.h" @@ -31,111 +32,41 @@ #include "content/shell/grit/shell_resources.h" #include "net/base/net_errors.h" #include "net/socket/tcp_server_socket.h" +#include "third_party/zlib/google/compression_utils.h" #include "ui/base/resource/resource_bundle.h" using content::BrowserThread; using content::DevToolsHttpHandler; -namespace { - -// Copy of internal class implementation from -// content/shell/browser/shell_devtools_delegate.cc - -const uint16_t kMinTetheringPort = 9333; -const uint16_t kMaxTetheringPort = 9444; -const int kBackLog = 10; - -class TCPServerSocketFactory : public content::DevToolsSocketFactory { - public: - TCPServerSocketFactory(const std::string& address, uint16_t port) - : address_(address), port_(port) {} - - private: - std::unique_ptr CreateForHttpServer() override { - std::unique_ptr socket( - new net::TCPServerSocket(nullptr, net::NetLogSource())); - if (socket->ListenWithAddressAndPort(address_, port_, kBackLog) != net::OK) - return std::unique_ptr(); - - return socket; - } - - std::string address_; - uint16_t port_; -}; - -} // namespace - namespace content { -DevToolsDelegateEfl::DevToolsDelegateEfl(int port) : port_(0) { - // It's a hacky way to early detected if port is available. The problem is - // that the only thing we can do after checking is hope that noone will take - // the port until it's initialized on IO thread again. The best approach would - // be creating async callbacks that would inform when inspector server started - // and on which port. - static std::string addr = "0.0.0.0"; - std::unique_ptr sock( - new net::TCPServerSocket(NULL, net::NetLogSource())); - - const base::CommandLine* const command_line = - base::CommandLine::ForCurrentProcess(); - // See if the user specified a port on the command line (useful for - // automation). If not, use an ephemeral port by specifying 0. - if (!port && command_line->HasSwitch(switches::kRemoteDebuggingPort)) { - int temp_port = 0; - std::string port_str = - command_line->GetSwitchValueASCII(switches::kRemoteDebuggingPort); - if (base::StringToInt(port_str, &temp_port) && (temp_port > 0) && - (temp_port < 65535)) { - port = temp_port; - } else { - DLOG(WARNING) << "Invalid http debugger port number " << temp_port; - } - } - - // why backlog is 1? - if (sock->ListenWithAddressAndPort(addr, port, 1) != net::OK) { - port_ = 0; - return; +/* LCOV_EXCL_START */ +std::string DevToolsDelegateEfl::GetDiscoveryPageHTML() { + std::string data = + std::string(ui::ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_CONTENT_SHELL_DEVTOOLS_DISCOVERY_PAGE)); + if (data.length() > 2 && data[0] == '\x1F' && data[1] == '\x8B') { + std::string uncompressed_data; + if (compression::GzipUncompress(data, &uncompressed_data)) + return uncompressed_data; + LOG(ERROR) << "Failed to uncompress "; } - - net::IPEndPoint givenIp; - sock->GetLocalAddress(&givenIp); - port_ = givenIp.port(); - -#if !defined(EWK_BRINGUP) // FIXME: m67 bringup - // FIXME: EWK_BRINGUP definition should be removed. - std::unique_ptr factory( - new TCPServerSocketFactory(addr, port_)); - - devtools_http_handler_.reset(new content::DevToolsHttpHandler( - std::move(factory), std::string(), this, base::FilePath(), - base::FilePath(), - EflWebView::VersionInfo::GetInstance() - ->ProductNameAndVersionForUserAgent(), - EflWebView::VersionInfo::GetInstance()->DefaultUserAgent())); -#endif // !defined(EWK_BRINGUP) + return data; } -DevToolsDelegateEfl::~DevToolsDelegateEfl() {} - -void DevToolsDelegateEfl::Stop() { - if (devtools_http_handler_) { - // The call below destroys this. - devtools_http_handler_.reset(); - } else { - BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this); - } +std::string DevToolsDelegateEfl::GetFrontendResource(const std::string& path) { + return content::DevToolsUtilManager::GetInstance()->GetFrontendResource(path); } -std::string DevToolsDelegateEfl::GetDiscoveryPageHTML() { - return ui::ResourceBundle::GetSharedInstance().LoadDataResourceString( - IDR_CONTENT_SHELL_DEVTOOLS_DISCOVERY_PAGE); +bool DevToolsDelegateEfl::HasBundledFrontendResources() { + return true; } -std::string DevToolsDelegateEfl::GetFrontendResource(const std::string& path) { - return content::DevToolsFrontendHost::GetFrontendResource(path); +#if defined(OS_TIZEN_TV_PRODUCT) +void DevToolsDelegateEfl::ReleasePort() { + content::DevToolsUtilManager::GetInstance()->ReleasePort(); } +#endif +/* LCOV_EXCL_STOP */ } // namespace content diff --git a/tizen_src/ewk/efl_integration/devtools_delegate_efl.h b/tizen_src/ewk/efl_integration/devtools_delegate_efl.h index 5300512..8d47461 100644 --- a/tizen_src/ewk/efl_integration/devtools_delegate_efl.h +++ b/tizen_src/ewk/efl_integration/devtools_delegate_efl.h @@ -18,27 +18,18 @@ class DevToolsHttpHandler; // This class is similar to ShellDevToolsDelegate, which also implements DevToolsHttpHandlerDelegate interface. class DevToolsDelegateEfl : public DevToolsManagerDelegate { public: - explicit DevToolsDelegateEfl(int = 0); - ~DevToolsDelegateEfl() override; + explicit DevToolsDelegateEfl() {} // LCOV_EXCL_LINE + virtual ~DevToolsDelegateEfl() {} // LCOV_EXCL_LIN // DevToolsManagerDelegate implementation. std::string GetDiscoveryPageHTML() override; - // Stops http server. - void Stop(); - std::string GetFrontendResource(const std::string& path); - DevToolsHttpHandler* devtools_http_handler() { - return devtools_http_handler_.get(); - } - int port() const { - return port_; - } - - private: - int port_; - std::unique_ptr devtools_http_handler_; + virtual bool HasBundledFrontendResources(); +#if BUILDFLAG(IS_TIZEN_TV) + void ReleasePort(); +#endif }; } // namespace content diff --git a/tizen_src/ewk/efl_integration/devtools_port_manager.cc b/tizen_src/ewk/efl_integration/devtools_port_manager.cc new file mode 100644 index 0000000..4f35dba --- /dev/null +++ b/tizen_src/ewk/efl_integration/devtools_port_manager.cc @@ -0,0 +1,304 @@ +// Copyright 2016 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "devtools_port_manager.h" + +#include +#include +#include +#include +#include "base/logging.h" +#include "devtools_port_msg.h" +#if defined(OS_TIZEN) +#include +#endif +namespace devtools_http_handler { + +DevToolsPortManager* DevToolsPortManager::s_PortManager = 0; +const int DevToolsPortManager::s_ValidPortList[] = { + DevToolsPort_7011, DevToolsPort_7012, DevToolsPort_7013}; +const int DevToolsPortManager::s_ValidPortCount = + sizeof(s_ValidPortList) / sizeof(int); +const int DevToolsPortManager::s_ProceeNameLength = 128; +// The size of SHM is composed of +// PortCount|Port1|Port2|Port3|pid1|pid2|pid3|appName1|appName2|appName3 +const int DevToolsPortManager::s_DevToolsPortSharedMemorySize = + sizeof(int) + DevToolsPortManager::s_ValidPortCount * sizeof(int) * 2 + + s_ProceeNameLength * sizeof(char) * 3; + +DevToolsPortManager* DevToolsPortManager::GetInstance() { + if (!s_PortManager) { + DevToolsPortSharedMemory* dpsm = + DevToolsPortSharedMemory::Create(s_DevToolsPortSharedMemorySize); + if (dpsm) { + char* memp = (char*)dpsm->Data(); + s_PortManager = new DevToolsPortManager(dpsm); + s_PortManager->m_UsedPortList = (int*)(dpsm->Data()); + s_PortManager->m_PIDList = + s_PortManager->m_UsedPortList + s_ValidPortCount + 1; + s_PortManager->m_AppName = memp; + s_PortManager->m_AppName += + sizeof(int) + DevToolsPortManager::s_ValidPortCount * sizeof(int) * 2; + } + } + + return s_PortManager; +} + +DevToolsPortManager::DevToolsPortManager(DevToolsPortSharedMemory* p) + : m_UsedPortList(0), m_DevToolsSHM(p), usedPort(0) {} + +bool DevToolsPortManager::IsPortUsed(const int port) { + DevToolsLockHolder h(m_DevToolsSHM); + + int usedPortCount = m_UsedPortList[0]; + if (!usedPortCount) + return false; + + if (usedPortCount <= s_ValidPortCount) { + while (usedPortCount > 0) { + if (m_UsedPortList[usedPortCount] == port && + getpid() == m_PIDList[usedPortCount - 1]) + return true; + + usedPortCount--; + } + } + + return false; +} + +bool DevToolsPortManager::GetValidPort(int& port) { + int pid = 0; + + if (GetValidPort(port, pid)) { + if (pid) { + DevToolsPortMsg* dpm = new DevToolsPortMsg(); + dpm->Send(pid, port); + } + m_DevToolsSHM->Lock_Port(port); + if (pid) + UpdatePortInfoInMem(port); + return true; + } + + return false; +} + +bool DevToolsPortManager::GetValidPort(int& port, int& pid) { + DevToolsLockHolder h(m_DevToolsSHM); + + int usedPortCount = m_UsedPortList[0]; + if (usedPortCount == s_ValidPortCount) { + port = m_UsedPortList[1]; + pid = m_PIDList[0]; + } else { + int i = 0; + int j = 0; + bool selected = 0; + std::string processName = GetCurrentProcessName(); + for (i = 0; i < s_ValidPortCount; i++) { + selected = 0; + for (j = 1; j <= usedPortCount; j++) { + if (s_ValidPortList[i] == m_UsedPortList[j]) + selected = 1; + } + if (!selected) + break; + } + if (i < s_ValidPortCount && !selected) { + usedPortCount++; + m_UsedPortList[usedPortCount] = s_ValidPortList[i]; + m_PIDList[usedPortCount - 1] = getpid(); + memset(m_AppName + (usedPortCount - 1) * s_ProceeNameLength, 0, + s_ProceeNameLength); + memcpy(m_AppName + (usedPortCount - 1) * s_ProceeNameLength, + processName.c_str(), processName.length()); + m_UsedPortList[0] = usedPortCount; + port = s_ValidPortList[i]; + } else + return false; + } + return true; +} + +void DevToolsPortManager::UpdatePortInfoInMem(int port) { + DevToolsLockHolder h(m_DevToolsSHM); + std::string processName = GetCurrentProcessName(); + int usedPortCount = m_UsedPortList[0]; + + if (usedPortCount < s_ValidPortCount) { + usedPortCount++; + m_UsedPortList[usedPortCount] = port; + m_PIDList[usedPortCount - 1] = getpid(); + memset(m_AppName + (usedPortCount - 1) * s_ProceeNameLength, 0, + s_ProceeNameLength); + memcpy(m_AppName + (usedPortCount - 1) * s_ProceeNameLength, + processName.c_str(), processName.length()); + m_UsedPortList[0] = usedPortCount; + } +} + +bool DevToolsPortManager::ReleasePort() { + DevToolsLockHolder h(m_DevToolsSHM); + std::string PrcocessName; + PrcocessName = DevToolsPortManager::GetCurrentProcessName(); + int i; + int port = 0; + int usedPortCount = m_UsedPortList[0]; + bool isPortExist = false; + if (usedPort) + port = usedPort; + + if (!usedPortCount) + return false; + for (i = 1; i <= usedPortCount; i++) { + if (m_UsedPortList[i] == port && getpid() == m_PIDList[i - 1]) { + isPortExist = true; + break; + } + } + if (isPortExist) { + m_UsedPortList[i] = 0; + m_PIDList[i - 1] = 0; + memset(m_AppName + (i - 1) * s_ProceeNameLength, 0, s_ProceeNameLength); + for (int k = i + 1; k <= usedPortCount; k++) { + m_UsedPortList[i] = m_UsedPortList[k]; + m_PIDList[i - 1] = m_PIDList[k - 1]; + memset(m_AppName + (i - 1) * s_ProceeNameLength, 0, s_ProceeNameLength); + memcpy(m_AppName + (i - 1) * s_ProceeNameLength, + m_AppName + (k - 1) * s_ProceeNameLength, s_ProceeNameLength); + i++; + } + m_UsedPortList[usedPortCount] = 0; + m_PIDList[usedPortCount - 1] = 0; + memset(m_AppName + (usedPortCount - 1) * s_ProceeNameLength, 0, + s_ProceeNameLength); + usedPortCount--; + m_UsedPortList[0] = usedPortCount; + m_DevToolsSHM->UnLock_Port(usedPort); + } + return isPortExist; +} + +bool DevToolsPortManager::IsValidPort(const int port) { + for (int i = 0; i < s_ValidPortCount; i++) { + if (s_ValidPortList[i] == port) + return true; + } + + return false; +} + +void DevToolsPortManager::GetMappingInfo(std::string& usedMappingInfo) { + DevToolsLockHolder h(m_DevToolsSHM); + + int usedPortCount = m_UsedPortList[0]; + std::string processName; + char portNumber[] = " 99999"; + bool isPortExist = false; + + if (usedPortCount <= 0 || usedPortCount > s_ValidPortCount) + return; + + usedMappingInfo.append("RWI mapping info \n"); + + for (int i = 0; i < s_ValidPortCount; i++) { + isPortExist = false; + + char processName[s_ProceeNameLength]; + + for (int j = 1; j <= usedPortCount; j++) { + if (s_ValidPortList[i] == m_UsedPortList[j]) { + isPortExist = true; + for (int k = 0; k < s_ProceeNameLength; k++) + processName[k] = m_AppName[k + (j - 1) * s_ProceeNameLength]; + + break; + } + } + + snprintf(portNumber, sizeof(portNumber), " %d", s_ValidPortList[i]); + usedMappingInfo.append(portNumber); + usedMappingInfo.append("(RWI):"); + if (isPortExist) + usedMappingInfo.append(processName); + else + usedMappingInfo.append("N/A"); + + usedMappingInfo.append("\n"); + } +} + +bool DevToolsPortManager::ProcessCompare() { + std::string processName = GetCurrentProcessName(); + +#if defined(OS_TIZEN) + char* vconfWidgetName = vconf_get_str("db/rwi/inspected_appid"); +#else + char* vconfWidgetName = NULL; +#endif + if (!vconfWidgetName) { + LOG(INFO) << "[RWI] vconf_ None"; + return false; + } + + std::string widgetName = vconfWidgetName; + free(vconfWidgetName); + LOG(INFO) << "[RWI] WidgetName = " << widgetName.c_str(); + LOG(INFO) << "[RWI] ProcessName = " << processName.c_str(); + + if (!processName.empty()) { + if (widgetName == "org.tizen.browser") + widgetName = "browser"; + else if(widgetName == "org.tizen.wizard") + widgetName = "wizard"; + + if (processName == widgetName) + return true; + } + + return false; +} + +std::string DevToolsPortManager::GetCurrentProcessName() { + std::string processName = GetUniqueName("/proc/self/cmdline"); + + if (!processName.empty()) { + unsigned int slashIndex = processName.rfind('/'); + + if (slashIndex != std::string::npos && slashIndex < processName.size()) + processName = processName.substr(slashIndex + 1); + } + + return processName; +} + +std::string DevToolsPortManager::GetUniqueName(const char* name) { + if (!access(name, F_OK)) { + FILE* file = fopen(name, "r"); + + if (file) { + const int MAX_BUFF = 100; + char buff[MAX_BUFF] = { + 0, + }; + unsigned index = 0; + + while (index < MAX_BUFF) { + int ch = fgetc(file); + if (ch == EOF) + break; + + buff[index] = ch; + index++; + } + + fclose(file); + return std::string(buff); + } + } + return std::string(); +} +} // namespace devtools_http_handler diff --git a/tizen_src/ewk/efl_integration/devtools_port_manager.h b/tizen_src/ewk/efl_integration/devtools_port_manager.h new file mode 100644 index 0000000..8fcf2c26 --- /dev/null +++ b/tizen_src/ewk/efl_integration/devtools_port_manager.h @@ -0,0 +1,62 @@ +// Copyright 2016 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVTOOLS_PORT_MANAGER_H_ +#define DEVTOOLS_PORT_MANAGER_H_ + +#include "devtools_port_shared_memory.h" + +#include +#include + +namespace devtools_http_handler { +enum DevToolsPortType { + DevToolsPort_7011 = 7011, + DevToolsPort_7012 = 7012, + DevToolsPort_7013 = 7013 +}; + +class DevToolsPortManager { + public: + bool IsPortUsed(const int port); + bool GetValidPort(int& port); + bool GetValidPort(int& port, int& pid); + void GetMappingInfo(std::string& usedMappingInfo); + bool ReleasePort(); + void SetPort(const int port) { usedPort = port; } + int GetPort() { return usedPort; } + void UpdatePortInfoInMem(int port); + void DumpSharedMemeory(); + + ~DevToolsPortManager(); + + static DevToolsPortManager* GetInstance(); + static bool ProcessCompare(); + static std::string GetCurrentProcessName(); + static std::string GetUniqueName(const char* name); + + private: + DevToolsPortManager(DevToolsPortSharedMemory*); + bool IsValidPort(const int port); + + // PortCount|Port1|Port2|Port3 + int* m_UsedPortList; + // pid1|pid2|pid3 + int* m_PIDList; + // appName1|appName2|appName3 + char* m_AppName; + + DevToolsPortSharedMemory* m_DevToolsSHM; + + int usedPort; + + static DevToolsPortManager* s_PortManager; + + static const int s_ValidPortList[]; + static const int s_ValidPortCount; + static const int s_DevToolsPortSharedMemorySize; + static const int s_ProceeNameLength; +}; +} // namespace devtools_http_handler +#endif // DEVTOOLS_PORT_MANAGER_H_ diff --git a/tizen_src/ewk/efl_integration/devtools_port_msg.cc b/tizen_src/ewk/efl_integration/devtools_port_msg.cc new file mode 100644 index 0000000..ea89831 --- /dev/null +++ b/tizen_src/ewk/efl_integration/devtools_port_msg.cc @@ -0,0 +1,67 @@ +// Copyright 2016 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "devtools_port_msg.h" + +#include +#include +#include +#include +#include +#include + +bool DevToolsPortMsg::Send(int pid, int port) { + int sockfd; + struct ifreq ifr; + sockfd = socket(AF_INET, SOCK_STREAM, 0); + char eth[] = "eth0"; + ifr.ifr_addr.sa_family = AF_INET; + strncpy(ifr.ifr_name, eth, sizeof(eth)); + + if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0) { + close(sockfd); + return false; + } + struct sockaddr_in servaddr; + bzero(&servaddr, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(port); + + char* addr = inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr); + if (inet_pton(AF_INET, addr, &servaddr.sin_addr) <= 0) { + close(sockfd); + return false; + } + + if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { + return false; + } + const int str_len = 128; + char closeport[str_len]; + memset(closeport, 0, str_len); + strncat(closeport, "GET /closeport HTTP/1.1\n", + sizeof(closeport) - strlen(closeport) - 1); + strncat(closeport, "\r\n", sizeof(closeport) - strlen(closeport) - 1); + int send_size = + send(sockfd, closeport, strlen(closeport), MSG_WAITALL | MSG_NOSIGNAL); + + if (send_size < 0) { + close(sockfd); + return false; + } else { + while (1) { + char read_buf[str_len]; + memset(read_buf, 0, str_len); + int read_size = read(sockfd, read_buf, str_len); + if (read_size) { + continue; + } else { + close(sockfd); + return true; + } + } + } + close(sockfd); + return false; +} diff --git a/tizen_src/ewk/efl_integration/devtools_port_msg.h b/tizen_src/ewk/efl_integration/devtools_port_msg.h new file mode 100644 index 0000000..d9b1fdd --- /dev/null +++ b/tizen_src/ewk/efl_integration/devtools_port_msg.h @@ -0,0 +1,14 @@ +// Copyright 2016 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVTOOLS_PORT_MSG_H_ +#define DEVTOOLS_PORT_MSG_H_ + +class DevToolsPortMsg { + public: + DevToolsPortMsg(){}; + bool Send(int pid, int port); +}; + +#endif // DEVTOOLS_PORT_MSG_H_ diff --git a/tizen_src/ewk/efl_integration/devtools_port_shared_memory.cc b/tizen_src/ewk/efl_integration/devtools_port_shared_memory.cc new file mode 100644 index 0000000..c4ce11e --- /dev/null +++ b/tizen_src/ewk/efl_integration/devtools_port_shared_memory.cc @@ -0,0 +1,137 @@ +// Copyright 2016 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "devtools_port_shared_memory.h" + +#include +#include +#include +#include +#include + +namespace devtools_http_handler { +const char* SEM_NAME_ARRAY[4] = {"DevToolsPort.lock", "DevToolsPort.lock_7011", + "DevToolsPort.lock_7012", + "DevToolsPort.lock_7013"}; +#define INSPECTOR_PORT_7011 7011 +#define INSPECTOR_PORT_7012 7012 +#define INSPECTOR_PORT_7013 7013 + +DevToolsLocker::DevToolsLocker(int port) : m_sem(0) { + const char* sem_name; + if (!port) + sem_name = SEM_NAME_ARRAY[0]; + else + sem_name = SEM_NAME_ARRAY[port - 7010]; + m_port = port; + m_sem = sem_open(sem_name, O_CREAT, 0644, 1); + if (m_sem == SEM_FAILED) + sem_unlink(sem_name); +} + +DevToolsLocker::~DevToolsLocker() { + const char* sem_name; + if (!m_sem) + return; + if (!m_port) + sem_name = SEM_NAME_ARRAY[m_port]; + else + sem_name = SEM_NAME_ARRAY[m_port - 7010]; + sem_close(m_sem); +} + +bool DevToolsLocker::Lock() { + if (!m_sem) + return false; + + int result = sem_wait(m_sem); + + return !result; +} + +bool DevToolsLocker::TryLock() { + if (!m_sem) + return false; + + int result = sem_trywait(m_sem); + + return !result; +} + +bool DevToolsLocker::Unlock() { + if (!m_sem) + return false; + + int result = sem_post(m_sem); + + return !result; +} + +const char* DevToolsPortSharedMemory::s_SHMKey = + "/WK2SharedMemory.inspector.port"; + +DevToolsPortSharedMemory::DevToolsPortSharedMemory() { + for (int i = 0; i < 3; i++) { + m_PortLocker[i] = new DevToolsLocker(i + 7011); + } +} + +DevToolsPortSharedMemory::~DevToolsPortSharedMemory() { + if (!(*(int*)m_data)) + shm_unlink(s_SHMKey); + + for (int i = 0; i < 3; i++) { + if (m_PortLocker[i]) + delete (m_PortLocker[i]); + } + munmap(m_data, m_size); +} + +void DevToolsPortSharedMemory::Lock_Port(int port) { + if (port >= INSPECTOR_PORT_7011 && port <= INSPECTOR_PORT_7013) + m_PortLocker[port - INSPECTOR_PORT_7011]->Lock(); +} + +void DevToolsPortSharedMemory::UnLock_Port(int port) { + if (port >= INSPECTOR_PORT_7011 && port <= INSPECTOR_PORT_7013) + m_PortLocker[port - INSPECTOR_PORT_7011]->Unlock(); +} + +bool DevToolsPortSharedMemory::Lock() { + return m_Locker.Lock(); +} + +bool DevToolsPortSharedMemory::Unlock() { + return m_Locker.Unlock(); +} + +DevToolsPortSharedMemory* DevToolsPortSharedMemory::Create(size_t size) { + int fd = shm_open(s_SHMKey, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + if (fd == -1) + return 0; + + while (ftruncate(fd, size) == -1) { + if (errno != EINTR) { + close(fd); + shm_unlink(s_SHMKey); + return 0; + } + } + + void* data = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + close(fd); + shm_unlink(s_SHMKey); + return 0; + } + + close(fd); + + static DevToolsPortSharedMemory devtoolsSHM; + devtoolsSHM.m_data = data; + devtoolsSHM.m_size = size; + + return &devtoolsSHM; +} +} // namespace devtools_http_handler diff --git a/tizen_src/ewk/efl_integration/devtools_port_shared_memory.h b/tizen_src/ewk/efl_integration/devtools_port_shared_memory.h new file mode 100644 index 0000000..a44091c --- /dev/null +++ b/tizen_src/ewk/efl_integration/devtools_port_shared_memory.h @@ -0,0 +1,64 @@ +// Copyright 2016 Samsung Electronics. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVTOOLS_PORT_SHARED_MEMORY_H_ +#define DEVTOOLS_PORT_SHARED_MEMORY_H_ + +#include +#include +#include +#include + +namespace devtools_http_handler { + +class DevToolsLocker { + public: + DevToolsLocker(int port = 0); + ~DevToolsLocker(); + bool Lock(); + bool TryLock(); + bool Unlock(); + + private: + sem_t* m_sem; + int m_port; +}; + +class DevToolsPortSharedMemory { + public: + // Create a shared memory object with the given size. Will return 0 on + // failure. + static DevToolsPortSharedMemory* Create(size_t); + + ~DevToolsPortSharedMemory(); + + size_t Size() const { return m_size; } + void* Data() const { return m_data; } + bool Lock(); + bool Unlock(); + void Lock_Port(int port); + void UnLock_Port(int port); + + private: + static const char* s_SHMKey; + size_t m_size; + void* m_data; + DevToolsLocker m_Locker; + DevToolsLocker* m_PortLocker[3]; + DevToolsPortSharedMemory(); +}; + +class DevToolsLockHolder { + private: + DevToolsPortSharedMemory* m_lock; + + public: + inline explicit DevToolsLockHolder(DevToolsPortSharedMemory* shmLock) + : m_lock(shmLock) { + shmLock->Lock(); + } + inline ~DevToolsLockHolder() { m_lock->Unlock(); } +}; +} // namespace devtools_http_handler +#endif // DEVTOOLS_PORT_SHARED_MEMORY_H_ diff --git a/tizen_src/ewk/efl_integration/eweb_context.cc b/tizen_src/ewk/efl_integration/eweb_context.cc index ff0aaef..0d9f7a7 100644 --- a/tizen_src/ewk/efl_integration/eweb_context.cc +++ b/tizen_src/ewk/efl_integration/eweb_context.cc @@ -20,6 +20,7 @@ #include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/password_manager/core/browser/password_form.h" #include "components/password_manager/core/browser/password_store.h" +#include "content/browser/inspector/devtools_util_manager.h" #include "components/services/storage/public/cpp/buckets/bucket_locator.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" @@ -66,6 +67,8 @@ #if BUILDFLAG(IS_TIZEN_TV) #include "common/application_type.h" +#include "content_main_delegate_efl.h" +#include "net/disk_cache/cache_util.h" #include "wrt/hbbtv_dynamicplugin.h" #include "wrt/hbbtv_widget_host.h" #endif @@ -331,6 +334,7 @@ EWebContext::EWebContext(bool incognito, const std::string& injectedBundlePath) widget_scale_(0), #if BUILDFLAG(IS_TIZEN_TV) application_type_(EWK_APPLICATION_TYPE_WEBBROWSER), + is_showing_mapping_info_(false), #endif m_pixmap(0), inspector_server_(NULL) { @@ -872,18 +876,28 @@ void EWebContext::GetPasswordDataList( } unsigned int EWebContext::InspectorServerStart(unsigned int port) { + LOG(INFO) << "EWebContext::InspectorServerStart"; +#if BUILDFLAG(IS_TIZEN_TV) + is_showing_mapping_info_ = true; + EwkGlobalData::GetInstance()->GetContentMainDelegateEfl().SetInspectorStatus( + true); + if (content::DevToolsUtilManager::GetPort()) + return content::DevToolsUtilManager::GetPort(); +#endif InspectorServerStop(); - inspector_server_ = new content::DevToolsDelegateEfl(port); - return inspector_server_ ? inspector_server_->port() : 0; + return content::DevToolsUtilManager::GetInstance()->InspectorServerStart( + port); } bool EWebContext::InspectorServerStop() { - if (!inspector_server_) +#if BUILDFLAG(IS_TIZEN_TV) + if (!content::DevToolsUtilManager::GetPort()) return false; - // The call below destroys inspector_server_. - inspector_server_->Stop(); - inspector_server_ = NULL; - return true; + is_showing_mapping_info_ = false; + EwkGlobalData::GetInstance()->GetContentMainDelegateEfl().SetInspectorStatus( + false); +#endif + return content::DevToolsUtilManager::GetInstance()->InspectorServerStop(); } void EWebContext::SetNotificationCallbacks( @@ -989,6 +1003,18 @@ void EWebContext::SetApplicationType( } } +bool EWebContext::GetInspectorServerState() { + return content::DevToolsUtilManager::GetPort(); +} + +bool EWebContext::ShowInspectorPortInfoState() { + if (!is_showing_mapping_info_) + return false; + + is_showing_mapping_info_ = false; + return content::DevToolsUtilManager::GetPort(); +} + void EWebContext::RegisterJSPluginMimeTypes(const Eina_List* mime_types_list) { std::string mime_types; const Eina_List* it; diff --git a/tizen_src/ewk/efl_integration/eweb_context.h b/tizen_src/ewk/efl_integration/eweb_context.h index 067c619..dab08bc 100644 --- a/tizen_src/ewk/efl_integration/eweb_context.h +++ b/tizen_src/ewk/efl_integration/eweb_context.h @@ -202,6 +202,9 @@ class EWebContext { #if BUILDFLAG(IS_TIZEN_TV) void SetApplicationType(const Ewk_Application_Type application_type); Ewk_Application_Type GetApplicationType() const { return application_type_; } + // To control applocation only show once inspector port info + bool ShowInspectorPortInfoState(); + bool GetInspectorServerState(); void RegisterJSPluginMimeTypes(const Eina_List*); void RegisterURLSchemesAsCORSEnabled(const Eina_List* schemes_list); void SetTimeOffset(double time_offset); @@ -246,6 +249,8 @@ class EWebContext { int m_pixmap; #if BUILDFLAG(IS_TIZEN_TV) Ewk_Application_Type application_type_; + // For processes which are preloaded and with unknown app id + bool is_showing_mapping_info_; #endif content::DevToolsDelegateEfl* inspector_server_; diff --git a/tizen_src/ewk/efl_integration/eweb_view.cc b/tizen_src/ewk/efl_integration/eweb_view.cc index 909d773..e459577 100644 --- a/tizen_src/ewk/efl_integration/eweb_view.cc +++ b/tizen_src/ewk/efl_integration/eweb_view.cc @@ -100,6 +100,12 @@ #include "components/autofill/core/common/autofill_switches.h" #endif +#if BUILDFLAG(IS_TIZEN_TV) +#include "common/application_type.h" +#include "devtools_port_manager.h" +#include "public/ewk_media_downloadable_font_info.h" +#endif // OS_TIZEN_TV_PRODUCT + using namespace content; using web_contents_utils::WebViewFromWebContents; @@ -333,6 +339,10 @@ EWebView::EWebView(Ewk_Context* context, Evas_Object* object) page_scale_factor_(1.0), x_delta_(0.0), y_delta_(0.0), +#if BUILDFLAG(IS_TIZEN_TV) + use_early_rwi_(false), + rwi_info_showed_(false), +#endif is_initialized_(false) { if (evas_object_) { evas_object_smart_callback_add(evas_object_, @@ -618,6 +628,15 @@ void EWebView::SetURL(const GURL& url, bool from_api) { ui::PAGE_TRANSITION_LINK | ui::PAGE_TRANSITION_FROM_API); } +#if BUILDFLAG(IS_TIZEN_TV) + if (use_early_rwi_) { + LOG(INFO) << "[FAST RWI] SetURL Replace [" << url.spec() + << "] to [about:blank]"; + rwi_gurl_ = url; + params.url = GURL("about:blank"); + } +#endif + params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE; web_contents_->GetController().LoadURLWithParams(params); } @@ -2486,10 +2505,30 @@ std::string EWebView::GetPlatformLocale() { } int EWebView::StartInspectorServer(int port) { +#if BUILDFLAG(IS_TIZEN_TV) + if (IsTIZENWRT()) { + use_early_rwi_ = false; + rwi_info_showed_ = false; + } + if (!context_->GetImpl()->GetInspectorServerState()) { + int validPort = 0; + if (!devtools_http_handler::DevToolsPortManager::GetInstance() + ->GetValidPort(validPort)) + return 0; + + port = validPort; + } +#endif return context_->InspectorServerStart(port); } bool EWebView::StopInspectorServer() { +#if BUILDFLAG(IS_TIZEN_TV) + if (IsTIZENWRT()) { + use_early_rwi_ = false; + rwi_info_showed_ = false; + } +#endif return context_->InspectorServerStop(); } @@ -2525,6 +2564,11 @@ void EWebView::HandleRendererProcessCrash() { } void EWebView::InitializeContent() { + LOG(INFO) << "eweb_view.cc InitializeContent" ; +#if BUILDFLAG(IS_TIZEN_TV) + // When initialize content init inspector server + InitInspectorServer(); +#endif WebContents* new_contents = create_new_window_web_contents_cb_.Run(this); if (!new_contents) { WebContents::CreateParams params(context_->browser_context()); @@ -2595,6 +2639,31 @@ void EWebView::InitializeContent() { InitializeWindowTreeHost(); } +#if BUILDFLAG(IS_TIZEN_TV) +void EWebView::OnDialogClosed() { + if (!use_early_rwi_) + return; + + use_early_rwi_ = false; + LOG(INFO) << "[FAST RWI] SetURL Restore [" << rwi_gurl_.spec() + << "] from [about:blank]"; + SetURL(rwi_gurl_); + rwi_gurl_ = GURL(); + rwi_info_showed_ = true; +} + +void EWebView::InitInspectorServer() { + if (devtools_http_handler::DevToolsPortManager::GetInstance() + ->ProcessCompare()) { + int res = StartInspectorServer(0); + if (res) { + LOG(INFO) << "InitInspectorServer SetPort"; + devtools_http_handler::DevToolsPortManager::GetInstance()->SetPort(res); + } + } +} +#endif + void EWebView::InitializeWindowTreeHost() { CHECK(aura::Env::GetInstance()); diff --git a/tizen_src/ewk/efl_integration/eweb_view.h b/tizen_src/ewk/efl_integration/eweb_view.h index bd71c11..6f05ceb 100644 --- a/tizen_src/ewk/efl_integration/eweb_view.h +++ b/tizen_src/ewk/efl_integration/eweb_view.h @@ -712,6 +712,15 @@ class EWebView { void OnSelectionRectReceived(const gfx::Rect& selection_rect) const; +#if BUILDFLAG(IS_TIZEN_TV) + bool SetMixedContents(bool allow); + void ClearAllTilesResources(); + bool UseEarlyRWI() { return use_early_rwi_; } + bool RWIInfoShowed() { return rwi_info_showed_; } + GURL RWIURL() { return rwi_gurl_; } + void OnDialogClosed(); +#endif // OS_TIZEN_TV_PRODUCT + private: static void NativeViewResize(void* data, Evas* e, @@ -727,6 +736,11 @@ class EWebView { int y, Ewk_Hit_Test_Mode mode, WebViewAsyncRequestHitTestDataCallback* cb); + +#if BUILDFLAG(IS_TIZEN_TV) + void InitInspectorServer(); +#endif + #if BUILDFLAG(IS_TIZEN) && !defined(EWK_BRINGUP) static void cameraResultCb(service_h request, service_h reply, @@ -890,6 +904,12 @@ class EWebView { bool is_initialized_; +#if BUILDFLAG(IS_TIZEN_TV) + bool use_early_rwi_; + bool rwi_info_showed_; + GURL rwi_gurl_; +#endif + std::unique_ptr<_Ewk_Back_Forward_List> back_forward_list_; static content::WebContentsEflDelegate::WebContentsCreateCallback diff --git a/tizen_src/ewk/efl_integration/web_contents_delegate_efl.cc b/tizen_src/ewk/efl_integration/web_contents_delegate_efl.cc index 1b9ab28..4fd18d2 100644 --- a/tizen_src/ewk/efl_integration/web_contents_delegate_efl.cc +++ b/tizen_src/ewk/efl_integration/web_contents_delegate_efl.cc @@ -58,6 +58,10 @@ #include "browser/autofill/autofill_request_manager.h" #endif +#if BUILDFLAG(IS_TIZEN_TV) +#include "devtools_port_manager.h" +#endif // OS_TIZEN_TV_PRODUCT + #if defined(TIZEN_AUTOFILL) #include "base/command_line.h" #include "browser/autofill/autofill_client_efl.h" @@ -154,6 +158,10 @@ WebContentsDelegateEfl::~WebContentsDelegateEfl() { delete dialog_manager_; } +static bool IsMainFrame(RenderFrameHost* render_frame_host) { + return !render_frame_host->GetParent(); +} + WebContents* WebContentsDelegateEfl::OpenURLFromTab( WebContents* source, const OpenURLParams& params) { @@ -684,6 +692,40 @@ void WebContentsDelegateEfl::OnDidGetManifest( } #if BUILDFLAG(IS_TIZEN_TV) +void WebContentsDelegateEfl::ShowInspectorPortInfo() { + std::string mappingInfo; + devtools_http_handler::DevToolsPortManager::GetInstance()->GetMappingInfo( + mappingInfo); + if (web_view_->UseEarlyRWI()) { + mappingInfo.append( + "\r\nFast RWI is used, [about:blank] is loaded fist instead of \r\n["); + mappingInfo.append(web_view_->RWIURL().spec()); + mappingInfo.append( + "]\r\nClick OK button will start the real loading.\r\nNotes:\r\nPlease " + "connect to RWI in PC before click OK button.\r\nThen you can get " + "network log from the initial loading.\r\nPlease click Record button " + "in Timeline panel in PC before click OK button,\r\nThen you can get " + "profile log from the initial loading."); + } + LOG(INFO) << "[RWI] WebContentsDelegateEfl::ShowPortInfo mappingInfo = " + << mappingInfo.c_str(); + + if (!mappingInfo.empty()) { + const GURL kGURL(""); + WebContentsImpl* wci = static_cast(&web_contents_); + auto dialog_closed_callback = + base::BindOnce([](JavaScriptDialogManager* manager, bool success, + const std::u16string& response) {}, + dialog_manager_); + wci->RunJavaScriptDialog( + wci->GetPrimaryMainFrame(), base::ASCIIToUTF16(mappingInfo), + base::ASCIIToUTF16(base::StringPiece("OK")), + JAVASCRIPT_DIALOG_TYPE_ALERT, false, std::move(dialog_closed_callback)); + } +} +#endif + +#if BUILDFLAG(IS_TIZEN_TV) void WebContentsDelegateEfl::UpdateTargetURL(WebContents* /*source*/, const GURL& url) { std::string absolute_link_url(url.spec()); diff --git a/tizen_src/ewk/efl_integration/web_contents_delegate_efl.h b/tizen_src/ewk/efl_integration/web_contents_delegate_efl.h index a396563..70b905a 100644 --- a/tizen_src/ewk/efl_integration/web_contents_delegate_efl.h +++ b/tizen_src/ewk/efl_integration/web_contents_delegate_efl.h @@ -129,6 +129,7 @@ class WebContentsDelegateEfl : public WebContentsDelegate { #if BUILDFLAG(IS_TIZEN_TV) void UpdateTargetURL(WebContents* source, const GURL& url) override; + void ShowInspectorPortInfo(); #endif #if defined(TIZEN_AUTOFILL) diff --git a/tizen_src/ewk/efl_integration/web_contents_observer_efl.cc b/tizen_src/ewk/efl_integration/web_contents_observer_efl.cc index 415d1c8..8768401 100644 --- a/tizen_src/ewk/efl_integration/web_contents_observer_efl.cc +++ b/tizen_src/ewk/efl_integration/web_contents_observer_efl.cc @@ -30,9 +30,6 @@ #include "url/gurl.h" #if defined(OS_TIZEN_TV_PRODUCT) -#if !defined(EWK_BRINGUP) -#include "devtools_port_manager.h" -#endif #include "private/ewk_context_private.h" #endif @@ -142,10 +139,21 @@ void WebContentsObserverEfl::LoadProgressChanged(double progress) { void WebContentsObserverEfl::DidFinishLoad(RenderFrameHost* render_frame_host, const GURL& validated_url) { + LOG(INFO) << "WebContentsObserverEfl::DidFinishLoad"; if (!IsMainFrame(render_frame_host)) return; web_view_->SmartCallback().call(); +#if BUILDFLAG(IS_TIZEN_TV) + // After load finish show inspector port info + if (web_view_->context() && web_view_->context()->GetImpl() && + web_view_->context()->GetImpl()->ShowInspectorPortInfoState()) { + if (!web_view_->RWIInfoShowed()) + web_contents_delegate_->ShowInspectorPortInfo(); + } +#endif + + TTRACE_WEB("WebContentsObserverEfl::DidFinishLoad"); web_contents_.Focus(); } diff --git a/wrt/src/browser/api/tv/wrt_api_tv_extension.cc b/wrt/src/browser/api/tv/wrt_api_tv_extension.cc index 6951437..1b8273c 100644 --- a/wrt/src/browser/api/tv/wrt_api_tv_extension.cc +++ b/wrt/src/browser/api/tv/wrt_api_tv_extension.cc @@ -17,9 +17,7 @@ #include "electron/shell/common/gin_converters/content_converter.h" #include "gin/object_template_builder.h" #include "tizen_src/chromium_impl/tizen/vconf_handle.h" -#if !defined(WRT_JS_BRINGUP) #include "tizen_src/ewk/efl_integration/devtools_port_manager.h" -#endif #include "v8/include/v8.h" #include "wrt/src/base/platform_info.h" #include "wrt/src/browser/native_web_runtime.h" @@ -140,12 +138,11 @@ TVExtension::TVExtension() {} TVExtension::~TVExtension() {} bool TVExtension::NeedUseInspector() const { -#if defined(WRT_JS_BRINGUP) + if (devtools_http_handler::DevToolsPortManager::GetInstance() + ->ProcessCompare()) { + return true; + } return false; -#else - return devtools_http_handler::DevToolsPortManager::GetInstance() - ->ProcessCompare(); -#endif } bool TVExtension::IsAlwaysReload() const { diff --git a/wrt/src/browser/api/wrt_api_web_runtime.cc b/wrt/src/browser/api/wrt_api_web_runtime.cc index 619c3c4..c845c00 100755 --- a/wrt/src/browser/api/wrt_api_web_runtime.cc +++ b/wrt/src/browser/api/wrt_api_web_runtime.cc @@ -16,9 +16,7 @@ #include "electron/shell/common/gin_helper/dictionary.h" #include "electron/shell/common/node_includes.h" #include "gin/object_template_builder.h" -#if !defined(WRT_JS_BRINGUP) #include "tizen_src/chromium_impl/content/browser/inspector/devtools_util_manager.h" -#endif #include "tizen_src/chromium_impl/efl/window_factory.h" #include "tizen_src/chromium_impl/tizen/system_info.h" #include "wrt/src/base/file_utils.h" @@ -225,15 +223,11 @@ bool WebRuntime::GetBackgroundSupport() const { } unsigned int WebRuntime::StartInspectorServer() const { -#if !defined(WRT_JS_BRINGUP) return content::DevToolsUtilManager::GetInstance()->InspectorServerStart(); -#endif } void WebRuntime::StopInspectorServer() const { -#if !defined(WRT_JS_BRINGUP) content::DevToolsUtilManager::GetInstance()->InspectorServerStop(); -#endif } void WebRuntime::HandleCertificateError( @@ -715,6 +709,7 @@ gin::ObjectTemplateBuilder WebRuntime::GetObjectTemplateBuilder( v8::Isolate* isolate) { auto object_builder = gin::Wrappable::GetObjectTemplateBuilder(isolate); + if (!ApplicationData::IsServiceApp()) { object_builder .SetMethod("exit", &WebRuntime::Exit) diff --git a/wrt/src/browser/wrt_devtools_manager_delegate.cc b/wrt/src/browser/wrt_devtools_manager_delegate.cc index 0994039..cdd7358 100755 --- a/wrt/src/browser/wrt_devtools_manager_delegate.cc +++ b/wrt/src/browser/wrt_devtools_manager_delegate.cc @@ -4,7 +4,7 @@ #include "wrt/src/browser/wrt_devtools_manager_delegate.h" -#if BUILDFLAG(IS_TIZEN_TV) && !defined(WRT_JS_BRINGUP) +#if BUILDFLAG(IS_TIZEN_TV) #include "tizen_src/chromium_impl/content/browser/inspector/devtools_util_manager.h" #endif @@ -14,7 +14,7 @@ bool WRTDevToolsManagerDelegate::HasBundledFrontendResources() { return true; } -#if BUILDFLAG(IS_TIZEN_TV) && !defined(WRT_JS_BRINGUP) +#if BUILDFLAG(IS_TIZEN_TV) void WRTDevToolsManagerDelegate::ReleasePort() { content::DevToolsUtilManager::GetInstance()->ReleasePort(); } diff --git a/wrt/src/browser/wrt_devtools_manager_delegate.h b/wrt/src/browser/wrt_devtools_manager_delegate.h index eeb95cc..31776a3 100755 --- a/wrt/src/browser/wrt_devtools_manager_delegate.h +++ b/wrt/src/browser/wrt_devtools_manager_delegate.h @@ -19,7 +19,7 @@ class WRTDevToolsManagerDelegate : public electron::DevToolsManagerDelegate { = delete; // Chromium DevToolsHttpHandler::Delegate overrides. -#if BUILDFLAG(IS_TIZEN_TV) && !defined(WRT_JS_BRINGUP) +#if BUILDFLAG(IS_TIZEN_TV) void ReleasePort() override; #endif -- 2.7.4 From 6c3dbe3674f8aad76fba7bc76a9fb7b92192911d Mon Sep 17 00:00:00 2001 From: pengxia Date: Thu, 2 Mar 2023 10:23:29 +0800 Subject: [PATCH 05/16] [M108 Aura Migration][NaCl][PPAPI] Fixing error codes in PPB_FileRef Trying to delete a non-empty directory or rename any directory to an existing, non-empty one results in generic error (PP_ERROR_FAILED that is translated to EPERM by nacl_io). Expected result of such operation would be something that translates to EEXIST or ENOTEMPTY. This patch makes PPB_FileRef methods mentioned above result in PP_ERROR_FILEEXISTS, so that it is translated to EEXIST by nacl_io. Ported patch from M94 Aura: https://review.tizen.org/gerrit/#/c/platform/framework/web/chromium-efl/+/280551/ Change-Id: Ifebf80cc78370a3a170a86dcbd4eb2d10bb41c5a Signed-off-by: pengxia --- ppapi/shared_impl/file_type_conversion.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/ppapi/shared_impl/file_type_conversion.cc b/ppapi/shared_impl/file_type_conversion.cc index 8b6cd3b..3e52485 100644 --- a/ppapi/shared_impl/file_type_conversion.cc +++ b/ppapi/shared_impl/file_type_conversion.cc @@ -16,6 +16,7 @@ int FileErrorToPepperError(base::File::Error error_code) { case base::File::FILE_OK: return PP_OK; case base::File::FILE_ERROR_EXISTS: + case base::File::FILE_ERROR_NOT_EMPTY: return PP_ERROR_FILEEXISTS; case base::File::FILE_ERROR_NOT_FOUND: return PP_ERROR_FILENOTFOUND; -- 2.7.4 From b04cfc174ef6715dc690816a715370bf20d2f689 Mon Sep 17 00:00:00 2001 From: "feifei08.liu" Date: Tue, 28 Feb 2023 13:37:00 +0800 Subject: [PATCH 06/16] [M108 Migration][VD] Fix office 365 Word/Excel show empty blank pages issue 1. Fix redirection issue in WebApp. Now m85, exclude "file://" URLs frome default SiteInstance. So if webapp redirect url in file:///index.html. It will create a new SiteInstance and RenderFrameHost for the redirected url. As WRT only get and store main frame once time (the first time UIprocess communicated with RenderProcess). So if frame changed, wrt cannot send message to the right frame. So avoid this code that will not create new frame while redirection in "file://" URLs. 2. [VD] Disable "OriginIsolationHeader" feature to fix office 365 Word/Excel show empty blank pages issue. "OriginIsolationHeader" enabled in M94 which is in development, it will cause new webview created and some information do not included in requests, this feature disabled in M85, so we follow M85 logic disable this feature. Reference: - https://review.tizen.org/gerrit/286949/ Change-Id: Ic26c5a4ac80bfa246a3f1d205095093b503ae372 Signed-off-by: feifei08.liu --- content/browser/site_instance_impl.cc | 2 ++ content/public/common/content_features.cc | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc index f591ec3..e48f32d 100644 --- a/content/browser/site_instance_impl.cc +++ b/content/browser/site_instance_impl.cc @@ -1204,11 +1204,13 @@ bool SiteInstanceImpl::CanBePlacedInDefaultSiteInstance( return false; } +#if !BUILDFLAG(IS_TIZEN_TV) // Exclude "file://" URLs from the default SiteInstance to prevent the // default SiteInstance process from accumulating file access grants that // could be exploited by other non-isolated sites. if (url.SchemeIs(url::kFileScheme)) return false; +#endif // Don't use the default SiteInstance when // kProcessSharingWithStrictSiteInstances is enabled because we want each diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 2ce7fba..f6160a8 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc @@ -741,9 +741,15 @@ BASE_FEATURE(kNotificationTriggers, // // The name is "OriginIsolationHeader" because that was the old name when the // feature was under development. +#if BUILDFLAG(IS_TIZEN_TV) +BASE_FEATURE(kOriginIsolationHeader, + "OriginIsolationHeader", + base::FEATURE_DISABLED_BY_DEFAULT); +#else BASE_FEATURE(kOriginIsolationHeader, "OriginIsolationHeader", base::FEATURE_ENABLED_BY_DEFAULT); +#endif // History navigation in response to horizontal overscroll (aka gesture-nav). BASE_FEATURE(kOverscrollHistoryNavigation, -- 2.7.4 From 6ca37984fa8438ebb2a2476167e1d7ccb319d573 Mon Sep 17 00:00:00 2001 From: DongHyun Song Date: Thu, 9 Mar 2023 08:53:57 +0900 Subject: [PATCH 07/16] [M108 Migration][WRTjs] Lazy initialization of ContentMainRunner for wrt-loader In case cold booting case, WRT initialization takes much time on the low-end product. (5s ~ 7s) Even though wrt-loader is prepared on cold booting sequence as soon as possible, the candidate launch can be failed because wrt-loader is not yet ready. To make short the initialization time, this patch defers the jobs of WRTContentMain's initialization with ecore_idler, and return loader's create callback early to prepare wrt-loader. Reference: https://review.tizen.org/gerrit/284208/ Change-Id: Icb1be128397415903d3de8b3346a862a98e7f1e2 Signed-off-by: DongHyun Song --- wrt/src/app/wrt_content_main.cc | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/wrt/src/app/wrt_content_main.cc b/wrt/src/app/wrt_content_main.cc index 4fb0b5c..b6c0fcc 100644 --- a/wrt/src/app/wrt_content_main.cc +++ b/wrt/src/app/wrt_content_main.cc @@ -55,9 +55,14 @@ class WRTContentMain::Loader { loader_lifecycle_callback_s callback; callback.create = [](bundle* extra, int type, void* user_data) { LOG(INFO) << "loader created"; - auto* content_main = static_cast(user_data)->content_main_; - content_main->Initialize(); - content_main->main_delegate_->LoaderCreated(); + ecore_idler_add( + [](void* data) { + LOG(INFO) << "ContentMain will be initialized in idler."; + auto* content_main = static_cast(data); + content_main->Initialize(); + content_main->main_delegate_->LoaderCreated(); + return ECORE_CALLBACK_CANCEL; + }, static_cast(user_data)->content_main_); }; #if TIZEN_VERSION_AT_LEAST(6, 5, 0) callback.prelaunch = [](int argc, char** argv, const char* app_path, -- 2.7.4 From cb45d4c10b8de2cae7f7fa37eea5c3b05d6363a3 Mon Sep 17 00:00:00 2001 From: YongGeol Jung Date: Wed, 8 Mar 2023 00:49:22 -0800 Subject: [PATCH 08/16] [Onscreen] Request to redraw window surface when showing. A black scene is observed when app is displayed from a resume activity. Modified to redraw window surface when showing. Change-Id: Ifacbdcc58b0fb8ba107011eafd7f94f669845fa8 Signed-off-by: YongGeol Jung --- tizen_src/chromium_impl/ui/ozone/platform/efl/efl_window.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tizen_src/chromium_impl/ui/ozone/platform/efl/efl_window.cc b/tizen_src/chromium_impl/ui/ozone/platform/efl/efl_window.cc index c70585c..6cf4d58 100644 --- a/tizen_src/chromium_impl/ui/ozone/platform/efl/efl_window.cc +++ b/tizen_src/chromium_impl/ui/ozone/platform/efl/efl_window.cc @@ -73,6 +73,10 @@ void EflWindow::Show(bool inactive) { evas_object_show(native_view_); ecore_evas_show(ee_); + + // Request to redraw window surface when showing. If not, a black screen will + // appear. + delegate_->OnDamageRect(bounds_); } void EflWindow::Hide() { -- 2.7.4 From bac9fab87a08b2d8e331e863b1e14e7b415ea1b3 Mon Sep 17 00:00:00 2001 From: zhaosy Date: Thu, 9 Mar 2023 08:04:59 +0800 Subject: [PATCH 09/16] [M108 Migration][WRTjs] Use BUILDFLAG(IS_XXX) for OS checking This patch replaces all occurances of defined(OS_XXX) with BUILDFLAG(IS_XXX) as per upstream changes mentioned in [1]. [1] https://bugs.chromium.org/p/chromium/issues/detail?id=1234043 Below efl/tizen build flags are replaced: USE_EFL -> IS_EFL OS_TIZEN -> IS_TIZEN OS_TIZEN_TV_PRODUCT -> IS_TIZEN_TV Reference: https://review.tizen.org/gerrit/#/c/platform/framework/web/chromium-efl/+/289238/ Change-Id: I387487f030919116dee9210261f23b215b6c4b60 Signed-off-by: zhaosy --- content/common/zygote/zygote_communication_linux.cc | 2 -- electron/shell/browser/api/electron_api_web_contents.cc | 2 +- electron/shell/browser/electron_browser_main_parts.cc | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/content/common/zygote/zygote_communication_linux.cc b/content/common/zygote/zygote_communication_linux.cc index 9e2d158..f707c1b4 100644 --- a/content/common/zygote/zygote_communication_linux.cc +++ b/content/common/zygote/zygote_communication_linux.cc @@ -361,9 +361,7 @@ void ZygoteCommunication::DropProcessPrivileges(const std::string& app_id) { pid_t ZygoteCommunication::GetZygotePid() { return pid_; } -#endif -#if BUILDFLAG(IS_TIZEN_TV) void ZygoteCommunication::SetTimeZoneOffset( const std::string& time_zone_offset) { DCHECK(init_); diff --git a/electron/shell/browser/api/electron_api_web_contents.cc b/electron/shell/browser/api/electron_api_web_contents.cc index 18cea53..c88f1ad 100644 --- a/electron/shell/browser/api/electron_api_web_contents.cc +++ b/electron/shell/browser/api/electron_api_web_contents.cc @@ -3061,7 +3061,7 @@ void WebContents::Focus() { if (owner_window()) owner_window()->Focus(true); #endif -#if !defined(ENABLE_WRT_JS) || !defined(OS_TIZEN_TV_PRODUCT) +#if !defined(ENABLE_WRT_JS) || !BUILDFLAG(IS_TIZEN_TV) web_contents()->Focus(); #endif } diff --git a/electron/shell/browser/electron_browser_main_parts.cc b/electron/shell/browser/electron_browser_main_parts.cc index 40c1830..023bdb0 100644 --- a/electron/shell/browser/electron_browser_main_parts.cc +++ b/electron/shell/browser/electron_browser_main_parts.cc @@ -267,7 +267,7 @@ int ElectronBrowserMainParts::PreEarlyInitialization() { } void ElectronBrowserMainParts::PostEarlyInitialization() { -#if defined(ENABLE_WRT_JS) && defined(OS_TIZEN_TV_PRODUCT) +#if defined(ENABLE_WRT_JS) && BUILDFLAG(IS_TIZEN_TV) LOG(INFO) << "Start Electron PostEarlyInitialization"; #endif @@ -322,7 +322,7 @@ void ElectronBrowserMainParts::PostEarlyInitialization() { // Initialize after user script environment creation. fake_browser_process_->PostEarlyInitialization(); -#if defined(ENABLE_WRT_JS) && defined(OS_TIZEN_TV_PRODUCT) +#if defined(ENABLE_WRT_JS) && BUILDFLAG(IS_TIZEN_TV) LOG(INFO) << "End Electron PostEarlyInitialization"; #endif } -- 2.7.4 From cf59503bd17bb4020fb10e9f0988966605a75e22 Mon Sep 17 00:00:00 2001 From: jiangyuwei Date: Fri, 3 Mar 2023 09:56:18 +0800 Subject: [PATCH 10/16] [M108 Migration] Fix Crash in webview. Add protection in EWebView::SetOrientation. Reference: - https://review.tizen.org/gerrit/#/c/282815/ Change-Id: If424bac3ecba47971b95c7d4df771c626f3b0fb0 Signed-off-by: jiangyuwei --- tizen_src/ewk/efl_integration/eweb_view.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tizen_src/ewk/efl_integration/eweb_view.cc b/tizen_src/ewk/efl_integration/eweb_view.cc index e459577..3503521 100644 --- a/tizen_src/ewk/efl_integration/eweb_view.cc +++ b/tizen_src/ewk/efl_integration/eweb_view.cc @@ -503,6 +503,10 @@ EWebView::~EWebView() { OnCustomScrollBeginCallback); evas_object_smart_callback_del(evas_object_, kCustomScrollEndSignalName, OnCustomScrollEndCallback); +#if BUILDFLAG(IS_TIZEN) + if (window_rotate_handler_) + ecore_event_handler_del(window_rotate_handler_); +#endif } } -- 2.7.4 From 4fdde5f687faf07bef26eb53d4f02ea29c322b1c Mon Sep 17 00:00:00 2001 From: "fr.fang" Date: Wed, 1 Mar 2023 20:59:34 +0800 Subject: [PATCH 11/16] [M108 Migration][VD] Ensure plugin props are setting correctly. Internally, properties of plugin belong to 2 different targets, one is HTMLPluginElement, one is the corresponding scriptable object. Need to set properties to the correct target. Reference: https://review.tizen.org/gerrit/#/c/282087 Change-Id: Ic7509825520413e633114ce93c7a32dfcbed4b1c Signed-off-by: fr.fang --- .../core/v8/custom/v8_html_plugin_element_custom.cc | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/third_party/blink/renderer/bindings/core/v8/custom/v8_html_plugin_element_custom.cc b/third_party/blink/renderer/bindings/core/v8/custom/v8_html_plugin_element_custom.cc index 004130f..944ce8b 100644 --- a/third_party/blink/renderer/bindings/core/v8/custom/v8_html_plugin_element_custom.cc +++ b/third_party/blink/renderer/bindings/core/v8/custom/v8_html_plugin_element_custom.cc @@ -106,11 +106,31 @@ void SetScriptableObjectProperty( v8::Local context = state->GetContext(); bool instance_has_property; bool holder_has_property; +#if BUILDFLAG(IS_TIZEN_TV) + if (!info.Holder() + ->Has(state->GetContext(), v8_name) + .To(&holder_has_property) || + holder_has_property) { + // hbbtv uses Object.defineProperties to add attribututes to the + // scriptable object. Need to set these properties here. + if (!instance + ->HasOwnProperty(info.GetIsolate()->GetCurrentContext(), v8_name) + .To(&instance_has_property) || + instance_has_property) { + [[maybe_unused]] v8::Maybe unused = + instance->Set(info.GetIsolate()->GetCurrentContext(), v8_name, value); + + V8SetReturnValue(info, value); + } + return; + } +#else if (!instance->HasOwnProperty(context, v8_name).To(&instance_has_property) || !info.Holder()->Has(context, v8_name).To(&holder_has_property) || (!instance_has_property && holder_has_property)) { return; } +#endif // FIXME: The gTalk pepper plugin is the only plugin to make use of // SetProperty and that is being deprecated. This can be removed as soon as -- 2.7.4 From 9107378744171945e92e87c05b4cd003b673afff Mon Sep 17 00:00:00 2001 From: liuxd Date: Tue, 28 Feb 2023 14:37:33 +0800 Subject: [PATCH 12/16] [M108 Migration][VD] Fix FocusInOutCallbacks not handled issue FocusInOutCallbacks been set on RenderViewReady, and been handled on OnFocusIn/OnFocusOut. On below case, the FocusInOutCallbacks not handled. 1. open office365 word: open office365 word will CreateNewWindow, and on the process without PostRenderViewReady, cause FocusInOutCallbacks without set. So add PostRenderViewReady when CreateNewWindow. 2. open website by deeplink: ewk_view_focus_set set after PostRenderViewReady. Becasue it takes a long time from PostRenderViewReady to receiving RenderViewReady, cause EWebView receive RenderViewReady later than ewk_view_focus_set. It cause FocusInOutCallbacks set later then OnFocusIn/OnFocusOut, cause FocusInOutCallbacks not handled. So call RenderViewReady directly on PostRenderViewReady. 3. open website by window.open: ewk_view_focus_set set before RenderViewReady, It cause FocusInOutCallbacks set later then OnFocusIn/OnFocusOut, cause FocusInOutCallbacks not handled. So pending setfocus when RenderView is not Live. Refer: https://review.tizen.org/gerrit/#/c/284765 Change-Id: I591ce004f418dca05b56a22c42c7d196a3337024 Signed-off-by: liuxd --- .../browser/renderer_host/render_frame_host_impl.cc | 6 ++++++ .../browser/renderer_host/render_view_host_impl.cc | 4 ++++ tizen_src/ewk/efl_integration/eweb_view.cc | 21 +++++++++++++++++++++ tizen_src/ewk/efl_integration/eweb_view.h | 7 +++++++ 4 files changed, 38 insertions(+) diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index cf3daa1..eab33b2 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc @@ -7630,6 +7630,12 @@ void RenderFrameHostImpl::CreateNewWindow( // The mojom reply callback with kSuccess causes the renderer to create the // renderer-side objects. new_main_rfh->render_view_host()->RenderViewCreated(new_main_rfh); + +#if BUILDFLAG(IS_TIZEN_TV) + // This must be posted after the RenderViewHost is marked live, with + // `renderer_view_created_`. + new_main_rfh->render_view_host()->PostRenderViewReady(); +#endif } void RenderFrameHostImpl::CreatePortal( diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index 726013f..a406a51 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc @@ -913,8 +913,12 @@ void RenderViewHostImpl::EnablePreferredSizeMode() { } void RenderViewHostImpl::PostRenderViewReady() { +#if BUILDFLAG(IS_TIZEN_TV) + RenderViewReady(); +#else GetProcess()->PostTaskWhenProcessIsReady(base::BindOnce( &RenderViewHostImpl::RenderViewReady, weak_factory_.GetWeakPtr())); +#endif } void RenderViewHostImpl::OnGpuSwitched(gl::GpuPreference active_gpu_heuristic) { diff --git a/tizen_src/ewk/efl_integration/eweb_view.cc b/tizen_src/ewk/efl_integration/eweb_view.cc index 3503521..ae7d827 100644 --- a/tizen_src/ewk/efl_integration/eweb_view.cc +++ b/tizen_src/ewk/efl_integration/eweb_view.cc @@ -539,11 +539,32 @@ void EWebView::ResetContextMenuController() { return context_menu_.reset(); } +#if BUILDFLAG(IS_TIZEN_TV) +void EWebView::RunPendingSetFocus(Eina_Bool focus) { + if (!web_contents_ || !rwhva() || (HasFocus() == focus)) + return; + rwhva()->offscreen_helper()->Focus(focus); +} +#endif + void EWebView::SetFocus(Eina_Bool focus) { if (!web_contents_ || !rwhva() || (HasFocus() == focus)) return; +#if BUILDFLAG(IS_TIZEN_TV) + if (web_contents_->GetPrimaryMainFrame()->IsRenderFrameLive()) { + rwhva()->offscreen_helper()->Focus(focus); + + if (pending_setfocus_closure_) + pending_setfocus_closure_.Reset(); + } else { + LOG(ERROR) << "SEND DELAY SET FOCUS BIND"; + pending_setfocus_closure_ = base::BindOnce(&EWebView::RunPendingSetFocus, + base::Unretained(this), focus); + } +#else rwhva()->offscreen_helper()->Focus(focus); +#endif } Eina_Bool EWebView::HasFocus() const { diff --git a/tizen_src/ewk/efl_integration/eweb_view.h b/tizen_src/ewk/efl_integration/eweb_view.h index 6f05ceb..2a65608 100644 --- a/tizen_src/ewk/efl_integration/eweb_view.h +++ b/tizen_src/ewk/efl_integration/eweb_view.h @@ -789,6 +789,9 @@ class EWebView { void UpdateContextMenuWithParams(const content::ContextMenuParams& params); static Eina_Bool DelayedPopulateAndShowContextMenu(void* data); +#if BUILDFLAG(IS_TIZEN_TV) + void RunPendingSetFocus(Eina_Bool focus); +#endif scoped_refptr evas_event_handler_; scoped_refptr context_; @@ -944,6 +947,10 @@ class EWebView { #endif Ecore_Timer* delayed_show_context_menu_timer_ = nullptr; + +#if BUILDFLAG(IS_TIZEN_TV) + base::OnceClosure pending_setfocus_closure_; +#endif }; const unsigned int g_default_tilt_motion_sensitivity = 3; -- 2.7.4 From a7fda770bfbacd4bd7e93f833f02b694306a24eb Mon Sep 17 00:00:00 2001 From: liuxd Date: Mon, 6 Mar 2023 14:21:59 +0800 Subject: [PATCH 13/16] [M108 Migration][VD] Disable show DateTimeDialog for datetime input type Issue: click the below input type, will show black screen Solution: disable show DateTimeDialog for avoid show black screen Root Cause: Click the above datetime input type, will show DateTimeDialog. But the DateTimeDialog don't support well when CreateAndShowDateLayout, will show black screen. And we don't support show DateTimeDialog for datetime input type before. So follow as previous, don't support show DateTimeDialog. refer: https://review.tizen.org/gerrit/#/c/282731 Change-Id: Ia585744b046782061a96b490c10c8ac8718c0593 Signed-off-by: liuxd --- tizen_src/chromium_impl/content/browser/date_time_chooser_efl.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tizen_src/chromium_impl/content/browser/date_time_chooser_efl.cc b/tizen_src/chromium_impl/content/browser/date_time_chooser_efl.cc index 372ca2b..3cb6e55 100644 --- a/tizen_src/chromium_impl/content/browser/date_time_chooser_efl.cc +++ b/tizen_src/chromium_impl/content/browser/date_time_chooser_efl.cc @@ -35,10 +35,13 @@ void DateTimeChooserEfl::OpenDateTimeDialog( open_date_time_response_callback_ = std::move(callback); WebContentsImplEfl* wcie = static_cast(web_contents_); +// Don't support show DateTimeDialog for date/time input type as previos for TV. +#if !BUILDFLAG(IS_TIZEN_TV) if (wcie->GetEflDelegate()) wcie->GetEflDelegate()->OpenDateTimeDialog(value->dialog_type, value->dialog_value, this); else +#endif std::move(open_date_time_response_callback_).Run(false, ""); } -- 2.7.4 From 48a29088fe5bb26d0ea94769bdcebd8c0d98fcde Mon Sep 17 00:00:00 2001 From: Suhaspoornachandra Date: Mon, 6 Mar 2023 15:06:54 +0530 Subject: [PATCH 14/16] [M108 Migration] Support new pixel format in webrtc Support PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER and PIXEL_FORMAT_ENCODED. Reference: https://review.tizen.org/gerrit/#/c/279885 Change-Id: I30659a3c071b697ed06ff8eaf844ca82799d2b55 Signed-off-by: Suhaspoornachandra --- .../public/remoting_proto_enum_utils.cc | 3 + media/base/video_frame.cc | 92 ++++++++++++++++++++++ media/base/video_frame.h | 16 ++++ media/base/video_frame_layout.cc | 6 ++ media/base/video_types.cc | 19 +++++ media/base/video_types.h | 13 ++- media/mojo/mojom/stable/BUILD.gn | 9 +++ .../mojom/stable/stable_video_decoder_types.mojom | 7 ++ .../stable_video_decoder_types_mojom_traits.h | 26 ++++++ media/video/gpu_memory_buffer_video_frame_pool.cc | 3 + .../openscreen/src/cast/streaming/remoting.proto | 1 + 11 files changed, 192 insertions(+), 3 deletions(-) diff --git a/components/cast_streaming/public/remoting_proto_enum_utils.cc b/components/cast_streaming/public/remoting_proto_enum_utils.cc index 98af814..79b80df 100644 --- a/components/cast_streaming/public/remoting_proto_enum_utils.cc +++ b/components/cast_streaming/public/remoting_proto_enum_utils.cc @@ -374,6 +374,9 @@ absl::optional ToMediaVideoPixelFormat( CASE_RETURN_OTHER(PIXEL_FORMAT_P016LE); CASE_RETURN_OTHER(PIXEL_FORMAT_XR30); CASE_RETURN_OTHER(PIXEL_FORMAT_XB30); +#if BUILDFLAG(IS_TIZEN) + CASE_RETURN_OTHER(PIXEL_FORMAT_ENCODED); +#endif #if defined(TIZEN_TBM_SUPPORT) CASE_RETURN_OTHER(PIXEL_FORMAT_TBM_SURFACE); #endif diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc index fd0dd69..d845a3c 100644 --- a/media/base/video_frame.cc +++ b/media/base/video_frame.cc @@ -164,6 +164,9 @@ gfx::Size VideoFrame::SampleSize(VideoPixelFormat format, size_t plane) { case PIXEL_FORMAT_YUV420P12: case PIXEL_FORMAT_P016LE: case PIXEL_FORMAT_YUV420AP10: +#if defined(TIZEN_TBM_SUPPORT) + case PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER: +#endif return gfx::Size(2, 2); case PIXEL_FORMAT_UYVY: @@ -179,6 +182,9 @@ gfx::Size VideoFrame::SampleSize(VideoPixelFormat format, size_t plane) { case PIXEL_FORMAT_XB30: case PIXEL_FORMAT_BGRA: case PIXEL_FORMAT_RGBAF16: +#if BUILDFLAG(IS_TIZEN) + case PIXEL_FORMAT_ENCODED: +#endif #if defined(TIZEN_TBM_SUPPORT) case PIXEL_FORMAT_TBM_SURFACE: #endif @@ -215,8 +221,12 @@ static bool RequiresEvenSizeAllocation(VideoPixelFormat format) { case PIXEL_FORMAT_XB30: case PIXEL_FORMAT_BGRA: case PIXEL_FORMAT_RGBAF16: +#if BUILDFLAG(IS_TIZEN) + case PIXEL_FORMAT_ENCODED: +#endif #if defined(TIZEN_TBM_SUPPORT) case PIXEL_FORMAT_TBM_SURFACE: + case PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER: #endif return false; case PIXEL_FORMAT_NV12: @@ -400,6 +410,38 @@ scoped_refptr VideoFrame::WrapTBMSurface( frame->buffer_handle_ = handle; return frame; } + +#if BUILDFLAG(IS_TIZEN_TV) +scoped_refptr VideoFrame::WrapTBMInterProcessBuffer( + const gfx::Size& size, + base::TimeDelta timestamp, + gfx::TbmBufferHandle handle) { + const VideoPixelFormat format = PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER; +#if defined(TIZEN_VIDEO_HOLE) + const StorageType storage = STORAGE_HOLE; +#else + const StorageType storage = STORAGE_UNKNOWN; +#endif + const gfx::Rect visible_rect = gfx::Rect(size); + if (!IsValidConfig(format, storage, size, visible_rect, size)) { + DLOG(ERROR) << __FUNCTION__ << " WrapTBMInterProcessBuffer Invalid config." + << ConfigToString(format, storage, size, visible_rect, size); + return nullptr; + } + + auto layout = VideoFrameLayout::CreateWithStrides( + format, size, {handle.strides[0], handle.strides[1]}); + if (!layout) { + DLOG(ERROR) << "Invalid layout."; + return nullptr; + } + + scoped_refptr frame( + new VideoFrame(*layout, storage, gfx::Rect(size), size, timestamp)); + frame->buffer_handle_ = handle; + return frame; +} +#endif #endif // static @@ -960,6 +1002,13 @@ scoped_refptr VideoFrame::WrapVideoFrame( frame = frame->wrapped_frame_; } +#if defined(TIZEN_TBM_SUPPORT) + if (frame->format() == PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER || + frame->format() == PIXEL_FORMAT_TBM_SURFACE) { + wrapping_frame->buffer_handle_ = frame->buffer_handle_; + } +#endif + wrapping_frame->wrapped_frame_ = std::move(frame); return wrapping_frame; } @@ -1111,6 +1160,9 @@ int VideoFrame::BytesPerElement(VideoPixelFormat format, size_t plane) { case PIXEL_FORMAT_XBGR: case PIXEL_FORMAT_XR30: case PIXEL_FORMAT_XB30: +#if BUILDFLAG(IS_TIZEN) + case PIXEL_FORMAT_ENCODED: +#endif return 4; case PIXEL_FORMAT_RGB24: return 3; @@ -1130,6 +1182,9 @@ int VideoFrame::BytesPerElement(VideoPixelFormat format, size_t plane) { case PIXEL_FORMAT_YUV422AP10: case PIXEL_FORMAT_YUV444AP10: return 2; +#if defined(TIZEN_TBM_SUPPORT) + case PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER: +#endif case PIXEL_FORMAT_NV12: case PIXEL_FORMAT_NV21: { static const int bytes_per_element[] = {1, 2}; @@ -1321,6 +1376,29 @@ T VideoFrame::GetVisibleDataInternal(T data, size_t plane) const { const gfx::Size subsample = SampleSize(format(), plane); DCHECK(offset.x() % subsample.width() == 0); DCHECK(offset.y() % subsample.height() == 0); + +#if defined(TIZEN_TBM_SUPPORT) + const VideoPixelFormat fmt = format(); + if (PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER == fmt) { + if (!bufmgr_) + bufmgr_ = tbm_bufmgr_init(-1); + { + base::AutoLock autolock(tbm_map_lock_); + if (!vp_[plane]) { + bo_[plane] = tbm_bo_import(bufmgr_, buffer_handle_.key[plane]); + bo_handle_[plane] = + tbm_bo_map(bo_[plane], TBM_DEVICE_CPU, TBM_OPTION_READ); + + vp_[plane] = + (uint8_t*)bo_handle_[plane].ptr + + stride(plane) * (offset.y() / subsample.height()) + // Row offset. + BytesPerElement(format(), plane) * // Column offset. + (offset.x() / subsample.width()); + } + } + return vp_[plane]; + } +#endif return data + stride(plane) * (offset.y() / subsample.height()) + // Row offset. BytesPerElement(format(), plane) * // Column offset. @@ -1480,6 +1558,9 @@ VideoFrame::VideoFrame(const VideoFrameLayout& layout, << coded_size().ToString(); memset(&mailbox_holders_, 0, sizeof(mailbox_holders_)); memset(&data_, 0, sizeof(data_)); +#if defined(TIZEN_TBM_SUPPORT) + memset(bo_handle_, 0, sizeof(tbm_bo_handle) * TBM_BO_NUM_MAX); +#endif } VideoFrame::~VideoFrame() { @@ -1497,6 +1578,17 @@ VideoFrame::~VideoFrame() { for (auto& callback : done_callbacks_) std::move(callback).Run(); + +#if defined(TIZEN_TBM_SUPPORT) + for (int i = 0; i < TBM_BO_NUM_MAX; i++) { + if (bo_handle_[i].ptr) { + if (!tbm_bo_unmap(bo_[i])) + LOG(WARNING) << "unmap bo failed!"; + tbm_bo_unref(bo_[i]); + bo_handle_[i].ptr = nullptr; + } + } +#endif } // static diff --git a/media/base/video_frame.h b/media/base/video_frame.h index b856464..224802f 100644 --- a/media/base/video_frame.h +++ b/media/base/video_frame.h @@ -67,7 +67,9 @@ class GLES2Interface; namespace media { +#if defined(TIZEN_TBM_SUPPORT) constexpr auto TBM_BO_NUM_MAX = 4; +#endif class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe { public: @@ -357,6 +359,12 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe { const gfx::Size& natural_size); #if defined(TIZEN_TBM_SUPPORT) +#if BUILDFLAG(IS_TIZEN_TV) + static scoped_refptr WrapTBMInterProcessBuffer( + const gfx::Size& size, + base::TimeDelta timestamp, + gfx::TbmBufferHandle handle); +#endif // Needed when we have video-frame content in tbm surface. static scoped_refptr WrapTBMSurface(const gfx::Size& size, base::TimeDelta timestamp, @@ -834,6 +842,14 @@ class MEDIA_EXPORT VideoFrame : public base::RefCountedThreadSafe { gpu::gles2::GLES2Interface* gl_; unsigned image_id_; scoped_refptr context_provider_; + + mutable tbm_bo bo_[TBM_BO_NUM_MAX] = {nullptr}; + mutable tbm_bo_handle bo_handle_[TBM_BO_NUM_MAX] = { + {nullptr}, + }; + mutable tbm_key key_[TBM_BO_NUM_MAX] = {0}; + mutable uint8_t* vp_[TBM_BO_NUM_MAX] = {nullptr}; + mutable tbm_bufmgr bufmgr_ = {nullptr}; #endif base::TimeDelta timestamp_; diff --git a/media/base/video_frame_layout.cc b/media/base/video_frame_layout.cc index 47bbbffa..760f945 100644 --- a/media/base/video_frame_layout.cc +++ b/media/base/video_frame_layout.cc @@ -56,10 +56,16 @@ size_t VideoFrameLayout::NumPlanes(VideoPixelFormat format) { case PIXEL_FORMAT_XR30: case PIXEL_FORMAT_XB30: case PIXEL_FORMAT_RGBAF16: +#if BUILDFLAG(IS_TIZEN) + case PIXEL_FORMAT_ENCODED: +#endif return 1; case PIXEL_FORMAT_NV12: case PIXEL_FORMAT_NV21: case PIXEL_FORMAT_P016LE: +#if defined(TIZEN_TBM_SUPPORT) + case PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER: +#endif return 2; case PIXEL_FORMAT_I420: case PIXEL_FORMAT_YV12: diff --git a/media/base/video_types.cc b/media/base/video_types.cc index 4edcc27..f506483 100644 --- a/media/base/video_types.cc +++ b/media/base/video_types.cc @@ -85,9 +85,15 @@ std::string VideoPixelFormatToString(VideoPixelFormat format) { return "PIXEL_FORMAT_YUV422AP10"; case PIXEL_FORMAT_YUV444AP10: return "PIXEL_FORMAT_YUV444AP10"; +#if BUILDFLAG(IS_TIZEN) + case PIXEL_FORMAT_ENCODED: + return "PIXEL_FORMAT_ENCODED"; +#endif #if defined(TIZEN_TBM_SUPPORT) case PIXEL_FORMAT_TBM_SURFACE: return "PIXEL_FORMAT_TBM_SURFACE"; + case PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER: + return "PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER"; #endif } NOTREACHED() << "Invalid VideoPixelFormat provided: " << format; @@ -149,6 +155,9 @@ bool IsYuvPlanar(VideoPixelFormat format) { case PIXEL_FORMAT_YUV420AP10: case PIXEL_FORMAT_YUV422AP10: case PIXEL_FORMAT_YUV444AP10: +#if defined(TIZEN_TBM_SUPPORT) + case PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER: +#endif return true; case PIXEL_FORMAT_UNKNOWN: @@ -165,6 +174,9 @@ bool IsYuvPlanar(VideoPixelFormat format) { case PIXEL_FORMAT_XB30: case PIXEL_FORMAT_BGRA: case PIXEL_FORMAT_RGBAF16: +#if BUILDFLAG(IS_TIZEN) + case PIXEL_FORMAT_ENCODED: +#endif #if defined(TIZEN_TBM_SUPPORT) case PIXEL_FORMAT_TBM_SURFACE: #endif @@ -248,6 +260,7 @@ bool IsOpaque(VideoPixelFormat format) { case PIXEL_FORMAT_XB30: #if defined(TIZEN_TBM_SUPPORT) case PIXEL_FORMAT_TBM_SURFACE: + case PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER: #endif return true; case PIXEL_FORMAT_I420A: @@ -260,6 +273,9 @@ bool IsOpaque(VideoPixelFormat format) { case PIXEL_FORMAT_YUV420AP10: case PIXEL_FORMAT_YUV422AP10: case PIXEL_FORMAT_YUV444AP10: +#if BUILDFLAG(IS_TIZEN) + case PIXEL_FORMAT_ENCODED: +#endif break; } return false; @@ -291,6 +307,9 @@ size_t BitDepth(VideoPixelFormat format) { case PIXEL_FORMAT_BGRA: case PIXEL_FORMAT_I422A: case PIXEL_FORMAT_I444A: +#if defined(TIZEN_TBM_SUPPORT) + case PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER: +#endif return 8; case PIXEL_FORMAT_YUV420P9: case PIXEL_FORMAT_YUV422P9: diff --git a/media/base/video_types.h b/media/base/video_types.h index d7dad6d..c6b3709 100644 --- a/media/base/video_types.h +++ b/media/base/video_types.h @@ -89,13 +89,20 @@ enum VideoPixelFormat { PIXEL_FORMAT_YUV444AP10 = 38, // Please update UMA histogram enumeration when adding new formats here. +#if BUILDFLAG(IS_TIZEN) + PIXEL_FORMAT_ENCODED = 39, // encoded pixels, 1 plane #if defined(TIZEN_TBM_SUPPORT) - PIXEL_FORMAT_TBM_SURFACE = 39, - PIXEL_FORMAT_MAX = PIXEL_FORMAT_TBM_SURFACE, + PIXEL_FORMAT_TBM_SURFACE = 40, + PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER = 41, + PIXEL_FORMAT_MAX = PIXEL_FORMAT_TBM_INTER_PROCESS_BUFFER, +#else + PIXEL_FORMAT_MAX = + PIXEL_FORMAT_ENCODED, // Must always be equal to largest entry logged. +#endif // defined(TIZEN_TBM_SUPPORT) #else PIXEL_FORMAT_MAX = PIXEL_FORMAT_YUV444AP10, // Must always be equal to largest entry logged. -#endif +#endif // defined(OS_TIZEN) }; // These values are persisted to logs. Entries should not be renumbered and diff --git a/media/mojo/mojom/stable/BUILD.gn b/media/mojo/mojom/stable/BUILD.gn index 205688b..2cfd7dd 100644 --- a/media/mojo/mojom/stable/BUILD.gn +++ b/media/mojo/mojom/stable/BUILD.gn @@ -4,6 +4,9 @@ import("//media/gpu/args.gni") import("//mojo/public/tools/bindings/mojom.gni") +if (use_efl) { + import("//tizen_src/build/config/tizen_features.gni") +} mojom("stable_video_decoder") { generate_java = true @@ -17,6 +20,12 @@ mojom("stable_video_decoder") { if (is_linux || is_chromeos_ash) { enabled_features += [ "is_linux_or_chromeos_ash" ] } + if (is_tizen) { + enabled_features += [ "is_tizen" ] + } + if (tizen_tbm_support) { + enabled_features += [ "tizen_tbm_support" ] + } public_deps = [ ":native_pixmap_handle", diff --git a/media/mojo/mojom/stable/stable_video_decoder_types.mojom b/media/mojo/mojom/stable/stable_video_decoder_types.mojom index 02acd4e..637b44e 100644 --- a/media/mojo/mojom/stable/stable_video_decoder_types.mojom +++ b/media/mojo/mojom/stable/stable_video_decoder_types.mojom @@ -400,6 +400,13 @@ enum VideoPixelFormat { [MinVersion=1] kPixelFormatYUV420AP10 = 36, [MinVersion=1] kPixelFormatYUV422AP10 = 37, [MinVersion=1] kPixelFormatYUV444AP10 = 38, + + [EnableIf=is_tizen] kPixelFormatEncoded = 39, + + [EnableIf=tizen_tbm_support] kPixelFormatTbmSurface = 40, + + [EnableIf=tizen_tbm_support] kPixelFormatTbmInterProcessBuffer=41, + }; // Based on |media.mojom.EosVideoFrameData|. diff --git a/media/mojo/mojom/stable/stable_video_decoder_types_mojom_traits.h b/media/mojo/mojom/stable/stable_video_decoder_types_mojom_traits.h index 358f5c2..dbeac05 100644 --- a/media/mojo/mojom/stable/stable_video_decoder_types_mojom_traits.h +++ b/media/mojo/mojom/stable/stable_video_decoder_types_mojom_traits.h @@ -1313,6 +1313,17 @@ struct EnumTraits Date: Tue, 14 Feb 2023 21:24:55 -0800 Subject: [PATCH 15/16] [M108 Migration][MM][HBBTV] Check HLS to enable url demuxer. FFmpeg demuxer is not available for Http Live Streaming contents. Therefore, I modified to use url demuxer for HLS by referring to the existing android code. Reference: https://review.tizen.org/gerrit/#/c/288322/ Change-Id: I6827d16c8f298748743779ac4cb78957cb46ffdb Signed-off-by: Sun-woo Nam --- media/filters/ffmpeg_demuxer.cc | 2 +- .../platform/media/web_media_player_impl.cc | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc index 76661fc..f2c89c2 100644 --- a/media/filters/ffmpeg_demuxer.cc +++ b/media/filters/ffmpeg_demuxer.cc @@ -1237,7 +1237,7 @@ void FFmpegDemuxer::OnOpenContextDone(bool result) { return; } -#if BUILDFLAG(IS_ANDROID) +#if BUILDFLAG(IS_ANDROID) || defined(TIZEN_MULTIMEDIA) if (glue_->detected_hls()) { MEDIA_LOG(INFO, media_log_) << GetDisplayName() << ": detected HLS manifest"; diff --git a/third_party/blink/renderer/platform/media/web_media_player_impl.cc b/third_party/blink/renderer/platform/media/web_media_player_impl.cc index 8808a01..a61dad6 100644 --- a/third_party/blink/renderer/platform/media/web_media_player_impl.cc +++ b/third_party/blink/renderer/platform/media/web_media_player_impl.cc @@ -1938,14 +1938,18 @@ void WebMediaPlayerImpl::OnError(media::PipelineStatus status) { if (suppress_destruction_errors_) return; -#if BUILDFLAG(IS_ANDROID) +#if BUILDFLAG(IS_ANDROID) || defined(TIZEN_MULTIMEDIA) // `mb_data_source_` may be nullptr if someone passes in a m3u8 as a data:// // URL, since MediaPlayer doesn't support data:// URLs, fail playback now. - const bool found_hls = base::FeatureList::IsEnabled(media::kHlsPlayer) && - status == media::DEMUXER_ERROR_DETECTED_HLS; + const bool found_hls = +#if BUILDFLAG(IS_ANDROID) + base::FeatureList::IsEnabled(media::kHlsPlayer) && +#endif + status == media::DEMUXER_ERROR_DETECTED_HLS; if (found_hls && mb_data_source_) { demuxer_found_hls_ = true; +#if BUILDFLAG(IS_ANDROID) if (observer_) observer_->OnHlsManifestDetected(); @@ -1979,6 +1983,7 @@ void WebMediaPlayerImpl::OnError(media::PipelineStatus status) { renderer_factory_selector_->SetBaseRendererType( media::RendererType::kMediaPlayer); +#endif loaded_url_ = mb_data_source_->GetUrlAfterRedirects(); DCHECK(data_source_); @@ -2021,7 +2026,7 @@ void WebMediaPlayerImpl::OnError(media::PipelineStatus status) { ScheduleRestart(); return; } -#endif // BUILDFLAG(IS_ANDROID) +#endif // BUILDFLAG(IS_ANDROID) || defined(TIZEN_MULTIMEDIA) MaybeSetContainerNameForMetrics(); simple_watch_timer_.Stop(); @@ -3004,6 +3009,15 @@ void WebMediaPlayerImpl::StartPipeline() { demuxer_.get(), this, false, false); return; } +#elif defined(TIZEN_MULTIMEDIA) + if (demuxer_found_hls_) { + SetDemuxer(std::make_unique( + media_task_runner_, loaded_url_, frame_->GetDocument().SiteForCookies(), + frame_->GetDocument().TopFrameOrigin(), true, demuxer_found_hls_)); + pipeline_controller_->Start(media::Pipeline::StartType::kNormal, + demuxer_.get(), this, false, false); + return; + } #endif // BUILDFLAG(IS_ANDROID) // Figure out which demuxer to use. -- 2.7.4 From 1420a5b55f8391786b3e467e7b9620e7aa5e636a Mon Sep 17 00:00:00 2001 From: Sun-woo Nam Date: Thu, 9 Mar 2023 22:35:08 -0800 Subject: [PATCH 16/16] [M108 Migration][MM] Prevent suspend and release a player during prolonged pause. If a player pauses for 15 seconds, it becomes a 'stale' state. The stale players is suspended and released, but it causes unexpected behavior such as black screen. This patch therefore doesn't suspend the stale players. Reference: https://review.tizen.org/gerrit/#/c/276980/ https://review.tizen.org/gerrit/#/c/277231/ Change-Id: I9190275c60a5c0b66b583ca75cd7e8132a37bc58 Signed-off-by: Sun-woo Nam --- .../ewk/efl_integration/renderer/content_renderer_client_efl.cc | 7 +++++++ .../ewk/efl_integration/renderer/content_renderer_client_efl.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/tizen_src/ewk/efl_integration/renderer/content_renderer_client_efl.cc b/tizen_src/ewk/efl_integration/renderer/content_renderer_client_efl.cc index 56d5447..e54c574 100644 --- a/tizen_src/ewk/efl_integration/renderer/content_renderer_client_efl.cc +++ b/tizen_src/ewk/efl_integration/renderer/content_renderer_client_efl.cc @@ -320,3 +320,10 @@ std::unique_ptr ContentRendererClientEfl::OverrideDemuxerForUrl( } return nullptr; } + +#if defined(TIZEN_MULTIMEDIA) +bool ContentRendererClientEfl::IsIdleMediaSuspendEnabled() { + LOG(INFO) << __func__ << ", Disable idle media suspend : return false"; + return false; +} +#endif diff --git a/tizen_src/ewk/efl_integration/renderer/content_renderer_client_efl.h b/tizen_src/ewk/efl_integration/renderer/content_renderer_client_efl.h index 2067164..9d0b969 100644 --- a/tizen_src/ewk/efl_integration/renderer/content_renderer_client_efl.h +++ b/tizen_src/ewk/efl_integration/renderer/content_renderer_client_efl.h @@ -95,6 +95,10 @@ class ContentRendererClientEfl : public content::ContentRendererClient { const GURL& url, scoped_refptr task_runner) override; +#if defined(TIZEN_MULTIMEDIA) + bool IsIdleMediaSuspendEnabled() override; +#endif + bool shutting_down() const { return shutting_down_; } void set_shutting_down(bool shutting_down) { shutting_down_ = shutting_down; } -- 2.7.4