Skip to content

Commit

Permalink
add IntersectionObserver;
Browse files Browse the repository at this point in the history
  • Loading branch information
pengfei12.guo committed Oct 16, 2024
1 parent e76a469 commit 9b9a702
Show file tree
Hide file tree
Showing 28 changed files with 1,062 additions and 9 deletions.
9 changes: 9 additions & 0 deletions bridge/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,10 @@ if ($ENV{WEBF_JS_ENGINE} MATCHES "quickjs")
core/dom/legacy/bounding_client_rect.cc
core/input/touch.cc
core/input/touch_list.cc

#IntersectionObserver
core/dom/intersection_observer.cc
core/dom/intersection_observer_entry.cc
)

# Gen sources.
Expand Down Expand Up @@ -534,6 +538,11 @@ if ($ENV{WEBF_JS_ENGINE} MATCHES "quickjs")
out/element_attribute_names.cc
out/element_namespace_uris.cc

# IntersectionObserver
out/qjs_intersection_observer.cc
out/qjs_intersection_observer_entry.cc
out/qjs_intersection_observer_init.cc

# SVG generated
out/svg_names.cc
out/svg_element_factory.cc
Expand Down
6 changes: 6 additions & 0 deletions bridge/bindings/qjs/binding_initializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@
#include "qjs_widget_element.h"
#include "qjs_window.h"
#include "qjs_window_or_worker_global_scope.h"
#include "qjs_intersection_observer.h"
#include "qjs_intersection_observer_entry.h"

