Skip to content
Open
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
1 change: 1 addition & 0 deletions hippy.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Pod::Spec.new do |s|
'renderer/native/ios/**/NativeRenderManager.h',
'renderer/native/ios/**/HippyComponentMap.h',
'renderer/native/ios/**/UIView+DirectionalLayout.h',
'renderer/native/ios/**/HippyViewsRelation.h',
'modules/vfs/ios/**/!(*HippyVFSDefines).h' # Exclude the specified file
]
framework.public_header_files = [
Expand Down
72 changes: 5 additions & 67 deletions renderer/native/ios/renderer/HippyUIManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@
#import "HippyShadowTextView.h"
#import "HippyDeviceBaseInfo.h"
#import "HippyEventDispatcher.h"
#import "HippyViewsRelation.h"
#import "dom/root_node.h"
#import <objc/runtime.h>
#import <os/lock.h>
#import <unordered_map>


using HippyValue = footstone::value::HippyValue;
Expand All @@ -73,75 +73,13 @@
using DomEvent = hippy::DomEvent;
using RootNode = hippy::RootNode;


using HPViewBinding = std::map<int32_t, std::tuple<std::vector<int32_t>, std::vector<int32_t>>>;

constexpr char kVSyncKey[] = "frameupdate";

@interface NativeRenderViewsRelation : NSObject {
HPViewBinding _viewRelation;
}

- (void)addViewTag:(int32_t)viewTag forSuperViewTag:(int32_t)superviewTag atIndex:(int32_t)index;

- (void)enumerateViewsRelation:(void (^)(NSNumber *, NSArray<NSNumber *> *, NSArray<NSNumber *> *))block;

- (void)removeAllObjects;

@end

@implementation NativeRenderViewsRelation

- (void)addViewTag:(int32_t)viewTag forSuperViewTag:(int32_t)superviewTag atIndex:(int32_t)index {
if (superviewTag) {
auto &viewTuple = _viewRelation[superviewTag];
auto &subviewTagTuple = std::get<0>(viewTuple);
auto &subviewIndexTuple = std::get<1>(viewTuple);
subviewTagTuple.push_back(viewTag);
subviewIndexTuple.push_back(index);
}
}

- (void)enumerateViewsRelation:(void (^)(NSNumber *, NSArray<NSNumber *> *, NSArray<NSNumber *> *))block {
//using HPViewBinding = std::unordered_map<int32_t, std::tuple<std::vector<int32_t>, std::vector<int32_t>>>;
for (const auto &element : _viewRelation) {
NSNumber *superviewTag = @(element.first);
const auto &subviewTuple = element.second;
const auto &subviewTags = std::get<0>(subviewTuple);
NSMutableArray<NSNumber *> *subviewTagsArray = [NSMutableArray arrayWithCapacity:subviewTags.size()];
for (const auto &subviewTag : subviewTags) {
[subviewTagsArray addObject:@(subviewTag)];
}
const auto &subviewIndex = std::get<1>(subviewTuple);
NSMutableArray<NSNumber *> *subviewIndexArray = [NSMutableArray arrayWithCapacity:subviewIndex.size()];
for (const auto &subviewIndex : subviewIndex) {
[subviewIndexArray addObject:@(subviewIndex)];
}
block(superviewTag, [subviewTagsArray copy], [subviewIndexArray copy]);
}
}

- (void)enumerateViewsHierarchy:(void (^)(int32_t , const std::vector<int32_t> &, const std::vector<int32_t> &))block {
for (const auto &element : _viewRelation) {
int32_t tag = element.first;
const auto &subviewTuple = element.second;
const auto &subviewTags = std::get<0>(subviewTuple);
const auto &subviewIndex = std::get<1>(subviewTuple);
block(tag, subviewTags, subviewIndex);
}
}

- (void)removeAllObjects {
_viewRelation.clear();
}

@end

static void NativeRenderTraverseViewNodes(id<HippyComponent> view, void (^block)(id<HippyComponent>)) {
static void HippyTraverseViewNodes(id<HippyComponent> view, void (^block)(id<HippyComponent>)) {
if (view.hippyTag != nil) {
block(view);
for (id<HippyComponent> subview in view.hippySubviews) {
NativeRenderTraverseViewNodes(subview, block);
HippyTraverseViewNodes(subview, block);
}
}
}
Expand Down Expand Up @@ -504,7 +442,7 @@ - (void)purgeChildren:(NSArray<id<HippyComponent>> *)children
fromRegistry:(HippyComponentMap *)registryMap {
NSDictionary *currentRegistry = [registryMap componentsForRootTag:rootTag];
for (id<HippyComponent> child in children) {
NativeRenderTraverseViewNodes(currentRegistry[child.hippyTag], ^(id<HippyComponent> subview) {
HippyTraverseViewNodes(currentRegistry[child.hippyTag], ^(id<HippyComponent> subview) {
NSAssert(![subview isHippyRootView], @"Root views should not be unregistered");
if ([subview respondsToSelector:@selector(invalidate)]) {
[subview performSelector:@selector(invalidate)];
Expand Down Expand Up @@ -833,7 +771,7 @@ - (void)createRenderNodes:(std::vector<std::shared_ptr<DomNode>> &&)nodes
}
NSNumber *rootNodeTag = @(strongRootNode->GetId());
std::lock_guard<std::mutex> lock([self renderQueueLock]);
NativeRenderViewsRelation *manager = [[NativeRenderViewsRelation alloc] init];
HippyViewsRelation *manager = [[HippyViewsRelation alloc] init];
for (const std::shared_ptr<DomNode> &node : nodes) {
const auto& render_info = node->GetRenderInfo();
[manager addViewTag:render_info.id forSuperViewTag:render_info.pid atIndex:render_info.index];
Expand Down
51 changes: 51 additions & 0 deletions renderer/native/ios/renderer/HippyViewsRelation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*!
* iOS SDK
*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import <Foundation/Foundation.h>
#include <vector>

NS_ASSUME_NONNULL_BEGIN

/// Helper class for managing view hierarchy relationships during batch view creation.
/// Provides enumeration with subviews sorted by insertion indices.
///
/// @note This is an internal class and should not be exposed in public headers.
@interface HippyViewsRelation : NSObject

/// Adds a view tag to its superview at the specified index.
/// Only negative superview tags are rejected. Tags of 0 and negative indices are allowed.
- (void)addViewTag:(int32_t)viewTag forSuperViewTag:(int32_t)superviewTag atIndex:(int32_t)index;

/// Enumerates all view hierarchies with subviews sorted by their indices in ascending order.
/// The internal storage is not modified; sorting is performed on temporary copies.
- (void)enumerateViewsHierarchy:(void (^)(int32_t, const std::vector<int32_t> &, const std::vector<int32_t> &))block;

/// Returns YES if no relationships are stored.
- (BOOL)isEmpty;

/// Removes all stored relationships.
- (void)removeAllObjects;

@end

NS_ASSUME_NONNULL_END

114 changes: 114 additions & 0 deletions renderer/native/ios/renderer/HippyViewsRelation.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*!
* iOS SDK
*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#import "HippyViewsRelation.h"
#include <unordered_map>
#include <algorithm>
#include <tuple>

/// Maps superview tag -> (subview tags, subview indices)
using HPViewBinding = std::unordered_map<int32_t, std::tuple<std::vector<int32_t>, std::vector<int32_t>>>;

@implementation HippyViewsRelation {
HPViewBinding _viewRelation;
}

/// Sorts parallel vectors by indices in ascending order while maintaining tag-to-index correspondence.
/// Includes fast paths for already-sorted data and edge cases.
static inline void HP_SortByIndexAscending(const std::vector<int32_t> &inTags,
const std::vector<int32_t> &inIndices,
std::vector<int32_t> &outTags,
std::vector<int32_t> &outIndices) {
if (inTags.size() != inIndices.size() || inTags.empty()) {
outTags = inTags;
outIndices = inIndices;
return;
}

if (std::is_sorted(inIndices.begin(), inIndices.end())) {
outTags = inTags;
outIndices = inIndices;
return;
}

// Build and sort index permutation
std::vector<size_t> order;
order.reserve(inIndices.size());
for (size_t i = 0; i < inIndices.size(); ++i) {
order.push_back(i);
}
std::sort(order.begin(), order.end(), [&](size_t a, size_t b) {
return inIndices[a] < inIndices[b];
});

// Apply permutation
outTags.clear();
outIndices.clear();
outTags.reserve(inTags.size());
outIndices.reserve(inIndices.size());
for (size_t idx : order) {
outTags.push_back(inTags[idx]);
outIndices.push_back(inIndices[idx]);
}
}

- (void)addViewTag:(int32_t)viewTag forSuperViewTag:(int32_t)superviewTag atIndex:(int32_t)index {
// Only reject negative superview tags, as they have no valid use case
if (superviewTag < 0) {
return;
}

auto &viewTuple = _viewRelation[superviewTag];
auto &subviewTags = std::get<0>(viewTuple);
auto &subviewIndices = std::get<1>(viewTuple);
subviewTags.push_back(viewTag);
subviewIndices.push_back(index);
}

- (void)enumerateViewsHierarchy:(void (^)(int32_t, const std::vector<int32_t> &, const std::vector<int32_t> &))block {
if (!block) { return; }

for (const auto &element : _viewRelation) {
int32_t tag = element.first;
const auto &subviewTuple = element.second;
const auto &subviewTags = std::get<0>(subviewTuple);
const auto &subviewIndices = std::get<1>(subviewTuple);

// Sort by index to ensure correct insertion order
std::vector<int32_t> sortedTags;
std::vector<int32_t> sortedIndices;
HP_SortByIndexAscending(subviewTags, subviewIndices, sortedTags, sortedIndices);

block(tag, sortedTags, sortedIndices);
}
}

- (BOOL)isEmpty {
return _viewRelation.empty();
}

- (void)removeAllObjects {
_viewRelation.clear();
}

@end

Loading
Loading