Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions core/runtime/lepus/bindings/renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ constexpr static const char* kCFunctionAppendElement = "__AppendElement";
constexpr static const char* kCFunctionRemoveElement = "__RemoveElement";
constexpr static const char* kCFunctionInsertElementBefore =
"__InsertElementBefore";
constexpr static const char* kCFunctionInsertElementAt = "__InsertElementAt";
constexpr static const char* kCFunctionRemoveElementsAt = "__RemoveElementsAt";
constexpr static const char* kCFunctionMoveElements = "__MoveElements";
constexpr static const char* kCFunctionFirstElement = "__FirstElement";
constexpr static const char* kCFunctionLastElement = "__LastElement";
constexpr static const char* kCFunctionNextElement = "__NextElement";
Expand Down
171 changes: 171 additions & 0 deletions core/runtime/lepus/bindings/renderer_functions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3198,6 +3198,177 @@ RENDERER_FUNCTION_CC(FiberInsertElementBefore) {
RETURN(lepus::Value(std::move(child)));
}

RENDERER_FUNCTION_CC(FiberInsertElementAt) {
TRACE_EVENT(LYNX_TRACE_CATEGORY, FIBER_INSERT_ELEMENT_AT);
// parameter size = 3
// [0] Element -> parent element
// [1] Element -> child element
// [2] Number -> index
CHECK_ARGC_GE(FiberInsertElementAt, 3);
CONVERT_ARG_AND_CHECK_FOR_ELEMENT_API(arg0, 0, RefCounted,
FiberInsertElementAt);
CONVERT_ARG_AND_CHECK_FOR_ELEMENT_API(arg1, 1, RefCounted,
FiberInsertElementAt);
CONVERT_ARG_AND_CHECK_FOR_ELEMENT_API(arg2, 2, Number, FiberInsertElementAt);

auto parent = GetFiberElementFromValue(*arg0);
auto child = GetFiberElementFromValue(*arg1);
if (parent == nullptr || child == nullptr) {
ElementAPIError("FiberInsertElementAt parent and child should be Element");
RETURN_UNDEFINED();
}

const auto index = static_cast<int32_t>(arg2->Number());
const int64_t child_count = static_cast<int64_t>(parent->GetChildCount());
if (index < 0 || static_cast<int64_t>(index) > child_count) {
ElementAPIError(
"FiberInsertElementAt index is out of bounds, index: %d, size: %lld",
index, static_cast<long long>(child_count));
RETURN_UNDEFINED();
}

parent->InsertNode(child, index);
ON_NODE_ADDED(child);
RETURN_UNDEFINED();
}

RENDERER_FUNCTION_CC(FiberRemoveElementsAt) {
TRACE_EVENT(LYNX_TRACE_CATEGORY, FIBER_REMOVE_ELEMENTS_AT);
// parameter size = 3
// [0] Element -> parent element
// [1] Number -> index
// [2] Number -> count
CHECK_ARGC_GE(FiberRemoveElementsAt, 3);
CONVERT_ARG_AND_CHECK_FOR_ELEMENT_API(arg0, 0, RefCounted,
FiberRemoveElementsAt);
CONVERT_ARG_AND_CHECK_FOR_ELEMENT_API(arg1, 1, Number, FiberRemoveElementsAt);
CONVERT_ARG_AND_CHECK_FOR_ELEMENT_API(arg2, 2, Number, FiberRemoveElementsAt);

auto parent = GetFiberElementFromValue(*arg0);
if (parent == nullptr) {
ElementAPIError("FiberRemoveElementsAt parent should be Element");
RETURN_UNDEFINED();
}

const auto index = static_cast<int32_t>(arg1->Number());
const auto count = static_cast<int32_t>(arg2->Number());
const int64_t child_count = static_cast<int64_t>(parent->GetChildCount());
const int64_t range_end =
static_cast<int64_t>(index) + static_cast<int64_t>(count);
if (index < 0 || count < 0 || static_cast<int64_t>(index) > child_count ||
range_end > child_count) {
ElementAPIError(
"FiberRemoveElementsAt range is out of bounds, index: %d, count: %d, "
"size: %lld",
index, count, static_cast<long long>(child_count));
RETURN_UNDEFINED();
}

base::InlineVector<fml::RefPtr<Element>, 16> removed_elements;
for (int32_t offset = 0; offset < count; ++offset) {
const auto child_index =
static_cast<size_t>(static_cast<int64_t>(index) + offset);
auto* child = parent->GetChildAt(child_index);
if (child == nullptr) {
ElementAPIError(
"FiberRemoveElementsAt failed to resolve the complete child range");
RETURN_UNDEFINED();
}
removed_elements.emplace_back(fml::RefPtr<Element>(child));
}

for (const auto& child : removed_elements) {
ON_NODE_REMOVED(child);
parent->RemoveNode(child);
}
RETURN_UNDEFINED();
}

