Skip to content

Commit

Permalink
优化IntersectionObserver,支持thresholds;
Browse files Browse the repository at this point in the history
  • Loading branch information
pengfei12.guo committed Dec 11, 2024
1 parent 96870df commit 03cabce
Show file tree
Hide file tree
Showing 17 changed files with 249 additions and 192 deletions.
4 changes: 0 additions & 4 deletions bridge/core/binding_object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -432,8 +432,4 @@ bool BindingObject::IsCanvasGradient() const {
return false;
}

bool BindingObject::IsIntersectionObserverEntry() const {
return false;
}

} // namespace webf
1 change: 0 additions & 1 deletion bridge/core/binding_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ class BindingObject : public ScriptWrappable {
virtual bool IsTouchList() const;
virtual bool IsComputedCssStyleDeclaration() const;
virtual bool IsCanvasGradient() const;
virtual bool IsIntersectionObserverEntry() const;

protected:
void TrackPendingPromiseBindingContext(BindingObjectPromiseContext* binding_object_promise_context);
Expand Down
3 changes: 2 additions & 1 deletion bridge/core/dom/dom_string_map.cc
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,8 @@ bool DOMStringMap::SetItem(const webf::AtomicString& key,
}

auto attribute_name = AtomicString(ctx(), ConvertPropertyNameToAttributeName(key.ToStdString(ctx())));
return owner_element_->attributes()->setAttribute(attribute_name, value, exception_state);
owner_element_->setAttribute(attribute_name, value, exception_state);
return true;
}

