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]; -}