namespace webf {

Expand Down Expand Up @@ -200,6 +202,10 @@ void InstallBindings(ExecutingContext* context) {
QJSSVGStyleElement::Install(context);
QJSSVGLineElement::Install(context);

//IntersectionObserver
QJSIntersectionObserver::Install(context);
QJSIntersectionObserverEntry::Install(context);

// Legacy bindings, not standard.
QJSElementAttributes::Install(context);
}
Expand Down
4 changes: 4 additions & 0 deletions bridge/bindings/qjs/wrapper_type_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ enum {
JS_CLASS_SVG_LENGTH,
JS_CLASS_SVG_ANIMATED_LENGTH,

// IntersectionObserver
JS_CLASS_INTERSECTION_OBSERVER,
JS_CLASS_INTERSECTION_OBSERVER_ENTRY,

JS_CLASS_CUSTOM_CLASS_INIT_COUNT /* last entry for predefined classes */
};

Expand Down
12 changes: 9 additions & 3 deletions bridge/core/binding_object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,11 @@ void NativeBindingObject::HandleCallFromDartSide(DartIsolateContext* dart_isolat

dart_isolate_context->profiler()->StartTrackEvaluation(profile_id);

AtomicString method = AtomicString(
binding_object->binding_target_->ctx(),
std::unique_ptr<AutoFreeNativeString>(reinterpret_cast<AutoFreeNativeString*>(native_method->u.ptr)));
auto context = binding_object->binding_target_->ctx();
AtomicString method = native_method != nullptr
? AtomicString(context, std::unique_ptr<AutoFreeNativeString>(
reinterpret_cast<AutoFreeNativeString *>(native_method->u.ptr)))
: AtomicString(context, "");
NativeValue result = binding_object->binding_target_->HandleCallFromDartSide(method, argc, argv, dart_object);

auto* return_value = new NativeValue();
Expand Down Expand Up @@ -430,4 +432,8 @@ bool BindingObject::IsCanvasGradient() const {
return false;
}

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

} // namespace webf
6 changes: 5 additions & 1 deletion bridge/core/binding_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ enum BindingMethodCallOperations {
kAsyncAnonymousFunction,
};

enum CreateBindingObjectType { kCreateDOMMatrix = 0 };
enum CreateBindingObjectType {
kCreateDOMMatrix = 0,
kCreateIntersectionObserver
};

struct BindingObjectPromiseContext : public DartReadable {
ExecutingContext* context;
Expand Down Expand Up @@ -136,6 +139,7 @@ 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
144 changes: 144 additions & 0 deletions bridge/core/dom/intersection_observer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Copyright (C) 2024-present The WebF authors. All rights reserved.

#include "core/dom/intersection_observer.h"

#include <algorithm>
#include <limits>

#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 "qjs_intersection_observer_init.h"
#include "foundation/logging.h"

namespace webf {

IntersectionObserver* IntersectionObserver::Create(ExecutingContext* context,
const std::shared_ptr<QJSFunction>& function,
ExceptionState& exception_state) {
return MakeGarbageCollected<IntersectionObserver>(context, function);
}

IntersectionObserver* IntersectionObserver::Create(ExecutingContext* context,
const std::shared_ptr<QJSFunction>& function,
const std::shared_ptr<IntersectionObserverInit>& observer_init,
ExceptionState& exception_state) {
return MakeGarbageCollected<IntersectionObserver>(context, function, observer_init);
}

IntersectionObserver::IntersectionObserver(ExecutingContext* context, const std::shared_ptr<QJSFunction>& function)
: BindingObject(context->ctx()), function_(function) {
GetExecutingContext()->dartMethodPtr()->createBindingObject(
GetExecutingContext()->isDedicated(), GetExecutingContext()->contextId(), bindingObject(),
CreateBindingObjectType::kCreateIntersectionObserver, nullptr, 0);
}

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()) {
root_ = observer_init->root();
}
GetExecutingContext()->dartMethodPtr()->createBindingObject(
GetExecutingContext()->isDedicated(), GetExecutingContext()->contextId(), bindingObject(),
CreateBindingObjectType::kCreateIntersectionObserver, nullptr, 0);
}

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

void IntersectionObserver::observe(Element* target, ExceptionState& exception_state) {
if (!RootIsValid() || !target)
return;

// TODO([email protected]): 通知dart,注册IntersectionObserver
GetExecutingContext()->uiCommandBuffer()->AddCommand(UICommand::kAddIntersectionObserver, nullptr, bindingObject(),
target->bindingObject());
}

void IntersectionObserver::unobserve(Element* target, ExceptionState& exception_state) {
if (!target)
return;

GetExecutingContext()->uiCommandBuffer()->AddCommand(UICommand::kRemoveIntersectionObserver, nullptr, bindingObject(),
target->bindingObject());
}

void IntersectionObserver::disconnect(ExceptionState& exception_state) {
GetExecutingContext()->uiCommandBuffer()->AddCommand(UICommand::kDisconnectIntersectionObserver, nullptr,
bindingObject(), nullptr);
}

// std::vector<Member<IntersectionObserverEntry>> IntersectionObserver::takeRecords(ExceptionState& exception_state) {
// std::vector<Member<IntersectionObserverEntry>> entries;
// for (auto& observation : observations_)
// observation->TakeRecords(entries);
// active_observations_.clear();
// return entries;
// }

// AtomicString IntersectionObserver::rootMargin() const {
// return StringifyMargin(RootMargin());
// }

// AtomicString IntersectionObserver::scrollMargin() const {
// 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,
Dart_Handle dart_object) {
if (!GetExecutingContext() || !GetExecutingContext()->IsContextValid()) {
WEBF_LOG(ERROR) << "[IntersectionObserver]: HandleCallFromDartSide Context Valid" << std::endl;
return Native_NewNull();
}

WEBF_LOG(DEBUG) << "[IntersectionObserver]: HandleCallFromDartSide NativeValueConverter" << std::endl;
NativeValue native_entry_list = argv[0];
std::vector<IntersectionObserverEntry*> entries =
NativeValueConverter<NativeTypeArray<NativeTypePointer<IntersectionObserverEntry>>>::FromNativeValue(
ctx(), native_entry_list);

if (!entries.empty()) {
assert(function_ != nullptr);

WEBF_LOG(DEBUG) << "[IntersectionObserver]: HandleCallFromDartSide To JSValue" << std::endl;
JSValue v = Converter<IDLSequence<IntersectionObserverEntry>>::ToValue(ctx(), entries);
ScriptValue arguments[] = {ScriptValue(ctx(), v), ToValue()};

JS_FreeValue(ctx(), v);

WEBF_LOG(DEBUG) << "[IntersectionObserver]: HandleCallFromDartSide function_ Invoke" << std::endl;
function_->Invoke(ctx(), ToValue(), 2, arguments);
} else {
WEBF_LOG(ERROR) << "[IntersectionObserver]: HandleCallFromDartSide entries is empty";
}

return Native_NewNull();
}

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

function_->Trace(visitor);
}

} // namespace webf
31 changes: 31 additions & 0 deletions bridge/core/dom/intersection_observer.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// https://www.w3.org/TR/intersection-observer/#intersection-observer-interface

// Copyright (C) 2024-present The WebF authors. All rights reserved.

import {IntersectionObserverInit} from "./intersection_observer_init";
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;
//readonly rootMargin: string;
//readonly scrollMargin: string;
//readonly thresholds: number[];
//readonly delay: number;
//readonly trackVisibility: boolean;

observe(target: Element): void;
unobserve(target: Element): void;
disconnect(): void;
//takeRecords(): IntersectionObserverEntry[];
}
Loading

0 comments on commit 9b9a702

Please sign in to comment.