bool DOMStringMap::DeleteItem(const webf::AtomicString& key, webf::ExceptionState& exception_state) {
Expand Down
56 changes: 31 additions & 25 deletions bridge/core/dom/intersection_observer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,17 @@
#include <algorithm>
#include <limits>

#include "bindings/qjs/converter_impl.h"
#include "core/dom/element.h"
#include <native_value_converter.h>
#include "bindings/qjs/converter_impl.h"
#include "core/dom/intersection_observer_entry.h"
#include "core/dom/node.h"
#include "core/executing_context.h"
#include "foundation/logging.h"
#include "foundation/native_value_converter.h"
#include "qjs_intersection_observer_init.h"
#include "foundation/logging.h"

namespace webf {

struct NativeIntersectionObserverEntry : public DartReadable {
int8_t is_intersecting;
NativeBindingObject* target;
};

IntersectionObserver* IntersectionObserver::Create(ExecutingContext* context,
const std::shared_ptr<QJSFunction>& function,
ExceptionState& exception_state) {
Expand All @@ -49,30 +44,46 @@ IntersectionObserver::IntersectionObserver(ExecutingContext* context,
const std::shared_ptr<QJSFunction>& function,
const std::shared_ptr<IntersectionObserverInit>& observer_init)
: BindingObject(context->ctx()), function_(function) {
if (observer_init->hasRoot()) {
if (observer_init && observer_init->hasRoot()) {
root_ = observer_init->root();
}
NativeValue arguments[1];
if (observer_init && observer_init->hasThreshold()) {
#if ENABLE_LOG
WEBF_LOG(DEBUG) << "[IntersectionObserver]: Constructor threshold.size = " << observer_init->threshold().size()
<< std::endl;
#endif
thresholds_ = std::move(observer_init->threshold());
std::sort(thresholds_.begin(), thresholds_.end());
arguments[0] = NativeValueConverter<NativeTypeArray<NativeTypeDouble>>::ToNativeValue(thresholds_);
}
GetExecutingContext()->dartMethodPtr()->createBindingObject(
GetExecutingContext()->isDedicated(), GetExecutingContext()->contextId(), bindingObject(),
CreateBindingObjectType::kCreateIntersectionObserver, nullptr, 0);
CreateBindingObjectType::kCreateIntersectionObserver, arguments, 1);
}

bool IntersectionObserver::RootIsValid() const {
return RootIsImplicit() || root();
}

void IntersectionObserver::observe(Element* target, ExceptionState& exception_state) {
if (!RootIsValid() || !target)
if (!RootIsValid() || !target) {
WEBF_LOG(ERROR) << "[IntersectionObserver]: observe valid:" << std::endl;
return;
}

// TODO([email protected]): 通知dart,注册IntersectionObserver
#if ENABLE_LOG
WEBF_LOG(DEBUG) << "[IntersectionObserver]: observe target=" << target << ",tagName=" << target->nodeName() << std::endl;
#endif
GetExecutingContext()->uiCommandBuffer()->AddCommand(UICommand::kAddIntersectionObserver, nullptr, bindingObject(),
target->bindingObject());
}

void IntersectionObserver::unobserve(Element* target, ExceptionState& exception_state) {
if (!target)
if (!target) {
WEBF_LOG(ERROR) << "[IntersectionObserver]: unobserve valid:" << std::endl;
return;
}

GetExecutingContext()->uiCommandBuffer()->AddCommand(UICommand::kRemoveIntersectionObserver, nullptr, bindingObject(),
target->bindingObject());
Expand All @@ -99,13 +110,6 @@ void IntersectionObserver::disconnect(ExceptionState& exception_state) {
// return StringifyMargin(ScrollMargin());
// }

// using InvokeBindingMethodsFromDart = void (*)(NativeBindingObject* binding_object,
// int64_t profile_id,
// NativeValue* method,
// int32_t argc,
// NativeValue* argv,
// Dart_Handle dart_object,
// DartInvokeResultCallback result_callback);
NativeValue IntersectionObserver::HandleCallFromDartSide(const AtomicString& method,
int32_t argc,
const NativeValue* argv,
Expand All @@ -116,24 +120,27 @@ NativeValue IntersectionObserver::HandleCallFromDartSide(const AtomicString& met
}

MemberMutationScope scope{GetExecutingContext()};
WEBF_LOG(DEBUG) << "[IntersectionObserver]: HandleCallFromDartSide NativeValueConverter" << std::endl;

NativeIntersectionObserverEntry* native_entry =
NativeValueConverter<NativeTypePointer<NativeIntersectionObserverEntry>>::FromNativeValue(argv[0]);
size_t length = NativeValueConverter<NativeTypeInt64>::FromNativeValue(argv[1]);

if (length > 0) {
assert(function_ != nullptr);
WEBF_LOG(DEBUG) << "[IntersectionObserver]: HandleCallFromDartSide To JSValue" << std::endl;
JSValue js_array = JS_NewArray(ctx());
for (int i = 0; i < length; i++) {
auto* entry = MakeGarbageCollected<IntersectionObserverEntry>(
GetExecutingContext(), native_entry[i].is_intersecting,
GetExecutingContext(), native_entry[i].is_intersecting, native_entry[i].intersectionRatio,
DynamicTo<Element>(BindingObject::From(native_entry[i].target)));
JS_SetPropertyUint32(ctx(), js_array, i, entry->ToQuickJS());
}
ScriptValue arguments[] = {ScriptValue(ctx(), js_array), ToValue()};

WEBF_LOG(DEBUG) << "[IntersectionObserver]: HandleCallFromDartSide function_ Invoke" << std::endl;
#if ENABLE_LOG
WEBF_LOG(DEBUG) << "[IntersectionObserver]: HandleCallFromDartSide length=" << length << ",JS function_ Invoke"
<< std::endl;
#endif

function_->Invoke(ctx(), ToValue(), 2, arguments);

JS_FreeValue(ctx(), js_array);
Expand All @@ -146,7 +153,6 @@ NativeValue IntersectionObserver::HandleCallFromDartSide(const AtomicString& met

void IntersectionObserver::Trace(GCVisitor* visitor) const {
BindingObject::Trace(visitor);
BindingObject::Trace(visitor);

function_->Trace(visitor);
}
Expand Down
3 changes: 0 additions & 3 deletions bridge/core/dom/intersection_observer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ import {IntersectionObserverEntry} from "./intersection_observer_entry";
import {Node} from "./node";
import {Element} from "./element";

//type IntersectionObserverCallback = (entries: IntersectionObserverEntry[], observer: IntersectionObserver)

interface IntersectionObserver {
//new (callback: IntersectionObserverCallback, options?: IntersectionObserverInit): IntersectionObserver;
new(callback: Function, options?: IntersectionObserverInit): IntersectionObserver;

//readonly root: Node | null;
Expand Down
7 changes: 4 additions & 3 deletions bridge/core/dom/intersection_observer.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,13 @@ class IntersectionObserver final : public BindingObject {
// std::vector<Member<IntersectionObserverEntry>> takeRecords(ExceptionState&);

// API attributes.
Node* root() const { return root_; }
[[nodiscard]] Node* root() const { return root_; }
// TODO(pengfei12.guo): not supported
//AtomicString rootMargin() const;
// TODO(pengfei12.guo): not supported
//AtomicString scrollMargin() const;
// TODO(pengfei12.guo): not supported
//const std::vector<double>& thresholds() const { return thresholds_; }

[[nodiscard]] const std::vector<double>& thresholds() const { return thresholds_; }
// TODO(pengfei12.guo): not supported
// DOMHighResTimeStamp delay() const {
// if (delay_ != std::numeric_limits<int64_t>::min() && delay_ != std::numeric_limits<int64_t>::max()) {
Expand Down Expand Up @@ -192,6 +192,7 @@ class IntersectionObserver final : public BindingObject {

// We use UntracedMember<> here to do custom weak processing.
Node* root_;
std::vector<double> thresholds_;

// TODO(pengfei12.guo): not support
// const std::vector<Length> margin_;
Expand Down
24 changes: 8 additions & 16 deletions bridge/core/dom/intersection_observer_entry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,14 @@

namespace webf {

IntersectionObserverEntry::IntersectionObserverEntry(ExecutingContext* context, bool isIntersecting, Element* target)
: BindingObject(context->ctx()), isIntersecting_(isIntersecting), target_(target) {}

// DOMRectReadOnly* IntersectionObserverEntry::boundingClientRect() const {
// return DOMRectReadOnly::FromRectF(gfx::RectF(geometry_.TargetRect()));
// }
//
// DOMRectReadOnly* IntersectionObserverEntry::rootBounds() const {
// if (geometry_.ShouldReportRootBounds())
// return DOMRectReadOnly::FromRectF(gfx::RectF(geometry_.RootRect()));
// return nullptr;
// }
//
// DOMRectReadOnly* IntersectionObserverEntry::intersectionRect() const {
// return DOMRectReadOnly::FromRectF(gfx::RectF(geometry_.IntersectionRect()));
// }
IntersectionObserverEntry::IntersectionObserverEntry(ExecutingContext* context,
bool isIntersecting,
double intersectionRatio,
Element* target)
: ScriptWrappable(context->ctx()),
isIntersecting_(isIntersecting),
intersectionRatio_(intersectionRatio),
target_(target) {}

void IntersectionObserverEntry::Trace(GCVisitor* visitor) const {
visitor->TraceMember(target_);
Expand Down
19 changes: 7 additions & 12 deletions bridge/core/dom/intersection_observer_entry.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,17 @@
import {Element} from "./element";

export interface IntersectionObserverEntry {
// TODO(pengfei12.guo): DOMHighResTimeStamp not supported
//readonly time: DOMHighResTimeStamp;

// TODO(pengfei12.guo): DOMRectReadOnly not supported
// TODO(pengfei12.guo): not supported
// readonly time: DOMHighResTimeStamp;
// TODO(szager): |rootBounds| should not be nullable.
//readonly rootBounds: DOMRectReadOnly | null; // rootBounds 可以为 null
//readonly boundingClientRect: DOMRectReadOnly;
//readonly intersectionRect: DOMRectReadOnly;
// readonly rootBounds: DOMRectReadOnly | null;
// readonly boundingClientRect: DOMRectReadOnly;
// readonly intersectionRect: DOMRectReadOnly;
// readonly isVisible: boolean;

readonly isIntersecting: boolean;

// TODO(pengfei12.guo): isVisible not supported
//readonly isVisible: boolean;

// TODO(pengfei12.guo): intersectionRatio not supported
//readonly intersectionRatio: number;
readonly intersectionRatio: number;

readonly target: Element;

Expand Down
29 changes: 15 additions & 14 deletions bridge/core/dom/intersection_observer_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,32 @@
#define WEBF_CORE_INTERSECTION_OBSERVER_INTERSECTION_OBSERVER_ENTRY_H_

#include "bindings/qjs/cppgc/member.h"
#include "core/binding_object.h"
#include "bindings/qjs/script_wrappable.h"

namespace webf {

class Element;

class IntersectionObserverEntry final : public BindingObject {
struct NativeIntersectionObserverEntry : public DartReadable {
int8_t is_intersecting;
double intersectionRatio;
NativeBindingObject* target;
};

class IntersectionObserverEntry final : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();

public:
using ImplType = IntersectionObserverEntry*;
IntersectionObserverEntry() = delete;
explicit IntersectionObserverEntry(ExecutingContext* context,
bool isIntersecting,
double intersectionRatio,
Element* target);

IntersectionObserverEntry(ExecutingContext* context, bool isIntersecting, Element* target);
// TODO(pengfei12.guo): not supported
// IDL interface
// double time() const { return time_; }
// double intersectionRatio() const {
// return geometry_.IntersectionRatio();
//}
double intersectionRatio() const { return intersectionRatio_; }
// DOMRectReadOnly* boundingClientRect() const;
// DOMRectReadOnly* rootBounds() const;
// DOMRectReadOnly* intersectionRect() const;
Expand All @@ -43,20 +50,14 @@ class IntersectionObserverEntry final : public BindingObject {
// const IntersectionGeometry& GetGeometry() const { return geometry_; }
void Trace(GCVisitor*) const override;

bool IsIntersectionObserverEntry() const override { return true; };

private:
// IntersectionGeometry geometry_;
double intersectionRatio_;
bool isIntersecting_;
// DOMHighResTimeStamp time_;
Member<Element> target_;
};

template <>
struct DowncastTraits<IntersectionObserverEntry> {
static bool AllowFrom(const BindingObject& binding_object) { return binding_object.IsIntersectionObserverEntry(); }
};

} // namespace webf

#endif // WEBF_CORE_INTERSECTION_OBSERVER_INTERSECTION_OBSERVER_ENTRY_H_
7 changes: 5 additions & 2 deletions bridge/foundation/ui_command_strategy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ void UICommandSyncStrategy::RecordUICommand(UICommand type,
case UICommand::kSetAttribute:
case UICommand::kRemoveEvent:
case UICommand::kAddEvent:
case UICommand::kDisposeBindingObject: {
case UICommand::kDisposeBindingObject:
case UICommand::kAddIntersectionObserver:
case UICommand::kRemoveIntersectionObserver:
case UICommand::kDisconnectIntersectionObserver: {
host_->waiting_buffer_->addCommand(type, std::move(args_01), native_binding_object, native_ptr2,
request_ui_update);
break;
Expand Down Expand Up @@ -141,4 +144,4 @@ void UICommandSyncStrategy::RecordOperationForPointer(NativeBindingObject* ptr)
SyncToReserveIfNecessary();
}

} // namespace webf
} // namespace webf
2 changes: 1 addition & 1 deletion webf/lib/src/bridge/binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ abstract class BindingBridge {
return;
}
case CreateBindingObjectType.createIntersectionObserver: {
IntersectionObserver intersectionObserver = IntersectionObserver(BindingContext(controller.view, contextId, pointer));
IntersectionObserver intersectionObserver = IntersectionObserver(BindingContext(controller.view, contextId, pointer), arguments);
controller.view.setBindingObject(pointer, intersectionObserver);
return;
}
Expand Down
Loading

0 comments on commit 03cabce

Please sign in to comment.