Skip to content

Commit

Permalink
Feat/add hybird router support (#599)
Browse files Browse the repository at this point in the history
  • Loading branch information
andycall authored Jul 10, 2024
2 parents efe0664 + c55b137 commit b1e37c7
Show file tree
Hide file tree
Showing 32 changed files with 557 additions and 33 deletions.
3 changes: 3 additions & 0 deletions bridge/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ if ($ENV{WEBF_JS_ENGINE} MATCHES "quickjs")
core/events/input_event.cc
core/events/touch_event.cc
core/events/mouse_event.cc
core/events/hybrid_router_change_event.cc
core/events/pop_state_event.cc
core/events/pointer_event.cc
core/events/transition_event.cc
Expand Down Expand Up @@ -442,6 +443,8 @@ if ($ENV{WEBF_JS_ENGINE} MATCHES "quickjs")
out/qjs_mutation_observer_registration.cc
out/qjs_touch_event.cc
out/qjs_touch_event_init.cc
out/qjs_hybrid_router_change_event.cc
out/qjs_hybrid_router_change_event_init.cc
out/qjs_pointer_event.cc
out/qjs_pointer_event_init.cc
out/qjs_mouse_event.cc
Expand Down
2 changes: 2 additions & 0 deletions bridge/bindings/qjs/binding_initializer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
#include "qjs_text.h"
#include "qjs_touch.h"
#include "qjs_touch_event.h"
#include "qjs_hybrid_router_change_event.h"
#include "qjs_touch_list.h"
#include "qjs_transition_event.h"
#include "qjs_ui_event.h"
Expand All @@ -117,6 +118,7 @@ void InstallBindings(ExecutingContext* context) {
QJSMessageEvent::Install(context);
QJSAnimationEvent::Install(context);
QJSCloseEvent::Install(context);
QJSHybridRouterChangeEvent::Install(context);
QJSFocusEvent::Install(context);
QJSGestureEvent::Install(context);
QJSHashchangeEvent::Install(context);
Expand Down
1 change: 1 addition & 0 deletions bridge/bindings/qjs/wrapper_type_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ enum {
JS_CLASS_CUSTOM_EVENT,
JS_CLASS_TRANSITION_EVENT,
JS_CLASS_INPUT_EVENT,
JS_CLASS_HYBRID_ROUTER_CHANGE_EVENT,
JS_CLASS_ANIMATION_EVENT,
JS_CLASS_FOCUS_EVENT,
JS_CLASS_GESTURE_EVENT,
Expand Down
4 changes: 4 additions & 0 deletions bridge/core/dom/events/event.cc
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,10 @@ bool Event::IsHashChangeEvent() const {
return false;
}

bool Event::IsHybridRouterChangeEvent() const {
return false;
}

bool Event::IsIntersectionchangeEvent() const {
return false;
}
Expand Down
1 change: 1 addition & 0 deletions bridge/core/dom/events/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ class Event : public ScriptWrappable {
virtual bool IsPopstateEvent() const;
virtual bool IsIntersectionchangeEvent() const;
virtual bool IsHashChangeEvent() const;
virtual bool IsHybridRouterChangeEvent() const;

// Drag events are a subset of mouse events.
virtual bool IsDragEvent() const;
Expand Down
6 changes: 6 additions & 0 deletions bridge/core/events/dart_created_events.json5
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@
},
"hashchange",
"input",
{
"class": "HybridRouterChangeEvent",
"types": [
"hybridrouterchange"
]
},
{
"class": "FocusEvent",
"types": [
Expand Down
3 changes: 2 additions & 1 deletion bridge/core/events/event_type_names.json5
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@
"wheel",
"zoom",
"intersectionchange",
"gcopen"
"gcopen",
"hybridrouterchange"
]
}
87 changes: 87 additions & 0 deletions bridge/core/events/hybrid_router_change_event.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright (C) 2022-present The WebF authors. All rights reserved.
*/

#include "hybrid_router_change_event.h"
#include "bindings/qjs/cppgc/gc_visitor.h"
#include "event_type_names.h"
#include "qjs_hybrid_router_change_event.h"

namespace webf {

HybridRouterChangeEvent* HybridRouterChangeEvent::Create(ExecutingContext* context, ExceptionState& exception_state) {
return MakeGarbageCollected<HybridRouterChangeEvent>(context, event_type_names::khybridrouterchange, exception_state);
}

HybridRouterChangeEvent* HybridRouterChangeEvent::Create(
ExecutingContext* context,
const AtomicString& type,
const std::shared_ptr<HybridRouterChangeEventInit>& initializer,
ExceptionState& exception_state) {
return MakeGarbageCollected<HybridRouterChangeEvent>(context, type, initializer, exception_state);
}

HybridRouterChangeEvent::HybridRouterChangeEvent(ExecutingContext* context,
const AtomicString& type,
ExceptionState& exception_state)
: Event(context, type) {}

HybridRouterChangeEvent::HybridRouterChangeEvent(ExecutingContext* context,
const AtomicString& type,
const std::shared_ptr<HybridRouterChangeEventInit>& initializer,
ExceptionState& exception_state)
: Event(context, type),
state_(initializer->hasState() ? initializer->state() : ScriptValue::Empty(ctx())),
kind_(initializer->hasKind() ? initializer->kind() : AtomicString::Empty()),
name_(initializer->hasName() ? initializer->name() : AtomicString::Empty()) {}

HybridRouterChangeEvent::HybridRouterChangeEvent(ExecutingContext* context,
const AtomicString& type,
NativeHybridRouterChangeEvent* native_event)
: Event(context, type, &native_event->native_event),
#if ANDROID_32_BIT
state_(ScriptValue::CreateJsonObject(context->ctx(),
reinterpret_cast<const char*>(native_event->state),
strlen(reinterpret_cast<const char*>(native_event->state)))),
kind_(AtomicString(
ctx(),
std::unique_ptr<AutoFreeNativeString>(reinterpret_cast<AutoFreeNativeString*>(native_event->kind)))),
name_(AtomicString(
ctx(),
std::unique_ptr<AutoFreeNativeString>(reinterpret_cast<AutoFreeNativeString*>(native_event->name))))
#else
state_(ScriptValue::CreateJsonObject(context->ctx(),
static_cast<const char*>(native_event->state),
strlen(static_cast<const char*>(native_event->state)))),
kind_(AtomicString(
ctx(),
std::unique_ptr<AutoFreeNativeString>(reinterpret_cast<AutoFreeNativeString*>(native_event->kind)))),
name_(AtomicString(
ctx(),
std::unique_ptr<AutoFreeNativeString>(reinterpret_cast<AutoFreeNativeString*>(native_event->name))))
#endif
{
}

ScriptValue HybridRouterChangeEvent::state() const {
return state_;
}

AtomicString HybridRouterChangeEvent::kind() const {
return kind_;
}

AtomicString HybridRouterChangeEvent::name() const {
return name_;
}

bool HybridRouterChangeEvent::IsHybridRouterChangeEvent() const {
return true;
}

void HybridRouterChangeEvent::Trace(GCVisitor* visitor) const {
state_.Trace(visitor);
Event::Trace(visitor);
}

} // namespace webf
8 changes: 8 additions & 0 deletions bridge/core/events/hybrid_router_change_event.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {Event} from "../dom/events/event";

interface HybridRouterChangeEvent extends Event {
readonly state: any;
readonly kind: string;
readonly name: string;
new(): HybridRouterChangeEvent;
}
58 changes: 58 additions & 0 deletions bridge/core/events/hybrid_router_change_event.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2022-present The WebF authors. All rights reserved.
*/

#ifndef WEBF_CORE_EVENTS_HYBRID_ROUTER_CHANGE_EVENT_H_
#define WEBF_CORE_EVENTS_HYBRID_ROUTER_CHANGE_EVENT_H_

#include "core/dom/events/event.h"
#include "qjs_hybrid_router_change_event_init.h"

namespace webf {

struct NativeHybridRouterChangeEvent;

class HybridRouterChangeEvent : public Event {
DEFINE_WRAPPERTYPEINFO();

public:
using ImplType = HybridRouterChangeEvent*;

static HybridRouterChangeEvent* Create(ExecutingContext* context, ExceptionState& exception_state);

static HybridRouterChangeEvent* Create(ExecutingContext* context,
const AtomicString& type,
const std::shared_ptr<HybridRouterChangeEventInit>& initializer,
ExceptionState& exception_state);

explicit HybridRouterChangeEvent(ExecutingContext* context, const AtomicString& type, ExceptionState& exception_state);

explicit HybridRouterChangeEvent(ExecutingContext* context,
const AtomicString& type,
const std::shared_ptr<HybridRouterChangeEventInit>& initializer,
ExceptionState& exception_state);

explicit HybridRouterChangeEvent(ExecutingContext* context, const AtomicString& type, NativeHybridRouterChangeEvent* native_ui_event);

ScriptValue state() const;
AtomicString kind() const;
AtomicString name() const;

bool IsHybridRouterChangeEvent() const override;

void Trace(GCVisitor* visitor) const override;

private:
ScriptValue state_;
AtomicString kind_;
AtomicString name_;
};

template <>
struct DowncastTraits<HybridRouterChangeEvent> {
static bool AllowFrom(const Event& event) { return event.IsHybridRouterChangeEvent(); }
};

} // namespace webf

#endif // WEBF_CORE_EVENTS_HYBRID_ROUTER_CHANGE_EVENT_H_
9 changes: 9 additions & 0 deletions bridge/core/events/hybrid_router_change_event_init.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {EventInit} from "../dom/events/event_init";

// @ts-ignore
@Dictionary()
export interface HybridRouterChangeEventInit extends EventInit {
kind?: string;
name?: string;
state?: any;
}
26 changes: 26 additions & 0 deletions bridge/polyfill/src/hybrid-history.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2019-2022 The Kraken authors. All rights reserved.
* Copyright (C) 2022-present The WebF authors. All rights reserved.
*/

import { webf } from './webf';

class HybridHistory {
get state() {
return JSON.parse(webf.invokeModule('HybridHistory', 'state'));
}

back() {
webf.invokeModule('HybridHistory', 'back');
}

pushState(state: any, name: string) {
if (arguments.length < 2) {
throw TypeError("Failed to execute 'pushState' on 'HybridHistory': 2 arguments required, but only " + arguments.length + " present");
}

webf.invokeModule('HybridHistory', 'pushState', [state, name]);
}
}

export const hybridHistory = new HybridHistory();
2 changes: 2 additions & 0 deletions bridge/polyfill/src/webf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@

import { addWebfModuleListener, webfInvokeModule, clearWebfModuleListener, removeWebfModuleListener } from './bridge';
import { methodChannel, triggerMethodCallHandler } from './method-channel';
import { hybridHistory } from './hybrid-history';

addWebfModuleListener('MethodChannel', (event, data) => triggerMethodCallHandler(data[0], data[1]));

export const webf = {
methodChannel,
invokeModule: webfInvokeModule,
hybridHistory: hybridHistory,
addWebfModuleListener: addWebfModuleListener,
clearWebfModuleListener: clearWebfModuleListener,
removeWebfModuleListener: removeWebfModuleListener
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion webf/example/assets/bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ p.appendChild(text1);
p.appendChild(br);
p.appendChild(text2);

document.body.appendChild(p);
document.body.appendChild(p);
1 change: 1 addition & 0 deletions webf/lib/html.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export 'src/html/listview.dart';
export 'src/html/script.dart';
export 'src/html/sections.dart';
export 'src/html/semantics_text.dart';
export 'src/html/router_link.dart';
export 'src/html/template.dart';
export 'src/html/textarea.dart';
export 'src/html/pseudo.dart';
1 change: 1 addition & 0 deletions webf/lib/module.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ export 'src/module/schedule_frame.dart';
export 'src/module/timer.dart';
export 'src/module/location.dart';
export 'src/module/history.dart';
export 'src/module/hybrid_history.dart';
export 'src/module/navigation.dart';
export 'src/module/navigator.dart';
18 changes: 15 additions & 3 deletions webf/lib/src/dom/element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ abstract class Element extends ContainerNode with ElementBase, ElementEventMixin
}

SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
if (!previousRenderBoxModel.disposed) {
if (!previousRenderBoxModel.disposed && !managedByFlutterWidget) {
previousRenderBoxModel.dispose();
}
});
Expand Down Expand Up @@ -1329,18 +1329,30 @@ abstract class Element extends ContainerNode with ElementBase, ElementEventMixin
containingBlockRenderBox = parentNode!.renderer;
break;
case CSSPositionType.absolute:
Element viewportElement = ownerDocument.documentElement!;

if (ownerView.activeRouterRoot != null) {
viewportElement = (ownerView.activeRouterRoot!.firstChild as RenderBoxModel).renderStyle.target;
}

// If the element has 'position: absolute', the containing block is established by the nearest ancestor with
// a 'position' of 'absolute', 'relative' or 'fixed', in the following way:
// 1. In the case that the ancestor is an inline element, the containing block is the bounding box around
// the padding boxes of the first and the last inline boxes generated for that element.
// In CSS 2.1, if the inline element is split across multiple lines, the containing block is undefined.
// 2. Otherwise, the containing block is formed by the padding edge of the ancestor.
containingBlockRenderBox = _findContainingBlock(this, ownerDocument.documentElement!)?._renderLayoutBox;
containingBlockRenderBox = _findContainingBlock(this, viewportElement)?._renderLayoutBox;
break;
case CSSPositionType.fixed:
Element viewportElement = ownerDocument.documentElement!;

if (ownerView.activeRouterRoot != null) {
viewportElement = (ownerView.activeRouterRoot!.firstChild as RenderBoxModel).renderStyle.target;
}

// If the element has 'position: fixed', the containing block is established by the viewport
// in the case of continuous media or the page area in the case of paged media.
containingBlockRenderBox = ownerDocument.documentElement!._renderLayoutBox;
containingBlockRenderBox = viewportElement.renderer;
break;
}
return containingBlockRenderBox;
Expand Down
4 changes: 4 additions & 0 deletions webf/lib/src/dom/element_registry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import 'package:webf/dom.dart';
import 'package:webf/html.dart';
import 'package:webf/foundation.dart';
import 'package:webf/src/html/router_link.dart';
import 'package:webf/svg.dart';

typedef ElementCreator = Element Function(BindingContext? context);
Expand Down Expand Up @@ -183,6 +184,9 @@ void defineBuiltInElements() {
defineElement(CANVAS, (context) => CanvasElement(context));
defineElement(LISTVIEW, (context) => FlutterListViewElement(context));

// Hybrid Routers
defineElement(ROUTER_LINK, (context) => RouterLinkElement(context));

svgElementsRegistry.forEach((key, value) {
_svgRegistry[key.toUpperCase()] = value;
});
Expand Down
Loading

0 comments on commit b1e37c7

Please sign in to comment.