You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by ac...@apache.org on 2018/04/26 12:39:56 UTC
[04/16] incubator-weex git commit: [WEEX-311] [iOS] use new
layoutEngin to replace yoga
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.cpp
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.cpp b/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.cpp
new file mode 100644
index 0000000..11f8dc8
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.cpp
@@ -0,0 +1,247 @@
+#include "WXCoreStyle.h"
+
+namespace WeexCore {
+
+ bool WXCoreMargin::setMargin(const WXCoreMarginEdge &edge, float margin) {
+ bool dirty = false;
+ switch (edge) {
+ case kMarginALL:
+ if (mMarginLeft != margin
+ || mMarginTop != margin
+ || mMarginRight != margin
+ || mMarginBottom != margin) {
+ mMarginLeft = margin;
+ mMarginTop = margin;
+ mMarginRight = margin;
+ mMarginBottom = margin;
+ dirty = true;
+ }
+ break;
+ case kMarginLeft:
+ if (mMarginLeft != margin) {
+ mMarginLeft = margin;
+ dirty = true;
+ }
+ break;
+ case kMarginTop:
+ if (mMarginTop != margin) {
+ mMarginTop = margin;
+ dirty = true;
+ }
+ break;
+ case kMarginRight:
+ if (mMarginRight != margin) {
+ mMarginRight = margin;
+ dirty = true;
+ }
+ break;
+ case kMarginBottom:
+ if (mMarginBottom != margin) {
+ mMarginBottom = margin;
+ dirty = true;
+ }
+ break;
+ }
+ return dirty;
+ }
+
+ float WXCoreMargin::getMargin(const WXCoreMarginEdge &edge)const {
+ float margin = 0;
+ switch (edge) {
+ case kMarginLeft:
+ margin = mMarginLeft;
+ break;
+ case kMarginTop:
+ margin = mMarginTop;
+ break;
+ case kMarginRight:
+ margin = mMarginRight;
+ break;
+ case kMarginBottom:
+ margin = mMarginBottom;
+ break;
+ default:
+ break;
+ }
+ return margin;
+ }
+
+ bool WXCorePadding::setPadding(const WXCorePaddingEdge &edge, float padding) {
+ bool dirty = false;
+ switch (edge) {
+ case kPaddingALL:
+ if (mPaddingLeft != padding
+ || mPaddingTop != padding
+ || mPaddingRight != padding
+ || mPaddingBottom != padding) {
+ mPaddingLeft = padding;
+ mPaddingTop = padding;
+ mPaddingRight = padding;
+ mPaddingBottom = padding;
+ dirty = true;
+ }
+ break;
+ case kPaddingLeft:
+ if (mPaddingLeft != padding) {
+ mPaddingLeft = padding;
+ dirty = true;
+ }
+ break;
+ case kPaddingTop:
+ if (mPaddingTop != padding) {
+ mPaddingTop = padding;
+ dirty = true;
+ }
+ break;
+ case kPaddingRight:
+ if (mPaddingRight != padding) {
+ mPaddingRight = padding;
+ dirty = true;
+ }
+ break;
+ case kPaddingBottom:
+ if (mPaddingBottom != padding) {
+ mPaddingBottom = padding;
+ dirty = true;
+ }
+ break;
+ }
+ return dirty;
+ }
+
+ float WXCorePadding::getPadding(const WXCorePaddingEdge &edge)const {
+ float padding = 0;
+ switch (edge) {
+ case kPaddingLeft:
+ padding = mPaddingLeft;
+ break;
+ case kPaddingTop:
+ padding = mPaddingTop;
+ break;
+ case kPaddingRight:
+ padding = mPaddingRight;
+ break;
+ case kPaddingBottom:
+ padding = mPaddingBottom;
+ break;
+ default:
+ break;
+ }
+ return padding;
+ }
+
+ bool WXCoreBorderWidth::setBorderWidth(const WXCoreBorderWidthEdge &edge, float borderWidth) {
+ bool dirty = false;
+ switch (edge) {
+ case kBorderWidthALL:
+ if (mBorderWidthLeft != borderWidth
+ || mBorderWidthTop != borderWidth
+ || mBorderWidthRight != borderWidth
+ || mBorderWidthBottom != borderWidth) {
+ mBorderWidthLeft = borderWidth;
+ mBorderWidthTop = borderWidth;
+ mBorderWidthRight = borderWidth;
+ mBorderWidthBottom = borderWidth;
+ dirty = true;
+ }
+ break;
+ case kBorderWidthLeft:
+ if (mBorderWidthLeft != borderWidth) {
+ mBorderWidthLeft = borderWidth;
+ dirty = true;
+ }
+ break;
+ case kBorderWidthTop:
+ if (mBorderWidthTop != borderWidth) {
+ mBorderWidthTop = borderWidth;
+ dirty = true;
+ }
+ break;
+ case kBorderWidthRight:
+ if (mBorderWidthRight != borderWidth) {
+ mBorderWidthRight = borderWidth;
+ dirty = true;
+ }
+ break;
+ case kBorderWidthBottom:
+ if (mBorderWidthBottom != borderWidth) {
+ mBorderWidthBottom = borderWidth;
+ dirty = true;
+ }
+ break;
+ }
+ return dirty;
+ }
+
+ float WXCoreBorderWidth::getBorderWidth(const WXCoreBorderWidthEdge &edge)const {
+ float borderWidth = 0;
+ switch (edge) {
+ case kBorderWidthLeft:
+ borderWidth = mBorderWidthLeft;
+ break;
+ case kBorderWidthTop:
+ borderWidth = mBorderWidthTop;
+ break;
+ case kBorderWidthRight:
+ borderWidth = mBorderWidthRight;
+ break;
+ case kBorderWidthBottom:
+ borderWidth = mBorderWidthBottom;
+ break;
+ default:
+ break;
+ }
+ return borderWidth;
+ }
+
+ bool WXCorePosition::setPosition(const WXCorePositionEdge &edge, float position) {
+ bool dirty = false;
+ switch (edge) {
+ case kPositionEdgeLeft:
+ if (mLeft != position) {
+ mLeft = position;
+ dirty = true;
+ }
+ break;
+ case kPositionEdgeTop:
+ if (mTop != position) {
+ mTop = position;
+ dirty = true;
+ }
+ break;
+ case kPositionEdgeRight:
+ if (mRight != position) {
+ mRight = position;
+ dirty = true;
+ }
+ break;
+ case kPositionEdgeBottom:
+ if (mBottom != position) {
+ mBottom = position;
+ dirty = true;
+ }
+ break;
+ }
+ return dirty;
+ }
+
+ float WXCorePosition::getPosition(const WXCorePositionEdge &edge) {
+ float position = 0;
+ switch (edge) {
+ case kPositionEdgeLeft:
+ position = mLeft;
+ break;
+ case kPositionEdgeTop:
+ position = mTop;
+ break;
+ case kPositionEdgeRight:
+ position = mRight;
+ break;
+ case kPositionEdgeBottom:
+ position = mBottom;
+ break;
+ }
+ return position;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.h b/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.h
new file mode 100644
index 0000000..bc7dd06
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXCoreStyle.h
@@ -0,0 +1,285 @@
+#ifdef __cplusplus
+
+#ifndef WEEXCORE_FLEXLAYOUT_WXCOREFLEXENUMS_H
+#define WEEXCORE_FLEXLAYOUT_WXCOREFLEXENUMS_H
+
+
+#include "WXCoreFlexEnum.h"
+#include <cmath>
+
+namespace WeexCore {
+
+ /**
+ * Margin: margin-left、margin-right、margin-top、margin-bottom
+ */
+ class WXCoreMargin {
+ private:
+ float mMarginTop;
+ float mMarginBottom;
+ float mMarginLeft;
+ float mMarginRight;
+
+ public:
+ WXCoreMargin() : mMarginTop(0),
+ mMarginBottom(0),
+ mMarginLeft(0),
+ mMarginRight(0) {}
+
+ ~WXCoreMargin() {
+ mMarginTop = 0;
+ mMarginBottom = 0;
+ mMarginLeft = 0;
+ mMarginRight = 0;
+ }
+
+ bool setMargin(const WXCoreMarginEdge &edge, float margin);
+
+ float getMargin(const WXCoreMarginEdge &edge)const;
+ };
+
+
+ /**
+ * Padding:padding-left、padding-right、padding-top、padding-bottom
+ */
+ class WXCorePadding {
+ private:
+ float mPaddingTop;
+ float mPaddingBottom;
+ float mPaddingLeft;
+ float mPaddingRight;
+
+ public:
+ WXCorePadding() : mPaddingTop(0),
+ mPaddingBottom(0),
+ mPaddingLeft(0),
+ mPaddingRight(0) {}
+
+ ~WXCorePadding() {
+ mPaddingTop = 0;
+ mPaddingBottom = 0;
+ mPaddingLeft = 0;
+ mPaddingRight = 0;
+ }
+
+ bool setPadding(const WXCorePaddingEdge &edge, float padding);
+
+ float getPadding(const WXCorePaddingEdge &edge)const;
+ };
+
+
+ /**
+ * BorderWidth:borderwidth-left、borderwidth-right、borderwidth-top、borderwidth-bottom
+ */
+ class WXCoreBorderWidth {
+ private:
+ float mBorderWidthTop;
+ float mBorderWidthBottom;
+ float mBorderWidthLeft;
+ float mBorderWidthRight;
+
+ public:
+ WXCoreBorderWidth() : mBorderWidthTop(0),
+ mBorderWidthBottom(0),
+ mBorderWidthLeft(0),
+ mBorderWidthRight(0) {}
+
+ ~WXCoreBorderWidth() {
+ mBorderWidthTop = 0;
+ mBorderWidthBottom = 0;
+ mBorderWidthLeft = 0;
+ mBorderWidthRight = 0;
+ }
+
+ bool setBorderWidth(const WXCoreBorderWidthEdge &edge, float borderWidth);
+
+ float getBorderWidth(const WXCoreBorderWidthEdge &edge)const;
+ };
+
+
+ /**
+ * position:left、right、top、bottom
+ */
+ class WXCorePosition {
+ private:
+ float mTop;
+ float mBottom;
+ float mLeft;
+ float mRight;
+
+ public:
+ WXCorePosition() : mTop(NAN),
+ mBottom(NAN),
+ mLeft(NAN),
+ mRight(NAN) {}
+
+ ~WXCorePosition() {
+ reset();
+ }
+
+ inline bool isNAN() {
+ return isnan(mTop) || isnan(mBottom) || isnan(mLeft) || isnan(mRight);
+ }
+
+ inline void reset() {
+ mTop = 0;
+ mBottom = 0;
+ mLeft = 0;
+ mRight = 0;
+ }
+
+ bool setPosition(const WXCorePositionEdge &edge, float position);
+
+ float getPosition(const WXCorePositionEdge &edge);
+ };
+
+ enum DimensionLevel{
+ CSS_STYLE = 1,
+ INSTANCE_STYLE = 2,
+ FALLBACK_STYLE = 3
+ };
+
+ /**
+ * css-style
+ */
+ class WXCoreCSSStyle {
+ public:
+ /**
+ * The direction children items are placed inside the Flexbox layout, it determines the
+ * direction of the main axis (and the cross axis, perpendicular to the main axis).
+ * The default value is {@link WXCoreFlexDirection #WXCore_Flex_Direction_Row}.
+ */
+ WXCoreFlexDirection mFlexDirection;
+
+ /**
+ * This attribute controls whether the flex container is single-line or multi-line, and the
+ * direction of the cross axis.
+ * <ul>
+ * <li>{@link WXCoreFlexWrap}: The flex container is single-line.</li>
+ * <li>{@link WXCoreFlexWrap}: The flex container is multi-line.</li>
+ * <li>{@link WXCoreFlexWrap}: The flex container is multi-line. The direction of the
+ * cross axis is opposed to the direction as the {@link WXCoreFlexWrap}</li>
+ * </ul>
+ * The default value is {@link WXCoreFlexWrap #WXCore_Wrap_NoWrap}.
+ */
+ WXCoreFlexWrap mFlexWrap;
+
+ /**
+ * This attribute controls the alignment along the main axis.
+ * The default value is {@link WXCoreJustifyContent #WXCore_Justify_Flex_Start}.
+ */
+ WXCoreJustifyContent mJustifyContent;
+
+ /**
+ * This attribute controls the alignment along the cross axis.
+ * The default value is {@link WXCoreAlignItems #WXCore_AlignItems_Stretch}.
+ */
+ WXCoreAlignItems mAlignItems;
+
+ /**
+ * This attribute controls the alignment along the cross axis.
+ * The default value is {@link WXCoreAlignSelf #WXCore_AlignSelf_Auto}.
+ */
+ WXCoreAlignSelf mAlignSelf;
+
+ WXCorePositionType mPositionType;
+
+ float mFlexGrow;
+
+ float mMinWidth;
+
+ float mMinHeight;
+
+ float mMaxWidth;
+
+ float mMaxHeight;
+
+ float mStyleWidth;
+
+ float mStyleHeight;
+
+ DimensionLevel mStyleWidthLevel;
+
+ DimensionLevel mStyleHeightLevel;
+
+ WXCoreMargin mMargin;
+
+ WXCorePadding mPadding;
+
+ WXCoreBorderWidth mBorderWidth;
+
+ WXCorePosition mStylePosition;
+
+ constexpr static float kFlexGrowDefault = 0;
+
+ constexpr static WXCoreFlexDirection kFlexDirectionDefault= kFlexDirectionColumn;
+
+ constexpr static WXCoreFlexWrap kFlexWrapDefault = kNoWrap;
+
+ constexpr static WXCoreJustifyContent kFlexJustifyContentDefault = kJustifyFlexStart;
+
+ constexpr static WXCoreAlignItems kFlexAlignItemsDefault = kAlignItemsStretch;
+
+ constexpr static WXCoreAlignSelf kFlexAlignSelfDefault = kAlignSelfAuto;
+
+ constexpr static WXCorePositionType kWXCorePositionTypeDefault = kRelative;
+
+ WXCoreCSSStyle() : mFlexDirection(kFlexDirectionDefault),
+ mFlexWrap(kFlexWrapDefault),
+ mJustifyContent(kFlexJustifyContentDefault),
+ mAlignItems(kFlexAlignItemsDefault),
+ mAlignSelf(kFlexAlignSelfDefault),
+ mFlexGrow(kFlexGrowDefault),
+ mPositionType(kWXCorePositionTypeDefault),
+ mStyleWidth(NAN), mStyleHeight(NAN),
+ mStyleHeightLevel(FALLBACK_STYLE), mStyleWidthLevel(FALLBACK_STYLE),
+ mMaxWidth(NAN), mMaxHeight(NAN),
+ mMinWidth(NAN), mMinHeight(NAN) {
+
+ }
+
+ ~WXCoreCSSStyle() {
+ mFlexDirection = kFlexDirectionDefault;
+ mFlexWrap = kFlexWrapDefault;
+ mJustifyContent = kFlexJustifyContentDefault;
+ mAlignItems = kFlexAlignItemsDefault;
+ mAlignSelf = kFlexAlignSelfDefault;
+ mFlexGrow = kFlexGrowDefault;
+ mStyleWidth = NAN;
+ mStyleHeight = NAN;
+ mStyleWidthLevel = FALLBACK_STYLE;
+ mStyleHeightLevel = FALLBACK_STYLE;
+ mMaxWidth = NAN;
+ mMaxHeight = NAN;
+ mMinWidth = NAN;
+ mMinHeight = NAN;
+ }
+
+ inline float sumPaddingBorderOfEdge(const WXCoreEdge edge){
+ switch (edge) {
+ case kTop:
+ return mPadding.getPadding(kPaddingTop)
+ + mBorderWidth.getBorderWidth(kBorderWidthTop);
+ case kRight:
+ return mPadding.getPadding(kPaddingRight)
+ + mBorderWidth.getBorderWidth(kBorderWidthRight);
+ case kBottom:
+ return mPadding.getPadding(kPaddingBottom)
+ + mBorderWidth.getBorderWidth(kBorderWidthBottom);
+ case kLeft:
+ return mPadding.getPadding(kPaddingLeft)
+ + mBorderWidth.getBorderWidth(kBorderWidthLeft);
+ }
+ }
+
+ float sumMarginOfDirection(bool horizontal){
+ if(horizontal){
+ return mMargin.getMargin(kMarginLeft) + mMargin.getMargin(kMarginRight);
+ }
+ else{
+ return mMargin.getMargin(kMarginTop) + mMargin.getMargin(kMarginBottom);
+ }
+ }
+ };
+}
+#endif //WEEXCORE_FLEXLAYOUT_WXCOREFLEXENUMS_H
+#endif
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXLayoutDefine.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXLayoutDefine.h b/ios/sdk/WeexSDK/Sources/Layout/WXLayoutDefine.h
index 7670085..93f43e9 100644
--- a/ios/sdk/WeexSDK/Sources/Layout/WXLayoutDefine.h
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXLayoutDefine.h
@@ -17,6 +17,9 @@
* under the License.
*/
+#if defined __cplusplus
+extern "C" {
+#endif
#define WX_LAYOUT_NAMESPACE wx_
@@ -53,5 +56,8 @@
#import "Layout.h"
+#if defined __cplusplus
+};
+#endif
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.h b/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.h
new file mode 100644
index 0000000..c9b633f
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.h
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "WXScrollerComponent.h"
+#import "WXComponent+Layout.h"
+
+
+@interface WXScrollerComponent ()
+{
+//#ifndef USE_FLEX
+ css_node_t *_scrollerCSSNode;
+//#else
+ WeexCore::WXCoreLayoutNode *_flexScrollerCSSNode;
+//#endif
+}
+@end
+
+@interface WXScrollerComponent (FlexLayout)
+
+//#ifndef USE_FLEX
+@property (nonatomic, readonly, assign) css_node_t *scrollerCSSNode;
+//#else
+@property (nonatomic, readonly, assign) WeexCore::WXCoreLayoutNode *flexScrollerCSSNode;
+//#endif
+
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.mm
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.mm b/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.mm
new file mode 100644
index 0000000..6eb8c9d
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXScrollerComponent+Layout.mm
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "WXScrollerComponent+Layout.h"
+#import "WXLog.h"
+
+@implementation WXScrollerComponent (FlexLayout)
+
+//#ifndef USE_FLEX
+- (css_node_t *)scrollerCSSNode
+{
+ return _scrollerCSSNode;
+}
+//#else
+- (WeexCore::WXCoreLayoutNode *)flexScrollerCSSNode{
+ return _flexScrollerCSSNode;
+}
+
+- (void)_insertChildCssNode:(WXComponent *)subcomponent atIndex:(NSInteger)index
+{
+ self.flexScrollerCSSNode->addChildAt(subcomponent.flexCssNode, (uint32_t) index);
+#ifdef DEBUG
+ WXLogDebug(@"flexLayout -> ref:%@,subNodeIndex:%ld,childCount:%ld",self.ref,(long)index,_flexScrollerCSSNode->getChildCount());
+#endif
+
+// WXLogInfo(@"FlexLayout -- P:%@ -> C:%@",self,subcomponent);
+}
+- (void)_rmChildCssNode:(WXComponent *)subcomponent
+{
+ self.flexScrollerCSSNode->removeChild(subcomponent->_flexCssNode);
+#ifdef DEBUG
+ WXLogDebug(@"flexLayout -> ref:%@ ,scrollerCSSNode->removeChild ,childRef:%@",self.ref,subcomponent.ref);
+#endif
+}
+
+//#endif
+@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.m b/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.m
deleted file mode 100644
index 175aeb7..0000000
--- a/ios/sdk/WeexSDK/Sources/Manager/WXComponentManager.m
+++ /dev/null
@@ -1,958 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 "WXComponentManager.h"
-#import "WXComponent.h"
-#import "WXComponent_internal.h"
-#import "WXComponent+DataBinding.h"
-#import "WXComponentFactory.h"
-#import "WXDefine.h"
-#import "NSArray+Weex.h"
-#import "WXSDKInstance.h"
-#import "WXAssert.h"
-#import "WXUtility.h"
-#import "WXMonitor.h"
-#import "WXScrollerProtocol.h"
-#import "WXSDKManager.h"
-#import "WXSDKError.h"
-#import "WXInvocationConfig.h"
-#import "WXHandlerFactory.h"
-#import "WXValidateProtocol.h"
-#import "WXPrerenderManager.h"
-#import "WXTracingManager.h"
-#import "WXLayoutDefine.h"
-#import "WXSDKInstance_performance.h"
-#import "WXRootView.h"
-
-static NSThread *WXComponentThread;
-
-#define WXAssertComponentExist(component) WXAssert(component, @"component not exists")
-
-@implementation WXComponentManager
-{
- __weak WXSDKInstance *_weexInstance;
- BOOL _isValid;
-
- BOOL _stopRunning;
- NSUInteger _noTaskTickCount;
-
- // access only on component thread
- NSMapTable<NSString *, WXComponent *> *_indexDict;
- NSMutableArray<dispatch_block_t> *_uiTaskQueue;
- NSMutableDictionary *_uiPrerenderTaskQueue;
-
- WXComponent *_rootComponent;
- NSMutableArray *_fixedComponents;
-
- css_node_t *_rootCSSNode;
- CADisplayLink *_displayLink;
-}
-
-+ (instancetype)sharedManager
-{
- static id _sharedInstance = nil;
- static dispatch_once_t oncePredicate;
- dispatch_once(&oncePredicate, ^{
- _sharedInstance = [[self alloc] init];
- });
- return _sharedInstance;
-}
-
-- (instancetype)initWithWeexInstance:(id)weexInstance
-{
- if (self = [self init]) {
- _weexInstance = weexInstance;
-
- _indexDict = [NSMapTable strongToWeakObjectsMapTable];
- _fixedComponents = [NSMutableArray wx_mutableArrayUsingWeakReferences];
- _uiTaskQueue = [NSMutableArray array];
- _isValid = YES;
- [self _startDisplayLink];
- }
-
- return self;
-}
-
-- (void)dealloc
-{
- free_css_node(_rootCSSNode);
- [NSMutableArray wx_releaseArray:_fixedComponents];
-}
-
-#pragma mark Thread Management
-
-+ (NSThread *)componentThread
-{
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, ^{
- WXComponentThread = [[NSThread alloc] initWithTarget:[self sharedManager] selector:@selector(_runLoopThread) object:nil];
- [WXComponentThread setName:WX_COMPONENT_THREAD_NAME];
- if(WX_SYS_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
- [WXComponentThread setQualityOfService:[[NSThread mainThread] qualityOfService]];
- } else {
- [WXComponentThread setThreadPriority:[[NSThread mainThread] threadPriority]];
- }
-
- [WXComponentThread start];
- });
-
- return WXComponentThread;
-}
-
-- (void)_runLoopThread
-{
- [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
-
- while (!_stopRunning) {
- @autoreleasepool {
- [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
- }
- }
-}
-
-+ (void)_performBlockOnComponentThread:(void (^)(void))block
-{
- if([NSThread currentThread] == [self componentThread]){
- block();
- } else {
- [self performSelector:@selector(_performBlockOnComponentThread:)
- onThread:WXComponentThread
- withObject:[block copy]
- waitUntilDone:NO];
- }
-}
-
-+ (void)_performBlockSyncOnComponentThread:(void (^)(void))block
-{
- if([NSThread currentThread] == [self componentThread]){
- block();
- } else {
- [self performSelector:@selector(_performBlockOnComponentThread:)
- onThread:WXComponentThread
- withObject:[block copy]
- waitUntilDone:YES];
- }
-}
-
-- (void)startComponentTasks
-{
- [self _awakeDisplayLink];
-}
-
-- (void)rootViewFrameDidChange:(CGRect)frame
-{
- WXAssertComponentThread();
-
- if (_rootCSSNode) {
- [self _applyRootFrame:frame toRootCSSNode:_rootCSSNode];
- if (!_rootComponent.styles[@"width"]) {
- _rootComponent.cssNode->style.dimensions[CSS_WIDTH] = frame.size.width ?: CSS_UNDEFINED;
- }
- if (!_rootComponent.styles[@"height"]) {
- _rootComponent.cssNode->style.dimensions[CSS_HEIGHT] = frame.size.height ?: CSS_UNDEFINED;
- }
- [_rootComponent setNeedsLayout];
- [self startComponentTasks];
- }
-}
-
-- (void)_applyRootFrame:(CGRect)rootFrame toRootCSSNode:(css_node_t *)rootCSSNode
-{
- _rootCSSNode->style.position[CSS_LEFT] = self.weexInstance.frame.origin.x;
- _rootCSSNode->style.position[CSS_TOP] = self.weexInstance.frame.origin.y;
-
- // if no instance width/height, use layout width/height, as Android's wrap_content
- _rootCSSNode->style.dimensions[CSS_WIDTH] = self.weexInstance.frame.size.width ?: CSS_UNDEFINED;
- _rootCSSNode->style.dimensions[CSS_HEIGHT] = self.weexInstance.frame.size.height ?: CSS_UNDEFINED;
-}
-
-- (void)_addUITask:(void (^)(void))block
-{
- if(!_uiPrerenderTaskQueue){
- _uiPrerenderTaskQueue = [NSMutableDictionary new];
- }
- if(self.weexInstance.needPrerender){
- NSMutableArray<dispatch_block_t> *tasks = [_uiPrerenderTaskQueue objectForKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
- if(!tasks){
- tasks = [NSMutableArray new];
- }
- [tasks addObject:block];
- [_uiPrerenderTaskQueue setObject:tasks forKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
- }else{
- [_uiTaskQueue addObject:block];
- }
-}
-
-- (void)excutePrerenderUITask:(NSString *)url
-{
- NSMutableArray *tasks = [_uiPrerenderTaskQueue objectForKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
- for (id block in tasks) {
- [_uiTaskQueue addObject:block];
- }
- tasks = [NSMutableArray new];
- [_uiPrerenderTaskQueue setObject:tasks forKey:[WXPrerenderManager getTaskKeyFromUrl:self.weexInstance.scriptURL.absoluteString]];
-}
-
-#pragma mark Component Tree Building
-
-- (void)createRoot:(NSDictionary *)data
-{
- WXAssertComponentThread();
- WXAssertParam(data);
-
- _rootComponent = [self _buildComponentForData:data supercomponent:nil];
-
- [self _initRootCSSNode];
-
- NSArray *subcomponentsData = [data valueForKey:@"children"];
- if (subcomponentsData) {
- BOOL appendTree = [_rootComponent.attributes[@"append"] isEqualToString:@"tree"];
- for(NSDictionary *subcomponentData in subcomponentsData){
- [self _recursivelyAddComponent:subcomponentData toSupercomponent:_rootComponent atIndex:-1 appendingInTree:appendTree];
- }
- }
-
- __weak typeof(self) weakSelf = self;
- WX_MONITOR_INSTANCE_PERF_END(WXFirstScreenJSFExecuteTime, self.weexInstance);
- [self _addUITask:^{
- [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:data[@"ref"] className:nil name:data[@"type"] phase:WXTracingBegin functionName:@"createBody" options:@{@"threadName":WXTUIThread}];
- __strong typeof(self) strongSelf = weakSelf;
- strongSelf.weexInstance.rootView.wx_component = strongSelf->_rootComponent;
- [strongSelf.weexInstance.rootView addSubview:strongSelf->_rootComponent.view];
- [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:data[@"ref"] className:nil name:data[@"type"] phase:WXTracingEnd functionName:@"createBody" options:@{@"threadName":WXTUIThread}];
- }];
-
-
-}
-
-static bool rootNodeIsDirty(void *context)
-{
- WXComponentManager *manager = (__bridge WXComponentManager *)(context);
- return [manager->_rootComponent needsLayout];
-}
-
-static css_node_t * rootNodeGetChild(void *context, int i)
-{
- WXComponentManager *manager = (__bridge WXComponentManager *)(context);
- if (i == 0) {
- return manager->_rootComponent.cssNode;
- } else if(manager->_fixedComponents.count >= i) {
- return ((WXComponent *)((manager->_fixedComponents)[i-1])).cssNode;
- }
-
- return NULL;
-}
-
-- (void)addComponent:(NSDictionary *)componentData toSupercomponent:(NSString *)superRef atIndex:(NSInteger)index appendingInTree:(BOOL)appendingInTree
-{
- WXAssertComponentThread();
- WXAssertParam(componentData);
- WXAssertParam(superRef);
-
- WXComponent *supercomponent = [_indexDict objectForKey:superRef];
- WXAssertComponentExist(supercomponent);
-
- [self _recursivelyAddComponent:componentData toSupercomponent:supercomponent atIndex:index appendingInTree:appendingInTree];
-}
-
-- (void)_recursivelyAddComponent:(NSDictionary *)componentData toSupercomponent:(WXComponent *)supercomponent atIndex:(NSInteger)index appendingInTree:(BOOL)appendingInTree
-{
- WXComponent *component = [self _buildComponentForData:componentData supercomponent:supercomponent];
- if (!supercomponent.subcomponents) {
- index = 0;
- } else {
- index = (index == -1 ? supercomponent->_subcomponents.count : index);
- }
-
- [supercomponent _insertSubcomponent:component atIndex:index];
- // use _lazyCreateView to forbid component like cell's view creating
- if(supercomponent && component && supercomponent->_lazyCreateView) {
- component->_lazyCreateView = YES;
- }
-
- [self recordMaximumVirtualDom:component];
-
- if (!component->_isTemplate) {
- __weak typeof(self) weakSelf = self;
- BOOL isFSCreateFinish = [self weexInstance].isJSCreateFinish;
- [self _addUITask:^{
- [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:componentData[@"ref"] className:nil name:componentData[@"type"] phase:WXTracingBegin functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
- [supercomponent insertSubview:component atIndex:index];
- [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:componentData[@"ref"] className:nil name:componentData[@"type"] phase:WXTracingEnd functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
- [weakSelf onElementChange:isFSCreateFinish];
- }];
- }
-
- NSArray *subcomponentsData = [componentData valueForKey:@"children"];
-
- BOOL appendTree = !appendingInTree && [component.attributes[@"append"] isEqualToString:@"tree"];
- // if ancestor is appending tree, child should not be laid out again even it is appending tree.
- for(NSDictionary *subcomponentData in subcomponentsData){
- [self _recursivelyAddComponent:subcomponentData toSupercomponent:component atIndex:-1 appendingInTree:appendTree || appendingInTree];
- }
-
- [component _didInserted];
-
- if (appendTree) {
- // If appending tree,force layout in case of too much tasks piling up in syncQueue
- [self _layoutAndSyncUI];
- }
-}
-
-- (void)moveComponent:(NSString *)ref toSuper:(NSString *)superRef atIndex:(NSInteger)index
-{
- WXAssertComponentThread();
- WXAssertParam(ref);
- WXAssertParam(superRef);
-
- WXComponent *component = [_indexDict objectForKey:ref];
- WXComponent *newSupercomponent = [_indexDict objectForKey:superRef];
- WXAssertComponentExist(component);
- WXAssertComponentExist(newSupercomponent);
-
- if (component.supercomponent == newSupercomponent && [newSupercomponent.subcomponents indexOfObject:component] < index) {
- // if the supercomponent moved to is the same as original supercomponent,
- // unify it into the index after removing.
- index--;
- }
-
- [component _moveToSupercomponent:newSupercomponent atIndex:index];
- __weak typeof(self) weakSelf = self;
- [self _addUITask:^{
- [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingBegin functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
- [component moveToSuperview:newSupercomponent atIndex:index];
- [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingEnd functionName:@"addElement" options:@{@"threadName":WXTUIThread}];
- }];
-}
-
-- (void)removeComponent:(NSString *)ref
-{
- WXAssertComponentThread();
- WXAssertParam(ref);
-
- WXComponent *component = [_indexDict objectForKey:ref];
- WXAssertComponentExist(component);
-
- [component _removeFromSupercomponent];
-
- [_indexDict removeObjectForKey:ref];
-
- __weak typeof(self) weakSelf = self;
- BOOL isFSCreateFinish = [self weexInstance].isJSCreateFinish;
- [self _addUITask:^{
- [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingBegin functionName:@"removeElement" options:@{@"threadName":WXTUIThread}];
- if (component.supercomponent) {
- [component.supercomponent willRemoveSubview:component];
- }
- [component removeFromSuperview];
- [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingEnd functionName:@"removeElement" options:@{@"threadName":WXTUIThread}];
- [weakSelf onElementChange:isFSCreateFinish];
- }];
-
- [self _checkFixedSubcomponentToRemove:component];
-
-}
-
-- (void)onElementChange:(BOOL)isFSCreateFinish
-{
- if (!isFSCreateFinish) {
- return;
- }
-
- UIView *root = [self weexInstance].rootView;
- BOOL hasEvent = TRUE;
- if (root && [root isKindOfClass:[WXRootView class]]) {
- WXRootView* wxRootView = (WXRootView *)root;
- hasEvent = [wxRootView isHasEvent];
- }
- if (hasEvent) {
- return;
- }
- double current = CACurrentMediaTime()*1000;
-
- double diff = current - [self weexInstance].performance.jsCreateFinishTime;
- if (diff > 8000) {
- return;
- }
- [self weexInstance].performance.interactionTime = current - self.weexInstance.performance.renderTimeOrigin;
-}
-
-- (void)recordMaximumVirtualDom:(WXComponent*) component
-{
- WXAssertComponentExist(component);
- if(!component){
- return;
- }
- int maxDeep =0;
- while (component) {
- maxDeep++;
- component = component.supercomponent;
- }
- if(maxDeep > [self weexInstance].performance.maxVdomDeep)
- {
- [self weexInstance].performance.maxVdomDeep = maxDeep;
- }
-
-}
-
-- (void)_checkFixedSubcomponentToRemove:(WXComponent *)component
-{
- for (WXComponent *subcomponent in component.subcomponents) {
- if (subcomponent->_positionType == WXPositionTypeFixed) {
- [self _addUITask:^{
- [subcomponent removeFromSuperview];
- }];
- }
-
- [self _checkFixedSubcomponentToRemove:subcomponent];
- }
-}
-
-- (WXComponent *)componentForRef:(NSString *)ref
-{
- WXAssertComponentThread();
-
- return [_indexDict objectForKey:ref];
-}
-
-- (WXComponent *)componentForRoot
-{
- return _rootComponent;
-}
-
-- (NSUInteger)numberOfComponents
-{
- WXAssertComponentThread();
-
- return _indexDict.count;
-}
-
-- (WXComponent *)_buildComponentForData:(NSDictionary *)data supercomponent:(WXComponent *)supercomponent
-{
- NSString *ref = data[@"ref"];
- NSString *type = data[@"type"];
- NSDictionary *styles = data[@"style"];
- NSDictionary *attributes = data[@"attr"];
- NSArray *events = data[@"event"];
-
- if (self.weexInstance.needValidate) {
- id<WXValidateProtocol> validateHandler = [WXHandlerFactory handlerForProtocol:@protocol(WXValidateProtocol)];
- if (validateHandler) {
- WXComponentValidateResult* validateResult;
- if ([validateHandler respondsToSelector:@selector(validateWithWXSDKInstance:component:supercomponent:)]) {
- validateResult = [validateHandler validateWithWXSDKInstance:self.weexInstance component:type supercomponent:supercomponent];
- }
- if (validateResult==nil || !validateResult.isSuccess) {
- type = validateResult.replacedComponent? validateResult.replacedComponent : @"div";
- WXLogError(@"%@",[validateResult.error.userInfo objectForKey:@"errorMsg"]);
- }
- }
- }
-
- WXComponentConfig *config = [WXComponentFactory configWithComponentName:type];
- BOOL isTemplate = [config.properties[@"isTemplate"] boolValue] || (supercomponent && supercomponent->_isTemplate);
- NSDictionary *bindingStyles;
- NSDictionary *bindingAttibutes;
- NSDictionary *bindingEvents;
- NSDictionary *bindingProps;
- if (isTemplate) {
- bindingProps = [self _extractBindingProps:&attributes];
- bindingStyles = [self _extractBindings:&styles];
- bindingAttibutes = [self _extractBindings:&attributes];
- bindingEvents = [self _extractBindingEvents:&events];
- }
-
- Class clazz = NSClassFromString(config.clazz);;
- WXComponent *component = [[clazz alloc] initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:self.weexInstance];
- if (isTemplate) {
- component->_isTemplate = YES;
- [component _storeBindingsWithProps:bindingProps styles:bindingStyles attributes:bindingAttibutes events:bindingEvents];
- }
-
- WXAssert(component, @"Component build failed for data:%@", data);
-
- [_indexDict setObject:component forKey:component.ref];
- [component readyToRender];// notify redyToRender event when init
- return component;
-}
-
-- (void)addComponent:(WXComponent *)component toIndexDictForRef:(NSString *)ref
-{
- [_indexDict setObject:component forKey:ref];
-}
-
-- (NSDictionary *)_extractBindings:(NSDictionary **)attributesOrStylesPoint
-{
- NSDictionary *attributesOrStyles = *attributesOrStylesPoint;
- if (!attributesOrStyles) {
- return nil;
- }
-
- NSMutableDictionary *newAttributesOrStyles = [attributesOrStyles mutableCopy];
- NSMutableDictionary *bindingAttributesOrStyles = [NSMutableDictionary dictionary];
-
- [attributesOrStyles enumerateKeysAndObjectsUsingBlock:^(id _Nonnull attributeOrStyleName, id _Nonnull attributeOrStyle, BOOL * _Nonnull stop) {
- if ([WXBindingMatchIdentify isEqualToString:attributeOrStyleName] // match
- || [WXBindingRepeatIdentify isEqualToString:attributeOrStyleName] // repeat
- || [WXBindingOnceIdentify isEqualToString:attributeOrStyleName] // once
- ||([attributeOrStyle isKindOfClass:[NSDictionary class]] && attributeOrStyle[WXBindingIdentify])) { // {"attributeOrStyleName": {"@binding":"bindingExpression"}
- bindingAttributesOrStyles[attributeOrStyleName] = attributeOrStyle;
- [newAttributesOrStyles removeObjectForKey:attributeOrStyleName];
- } else if ([attributeOrStyle isKindOfClass:[NSArray class]]) {
- // {"attributeOrStyleName":[..., "string", {"@binding":"bindingExpression"}, "string", {"@binding":"bindingExpression"}, ...]
- __block BOOL isBinding = NO;
- [attributeOrStyle enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
- if ([obj isKindOfClass:[NSDictionary class]] && obj[WXBindingIdentify]) {
- isBinding = YES;
- *stop = YES;
- }
- }];
-
- if (isBinding) {
- bindingAttributesOrStyles[attributeOrStyleName] = attributeOrStyle;
- [newAttributesOrStyles removeObjectForKey:attributeOrStyleName];
- }
- }
- }];
-
- *attributesOrStylesPoint = newAttributesOrStyles;
-
- return bindingAttributesOrStyles;
-}
-
-- (NSDictionary *)_extractBindingEvents:(NSArray **)eventsPoint
-{
- NSArray *events = *eventsPoint;
- NSMutableArray *newEvents = [events mutableCopy];
- NSMutableDictionary *bindingEvents = [NSMutableDictionary dictionary];
- [events enumerateObjectsUsingBlock:^(id _Nonnull event, NSUInteger idx, BOOL * _Nonnull stop) {
- if ([event isKindOfClass:[NSDictionary class]] && event[@"type"] && event[@"params"]) {
- NSString *eventName = event[@"type"];
- NSString *bindingParams = event[@"params"];
- bindingEvents[eventName] = bindingParams;
- newEvents[idx] = eventName;
- }
- }];
-
- *eventsPoint = newEvents;
- return bindingEvents;
-}
-
-- (NSDictionary *)_extractBindingProps:(NSDictionary **)attributesPoint
-{
- NSDictionary *attributes = *attributesPoint;
- if (attributes[@"@componentProps"]) {
- NSMutableDictionary *newAttributes = [attributes mutableCopy];
- [newAttributes removeObjectForKey:@"@componentProps"];
- *attributesPoint = newAttributes;
- return attributes[@"@componentProps"];
- }
-
- return nil;
-}
-
-#pragma mark Reset
--(BOOL)isShouldReset:(id )value
-{
- if([value isKindOfClass:[NSString class]]) {
- if(!value || [@"" isEqualToString:value]) {
- return YES;
- }
- }
- return NO;
-}
-
--(void)filterStyles:(NSDictionary *)styles normalStyles:(NSMutableDictionary *)normalStyles resetStyles:(NSMutableArray *)resetStyles
-{
- for (NSString *key in styles) {
- id value = [styles objectForKey:key];
- if([self isShouldReset:value]) {
- [resetStyles addObject:key];
- }else{
- [normalStyles setObject:styles[key] forKey:key];
- }
- }
-}
-
-- (void)updateStyles:(NSDictionary *)styles forComponent:(NSString *)ref
-{
- [self handleStyles:styles forComponent:ref isUpdateStyles:YES];
-}
-
-- (void)updatePseudoClassStyles:(NSDictionary *)styles forComponent:(NSString *)ref
-{
- [self handleStyles:styles forComponent:ref isUpdateStyles:NO];
-}
-
-- (void)handleStyleOnMainThread:(NSDictionary*)styles forComponent:(WXComponent *)component isUpdateStyles:(BOOL)isUpdateStyles
-{
- WXAssertParam(styles);
- WXAssertParam(component);
- WXAssertMainThread();
-
- NSMutableDictionary *normalStyles = [NSMutableDictionary new];
- NSMutableArray *resetStyles = [NSMutableArray new];
- [self filterStyles:styles normalStyles:normalStyles resetStyles:resetStyles];
- [component _updateStylesOnMainThread:normalStyles resetStyles:resetStyles];
- [component readyToRender];
-
- WXPerformBlockOnComponentThread(^{
- [component _updateStylesOnComponentThread:normalStyles resetStyles:resetStyles isUpdateStyles:isUpdateStyles];
- });
-}
-
-- (void)handleStyles:(NSDictionary *)styles forComponent:(NSString *)ref isUpdateStyles:(BOOL)isUpdateStyles
-{
- WXAssertParam(styles);
- WXAssertParam(ref);
-
- WXComponent *component = [_indexDict objectForKey:ref];
- WXAssertComponentExist(component);
-
- NSMutableDictionary *normalStyles = [NSMutableDictionary new];
- NSMutableArray *resetStyles = [NSMutableArray new];
- [self filterStyles:styles normalStyles:normalStyles resetStyles:resetStyles];
- [component _updateStylesOnComponentThread:normalStyles resetStyles:resetStyles isUpdateStyles:isUpdateStyles];
- [self _addUITask:^{
- [component _updateStylesOnMainThread:normalStyles resetStyles:resetStyles];
- [component readyToRender];
- }];
-}
-
-- (void)updateAttributes:(NSDictionary *)attributes forComponent:(NSString *)ref
-{
- WXAssertParam(attributes);
- WXAssertParam(ref);
-
- WXComponent *component = [_indexDict objectForKey:ref];
- WXAssertComponentExist(component);
-
- [component _updateAttributesOnComponentThread:attributes];
- __weak typeof(self) weakSelf = self;
- [self _addUITask:^{
- [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingBegin functionName:@"updateAttrs" options:@{@"threadName":WXTUIThread}];
- [component _updateAttributesOnMainThread:attributes];
- [component readyToRender];
- [WXTracingManager startTracingWithInstanceId:weakSelf.weexInstance.instanceId ref:ref className:nil name:nil phase:WXTracingEnd functionName:@"updateAttrs" options:@{@"threadName":WXTUIThread}];
- }];
-}
-
-- (void)addEvent:(NSString *)eventName toComponent:(NSString *)ref
-{
- WXAssertComponentThread();
- WXAssertParam(eventName);
- WXAssertParam(ref);
-
- WXComponent *component = [_indexDict objectForKey:ref];
- WXAssertComponentExist(component);
-
- [component _addEventOnComponentThread:eventName];
-
- [self _addUITask:^{
- [component _addEventOnMainThread:eventName];
- }];
-}
-
-- (void)removeEvent:(NSString *)eventName fromComponent:(NSString *)ref
-{
- WXAssertComponentThread();
- WXAssertParam(eventName);
- WXAssertParam(ref);
-
- WXComponent *component = [_indexDict objectForKey:ref];
- WXAssertComponentExist(component);
-
- [component _removeEventOnComponentThread:eventName];
-
- [self _addUITask:^{
- [component _removeEventOnMainThread:eventName];
- }];
-}
-
-- (void)scrollToComponent:(NSString *)ref options:(NSDictionary *)options
-{
- WXAssertComponentThread();
- WXAssertParam(ref);
-
- WXComponent *toComponent = [_indexDict objectForKey:ref];
- WXAssertComponentExist(toComponent);
-
- id<WXScrollerProtocol> scrollerComponent = toComponent.ancestorScroller;
- if (!scrollerComponent) {
- return;
- }
-
- CGFloat offset = [[options objectForKey:@"offset"] floatValue];
- BOOL animated = YES;
- if ([options objectForKey:@"animated"]) {
- animated = [[options objectForKey:@"animated"] boolValue];
- }
-
- [self _addUITask:^{
- [scrollerComponent scrollToComponent:toComponent withOffset:offset animated:animated];
- }];
-}
-
-#pragma mark Life Cycle
-
-- (void)createFinish
-{
- WXAssertComponentThread();
-
- WXSDKInstance *instance = self.weexInstance;
- [self _addUITask:^{
- UIView *rootView = instance.rootView;
-
- //WX_MONITOR_INSTANCE_PERF_END(WXPTFirstScreenRender, instance);
- WX_MONITOR_INSTANCE_PERF_END(WXPTAllRender, instance);
- WX_MONITOR_SUCCESS(WXMTJSBridge);
- WX_MONITOR_SUCCESS(WXMTNativeRender);
-
- if(instance.renderFinish){
- [WXTracingManager startTracingWithInstanceId:instance.instanceId ref:nil className:nil name:nil phase:WXTracingInstant functionName:WXTRenderFinish options:@{@"threadName":WXTUIThread}];
- instance.renderFinish(rootView);
- }
- }];
- [instance updatePerDicAfterCreateFinish];
-}
-
-- (void)updateFinish
-{
- WXAssertComponentThread();
-
- WXSDKInstance *instance = self.weexInstance;
- WXComponent *root = [_indexDict objectForKey:WX_SDK_ROOT_REF];
-
- [self _addUITask:^{
- if(instance.updateFinish){
- instance.updateFinish(root.view);
- }
- }];
-}
-
-- (void)refreshFinish
-{
- WXAssertComponentThread();
-
- WXSDKInstance *instance = self.weexInstance;
- WXComponent *root = [_indexDict objectForKey:WX_SDK_ROOT_REF];
-
- [self _addUITask:^{
- if(instance.refreshFinish){
- instance.refreshFinish(root.view);
- }
- }];
-}
-
-- (void)unload
-{
- WXAssertComponentThread();
- [self invalidate];
- [self _stopDisplayLink];
- NSEnumerator *enumerator = [[_indexDict copy] objectEnumerator];
- dispatch_async(dispatch_get_main_queue(), ^{
- WXComponent *component;
- while ((component = [enumerator nextObject])) {
- [component _unloadViewWithReusing:NO];
- }
- _rootComponent = nil;
- });
-
- [_indexDict removeAllObjects];
- [_uiTaskQueue removeAllObjects];
-}
-
-- (void)invalidate
-{
- _isValid = NO;
-}
-
-- (BOOL)isValid
-{
- return _isValid;
-}
-
-#pragma mark Layout Batch
-
-- (void)_startDisplayLink
-{
- WXAssertComponentThread();
-
- if(!_displayLink){
- _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_handleDisplayLink)];
- [_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
- }
-}
-
-- (void)_stopDisplayLink
-{
- WXAssertComponentThread();
-
- if(_displayLink){
- [_displayLink invalidate];
- _displayLink = nil;
- }
-}
-
-- (void)_suspendDisplayLink
-{
- WXAssertComponentThread();
-
- if(_displayLink && !_displayLink.paused) {
- _displayLink.paused = YES;
- }
-}
-
-- (void)_awakeDisplayLink
-{
- WXAssertComponentThread();
-
- if(_displayLink && _displayLink.paused) {
- _displayLink.paused = NO;
- }
-}
-
-- (void)_handleDisplayLink
-{
- WXAssertComponentThread();
-
- [self _layoutAndSyncUI];
-}
-
-- (void)_layoutAndSyncUI
-{
- [self _layout];
- if(_uiTaskQueue.count > 0){
- [self _syncUITasks];
- _noTaskTickCount = 0;
- } else {
- // suspend display link when there's no task for 1 second, in order to save CPU time.
- _noTaskTickCount ++;
- if (_noTaskTickCount > 60) {
- [self _suspendDisplayLink];
- }
- }
-}
-
-- (void)_layout
-{
- BOOL needsLayout = NO;
-
- NSEnumerator *enumerator = [_indexDict objectEnumerator];
- WXComponent *component;
- while ((component = [enumerator nextObject])) {
- if ([component needsLayout]) {
- needsLayout = YES;
- break;
- }
- }
-
- if (!needsLayout) {
- return;
- }
-
- layoutNode(_rootCSSNode, _rootCSSNode->style.dimensions[CSS_WIDTH], _rootCSSNode->style.dimensions[CSS_HEIGHT], CSS_DIRECTION_INHERIT);
-
- if ([_rootComponent needsLayout]) {
- if ([WXLog logLevel] >= WXLogLevelDebug) {
- print_css_node(_rootCSSNode, CSS_PRINT_LAYOUT | CSS_PRINT_STYLE | CSS_PRINT_CHILDREN);
- }
- }
-
- NSMutableSet<WXComponent *> *dirtyComponents = [NSMutableSet set];
- [_rootComponent _calculateFrameWithSuperAbsolutePosition:CGPointZero gatherDirtyComponents:dirtyComponents];
- [self _calculateRootFrame];
-
- for (WXComponent *dirtyComponent in dirtyComponents) {
- [self _addUITask:^{
- [dirtyComponent _layoutDidFinish];
- }];
- }
-}
-
-- (void)_syncUITasks
-{
- NSArray<dispatch_block_t> *blocks = _uiTaskQueue;
- _uiTaskQueue = [NSMutableArray array];
- dispatch_async(dispatch_get_main_queue(), ^{
- for(dispatch_block_t block in blocks) {
- block();
- }
- });
-}
-
-- (void)_initRootCSSNode
-{
- _rootCSSNode = new_css_node();
-
- [self _applyRootFrame:self.weexInstance.frame toRootCSSNode:_rootCSSNode];
-
- _rootCSSNode->style.flex_wrap = CSS_NOWRAP;
- _rootCSSNode->is_dirty = rootNodeIsDirty;
- _rootCSSNode->get_child = rootNodeGetChild;
- _rootCSSNode->context = (__bridge void *)(self);
- _rootCSSNode->children_count = 1;
-}
-
-- (void)_calculateRootFrame
-{
- if (!_rootCSSNode->layout.should_update) {
- return;
- }
- _rootCSSNode->layout.should_update = false;
-
- CGRect frame = CGRectMake(WXRoundPixelValue(_rootCSSNode->layout.position[CSS_LEFT]),
- WXRoundPixelValue(_rootCSSNode->layout.position[CSS_TOP]),
- WXRoundPixelValue(_rootCSSNode->layout.dimensions[CSS_WIDTH]),
- WXRoundPixelValue(_rootCSSNode->layout.dimensions[CSS_HEIGHT]));
- WXPerformBlockOnMainThread(^{
- if(!self.weexInstance.isRootViewFrozen) {
- self.weexInstance.rootView.frame = frame;
- }
- });
-
- resetNodeLayout(_rootCSSNode);
-}
-
-
-#pragma mark Fixed
-
-- (void)addFixedComponent:(WXComponent *)fixComponent
-{
- [_fixedComponents addObject:fixComponent];
- _rootCSSNode->children_count = (int)[_fixedComponents count] + 1;
-}
-
-- (void)removeFixedComponent:(WXComponent *)fixComponent
-{
- [_fixedComponents removeObject:fixComponent];
- _rootCSSNode->children_count = (int)[_fixedComponents count] + 1;
-}
-
-@end
-
-void WXPerformBlockOnComponentThread(void (^block)(void))
-{
- [WXComponentManager _performBlockOnComponentThread:block];
-}
-
-void WXPerformBlockSyncOnComponentThread(void (^block)(void))
-{
- [WXComponentManager _performBlockSyncOnComponentThread:block];
-}