RENDERER_FUNCTION_CC(FiberMoveElements) {
TRACE_EVENT(LYNX_TRACE_CATEGORY, FIBER_MOVE_ELEMENTS);
// parameter size = 4
// [0] Element -> parent element
// [1] Number -> source index in the pre-change sequence
// [2] Number -> destination index in the pre-change sequence
// [3] Number -> count
CHECK_ARGC_GE(FiberMoveElements, 4);
CONVERT_ARG_AND_CHECK_FOR_ELEMENT_API(arg0, 0, RefCounted, FiberMoveElements);
CONVERT_ARG_AND_CHECK_FOR_ELEMENT_API(arg1, 1, Number, FiberMoveElements);
CONVERT_ARG_AND_CHECK_FOR_ELEMENT_API(arg2, 2, Number, FiberMoveElements);
CONVERT_ARG_AND_CHECK_FOR_ELEMENT_API(arg3, 3, Number, FiberMoveElements);

auto parent = GetFiberElementFromValue(*arg0);
if (parent == nullptr) {
ElementAPIError("FiberMoveElements parent should be Element");
RETURN_UNDEFINED();
}

const auto from = static_cast<int32_t>(arg1->Number());
const auto to = static_cast<int32_t>(arg2->Number());
const auto count = static_cast<int32_t>(arg3->Number());
const int64_t child_count = static_cast<int64_t>(parent->GetChildCount());
const int64_t source_end =
static_cast<int64_t>(from) + static_cast<int64_t>(count);
if (from < 0 || to < 0 || count < 0 ||
static_cast<int64_t>(from) > child_count ||
static_cast<int64_t>(to) > child_count || source_end > child_count) {
ElementAPIError(
"FiberMoveElements range is out of bounds, from: %d, to: %d, count: "
"%d, size: %lld",
from, to, count, static_cast<long long>(child_count));
RETURN_UNDEFINED();
}

if (count == 0 || from == to || static_cast<int64_t>(to) == source_end) {
RETURN_UNDEFINED();
}
if (from < to && static_cast<int64_t>(to) < source_end) {
ElementAPIError(
"FiberMoveElements destination overlaps the source range, from: %d, "
"to: %d, count: %d",
from, to, count);
RETURN_UNDEFINED();
}

const int64_t destination =
from > to ? static_cast<int64_t>(to)
: static_cast<int64_t>(to) - static_cast<int64_t>(count);
const int64_t destination_end = destination + static_cast<int64_t>(count);
if (destination < 0 || destination > child_count - count ||
destination_end - 1 > std::numeric_limits<int32_t>::max()) {
ElementAPIError(
"FiberMoveElements destination is out of bounds, from: %d, to: %d, "
"count: %d, destination: %lld, size: %lld",
from, to, count, static_cast<long long>(destination),
static_cast<long long>(child_count));
RETURN_UNDEFINED();
}

base::InlineVector<fml::RefPtr<Element>, 16> moving_elements;
for (int32_t offset = 0; offset < count; ++offset) {
const auto child_index =
static_cast<size_t>(static_cast<int64_t>(from) + offset);
auto* child = parent->GetChildAt(child_index);
if (child == nullptr) {
ElementAPIError(
"FiberMoveElements failed to resolve the complete source range");
RETURN_UNDEFINED();
}
moving_elements.emplace_back(fml::RefPtr<Element>(child));
}

for (const auto& child : moving_elements) {
ON_NODE_REMOVED(child);
parent->RemoveNode(child, false);
}
for (int32_t offset = 0; offset < count; ++offset) {
const auto& child = moving_elements[offset];
parent->InsertNode(child, static_cast<int32_t>(destination + offset));
ON_NODE_ADDED(child);
}
RETURN_UNDEFINED();
}

