diff --git a/core/renderer/dom/element.cc b/core/renderer/dom/element.cc index 1ee2c9b001..598841e58f 100644 --- a/core/renderer/dom/element.cc +++ b/core/renderer/dom/element.cc @@ -747,7 +747,8 @@ void Element::ResetAttribute(const base::String& key) { if (auto fragment = fragment_impl()) { if (name == PlatformEventPropName::kEventThrough || name == PlatformEventPropName::kEventThroughActiveRegions || - name == PlatformEventPropName::kEventsPassThrough) { + name == PlatformEventPropName::kEventsPassThrough || + name == PlatformEventPropName::kIgnoreFocus) { fragment->SetEventProp(name, lepus::Value()); } else { fragment->SetEventProp(name, lepus::Value(0)); diff --git a/core/renderer/dom/fragment/event/platform_event_bundle.h b/core/renderer/dom/fragment/event/platform_event_bundle.h index dae559de27..82c7986701 100644 --- a/core/renderer/dom/fragment/event/platform_event_bundle.h +++ b/core/renderer/dom/fragment/event/platform_event_bundle.h @@ -189,6 +189,7 @@ enum class PlatformEventPropName : int32_t { kEventThrough = 16, kEventThroughActiveRegions = 17, kEventsPassThrough = 18, + kIgnoreFocus = 19, }; inline PlatformEventPropName PlatformEventPropNameFromString( @@ -250,6 +251,9 @@ inline PlatformEventPropName PlatformEventPropNameFromString( if (name == "events-pass-through") { return PlatformEventPropName::kEventsPassThrough; } + if (name == "ignore-focus") { + return PlatformEventPropName::kIgnoreFocus; + } return PlatformEventPropName::kUnknown; } @@ -312,6 +316,9 @@ inline std::string_view PlatformEventPropNameToString( if (name == PlatformEventPropName::kEventsPassThrough) { return "events-pass-through"; } + if (name == PlatformEventPropName::kIgnoreFocus) { + return "ignore-focus"; + } return ""; } diff --git a/core/renderer/dom/fragment/event/platform_event_handler.cc b/core/renderer/dom/fragment/event/platform_event_handler.cc index 292fcc1924..e66b2725c5 100644 --- a/core/renderer/dom/fragment/event/platform_event_handler.cc +++ b/core/renderer/dom/fragment/event/platform_event_handler.cc @@ -47,7 +47,6 @@ bool PlatformEventHandler::OnInputEvent( fml::RefPtr target_tree, int int_event_data[], float float_event_data[]) { target_tree_ = target_tree; - event_handler_state_ = kStateNone; // int_event_data: [event_type, action_type, event_source, pointer_count, ...] int event_type = int_event_data[0]; switch (event_type) { @@ -85,20 +84,18 @@ bool PlatformEventHandler::OnInputEvent( } if (EventThrough()) { LOGI("PlatformEventHandler::OnInputEvent EventThrough") - event_handler_state_ = kStateEventThrough; return false; } // TODO(hexionghui): forward event to gesture. - event_handler_state_ = kStateNone; return true; } void PlatformEventHandler::OnTap() { float root_point[2] = {first_pointer_down_point_[0], first_pointer_down_point_[1]}; - if (!first_pointer_moved_ && CanRespondTap(first_target_)) { + if (CanRespondFocus()) { DispatchGestureEvent(EVENT_TAP, root_point); } auto click_target = @@ -156,22 +153,6 @@ void PlatformEventHandler::DispatchPointerEvent( platform_ref_->GetEventEmitter()->SendEvent(first_target_->Sign(), event); } -void PlatformEventHandler::OnGestureRecognized(int sign) { - gesture_recognized_target_set_.insert(sign); -} - -void PlatformEventHandler::SetFocusedTarget( - fml::RefPtr focused_target) { - focused_target_ = focused_target; -} - -void PlatformEventHandler::UnsetFocusedTarget( - fml::RefPtr focused_target) { - if (focused_target_ == focused_target) { - focused_target_ = nullptr; - } -} - bool PlatformEventHandler::EventThrough() { if (!first_target_) { return false; @@ -182,8 +163,6 @@ bool PlatformEventHandler::EventThrough() { return first_target_->EventThrough(target_point); } -int PlatformEventHandler::EventHandlerState() { return event_handler_state_; } - void PlatformEventHandler::SetTapSlop(const std::string& tap_slop) {} void PlatformEventHandler::SetLongPressDuration(int32_t long_press_duration) {} @@ -205,8 +184,14 @@ void PlatformEventHandler::InitPointerEnv(PlatformPointerEvent& event) { (hit_target ? std::to_string(hit_target->Sign()) : "null")) float down_point[2] = {pointer_x, pointer_y}; if (pointer_id == 0) { + ResetFocusInfo(); first_target_ = hit_target; memcpy(first_pointer_down_point_, down_point, sizeof(float) * 2); + if (hit_target != nullptr) { + hit_target_sign_ = hit_target->Sign(); + renderer_host_sign_ = hit_target->RendererHostSign(); + ignore_focus_ = hit_target->IgnoreFocus(); + } } target_pointer_map_.insert_or_assign( pointer_id, PlatformEventTargetDetail(hit_target, down_point)); @@ -315,7 +300,6 @@ void PlatformEventHandler::OnPointerDown(PlatformPointerEvent& event) { int num = event.PointerCount(); for (int i = 0; i < num; ++i) { if (event.PointerID()[i] == 0) { - gesture_recognized_target_set_.clear(); event_target_chain_.clear(); first_pointer_moved_ = false; first_pointer_outside_ = false; @@ -383,7 +367,6 @@ void PlatformEventHandler::OnPointerUp(PlatformPointerEvent& event) { for (int i = 0; i < num; ++i) { if (event.PointerID()[i] == 0) { ResetClickEnv(); - UpdateFocusedTarget(); DeactivatePseudoStatus(LynxPseudoStatus::kAll); break; } @@ -396,7 +379,6 @@ void PlatformEventHandler::OnPointerCancel(PlatformPointerEvent& event) { if (event.PointerID()[i] == 0) { ResetClickEnv(); scroll_offset_for_tap_.clear(); - UpdateFocusedTarget(); DeactivatePseudoStatus(LynxPseudoStatus::kAll); break; } @@ -450,17 +432,14 @@ fml::RefPtr PlatformEventHandler::FindTarget( return target_tree_->HitTest(point); } -void PlatformEventHandler::UpdateFocusedTarget() { - if (first_target_ && !first_target_->IgnoreFocus()) { - if (focused_target_) { - if (focused_target_ != first_target_) { - focused_target_->OnFocusChange(false, first_target_->Focusable()); - } - } - first_target_->OnFocusChange( - true, focused_target_ && focused_target_->Focusable()); - focused_target_ = first_target_; - } +void PlatformEventHandler::ResetFocusInfo() { + hit_target_sign_ = -1; + renderer_host_sign_ = -1; + ignore_focus_ = false; +} + +bool PlatformEventHandler::CanRespondFocus() { + return !first_pointer_moved_ && CanRespondTap(first_target_); } bool PlatformEventHandler::CanRespondTap( @@ -471,18 +450,6 @@ bool PlatformEventHandler::CanRespondTap( if (HasScrollContainerScrolledForTap()) { return false; } - if (gesture_recognized_target_set_.empty()) { - return true; - } - - while (target && target->ParentTarget() != target) { - if (gesture_recognized_target_set_.find(target->Sign()) != - gesture_recognized_target_set_.end()) { - // it means that a node in the event response chain is scrolling. - return false; - } - target = target->ParentTarget(); - } return true; } diff --git a/core/renderer/dom/fragment/event/platform_event_handler.h b/core/renderer/dom/fragment/event/platform_event_handler.h index 844ab23d8e..eff426e4d1 100644 --- a/core/renderer/dom/fragment/event/platform_event_handler.h +++ b/core/renderer/dom/fragment/event/platform_event_handler.h @@ -10,7 +10,6 @@ #include #include #include -#include #include #include "core/renderer/dom/fragment/event/platform_event_target.h" @@ -24,11 +23,6 @@ class NativePaintingCtxPlatformRef; class PlatformEventHandler { public: - enum EventHandlerState { - kStateNone = 0, - kStateEventThrough = 1, - }; - class PlatformEventTargetDetail { public: PlatformEventTargetDetail(fml::RefPtr target, @@ -57,12 +51,11 @@ class PlatformEventHandler { void DispatchPointerEvent(const std::string& name, const lepus::Value& target_pointer_map); - void OnGestureRecognized(int sign); - void SetFocusedTarget(fml::RefPtr focused_target); - void UnsetFocusedTarget(fml::RefPtr focused_target); - bool EventThrough(); - int EventHandlerState(); + int32_t HitTargetSign() const { return hit_target_sign_; } + int32_t RendererHostSign() const { return renderer_host_sign_; } + bool IgnoreFocus() const { return ignore_focus_; } + bool CanRespondFocus(); void SetTapSlop(const std::string& tap_slop); void SetLongPressDuration(int32_t long_press_duration); @@ -88,7 +81,7 @@ class PlatformEventHandler { void DispatchGestureEvent(const std::string& name, float root_point[2]); fml::RefPtr FindTarget(float pointer_x, float pointer_y); - void UpdateFocusedTarget(); + void ResetFocusInfo(); bool CanRespondTap(fml::RefPtr target); void ActivePseudoStatus(); void DeactivatePseudoStatus(LynxPseudoStatus status); @@ -102,15 +95,15 @@ class PlatformEventHandler { NativePaintingCtxPlatformRef* platform_ref_{nullptr}; // state - int event_handler_state_{kStateNone}; fml::RefPtr target_tree_{nullptr}; fml::RefPtr first_target_{nullptr}; - fml::RefPtr focused_target_{nullptr}; std::vector> event_target_chain_; std::deque> click_target_chain_; std::unordered_map target_pointer_map_; - std::unordered_set gesture_recognized_target_set_; std::unordered_map> scroll_offset_for_tap_; + int32_t hit_target_sign_{-1}; + int32_t renderer_host_sign_{-1}; + bool ignore_focus_{false}; bool has_pointer_moved_{false}; bool first_pointer_moved_{false}; bool first_pointer_outside_{false}; diff --git a/core/renderer/dom/fragment/event/platform_event_target.cc b/core/renderer/dom/fragment/event/platform_event_target.cc index 820080531c..fd798a4efa 100644 --- a/core/renderer/dom/fragment/event/platform_event_target.cc +++ b/core/renderer/dom/fragment/event/platform_event_target.cc @@ -264,11 +264,6 @@ void PlatformEventTarget::OffResponseChain() {} bool PlatformEventTarget::IsOnResponseChain() const { return false; } -void PlatformEventTarget::OnFocusChange(bool has_focus, - bool is_focus_transition) {} - -bool PlatformEventTarget::Focusable() const { return true; } - void PlatformEventTarget::OnPseudoStatusChanged( LynxPseudoStatus pre_status, LynxPseudoStatus current_status) {} @@ -337,7 +332,26 @@ float PlatformEventTarget::ConvertEventThroughSizeValue( return value.value; } -bool PlatformEventTarget::IgnoreFocus() const { return false; } +bool PlatformEventTarget::IgnoreFocus() const { + if (ignore_focus_ == LynxEventPropStatus::kEnable) { + return true; + } + if (ignore_focus_ == LynxEventPropStatus::kDisable) { + return false; + } + + // An event root does not inherit ignore-focus from another event root. A + // descendant may only inherit from a parent in the same event target tree. + if (IsRoot()) { + return false; + } + auto parent = ParentTarget(); + if (parent == nullptr || parent.get() == this || + parent->RootId() != RootId()) { + return false; + } + return parent->IgnoreFocus(); +} LynxPointerEventsValue PlatformEventTarget::PointerEvents() const { return LynxPointerEventsValue::kAuto; diff --git a/core/renderer/dom/fragment/event/platform_event_target.h b/core/renderer/dom/fragment/event/platform_event_target.h index 5397c5872c..1da26772fa 100644 --- a/core/renderer/dom/fragment/event/platform_event_target.h +++ b/core/renderer/dom/fragment/event/platform_event_target.h @@ -103,6 +103,7 @@ class PlatformEventTarget int32_t RootId() const { return root_id_; } int32_t Sign() const { return sign_; } + int32_t RendererHostSign() const { return renderer_host_sign_; } float Left() const { return left_; } float Top() const { return top_; } float Width() const { return width_; } @@ -183,8 +184,6 @@ class PlatformEventTarget void OffResponseChain(); bool IsOnResponseChain() const; - void OnFocusChange(bool has_focus, bool is_focus_transition); - bool Focusable() const; void OnPseudoStatusChanged(LynxPseudoStatus pre_status, LynxPseudoStatus current_status); LynxPseudoStatus GetPseudoStatus() const; @@ -241,6 +240,7 @@ class PlatformEventTarget void SetPlatformRendererType(PlatformRendererType type) { platform_renderer_type_ = type; } + void SetRendererHostSign(int32_t sign) { renderer_host_sign_ = sign; } void SetScrollContainer(bool is_scroll_container) { is_scroll_container_ = is_scroll_container; } @@ -258,6 +258,7 @@ class PlatformEventTarget void SetEventsPassThrough(LynxEventPropStatus value) { events_pass_through_ = value; } + void SetIgnoreFocus(LynxEventPropStatus value) { ignore_focus_ = value; } private: void UpdateScrollOffsetIfNeeded(); @@ -275,6 +276,7 @@ class PlatformEventTarget // target props int32_t root_id_; int32_t sign_; + int32_t renderer_host_sign_{-1}; float left_{0.f}; float top_{0.f}; float width_{0.f}; @@ -305,6 +307,7 @@ class PlatformEventTarget LynxEventPropStatus enable_exposure_ui_clip_{LynxEventPropStatus::kUndefined}; LynxEventPropStatus event_through_{LynxEventPropStatus::kUndefined}; LynxEventPropStatus events_pass_through_{LynxEventPropStatus::kUndefined}; + LynxEventPropStatus ignore_focus_{LynxEventPropStatus::kUndefined}; std::vector event_through_active_regions_; std::string id_selector_; std::string exposure_id_; diff --git a/core/renderer/dom/fragment/event/platform_event_target_helper.cc b/core/renderer/dom/fragment/event/platform_event_target_helper.cc index 98a757a95a..8fc0c08f19 100644 --- a/core/renderer/dom/fragment/event/platform_event_target_helper.cc +++ b/core/renderer/dom/fragment/event/platform_event_target_helper.cc @@ -145,6 +145,10 @@ void SetEventThrough(PlatformEventTarget* target, const lepus::Value& value) { target->SetEventThrough(EventPropValueToStatus(value)); } +void SetIgnoreFocus(PlatformEventTarget* target, const lepus::Value& value) { + target->SetIgnoreFocus(EventPropValueToStatus(value)); +} + bool ParseEventThroughSizeValue( const lepus::Value& value, PlatformEventTarget::EventThroughSizeValue* result) { @@ -297,6 +301,7 @@ GetEventPropSetterMap() { {PlatformEventPropName::kEventThroughActiveRegions, &SetEventThroughActiveRegions}, {PlatformEventPropName::kEventsPassThrough, &SetEventsPassThrough}, + {PlatformEventPropName::kIgnoreFocus, &SetIgnoreFocus}, }; return map; } @@ -536,6 +541,7 @@ PlatformEventTargetHelper::ReconstructEventTargetTreeRecursively( const auto type = static_cast(begin.type); auto event_target = fml::MakeRefCounted( this, tree_root_id, sign, begin.x, begin.y, begin.w, begin.h); + event_target->SetRendererHostSign(page_renderer->GetId()); event_target->SetPlatformRendererType(type); event_target->SetScrollContainer(IsScrollContainer(type, sign)); event_target->SetOverflow(begin.overflow_x != 0, begin.overflow_y != 0); diff --git a/core/renderer/ui_wrapper/painting/android/native_painting_context_android.cc b/core/renderer/ui_wrapper/painting/android/native_painting_context_android.cc index 2ab61cb3d9..4dac632274 100644 --- a/core/renderer/ui_wrapper/painting/android/native_painting_context_android.cc +++ b/core/renderer/ui_wrapper/painting/android/native_painting_context_android.cc @@ -190,12 +190,11 @@ jboolean IsPlatformEventTargetEventThrough(JNIEnv *env, jobject /*jcaller*/, : JNI_FALSE; } -jintArray GetMeaningfulPaintingAreaRecords(JNIEnv *env, jobject /*jcaller*/, - jlong nativePtr) { +jintArray GetPlatformFocusInfo(JNIEnv *env, jobject /*jcaller*/, + jlong nativePtr) { if (nativePtr == 0) { return nullptr; } - auto *context = reinterpret_cast(nativePtr); auto platform_ref = @@ -205,33 +204,39 @@ jintArray GetMeaningfulPaintingAreaRecords(JNIEnv *env, jobject /*jcaller*/, return nullptr; } - auto records = platform_ref->CollectMeaningfulPaintingAreaRecords(); - auto result = env->NewIntArray(static_cast(records.size())); - if (result == nullptr || records.empty()) { - return result; + auto focus_info = platform_ref->GetPlatformFocusInfo(); + auto result = env->NewIntArray(static_cast(focus_info.size())); + if (result == nullptr) { + return nullptr; } - env->SetIntArrayRegion(result, 0, static_cast(records.size()), - records.data()); + env->SetIntArrayRegion(result, 0, static_cast(focus_info.size()), + focus_info.data()); return result; } -jint GetPlatformEventHandlerState(JNIEnv *env, jobject /*jcaller*/, - jlong nativePtr) { - // Get the NativePaintingCtxAndroid instance from the native pointer +jintArray GetMeaningfulPaintingAreaRecords(JNIEnv *env, jobject /*jcaller*/, + jlong nativePtr) { if (nativePtr == 0) { - return 0; + return nullptr; } - lynx::tasm::NativePaintingCtxAndroid *context = + auto *context = reinterpret_cast(nativePtr); - auto platform_ref = std::static_pointer_cast( context->GetPlatformRef()); if (platform_ref == nullptr) { - return 0; + return nullptr; + } + + auto records = platform_ref->CollectMeaningfulPaintingAreaRecords(); + auto result = env->NewIntArray(static_cast(records.size())); + if (result == nullptr || records.empty()) { + return result; } - return platform_ref->GetPlatformEventHandlerState(); + env->SetIntArrayRegion(result, 0, static_cast(records.size()), + records.data()); + return result; } void Destroy(JNIEnv *env, jobject /*jcaller*/, jlong nativePtr) { diff --git a/core/renderer/ui_wrapper/painting/native_painting_context_platform_ref.cc b/core/renderer/ui_wrapper/painting/native_painting_context_platform_ref.cc index 9c18270944..e61b98acdd 100644 --- a/core/renderer/ui_wrapper/painting/native_painting_context_platform_ref.cc +++ b/core/renderer/ui_wrapper/painting/native_painting_context_platform_ref.cc @@ -235,8 +235,22 @@ bool NativePaintingCtxPlatformRef::IsPlatformEventTargetEventThrough( return hit_target->EventThrough(target_point); } -int NativePaintingCtxPlatformRef::GetPlatformEventHandlerState() { - return event_handler_->EventHandlerState(); +bool NativePaintingCtxPlatformRef::IsPlatformEventTargetIgnoreFocus( + int32_t event_target_root_id, float point_x, float point_y) { + auto event_target_tree = EnsureEventTargetTree(event_target_root_id); + if (event_target_tree == nullptr) { + return false; + } + + float root_point[2] = {point_x, point_y}; + auto hit_target = event_target_tree->HitTest(root_point); + return hit_target != nullptr && hit_target->IgnoreFocus(); +} + +std::array NativePaintingCtxPlatformRef::GetPlatformFocusInfo() { + return {event_handler_->HitTargetSign(), event_handler_->RendererHostSign(), + event_handler_->IgnoreFocus() ? 1 : 0, + event_handler_->CanRespondFocus() ? 1 : 0}; } void NativePaintingCtxPlatformRef::SendEvent(int32_t target_id, diff --git a/core/renderer/ui_wrapper/painting/native_painting_context_platform_ref.h b/core/renderer/ui_wrapper/painting/native_painting_context_platform_ref.h index 293747793b..02735beed4 100644 --- a/core/renderer/ui_wrapper/painting/native_painting_context_platform_ref.h +++ b/core/renderer/ui_wrapper/painting/native_painting_context_platform_ref.h @@ -5,6 +5,7 @@ #ifndef CORE_RENDERER_UI_WRAPPER_PAINTING_NATIVE_PAINTING_CONTEXT_PLATFORM_REF_H_ #define CORE_RENDERER_UI_WRAPPER_PAINTING_NATIVE_PAINTING_CONTEXT_PLATFORM_REF_H_ +#include #include #include #include @@ -88,9 +89,13 @@ class NativePaintingCtxPlatformRef // target lets the event pass through. bool IsPlatformEventTargetEventThrough(int32_t event_target_root_id, float point_x, float point_y); - // The current state of PlatformEventHandler is obtained to determine the - // gesture handling at the platform layer. - int GetPlatformEventHandlerState(); + // Hit-tests inside the given platform event root and returns whether the hit + // target ignores focus changes. + bool IsPlatformEventTargetIgnoreFocus(int32_t event_target_root_id, + float point_x, float point_y); + // Returns [hit target sign, renderer host sign, ignore focus, + // can respond focus] for the first pointer tracked by PlatformEventHandler. + std::array GetPlatformFocusInfo(); // Send event to the target element. void SendEvent(int32_t target_id, fml::RefPtr event); // Update the pseudo status of the target element. diff --git a/platform/android/api/lynx_android.api b/platform/android/api/lynx_android.api index 0f0df5cde5..05799aee3a 100644 --- a/platform/android/api/lynx_android.api +++ b/platform/android/api/lynx_android.api @@ -3174,8 +3174,8 @@ public interface com::lynx::tasm::behavior::IPaintingContext { public boolean com.lynx.tasm.behavior.IPaintingContext.dispatchPlatformMotionEvent(MotionEvent ev, int rootSign); public void com.lynx.tasm.behavior.IPaintingContext.dispatchPlatformLongPress(); public void com.lynx.tasm.behavior.IPaintingContext.dispatchPlatformTap(); + public void com.lynx.tasm.behavior.IPaintingContext.dispatchPlatformFocus(); public boolean com.lynx.tasm.behavior.IPaintingContext.isPlatformEventTargetEventThrough(int rootSign, float pointX, float pointY); - public int com.lynx.tasm.behavior.IPaintingContext.getPlatformEventHandlerState(); } public interface com::lynx::tasm::performance::IPerformanceObserver { @@ -8242,10 +8242,10 @@ public class com::lynx::tasm::behavior::render::NativePaintingContext : com.lynx public boolean com.lynx.tasm.behavior.render.NativePaintingContext.dispatchPlatformMotionEvent(MotionEvent ev, int rootSign); public void com.lynx.tasm.behavior.render.NativePaintingContext.dispatchPlatformLongPress(); public void com.lynx.tasm.behavior.render.NativePaintingContext.dispatchPlatformTap(); + public void com.lynx.tasm.behavior.render.NativePaintingContext.dispatchPlatformFocus(); public boolean com.lynx.tasm.behavior.render.NativePaintingContext.isPlatformEventTargetEventThrough(int rootSign, float pointX, float pointY); public void com.lynx.tasm.behavior.render.NativePaintingContext.setPlatformEventRootActive(int rootSign, boolean active); public void com.lynx.tasm.behavior.render.NativePaintingContext.setPlatformEventRootOffset(int rootSign, float offsetX, float offsetY); - public int com.lynx.tasm.behavior.render.NativePaintingContext.getPlatformEventHandlerState(); public List< MeaningfulPaintingArea > com.lynx.tasm.behavior.render.NativePaintingContext.getMeaningfulPaintingAreas(); } @@ -8619,8 +8619,8 @@ public class com::lynx::tasm::behavior::PaintingContext : com.lynx.tasm.behavior public boolean com.lynx.tasm.behavior.PaintingContext.dispatchPlatformMotionEvent(MotionEvent ev, int rootSign); public void com.lynx.tasm.behavior.PaintingContext.dispatchPlatformLongPress(); public void com.lynx.tasm.behavior.PaintingContext.dispatchPlatformTap(); + public void com.lynx.tasm.behavior.PaintingContext.dispatchPlatformFocus(); public boolean com.lynx.tasm.behavior.PaintingContext.isPlatformEventTargetEventThrough(int rootSign, float pointX, float pointY); - public int com.lynx.tasm.behavior.PaintingContext.getPlatformEventHandlerState(); public void com.lynx.tasm.behavior.PaintingContext.rebuildViewTree(); public void com.lynx.tasm.behavior.PaintingContext.updateLayout(int sign, float x, float y, float width, float height, float paddingLeft, float paddingTop, float paddingRight, float paddingBottom, float marginLeft, float marginTop, float marginRight, float marginBottom, float borderLeftWidth, float borderTopWidth, float borderRightWidth, float borderBottomWidth, float[] bounds, float[] sticky, float maxHeight, int nodeIndex, boolean displayNone); public void com.lynx.tasm.behavior.PaintingContext.updateProps(int sign, boolean tendToFlatten, PropBundle bundle, ReadableMapBuffer styles); @@ -8810,11 +8810,6 @@ public class abstract com::lynx::tasm::PlatformCallBack : { public abstract void com.lynx.tasm.PlatformCallBack.onSuccess(Object data); } -public class com::lynx::tasm::behavior::render::PlatformRendererContext::PlatformEventHandlerState : { - public final int com.lynx.tasm.behavior.render.PlatformRendererContext.PlatformEventHandlerState.kNone kNone; - public final int com.lynx.tasm.behavior.render.PlatformRendererContext.PlatformEventHandlerState.kEventThrough kEventThrough; -} - public class com::lynx::tasm::behavior::PlatformExtraBundleHolder : { public Object com.lynx.tasm.behavior.PlatformExtraBundleHolder.getBundle(int signature); public void com.lynx.tasm.behavior.PlatformExtraBundleHolder.putBundle(int signature, Object bundle); diff --git a/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/IPaintingContext.java b/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/IPaintingContext.java index a783d1ab16..f59fea6ff7 100644 --- a/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/IPaintingContext.java +++ b/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/IPaintingContext.java @@ -26,7 +26,7 @@ public interface IPaintingContext { void dispatchPlatformTap(); - boolean isPlatformEventTargetEventThrough(int rootSign, float pointX, float pointY); + void dispatchPlatformFocus(); - int getPlatformEventHandlerState(); + boolean isPlatformEventTargetEventThrough(int rootSign, float pointX, float pointY); } diff --git a/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/PaintingContext.java b/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/PaintingContext.java index 0c2106547c..c2d5abc6c7 100644 --- a/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/PaintingContext.java +++ b/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/PaintingContext.java @@ -352,13 +352,11 @@ public void dispatchPlatformLongPress() {} public void dispatchPlatformTap() {} @Override - public boolean isPlatformEventTargetEventThrough(int rootSign, float pointX, float pointY) { - return false; - } + public void dispatchPlatformFocus() {} @Override - public int getPlatformEventHandlerState() { - return 0; + public boolean isPlatformEventTargetEventThrough(int rootSign, float pointX, float pointY) { + return false; } @CalledByNative diff --git a/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/TouchEventDispatcher.java b/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/TouchEventDispatcher.java index 1a2974f0dc..631bac7f32 100644 --- a/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/TouchEventDispatcher.java +++ b/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/TouchEventDispatcher.java @@ -1234,6 +1234,7 @@ private boolean handlePlatformMotionEvent( if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { updateLongPressTimeout(); } else if (ev.getActionMasked() == MotionEvent.ACTION_UP) { + paintingContext.dispatchPlatformFocus(); paintingContext.dispatchPlatformTap(); } diff --git a/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/render/NativePaintingContext.java b/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/render/NativePaintingContext.java index d971282c18..f78df9f9ee 100644 --- a/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/render/NativePaintingContext.java +++ b/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/render/NativePaintingContext.java @@ -6,6 +6,7 @@ import android.graphics.PointF; import android.view.MotionEvent; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.lynx.tasm.behavior.BehaviorRegistry; import com.lynx.tasm.behavior.IPaintingContext; import com.lynx.tasm.behavior.LynxContext; @@ -20,6 +21,12 @@ * by the pipeline. */ public class NativePaintingContext implements IPaintingContext { + private static final int PLATFORM_FOCUS_INFO_SIZE = 4; + private static final int PLATFORM_FOCUS_TARGET_SIGN_INDEX = 0; + private static final int PLATFORM_FOCUS_RENDERER_HOST_SIGN_INDEX = 1; + private static final int PLATFORM_FOCUS_IGNORE_INDEX = 2; + private static final int PLATFORM_FOCUS_CAN_RESPOND_INDEX = 3; + private long mNativePtr = 0; @NonNull private final PlatformRendererContext mPlatformRendererContext; @@ -127,6 +134,24 @@ public void dispatchPlatformTap() { nativeDispatchPlatformTap(mNativePtr); } + @Override + public void dispatchPlatformFocus() { + if (mNativePtr == 0 || mDestroyed) { + return; + } + handlePlatformFocusInfo(nativeGetPlatformFocusInfo(mNativePtr)); + } + + void handlePlatformFocusInfo(@Nullable int[] focusInfo) { + if (focusInfo == null || focusInfo.length < PLATFORM_FOCUS_INFO_SIZE + || focusInfo[PLATFORM_FOCUS_IGNORE_INDEX] != 0 + || focusInfo[PLATFORM_FOCUS_CAN_RESPOND_INDEX] == 0) { + return; + } + mPlatformRendererContext.updatePlatformFocus(focusInfo[PLATFORM_FOCUS_TARGET_SIGN_INDEX], + focusInfo[PLATFORM_FOCUS_RENDERER_HOST_SIGN_INDEX]); + } + @Override public boolean isPlatformEventTargetEventThrough(int rootSign, float pointX, float pointY) { if (mNativePtr == 0 || mDestroyed) { @@ -164,14 +189,6 @@ public void setPlatformEventRootOffset(int rootSign, float offsetX, float offset nativeSetPlatformEventRootOffset(mNativePtr, rootSign, offsetX, offsetY); } - @Override - public int getPlatformEventHandlerState() { - if (mDestroyed || mNativePtr == 0) { - return 0; - } - return nativeGetPlatformEventHandlerState(mNativePtr); - } - public List getMeaningfulPaintingAreas() { if (mDestroyed || mNativePtr == 0) { return new ArrayList<>(); @@ -193,6 +210,8 @@ native boolean nativeDispatchPlatformInputEvent( native void nativeDispatchPlatformTap(long nativePtr); + native int[] nativeGetPlatformFocusInfo(long nativePtr); + native void nativeSetPlatformEventRootActive(long nativePtr, int rootSign, boolean active); native void nativeSetPlatformEventRootOffset( @@ -201,8 +220,6 @@ native void nativeSetPlatformEventRootOffset( native boolean nativeIsPlatformEventTargetEventThrough( long nativePtr, int rootSign, float pointX, float pointY); - native int nativeGetPlatformEventHandlerState(long nativePtr); - native void nativeDestroy(long nativePtr); native int[] nativeGetMeaningfulPaintingAreaRecords(long nativePtr); diff --git a/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/render/PlatformRendererContext.java b/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/render/PlatformRendererContext.java index 60a2e926c0..1fdd308228 100644 --- a/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/render/PlatformRendererContext.java +++ b/platform/android/lynx_android/src/main/java/com/lynx/tasm/behavior/render/PlatformRendererContext.java @@ -63,15 +63,12 @@ public static final class PlatformRendererType { public static final int kExtended = 8; } - public static final class PlatformEventHandlerState { - public static final int kNone = 0; - public static final int kEventThrough = 1; - } - WeakReference mRootView = null; HashMap mViewHolder = new HashMap<>(); + @Nullable private PlatformFocusTarget mFocusedTarget = null; + private LynxContext mContext; private BehaviorRegistry mBehaviorRegistry; private long mNativePtr = 0; @@ -451,8 +448,104 @@ private IRendererHost resolveRendererHost(@Nullable LynxBaseUI ui) { return null; } + void updatePlatformFocus(int targetSign, int rendererHostSign) { + PlatformFocusTarget nextTarget = resolvePlatformFocusTarget(targetSign, rendererHostSign); + PlatformFocusTarget previousTarget = mFocusedTarget; + if (previousTarget != null && previousTarget.isSameObject(nextTarget)) { + mFocusedTarget = nextTarget; + return; + } + + boolean nextFocusable = nextTarget.isFocusable(); + boolean previousFocusable = previousTarget != null && previousTarget.isFocusable(); + // Keep the same ordering as the existing focus transition: focus the new target before + // notifying the previous target that it lost focus. + mFocusedTarget = nextTarget; + if (nextFocusable) { + nextTarget.onFocusChanged(true, previousFocusable); + } + if (previousFocusable) { + previousTarget.onFocusChanged(false, nextFocusable); + } + } + + private PlatformFocusTarget resolvePlatformFocusTarget(int targetSign, int rendererHostSign) { + LynxUIOwner owner = mContext != null ? mContext.getLynxUIOwner() : null; + LynxBaseUI ui = owner != null ? owner.getNode(targetSign) : null; + + IRendererHost host = mViewHolder.get(targetSign); + if (host == null) { + host = mViewHolder.get(rendererHostSign); + } + if (ui == null && host != null) { + Renderer renderer = host.getRenderer(); + ui = renderer != null ? renderer.getUIHost() : null; + } + return new PlatformFocusTarget(targetSign, rendererHostSign, ui, host); + } + + private static final class PlatformFocusTarget { + private final int mTargetSign; + private final int mRendererHostSign; + @Nullable private final LynxBaseUI mUI; + @Nullable private final IRendererHost mRendererHost; + + PlatformFocusTarget(int targetSign, int rendererHostSign, @Nullable LynxBaseUI ui, + @Nullable IRendererHost rendererHost) { + mTargetSign = targetSign; + mRendererHostSign = rendererHostSign; + mUI = ui; + mRendererHost = rendererHost; + } + + boolean isSameObject(PlatformFocusTarget target) { + Object object = getFocusObject(); + Object targetObject = target.getFocusObject(); + if (object != null || targetObject != null) { + return object == targetObject; + } + return mTargetSign == target.mTargetSign && mRendererHostSign == target.mRendererHostSign; + } + + boolean containsSign(int sign) { + return mTargetSign == sign || mRendererHostSign == sign; + } + + boolean isFocusable() { + if (mUI != null) { + return mUI.isFocusable(); + } + View view = mRendererHost != null ? mRendererHost.getView() : null; + return view != null && view.isFocusable(); + } + + void onFocusChanged(boolean hasFocus, boolean isFocusTransition) { + if (mUI != null) { + mUI.onFocusChanged(hasFocus, isFocusTransition); + return; + } + View view = mRendererHost != null ? mRendererHost.getView() : null; + if (view == null) { + return; + } + if (hasFocus) { + view.requestFocus(); + } else { + view.clearFocus(); + } + } + + @Nullable + private Object getFocusObject() { + return mUI != null ? mUI : mRendererHost; + } + } + @CalledByNative public void destroyPlatformRenderer(int sign) { + if (mFocusedTarget != null && mFocusedTarget.containsSign(sign)) { + mFocusedTarget = null; + } LynxUIOwner owner = mContext.getLynxUIOwner(); boolean shouldRemoveFromNativeParent = false; if (owner != null && owner.getNode(sign) != null) { @@ -839,6 +932,7 @@ public void destroy() { nativeDestroy(mNativePtr); } mNativePtr = 0; + mFocusedTarget = null; mViewHolder.clear(); for (Object value : mExtraDatas.values()) { diff --git a/platform/darwin/ios/api/lynx_ios.api b/platform/darwin/ios/api/lynx_ios.api index 614ce0cd29..85f12071fa 100644 --- a/platform/darwin/ios/api/lynx_ios.api +++ b/platform/darwin/ios/api/lynx_ios.api @@ -1696,6 +1696,7 @@ public class LynxEventHandler : NSObject { public NSInteger LynxEventHandler()::checkCanRespondTapOrClick:withSet:(id< LynxEventTarget > ui, [withSet] NSSet *set); public void LynxEventHandler()::removeEventGestures(); public void LynxEventHandler()::markDispatchInCurrentLynxPageOnlyIfNeeded:(LynxTouchEvent *event); + public void LynxEventHandler()::handleFocusOnView:withContainer:andPoint:andEvent:ignoreFocus:(UIView *view, [withContainer] UIView *container, [andPoint] CGPoint point, [andEvent] nullable UIEvent *event, [ignoreFocus] BOOL ignoreFocus); } public protocol LynxEventObserver-p : { @@ -3940,7 +3941,7 @@ public class LynxTemplateRender : NSObject, , { public void LynxUIRenderer::SetPlatformEventRootActive:active:(NSInteger rootSign,[active] BOOL active); public void LynxUIRenderer::SetPlatformEventRootOffset:offsetX:offsetY:(NSInteger rootSign,[offsetX] CGFloat offsetX,[offsetY] CGFloat offsetY); public BOOL LynxUIRenderer::IsPlatformEventTargetEventThrough:point:(NSInteger rootSign,[point] CGPoint point); - public int LynxUIRenderer::GetPlatformEventHandlerState(); + public BOOL LynxUIRenderer::IsPlatformEventTargetIgnoreFocus:point:(NSInteger rootSign,[point] CGPoint point); } public class LynxUIRendererCreator : NSObject, { diff --git a/platform/darwin/ios/lynx/LynxTemplateRender+Internal.h b/platform/darwin/ios/lynx/LynxTemplateRender+Internal.h index 0cbc76dcb7..1bf953e046 100644 --- a/platform/darwin/ios/lynx/LynxTemplateRender+Internal.h +++ b/platform/darwin/ios/lynx/LynxTemplateRender+Internal.h @@ -81,7 +81,7 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)IsPlatformEventTargetEventThrough:(NSInteger)rootSign point:(CGPoint)point; -- (int)GetPlatformEventHandlerState; +- (BOOL)IsPlatformEventTargetIgnoreFocus:(NSInteger)rootSign point:(CGPoint)point; @end diff --git a/platform/darwin/ios/lynx/LynxTemplateRender.mm b/platform/darwin/ios/lynx/LynxTemplateRender.mm index ae6541c99b..4a621c1073 100644 --- a/platform/darwin/ios/lynx/LynxTemplateRender.mm +++ b/platform/darwin/ios/lynx/LynxTemplateRender.mm @@ -1455,11 +1455,11 @@ - (BOOL)IsPlatformEventTargetEventThrough:(NSInteger)rootSign point:(CGPoint)poi return NO; } -- (int)GetPlatformEventHandlerState { +- (BOOL)IsPlatformEventTargetIgnoreFocus:(NSInteger)rootSign point:(CGPoint)point { if ([_lynxUIRenderer isKindOfClass:[LynxUIRenderer class]]) { - return [(LynxUIRenderer*)_lynxUIRenderer GetPlatformEventHandlerState]; + return [(LynxUIRenderer*)_lynxUIRenderer IsPlatformEventTargetIgnoreFocus:rootSign point:point]; } - return 0; + return NO; } #pragma mark - Life Cycle diff --git a/platform/darwin/ios/lynx/LynxUIRenderer.h b/platform/darwin/ios/lynx/LynxUIRenderer.h index 28e620b1ac..277ed1d3d7 100644 --- a/platform/darwin/ios/lynx/LynxUIRenderer.h +++ b/platform/darwin/ios/lynx/LynxUIRenderer.h @@ -16,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN offsetX:(CGFloat)offsetX offsetY:(CGFloat)offsetY; - (BOOL)IsPlatformEventTargetEventThrough:(NSInteger)rootSign point:(CGPoint)point; -- (int)GetPlatformEventHandlerState; +- (BOOL)IsPlatformEventTargetIgnoreFocus:(NSInteger)rootSign point:(CGPoint)point; @end diff --git a/platform/darwin/ios/lynx/LynxUIRenderer.mm b/platform/darwin/ios/lynx/LynxUIRenderer.mm index c6ba2f4538..b74c3c0152 100644 --- a/platform/darwin/ios/lynx/LynxUIRenderer.mm +++ b/platform/darwin/ios/lynx/LynxUIRenderer.mm @@ -454,11 +454,12 @@ - (BOOL)IsPlatformEventTargetEventThrough:(NSInteger)rootSign point:(CGPoint)poi return NO; } -- (int)GetPlatformEventHandlerState { +- (BOOL)IsPlatformEventTargetIgnoreFocus:(NSInteger)rootSign point:(CGPoint)point { if (auto *platform_ref = CastToNativePaintingCtxPlatformRef(_paintingCtxPlatformRef)) { - return platform_ref->GetPlatformEventHandlerState(); + return platform_ref->IsPlatformEventTargetIgnoreFocus(static_cast(rootSign), point.x, + point.y); } - return 0; + return NO; } - (LynxGestureArenaManager *)getGestureArenaManager { diff --git a/platform/darwin/ios/lynx/LynxView.mm b/platform/darwin/ios/lynx/LynxView.mm index 89c26bd3dc..0d78c5f2e5 100644 --- a/platform/darwin/ios/lynx/LynxView.mm +++ b/platform/darwin/ios/lynx/LynxView.mm @@ -12,6 +12,7 @@ #import #import #import +#import #import #import #import @@ -27,6 +28,7 @@ #import #import #import +#import #import #import #import @@ -429,11 +431,24 @@ - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event { UIView* view = [super hitTest:point withEvent:event]; self.nestedScrollViewsChain = [LynxBaseScrollView generateNestedScrollChainWithHitTestTarget:view]; - [_templateRender.lynxUIRenderer handleFocus:touchTarget - onView:view - withContainer:self - andPoint:point - andEvent:event]; + id uiRenderer = _templateRender.lynxUIRenderer; + LynxEventHandler* eventHandler = uiRenderer.uiOwner.uiContext.eventHandler; + if (uiRenderer.uiOwner.uiContext.lynxContext.isFragmentLayerRenderOn) { + BOOL ignoreFocus = + eventHandler != nil && + [_templateRender IsPlatformEventTargetIgnoreFocus:eventHandler.eventRootSign point:point]; + [eventHandler handleFocusOnView:view + withContainer:self + andPoint:point + andEvent:event + ignoreFocus:ignoreFocus]; + } else { + [uiRenderer handleFocus:touchTarget + onView:view + withContainer:self + andPoint:point + andEvent:event]; + } // If target eventThrough, return nil to let event through LynxView. CGPoint targetPoint = point; if (touchTarget.view) { diff --git a/platform/darwin/ios/lynx/event/LynxEventHandler+Internal.h b/platform/darwin/ios/lynx/event/LynxEventHandler+Internal.h index 543d8cde14..d5828f88ff 100644 --- a/platform/darwin/ios/lynx/event/LynxEventHandler+Internal.h +++ b/platform/darwin/ios/lynx/event/LynxEventHandler+Internal.h @@ -27,6 +27,12 @@ NS_ASSUME_NONNULL_BEGIN - (void)removeEventGestures; - (void)markDispatchInCurrentLynxPageOnlyIfNeeded:(LynxTouchEvent *)event; +- (void)handleFocusOnView:(UIView *)view + withContainer:(UIView *)container + andPoint:(CGPoint)point + andEvent:(nullable UIEvent *)event + ignoreFocus:(BOOL)ignoreFocus; + @end NS_ASSUME_NONNULL_END diff --git a/platform/darwin/ios/lynx/event/LynxEventHandler.m b/platform/darwin/ios/lynx/event/LynxEventHandler.m index 63256ececc..f25989c8aa 100644 --- a/platform/darwin/ios/lynx/event/LynxEventHandler.m +++ b/platform/darwin/ios/lynx/event/LynxEventHandler.m @@ -1267,10 +1267,21 @@ - (void)handleFocus:(id)target withContainer:(UIView*)container andPoint:(CGPoint)point andEvent:(UIEvent*)event { + [self handleFocusOnView:view + withContainer:container + andPoint:point + andEvent:event + ignoreFocus:[target ignoreFocus]]; +} + +- (void)handleFocusOnView:(UIView*)view + withContainer:(UIView*)container + andPoint:(CGPoint)point + andEvent:(UIEvent*)event + ignoreFocus:(BOOL)ignoreFocus { if ([self needEndEditing:view] && ![[[[view superview] superview] superview] isKindOfClass:[UITextView class]] && - ![target ignoreFocus] && - ![self tapOnUICalloutBarButton:container withPoint:point andEvent:event]) { + !ignoreFocus && ![self tapOnUICalloutBarButton:container withPoint:point andEvent:event]) { // To free our touch handler from being blocked, dispatch endEditing asynchronously. // TODO(hexionghui): Use resignFirstResponder and becomeFirstResponder to replace endEditing. __weak UIView* weakView = container; diff --git a/platform/darwin/ios/lynx_xelement/overlay/LynxOverlayContainer.m b/platform/darwin/ios/lynx_xelement/overlay/LynxOverlayContainer.m index fa808b1218..7d7d31349a 100644 --- a/platform/darwin/ios/lynx_xelement/overlay/LynxOverlayContainer.m +++ b/platform/darwin/ios/lynx_xelement/overlay/LynxOverlayContainer.m @@ -183,9 +183,16 @@ - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { if (![rootView isKindOfClass:LynxView.class]) { return view; } + NSInteger eventRootSign = [self.uiDelegate getSign]; LynxTemplateRender *templateRender = ((LynxView *)rootView).templateRender; - BOOL platformEventThrough = - [templateRender IsPlatformEventTargetEventThrough:[self.uiDelegate getSign] point:point]; + BOOL ignoreFocus = [templateRender IsPlatformEventTargetIgnoreFocus:eventRootSign point:point]; + [self.eventHandler handleFocusOnView:view + withContainer:self + andPoint:point + andEvent:event + ignoreFocus:ignoreFocus]; + BOOL platformEventThrough = [templateRender IsPlatformEventTargetEventThrough:eventRootSign + point:point]; if (platformEventThrough) { return nil; }