RENDERER_FUNCTION_CC(FiberFirstElement) {
TRACE_EVENT(LYNX_TRACE_CATEGORY, FIBER_FIRST_ELEMENT);
// parameter size = 1
Expand Down
3 changes: 3 additions & 0 deletions core/runtime/lepus/bindings/renderer_functions_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@
V(FiberAppendElement) \
V(FiberRemoveElement) \
V(FiberInsertElementBefore) \
V(FiberInsertElementAt) \
V(FiberRemoveElementsAt) \
V(FiberMoveElements) \
V(FiberFirstElement) \
V(FiberLastElement) \
V(FiberNextElement) \
Expand Down
3 changes: 3 additions & 0 deletions core/runtime/lepusng/bindings/renderer_ng.cc
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,9 @@ const runtime::RenderBindingFunction* Renderer::GetBuiltinFunctionsForFiber(
/* 130 */ {kCFunctionRemoveNodeFromElementTemplate, &RendererFunctions::FiberRemoveNodeFromElementTemplate, true, true},
/* 131 */ {kCFunctionSerializeElementTemplate, &RendererFunctions::FiberSerializeElementTemplate, true, true},
/* 132 */ {kCFunctionCreateTypedElementTemplate, &RendererFunctions::FiberCreateTypedElementTemplate, true, true},
/* 133 */ {kCFunctionInsertElementAt, &RendererFunctions::FiberInsertElementAt, true, true},
/* 134 */ {kCFunctionRemoveElementsAt, &RendererFunctions::FiberRemoveElementsAt, true, true},
/* 135 */ {kCFunctionMoveElements, &RendererFunctions::FiberMoveElements, true, true},
};
// clang-format on
size = sizeof(kFuncs) / sizeof(kFuncs[0]);
Expand Down
14 changes: 14 additions & 0 deletions core/runtime/trace/runtime_trace_event_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,20 @@ inline constexpr const char* const FIBER_REMOVE_ELEMENT = "FiberRemoveElement";
*/
inline constexpr const char* const FIBER_INSERT_ELEMENT_BEFORE =
"FiberInsertElementBefore";
/**
* @trace_description: Insert a Fiber element at a child index.
*/
inline constexpr const char* const FIBER_INSERT_ELEMENT_AT =
"FiberInsertElementAt";
/**
* @trace_description: Remove Fiber elements from a child index range.
*/
inline constexpr const char* const FIBER_REMOVE_ELEMENTS_AT =
"FiberRemoveElementsAt";
/**
* @trace_description: Move Fiber elements between child indexes.
*/
inline constexpr const char* const FIBER_MOVE_ELEMENTS = "FiberMoveElements";
/**
* @trace_description: Get the first child element of a Fiber element.
*/
Expand Down
6 changes: 6 additions & 0 deletions js_libraries/type-element-api/types/element-api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@ declare global {

function __InsertElementBefore(parent: ElementRef, current: ElementRef, marker?: ElementRef): ElementRef;

function __InsertElementAt(parent: ElementRef, current: ElementRef, index: number): void;

function __RemoveElementsAt(parent: ElementRef, index: number, count: number): void;

function __MoveElements(parent: ElementRef, from: number, to: number, count: number): void;

function __SwapElement(left: ElementRef, right: ElementRef): void;

function __ReplaceElement(newElement: ElementRef, oldElement: ElementRef): void;
Expand Down
Loading