http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm b/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm new file mode 100644 index 0000000..0556ca5 --- /dev/null +++ b/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm @@ -0,0 +1,953 @@ +/* + * 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 "WXComponent.h" +#import "WXComponent_internal.h" +#import "WXComponentManager.h" +#import "WXSDKManager.h" +#import "WXSDKInstance.h" +#import "WXSDKInstance_private.h" +#import "WXDefine.h" +#import "WXLog.h" +#import "WXWeakObjectWrapper.h" +#import "WXUtility.h" +#import "WXConvert.h" +#import "WXMonitor.h" +#import "WXAssert.h" +#import "WXThreadSafeMutableDictionary.h" +#import "WXThreadSafeMutableArray.h" +#import "WXTransform.h" +#import "WXRoundedRect.h" +#import <pthread/pthread.h> +#import "WXComponent+PseudoClassManagement.h" +#import "WXComponent+BoxShadow.h" +#import "WXTracingManager.h" +#import "WXComponent+Events.h" +#import "WXComponent+Layout.h" + +#pragma clang diagnostic ignored "-Wincomplete-implementation" +#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation" + +@interface WXComponent () <UIGestureRecognizerDelegate> + +@end + +@implementation WXComponent +{ +@private + NSString *_ref; + NSMutableDictionary *_styles; + NSMutableDictionary *_attributes; + NSMutableArray *_events; + + // Protects properties styles/attributes/events/subcomponents which will be accessed from multiple threads. + pthread_mutex_t _propertyMutex; + pthread_mutexattr_t _propertMutexAttr; + + __weak WXComponent *_supercomponent; + __weak id<WXScrollerProtocol> _ancestorScroller; + __weak WXSDKInstance *_weexInstance; +} + +#pragma mark Life Cycle + +- (instancetype)initWithRef:(NSString *)ref + type:(NSString *)type + styles:(NSDictionary *)styles + attributes:(NSDictionary *)attributes + events:(NSArray *)events + weexInstance:(WXSDKInstance *)weexInstance +{ + if (self = [super init]) { + pthread_mutexattr_init(&_propertMutexAttr); + pthread_mutexattr_settype(&_propertMutexAttr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&_propertyMutex, &_propertMutexAttr); + + _ref = ref; + _type = type; + _weexInstance = weexInstance; + _componentType = WXComponentTypeCommon; + _styles = [self parseStyles:styles]; + _attributes = attributes ? [NSMutableDictionary dictionaryWithDictionary:attributes] : [NSMutableDictionary dictionary]; + _events = events ? [NSMutableArray arrayWithArray:events] : [NSMutableArray array]; + _subcomponents = [NSMutableArray array]; + _absolutePosition = CGPointMake(NAN, NAN); + + _displayType = WXDisplayTypeBlock; + _isNeedJoinLayoutSystem = YES; + _isLayoutDirty = YES; + _isViewFrameSyncWithCalculated = YES; + _ariaHidden = nil; + _accessible = nil; + _accessibilityHintContent = nil; + + _async = NO; + + if (styles[kWXTransitionProperty]) { + _transition = [[WXTransition alloc]initWithStyles:styles]; + } + + //TODO set indicator style + if ([type isEqualToString:@"indicator"]) { + _styles[@"position"] = @"absolute"; + if (!_styles[@"left"] && !_styles[@"right"]) { + _styles[@"left"] = @0.0f; + } + if (!_styles[@"top"] && !_styles[@"bottom"]) { + _styles[@"top"] = @0.0f; + } + } + + if (attributes[@"ariaHidden"]) { + + _ariaHidden = [WXConvert NSString:attributes[@"ariaHidden"]]; + } + if (attributes[@"role"]) { + _roles = attributes[@"role"]; + } + if (attributes[@"ariaLabel"]) { + _ariaLabel = [WXConvert NSString:attributes[@"ariaLabel"]]; + } + if (attributes[@"accessible"]) { + _accessible = [WXConvert NSString:attributes[@"accessible"]]; + } + if(attributes[@"accessibilityHint"]) { + _accessibilityHintContent = [WXConvert NSString:attributes[@"accessibilityHint"]]; + } + if (attributes[@"groupAccessibilityChildren"]) { + _groupAccessibilityChildren = [WXConvert NSString:attributes[@"groupAccessibilityChildren"]]; + } + + if (attributes[@"testId"]) { + _testId = [WXConvert NSString:attributes[@"testId"]]; + } + +#ifdef DEBUG + WXLogDebug(@"flexLayout -> init component: ref : %@ , styles: %@",ref,styles); + WXLogDebug(@"flexLayout -> init component: ref : %@ , attributes: %@",ref,attributes); +#endif + [self _setupNavBarWithStyles:_styles attributes:_attributes]; + + [self _initCSSNodeWithStyles:_styles]; + [self _initViewPropertyWithStyles:_styles]; + [self _initCompositingAttribute:_attributes]; + [self _handleBorders:styles isUpdating:NO]; + + } + + return self; +} + +- (id)copyWithZone:(NSZone *)zone +{ + NSInteger copyId = 0; + @synchronized(self){ + static NSInteger __copy = 0; + copyId = __copy % (1024*1024); + __copy++; + } + NSString *copyRef = [NSString stringWithFormat:@"%ldcopy_of%@", (long)copyId, _isTemplate ? self.ref : self->_templateComponent.ref]; + WXComponent *component = [[[self class] allocWithZone:zone] initWithRef:copyRef type:self.type styles:self.styles attributes:self.attributes events:self.events weexInstance:self.weexInstance]; + if (_isTemplate) { + component->_templateComponent = self; + } else { + component->_templateComponent = self->_templateComponent; + } +//#ifndef USE_FLEX + if(![WXComponent isUseFlex]) + { + memcpy(component->_cssNode, self.cssNode, sizeof(css_node_t)); + component->_cssNode->context = (__bridge void *)component; + } +//#else + else + { + //memcpy((void*)component->_flexCssNode,self.flexCssNode,sizeof(WeexCore::WXCoreLayoutNode)); + component->_flexCssNode->copyStyle(self.flexCssNode); + component->_flexCssNode->copyMeasureFunc(self.flexCssNode); + component->_flexCssNode->setContext((__bridge void *)component); + } +//#endif + component->_calculatedFrame = self.calculatedFrame; + + NSMutableArray *subcomponentsCopy = [NSMutableArray array]; + + if ([WXComponent isUseFlex]) { + component->_subcomponents = subcomponentsCopy; + NSUInteger count = [self.subcomponents count]; + for (NSInteger i = 0 ; i < count;i++){ + WXComponent *subcomponentCopy = [[self.subcomponents objectAtIndex:i] copy]; + [component _insertSubcomponent:subcomponentCopy atIndex:i]; + } + }else{ + for (WXComponent *subcomponent in self.subcomponents) { + WXComponent *subcomponentCopy = [subcomponent copy]; + subcomponentCopy->_supercomponent = component; + [subcomponentsCopy addObject:subcomponentCopy]; + } + component->_subcomponents = subcomponentsCopy; + } + + WXPerformBlockOnComponentThread(^{ + [self.weexInstance.componentManager addComponent:component toIndexDictForRef:copyRef]; + }); + + return component; +} + +- (UIAccessibilityTraits)_parseAccessibilityTraitsWithTraits:(UIAccessibilityTraits)trait roles:(NSString*)roleStr +{ + UIAccessibilityTraits newTrait = trait; + for (NSString * role in [roleStr componentsSeparatedByString:@" "]) { + newTrait |= [WXConvert WXUIAccessibilityTraits: role]; + } + + return newTrait; +} + +- (void)dealloc +{ +//#ifndef USE_FLEX + if(![WXComponent isUseFlex]) + { + free_css_node(_cssNode); + } +//#else + else + { + if(self.flexCssNode){ +#ifdef DEBUG + WXLogDebug(@"flexLayout -> dealloc %@",self.ref); +#endif + delete self.flexCssNode; + } + } +//#endif + + // remove all gesture and all + if (_isTemplate && self.attributes[@"@templateId"]) { + [[WXSDKManager bridgeMgr] callComponentHook:_weexInstance.instanceId componentId:self.attributes[@"@templateId"] type:@"lifecycle" hook:@"destroy" args:nil competion:nil]; + } + if (_tapGesture) { + [_tapGesture removeTarget:nil action:NULL]; + } + if ([_swipeGestures count]) { + for (UISwipeGestureRecognizer *swipeGestures in _swipeGestures) { + [swipeGestures removeTarget:nil action:NULL]; + } + } + + if (_longPressGesture) { + [_longPressGesture removeTarget:nil action:NULL]; + } + + if (_panGesture) { + [_panGesture removeTarget:nil action:NULL]; + } + + if (_positionType == WXPositionTypeFixed) { + [self.weexInstance.componentManager removeFixedComponent:self]; + } + + pthread_mutex_destroy(&_propertyMutex); + pthread_mutexattr_destroy(&_propertMutexAttr); + +} + +- (NSDictionary *)styles +{ + NSDictionary *styles; + pthread_mutex_lock(&_propertyMutex); + styles = _styles; + pthread_mutex_unlock(&_propertyMutex); + return styles; +} + +- (NSDictionary *)pseudoClassStyles +{ + NSDictionary *pseudoClassStyles; + pthread_mutex_lock(&_propertyMutex); + pseudoClassStyles = _pseudoClassStyles; + pthread_mutex_unlock(&_propertyMutex); + + return pseudoClassStyles; +} + +- (NSString *)type +{ + return _type; +} + +- (NSDictionary *)attributes +{ + NSDictionary *attributes; + pthread_mutex_lock(&_propertyMutex); + attributes = _attributes; + pthread_mutex_unlock(&_propertyMutex); + + return attributes; +} + +- (NSArray *)events +{ + NSArray *events; + pthread_mutex_lock(&_propertyMutex); + events = [_events copy]; + pthread_mutex_unlock(&_propertyMutex); + + return events; +} + +- (void)setDisplayType:(WXDisplayType)displayType +{ + if (_displayType != displayType) { + _displayType = displayType; + if (displayType == WXDisplayTypeNone) { + _isNeedJoinLayoutSystem = NO; + [self.supercomponent _recomputeCSSNodeChildren]; + WXPerformBlockOnMainThread(^{ + [self removeFromSuperview]; + }); + } else { + _isNeedJoinLayoutSystem = YES; + [self.supercomponent _recomputeCSSNodeChildren]; + WXPerformBlockOnMainThread(^{ + [self _buildViewHierarchyLazily]; + // TODO: insert into the correct index + [self.supercomponent.view addSubview:self.view]; + }); + } + [self setNeedsLayout]; + } +} + +- (WXSDKInstance *)weexInstance +{ + return _weexInstance; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@:%p ref=%@> %@", _type, self, _ref, _view]; +} + +#pragma mark Property + +- (UIView *)view +{ + if (_componentType != WXComponentTypeCommon) { + return nil; + } + if ([self isViewLoaded]) { + return _view; + } else { + WXAssertMainThread(); + + // compositing child will be drew by its composited ancestor + if (_isCompositingChild) { + return nil; + } + + [self viewWillLoad]; + + _view = [self loadView]; +#ifdef DEBUG + WXLogDebug(@"flexLayout -> loadView:addr-(%p),componentRef-(%@)",_view,self.ref); +#endif + _layer = _view.layer; + _view.frame = [self _fixIllegalFrame:_calculatedFrame]; + _view.hidden = _visibility == WXVisibilityShow ? NO : YES; + _view.clipsToBounds = _clipToBounds; + if (![self _needsDrawBorder]) { + _layer.borderColor = _borderTopColor.CGColor; + _layer.borderWidth = _borderTopWidth; + [self _resetNativeBorderRadius]; + _layer.opacity = _opacity; + _view.backgroundColor = _backgroundColor; + } + + if (_backgroundImage) { + [self setGradientLayer]; + } + + if (_transform) { + [_transform applyTransformForView:_view]; + } + + if (_boxShadow) { + [self configBoxShadow:_boxShadow]; + } + + _view.wx_component = self; + _view.wx_ref = self.ref; + _layer.wx_component = self; + + if (_roles) { + [_view setAccessibilityTraits:[self _parseAccessibilityTraitsWithTraits:self.view.accessibilityTraits roles:_roles]]; + } + + if (_testId) { + _view.accessibilityIdentifier = _testId; + } + + if (_accessibilityHintContent) { + [_view setAccessibilityHint:_accessibilityHintContent]; + } + + if (_ariaLabel) { + _view.accessibilityLabel = _ariaLabel; + } + if (_accessible) { + [_view setIsAccessibilityElement:[WXConvert BOOL:_accessible]]; + } + + if (_ariaHidden) { + [_view setAccessibilityElementsHidden:[WXConvert BOOL:_ariaHidden]]; + } + if (_groupAccessibilityChildren) { + [_view setShouldGroupAccessibilityChildren:[WXConvert BOOL:_groupAccessibilityChildren]]; + } + + [self _initEvents:self.events]; + [self _initPseudoEvents:_isListenPseudoTouch]; + + if (_positionType == WXPositionTypeSticky) { + [self.ancestorScroller addStickyComponent:self]; + } + + if (self.supercomponent && self.supercomponent->_async) { + self->_async = YES; + } + + [self setNeedsDisplay]; + [[NSNotificationCenter defaultCenter] postNotificationName:WX_COMPONENT_NOTIFICATION_VIEW_LOADED object:self]; + [self viewDidLoad]; + + if (_lazyCreateView) { + [self _buildViewHierarchyLazily]; + } + + [self _handleFirstScreenTime]; + + return _view; + } +} + +- (CGRect)_fixIllegalFrame:(CGRect)frame{ + CGPoint origin = frame.origin; + CGSize size = frame.size; + CGRect fixedFrame = CGRectMake(isnan(origin.x)?0.0f:origin.x + , isnan(origin.y)?0.0f:origin.y + , isnan(size.width)?0.0f:size.width + , isnan(size.height)?0.0f:size.height); + return fixedFrame; +} + +- (void)_buildViewHierarchyLazily +{ + if (self.supercomponent && !((WXComponent *)self.supercomponent)->_lazyCreateView) { + NSArray *subcomponents = ((WXComponent *)self.supercomponent).subcomponents; + + NSInteger index = [subcomponents indexOfObject:self]; + if (index != NSNotFound) { + [(WXComponent *)self.supercomponent insertSubview:self atIndex:index]; + } + } + + NSArray *subcomponents = self.subcomponents; + for (int i = 0; i < subcomponents.count; i++) { + WXComponent *subcomponent = subcomponents[i]; + [self insertSubview:subcomponent atIndex:i]; + } +} + +- (void)_resetNativeBorderRadius +{ + WXRoundedRect *borderRect = [[WXRoundedRect alloc] initWithRect:_calculatedFrame topLeft:_borderTopLeftRadius topRight:_borderTopRightRadius bottomLeft:_borderBottomLeftRadius bottomRight:_borderBottomRightRadius]; + _layer.cornerRadius = borderRect.radii.topLeft; +} + +- (void)_handleFirstScreenTime +{ + if (WX_MONITOR_INSTANCE_PERF_IS_RECORDED(WXPTFirstScreenRender, self.weexInstance)) { + return; + } + CGPoint absolutePosition = [self.supercomponent.view convertPoint:_view.frame.origin toView:_weexInstance.rootView]; + if (absolutePosition.y + _view.frame.size.height > self.weexInstance.rootView.frame.size.height + 1) { + WX_MONITOR_INSTANCE_PERF_END(WXPTFirstScreenRender, self.weexInstance); + } +} + +- (CALayer *)layer +{ + return _layer; +} + +- (CGRect)calculatedFrame +{ + return _calculatedFrame; +} + +- (CGPoint)absolutePosition +{ + return _absolutePosition; +} + +//#ifndef USE_FLEX +- (css_node_t *)cssNode +{ + return _cssNode; +} +//#else +//#endif + +- (void)_addEventParams:(NSDictionary *)params +{ + pthread_mutex_lock(&_propertyMutex); + if (!_eventParameters) { + _eventParameters = [NSMutableDictionary dictionary]; + } + [_eventParameters addEntriesFromDictionary:params]; + pthread_mutex_unlock(&_propertyMutex); +} + +- (NSArray *)_paramsForEvent:(NSString *)eventName +{ + NSArray *params; + pthread_mutex_lock(&_propertyMutex); + params = _eventParameters[eventName]; + pthread_mutex_unlock(&_propertyMutex); + + return params; +} + +#pragma mark Component Hierarchy + +- (NSArray<WXComponent *> *)subcomponents +{ + NSArray<WXComponent *> *subcomponents; + pthread_mutex_lock(&_propertyMutex); + subcomponents = [_subcomponents copy]; + pthread_mutex_unlock(&_propertyMutex); + + return subcomponents; +} + +- (WXComponent *)supercomponent +{ + return _supercomponent; +} + +- (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index +{ + WXAssert(subcomponent, @"The subcomponent to insert to %@ at index %d must not be nil", self, index); + if (index > [_subcomponents count]) { + WXLogError(@"the index of inserted %ld is out of range as the current is %lu", (long)index, (unsigned long)[_subcomponents count]); + return; + } + + subcomponent->_supercomponent = self; + + pthread_mutex_lock(&_propertyMutex); + [_subcomponents insertObject:subcomponent atIndex:index]; + pthread_mutex_unlock(&_propertyMutex); + + if (subcomponent->_positionType == WXPositionTypeFixed) { + [self.weexInstance.componentManager addFixedComponent:subcomponent]; + subcomponent->_isNeedJoinLayoutSystem = NO; + } + + if (_useCompositing || _isCompositingChild) { + subcomponent->_isCompositingChild = YES; + } +//#ifndef USE_FLEX + if(![WXComponent isUseFlex]) + { + + } +//#else + else + { + if (subcomponent->_isNeedJoinLayoutSystem) { + NSInteger actualIndex = [self getActualNodeIndex:subcomponent atIndex:index]; + [self _insertChildCssNode:subcomponent atIndex:actualIndex]; + }else{ +#ifdef DEBUG + WXLogDebug(@"flexLayout -> no need JoinLayoutSystem parent ref:%@ type:%@, self ref:%@ type:%@ ", + self.ref, + self.type, + subcomponent.ref, + subcomponent.type + ); +#endif + } + } +//#endif + + [self _recomputeCSSNodeChildren]; + [self setNeedsLayout]; +} + +- (void)_removeSubcomponent:(WXComponent *)subcomponent +{ + pthread_mutex_lock(&_propertyMutex); + [_subcomponents removeObject:subcomponent]; +//#ifndef USE_FLEX + if (![WXComponent isUseFlex]) { + } +//#else + else + { + //subcomponent->_isNeedJoinLayoutSystem = NO; + [self _rmChildCssNode:subcomponent]; + } +//#endif + pthread_mutex_unlock(&_propertyMutex); +} + +- (void)_removeFromSupercomponent +{ + [self.supercomponent _removeSubcomponent:self]; + [self.supercomponent _recomputeCSSNodeChildren]; + [self.supercomponent setNeedsLayout]; + + if (_positionType == WXPositionTypeFixed) { + [self.weexInstance.componentManager removeFixedComponent:self]; + self->_isNeedJoinLayoutSystem = YES; + } +} + +- (void)_moveToSupercomponent:(WXComponent *)newSupercomponent atIndex:(NSUInteger)index +{ + [self _removeFromSupercomponent]; + [newSupercomponent _insertSubcomponent:self atIndex:index]; +} + +- (void)_didInserted +{ + +} + +- (id<WXScrollerProtocol>)ancestorScroller +{ + if(!_ancestorScroller) { + WXComponent *supercomponent = self.supercomponent; + while (supercomponent) { + if([supercomponent conformsToProtocol:@protocol(WXScrollerProtocol)]) { + _ancestorScroller = (id<WXScrollerProtocol>)supercomponent; + break; + } + supercomponent = supercomponent.supercomponent; + } + } + + return _ancestorScroller; +} + +#pragma mark Updating +- (void)_updateStylesOnComponentThread:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles isUpdateStyles:(BOOL)isUpdateStyles +{ + NSLog(@"tempTest updating"); + + BOOL isTransitionTag = _transition ? [self _isTransitionTag:styles] : NO; + if (isTransitionTag) { + [_transition _handleTransitionWithStyles:styles resetStyles:resetStyles target:self]; + } else { + styles = [self parseStyles:styles]; + [self _updateCSSNodeStyles:styles]; + [self _resetCSSNodeStyles:resetStyles]; + } + if (isUpdateStyles) { + [self _modifyStyles:styles]; + if ([self needsLayout]) { + // call update style may take effect on layout, maybe the component + // displaylink has been paused, so we need to restart the component task, and it will auto-pause when task queue is empty. + [self.weexInstance.componentManager startComponentTasks]; + } + } +} + +- (BOOL)_isTransitionTag:(NSDictionary *)styles +{ + BOOL yesOrNo = false; + if (_transition.transitionOptions != WXTransitionOptionsNone) { + yesOrNo = true; + } + return yesOrNo; +} + +- (BOOL)_isTransitionOnMainThreadStyles:(NSDictionary *)styles +{ + BOOL yesOrNo = false; + if (_transition.transitionOptions != WXTransitionOptionsNone) { + if ((_transition.transitionOptions & WXTransitionOptionsBackgroundColor &&styles[@"backgroundColor"]) + ||(_transition.transitionOptions & WXTransitionOptionsTransform &&styles[@"transform"]) + ||(_transition.transitionOptions & WXTransitionOptionsOpacity &&styles[@"opacity"])) { + yesOrNo = true; + } + } + return yesOrNo; +} + +- (void)_modifyStyles:(NSDictionary *)styles +{ + pthread_mutex_lock(&_propertyMutex); + [_styles addEntriesFromDictionary:styles]; + pthread_mutex_unlock(&_propertyMutex); +} + +- (void)_updateAttributesOnComponentThread:(NSDictionary *)attributes +{ + pthread_mutex_lock(&_propertyMutex); + [_attributes addEntriesFromDictionary:attributes]; + pthread_mutex_unlock(&_propertyMutex); +} + +- (void)_addEventOnComponentThread:(NSString *)eventName +{ + pthread_mutex_lock(&_propertyMutex); + [_events addObject:eventName]; + pthread_mutex_unlock(&_propertyMutex); +} + +- (void)_removeEventOnComponentThread:(NSString *)eventName +{ + pthread_mutex_lock(&_propertyMutex); + [_events removeObject:eventName]; + pthread_mutex_unlock(&_propertyMutex); +} + +- (void)_updateStylesOnMainThread:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles +{ + WXAssertMainThread(); + if (![self _isTransitionOnMainThreadStyles:styles]) { + [self _updateViewStyles:styles]; + } else { + [self _transitionUpdateViewProperty:styles]; + } +#ifdef DEBUG + NSDictionary *copySelfStyle = [NSDictionary dictionaryWithDictionary:self.styles]; + WXLogDebug(@"flexLayout -> ref:%@ style before : %@",self.ref,copySelfStyle); + + if (styles) { + WXLogDebug(@"flexLayout -> ref:%@ update styles : %@",self.ref,styles); + } + + if (resetStyles) { + WXLogDebug(@"flexLayout -> ref:%@ update resetStyles : %@",self.ref,resetStyles); + } +#endif + + [self _resetStyles:resetStyles]; + [self _handleBorders:styles isUpdating:YES]; + [self updateStyles:styles]; + [self resetStyles:resetStyles]; + +#ifdef DEBUG + //self.styles may change + copySelfStyle = [NSDictionary dictionaryWithDictionary:self.styles]; + WXLogDebug(@"flexLayout -> ref:%@ style after : %@",self.ref,copySelfStyle); +#endif +} + +- (void)_updateAttributesOnMainThread:(NSDictionary *)attributes +{ + WXAssertMainThread(); + + [self _updateNavBarAttributes:attributes]; + + [self updateAttributes:attributes]; + [self _configWXComponentA11yWithAttributes:attributes]; +} + +- (void)updateStyles:(NSDictionary *)styles +{ + WXAssertMainThread(); +} + +- (void)updateAttributes:(NSDictionary *)attributes +{ + WXAssertMainThread(); +} + +- (void)setNativeTransform:(CGAffineTransform)transform +{ + WXAssertMainThread(); + + _transform = [[WXTransform alloc] initWithNativeTransform:CATransform3DMakeAffineTransform(transform) instance:self.weexInstance]; + if (!CGRectEqualToRect(self.calculatedFrame, CGRectZero)) { + [_transform applyTransformForView:_view]; + [_layer setNeedsDisplay]; + } +} + +- (void)readyToRender +{ + if (self.weexInstance.trackComponent) { + [self.supercomponent readyToRender]; + } +} + + +- (void)setGradientLayer +{ + if (CGRectEqualToRect(self.view.frame, CGRectZero)) { + return; + } + NSDictionary * linearGradient = [WXUtility linearGradientWithBackgroundImage:_backgroundImage]; + if (!linearGradient) { + return ; + } + + __weak typeof(self) weakSelf = self; + dispatch_async(dispatch_get_main_queue(), ^{ + __strong typeof(self) strongSelf = weakSelf; + if(strongSelf) { + UIColor * startColor = (UIColor*)linearGradient[@"startColor"]; + UIColor * endColor = (UIColor*)linearGradient[@"endColor"]; + CAGradientLayer * gradientLayer = [WXUtility gradientLayerFromColors:@[startColor, endColor] locations:nil frame:strongSelf.view.bounds gradientType:(WXGradientType)[linearGradient[@"gradientType"] integerValue]]; + if (gradientLayer) { + _backgroundColor = [UIColor colorWithPatternImage:[strongSelf imageFromLayer:gradientLayer]]; + strongSelf.view.backgroundColor = _backgroundColor; + } + } + }); +} + +- (void)_configWXComponentA11yWithAttributes:(NSDictionary *)attributes +{ + WX_CHECK_COMPONENT_TYPE(self.componentType) + if (attributes[@"role"]){ + _roles = attributes[@"role"]; + [self.view setAccessibilityTraits:[self _parseAccessibilityTraitsWithTraits:self.view.accessibilityTraits roles:_roles]]; + } + if (attributes[@"ariaHidden"]) { + _ariaHidden = [WXConvert NSString:attributes[@"ariaHidden"]]; + [self.view setAccessibilityElementsHidden:[WXConvert BOOL:_ariaHidden]]; + } + if (attributes[@"accessible"]) { + _accessible = [WXConvert NSString:attributes[@"accessible"]]; + [self.view setIsAccessibilityElement:[WXConvert BOOL:_accessible]]; + } + if (attributes[@"ariaLabel"]) { + _ariaLabel = [WXConvert NSString:attributes[@"ariaLabel"]]; + self.view.accessibilityValue = _ariaLabel; + } + if (attributes[@"accessibilityHint"]) { + _accessibilityHintContent = [WXConvert NSString:attributes[@"accessibilityHint"]]; + [self.view setAccessibilityHint:_accessibilityHintContent]; + } + + if (attributes[@"groupAccessibilityChildren"]) { + _groupAccessibilityChildren = [WXConvert NSString:attributes[@"groupAccessibilityChildren"]]; + [self.view setShouldGroupAccessibilityChildren:[WXConvert BOOL:_groupAccessibilityChildren]]; + } + + + if (attributes[@"testId"]) { + [self.view setAccessibilityIdentifier:[WXConvert NSString:attributes[@"testId"]]]; + } + +} + +- (UIImage *)imageFromLayer:(CALayer *)layer +{ + UIGraphicsBeginImageContextWithOptions(layer.frame.size, NO, 0); + [layer renderInContext:UIGraphicsGetCurrentContext()]; + UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return outputImage; +} + +#pragma mark Reset +- (void)resetStyles:(NSArray *)styles +{ + WXAssertMainThread(); +} + +#pragma mark Layout + +/** + * @see WXComponent+Layout.m + */ + +#pragma mark View Management + +/** + * @see WXComponent+ViewManagement.m + */ + +#pragma mark Events + +/** + * @see WXComponent+Events.m + */ + +#pragma mark Display + +/** + * @see WXComponent+Display.m + */ + +@end + + +@implementation UIView (WXComponent) + +- (WXComponent *)wx_component +{ + WXWeakObjectWrapper *weakWrapper = objc_getAssociatedObject(self, @selector(wx_component)); + return [weakWrapper weakObject]; +} + +- (void)setWx_component:(WXComponent *)wx_component +{ + id weakWrapper = [[WXWeakObjectWrapper alloc] initWithWeakObject:wx_component]; + objc_setAssociatedObject(self, @selector(wx_component), weakWrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (NSString *)wx_ref +{ + WXWeakObjectWrapper *weakWrapper = objc_getAssociatedObject(self, @selector(wx_ref)); + return [weakWrapper weakObject]; +} + +- (void)setWx_ref:(NSString *)wx_ref +{ + id weakWrapper = [[WXWeakObjectWrapper alloc] initWithWeakObject:wx_ref]; + objc_setAssociatedObject(self, @selector(wx_ref), weakWrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +@end + +@implementation CALayer (WXComponents_new) + +- (WXComponent *)wx_component +{ + WXWeakObjectWrapper *weakWrapper = objc_getAssociatedObject(self, @selector(wx_component)); + return [weakWrapper weakObject]; +} + +- (void)setWx_component:(WXComponent *)wx_component +{ + id weakWrapper = [[WXWeakObjectWrapper alloc] initWithWeakObject:wx_component]; + objc_setAssociatedObject(self, @selector(wx_component), weakWrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +@end
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m index 13fc4cf..b4c5a2e 100644 --- a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m +++ b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m @@ -76,7 +76,8 @@ typedef enum : NSUInteger { BOOL _needDestroy; BOOL _syncDestroyComponentManager; BOOL _debugJS; - id<WXBridgeProtocol> _instanceJavaScriptContext; // sandbox javaScript context + id<WXBridgeProtocol> _instanceJavaScriptContext; // sandbox javaScript context + CGFloat _defaultPixelScaleFactor; } - (void)dealloc @@ -102,7 +103,7 @@ typedef enum : NSUInteger { __instance++; } _instanceId = [NSString stringWithFormat:@"%ld", (long)instanceId]; - + [WXSDKManager storeInstance:self forID:_instanceId]; _bizType = @""; @@ -122,6 +123,7 @@ typedef enum : NSUInteger { if ([configCenter respondsToSelector:@selector(configForKey:defaultValue:isDefault:)]) { _syncDestroyComponentManager = [[configCenter configForKey:@"iOS_weex_ext_config.syncDestroyComponentManager" defaultValue:@(YES) isDefault:NULL] boolValue]; } + _defaultPixelScaleFactor = CGFLOAT_MIN; [self addObservers]; } @@ -183,6 +185,9 @@ typedef enum : NSUInteger { - (void)setFrame:(CGRect)frame { +#ifdef DEBUG + WXLogDebug(@"flexLayout -> setFrame :%@,instance :%@",NSStringFromCGRect(frame),self); +#endif if (!CGRectEqualToRect(frame, _frame)) { _frame = frame; WXPerformBlockOnMainThread(^{ @@ -583,7 +588,12 @@ typedef enum : NSUInteger { if (self.viewportWidth > 0) { return [WXUtility portraitScreenSize].width / self.viewportWidth; } else { - return [WXUtility defaultPixelScaleFactor]; + if (_defaultPixelScaleFactor != CGFLOAT_MIN) { + return _defaultPixelScaleFactor; + } + + _defaultPixelScaleFactor = [WXUtility defaultPixelScaleFactor]; + return _defaultPixelScaleFactor; } } http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Module/WXTransition.m ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Module/WXTransition.m b/ios/sdk/WeexSDK/Sources/Module/WXTransition.m deleted file mode 100644 index 8e982ac..0000000 --- a/ios/sdk/WeexSDK/Sources/Module/WXTransition.m +++ /dev/null @@ -1,519 +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. - */ - -#define SOLVE_EPS(dur) (1. / (1000. * (dur))) - -#import <QuartzCore/CATransaction.h> -#import <QuartzCore/CADisplayLink.h> -#import "WXComponentManager.h" -#import "WXSDKInstance.h" -#import "WXComponent+Layout.h" -#import "WXComponent_internal.h" -#import "WXTransition.h" -#import "WXUtility.h" -#import "WXAssert.h" -#import "WXSDKInstance_private.h" -#import "WXLength.h" - -@implementation WXTransitionInfo -@end - -@interface WXTransition() -{ - WXComponent *_targetComponent; - double ax; - double bx; - double cx; - - double ay; - double by; - double cy; - - float _transitionDuration; - float _transitionDelay; - NSUInteger _transitionCount; - - CAMediaTimingFunction *_transitionTimingFunction; - CADisplayLink *_transitionDisplayLink; - - NSMutableDictionary *_filterStyles; - NSMutableDictionary *_oldFilterStyles; -} - -@end - -@implementation WXTransition - -- (instancetype)initWithStyles:(NSDictionary *)styles -{ - if (self = [super init]) { - NSString *property = styles[kWXTransitionProperty]; - NSArray *properties = [property componentsSeparatedByString:@","]; - for (NSString *string in properties) { - _transitionOptions |= [self transitionOptionsFromString:string]; - } - } - return self; -} - -#pragma mark - HandleStyle -- (WXTransitionOptions)transitionOptionsFromString:(NSString *)string -{ - NSDictionary<NSString*,NSNumber*> *options = @{ - @"width": @(WXTransitionOptionsWidth), - @"height": @(WXTransitionOptionsHeight), - @"right": @(WXTransitionOptionsRight), - @"left": @(WXTransitionOptionsLeft), - @"bottom": @(WXTransitionOptionsBottom), - @"top": @(WXTransitionOptionsTop), - @"backgroundColor": @(WXTransitionOptionsBackgroundColor), - @"transform": @(WXTransitionOptionsTransform), - @"opacity": @(WXTransitionOptionsOpacity), - }; - return options[string].integerValue; -} - -- (void)_handleTransitionWithStyles:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles target:(WXComponent *)targetComponent -{ - BOOL isRunning = [self _isTransitionRunning]; - if (isRunning) { - [self _rollBackTransitionWithStyles:styles]; - } - else - { - [self _suspendTransitionDisplayLink]; - } - - _filterStyles = _filterStyles ?:[NSMutableDictionary new]; - _oldFilterStyles = _oldFilterStyles ?: [NSMutableDictionary new]; - NSMutableDictionary *futileStyles = [NSMutableDictionary new]; - - for (NSString *key in styles) { - if (self.transitionOptions & [self transitionOptionsFromString:key]) { - [_filterStyles setObject:styles[key] forKey:key]; - if (![key isEqualToString:@"transform"]) { - if (!isRunning) { - [_oldFilterStyles setObject:targetComponent.styles[key] forKey:key]; - } - } - } - else - { - [futileStyles setObject:styles[key] forKey:key]; - } - } - [self updateFutileStyles:futileStyles resetStyles:nil target:targetComponent]; - - _targetComponent = targetComponent; - NSMutableDictionary *componentStyles = [NSMutableDictionary dictionaryWithDictionary:styles]; - [componentStyles addEntriesFromDictionary:targetComponent.styles]; - - _transitionDuration = componentStyles[kWXTransitionDuration] ? [WXConvert CGFloat:componentStyles[kWXTransitionDuration]] : 0; - _transitionDelay = componentStyles[kWXTransitionDelay] ? [WXConvert CGFloat:componentStyles[kWXTransitionDelay]] : 0; - _transitionTimingFunction = [WXConvert CAMediaTimingFunction:componentStyles[kWXTransitionTimingFunction]]; - - if (_transitionDuration == 0 ) { - [self updateFutileStyles:_filterStyles resetStyles:nil target:targetComponent]; - return; - } - - if (![[NSString stringWithFormat:@"%@",_transitionTimingFunction] isEqualToString: kCAMediaTimingFunctionLinear]) { - float vec[4] = {0.}; - [_transitionTimingFunction getControlPointAtIndex:1 values:&vec[0]]; - [_transitionTimingFunction getControlPointAtIndex:2 values:&vec[2]]; - [self unitBezierp1x:vec[0] p1y:vec[1] p2x:vec[2] p2y:vec[3]]; - } - - [self _resloveTransitionProperty]; - [self performSelector:@selector(_startTransitionDisplayLink) withObject:self afterDelay:_transitionDelay/1000]; -} - -- (void)updateFutileStyles:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles target:(WXComponent *)targetComponent -{ - [targetComponent _updateCSSNodeStyles:styles]; - [targetComponent _resetCSSNodeStyles:resetStyles]; - WXPerformBlockOnMainThread(^{ - [targetComponent _updateViewStyles:styles]; - }); -} - -- (void)_rollBackTransitionWithStyles:(NSDictionary *)styles -{ - _transitionDuration = _transitionCount * 1000 / 60; - _transitionCount = 0; - _propertyArray = nil; -} - -- (void)_resloveTransitionProperty -{ - if (_filterStyles.count == 0) { - return; - } - for (NSString * name in _filterStyles.allKeys) { - [self _dealTransitionWithProperty:name]; - } -} - -- (void)_dealTransitionWithProperty:(NSString *)singleProperty -{ - if (_filterStyles[singleProperty]) - { - if (!_propertyArray) { - _propertyArray = [NSMutableArray new]; - } - if ([singleProperty isEqualToString:@"backgroundColor"]) { - WXTransitionInfo *info = [WXTransitionInfo new]; - info.fromValue = [self _dealWithColor:[WXConvert UIColor:_oldFilterStyles[singleProperty]]]; - info.toValue = [self _dealWithColor:[WXConvert UIColor:_filterStyles[singleProperty]]]; - info.perValue = [self _calculatePerColorRGB1:info.toValue RGB2:info.fromValue]; - info.propertyName = singleProperty; - [_propertyArray addObject:info]; - } - else if ([singleProperty isEqualToString:@"transform"]) { - NSString *transformOrigin = _filterStyles[@"transformOrigin"]; - WXTransform *wxTransform = [[WXTransform alloc] initWithCSSValue:_filterStyles[singleProperty] origin:transformOrigin instance:_targetComponent.weexInstance]; - WXTransform *oldTransform = _targetComponent->_transform; - if (wxTransform.rotateAngle != oldTransform.rotateAngle) { - WXTransitionInfo *info = [WXTransitionInfo new]; - info.propertyName = @"transform.rotation"; - info.fromValue = @(oldTransform.rotateAngle); - info.toValue = [NSNumber numberWithDouble:wxTransform.rotateAngle]; - info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); - [_propertyArray addObject:info]; - } - if (wxTransform.rotateX != oldTransform.rotateX) - { - WXTransitionInfo *info = [WXTransitionInfo new]; - info.propertyName = @"transform.rotation.x"; - info.fromValue = @(oldTransform.rotateX); - info.toValue = [NSNumber numberWithDouble:wxTransform.rotateX]; - info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); - [_propertyArray addObject:info]; - } - if (wxTransform.rotateY != oldTransform.rotateY) - { - WXTransitionInfo *info = [WXTransitionInfo new]; - info.propertyName = @"transform.rotation.y"; - info.fromValue = @(oldTransform.rotateY); - info.toValue = [NSNumber numberWithDouble:wxTransform.rotateY]; - info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); - [_propertyArray addObject:info]; - } - if (wxTransform.rotateZ != oldTransform.rotateZ) - { - WXTransitionInfo *info = [WXTransitionInfo new]; - info.propertyName = @"transform.rotation.z"; - info.fromValue = @(oldTransform.rotateZ); - info.toValue = [NSNumber numberWithDouble:wxTransform.rotateZ]; - info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); - [_propertyArray addObject:info]; - } - if (wxTransform.scaleX != oldTransform.scaleX) { - WXTransitionInfo *info = [WXTransitionInfo new]; - info.propertyName = @"transform.scale.x"; - info.fromValue = @(oldTransform.scaleX); - info.toValue = @(wxTransform.scaleX); - info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); - [_propertyArray addObject:info]; - } - if (wxTransform.scaleY != oldTransform.scaleY) { - WXTransitionInfo *info = [WXTransitionInfo new]; - info.propertyName = @"transform.scale.y"; - info.fromValue = @(oldTransform.scaleY); - info.toValue = @(wxTransform.scaleY); - info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); - [_propertyArray addObject:info]; - } - if (wxTransform.translateX && [wxTransform.translateX floatValue] !=[oldTransform.translateX floatValue]) { - WXTransitionInfo *info = [WXTransitionInfo new]; - info.propertyName = @"transform.translation.x"; - info.fromValue = @([oldTransform.translateX floatValue]); - info.toValue = @([wxTransform.translateX floatValue]); - info.perValue = @([wxTransform.translateX floatValue] - [oldTransform.translateX floatValue]); - [_propertyArray addObject:info]; - } - if (wxTransform.translateY && [wxTransform.translateY floatValue] !=[oldTransform.translateY floatValue]) { - WXTransitionInfo *info = [WXTransitionInfo new]; - info.propertyName = @"transform.translation.y"; - info.fromValue = @([oldTransform.translateY floatValue]); - info.toValue = @([wxTransform.translateY floatValue]); - info.perValue = @([wxTransform.translateY floatValue] - [oldTransform.translateY floatValue]); - [_propertyArray addObject:info]; - } - _targetComponent->_transform = wxTransform; - } - else - { - WXTransitionInfo *info = [WXTransitionInfo new]; - info.fromValue = @(_oldFilterStyles[singleProperty] ? [WXConvert CGFloat:_oldFilterStyles[singleProperty]] : 0); - info.toValue = @(_filterStyles[singleProperty] ? [WXConvert CGFloat:_filterStyles[singleProperty]] : 0 ); - info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); - info.propertyName = singleProperty; - [_propertyArray addObject:info]; - } - } -} - -- (NSArray *)_dealWithColor:(UIColor *)color -{ - CGFloat R, G, B, A; - [color getRed:&R green:&G blue:&B alpha:&A]; - return @[@(R),@(G),@(B),@(A)]; -} - -- (NSArray *)_calculatePerColorRGB1:(NSArray *)RGB1 RGB2:(NSArray *)RGB2 -{ - CGFloat R = [RGB1[0] doubleValue] - [RGB2[0] doubleValue]; - CGFloat G = [RGB1[1] doubleValue] - [RGB2[1] doubleValue]; - CGFloat B = [RGB1[2] doubleValue] - [RGB2[2] doubleValue]; - CGFloat A = [RGB1[3] doubleValue] - [RGB2[3] doubleValue]; - return @[@(R),@(G),@(B),@(A)]; -} - -- (void)_calculatetransitionProcessingStyle -{ - if (_propertyArray.count == 0) { - return; - } - double per = 1000 * (_transitionCount + 1 ) / (60 * _transitionDuration);//linear - if (![[NSString stringWithFormat:@"%@",_transitionTimingFunction] isEqualToString: kCAMediaTimingFunctionLinear]) { - per = [self solveWithx:((_transitionCount+2)*16)/_transitionDuration epsilon:SOLVE_EPS(_transitionDuration)]; - } - NSString *transformString = [NSString string]; - for (WXTransitionInfo *info in _propertyArray) { - if ([info.propertyName isEqualToString:@"backgroundColor"]) { - NSArray *array = @[ - @([info.fromValue[0] floatValue] + [info.perValue[0] floatValue] * per), - @([info.fromValue[1] floatValue] + [info.perValue[1] floatValue] * per), - @([info.fromValue[2] floatValue] + [info.perValue[2] floatValue] * per), - @([info.fromValue[3] floatValue] + [info.perValue[3] floatValue] * per)]; - UIColor *color = [UIColor colorWithRed:[array[0] floatValue] green:[array[1] floatValue] blue:[array[2] floatValue] alpha:[array[3] floatValue]]; - WXPerformBlockOnMainThread(^{ - _targetComponent.view.backgroundColor = color; - [_targetComponent.view setNeedsDisplay]; - }); - NSString *colorString = [WXConvert HexWithColor:color]; - [_oldFilterStyles setObject:colorString forKey:info.propertyName]; - } - else if ([info.propertyName hasPrefix:@"transform"]) - { - double currentValue = [info.fromValue doubleValue] + [info.perValue doubleValue] * per; - NSString *newString = [NSString string]; - if ([info.propertyName isEqualToString:@"transform.rotation"]) { - newString = [NSString stringWithFormat:@"rotate(%lfdeg)",currentValue * 180.0 / M_PI]; - transformString = [transformString stringByAppendingFormat:@" %@",newString]; - } - if ([info.propertyName isEqualToString:@"transform.rotation.x"]) { - newString = [NSString stringWithFormat:@"rotateX(%lfdeg)",currentValue * 180.0 / M_PI]; - transformString = [transformString stringByAppendingFormat:@" %@",newString]; - } - if ([info.propertyName isEqualToString:@"transform.rotation.y"]) { - newString = [NSString stringWithFormat:@"rotateY(%lfdeg)",currentValue * 180.0 / M_PI]; - transformString = [transformString stringByAppendingFormat:@" %@",newString]; - } - if ([info.propertyName isEqualToString:@"transform.rotation.z"]) { - newString = [NSString stringWithFormat:@"rotateZ(%lfdeg)",currentValue * 180.0 / M_PI]; - transformString = [transformString stringByAppendingFormat:@" %@",newString]; - } - if ([info.propertyName isEqualToString:@"transform.scale.x"]) { - newString = [NSString stringWithFormat:@"scaleX(%lf)",currentValue]; - transformString = [transformString stringByAppendingFormat:@" %@",newString]; - } - if ([info.propertyName isEqualToString:@"transform.scale.y"]) { - newString = [NSString stringWithFormat:@"scaleY(%lf)",currentValue]; - transformString = [transformString stringByAppendingFormat:@" %@",newString]; - } - if ([info.propertyName isEqualToString:@"transform.translation.x"]) { - newString = [NSString stringWithFormat:@"translateX(%lfpx)",currentValue / _targetComponent.weexInstance.pixelScaleFactor]; - transformString = [transformString stringByAppendingFormat:@" %@",newString]; - } - if ([info.propertyName isEqualToString:@"transform.translation.y"]) { - newString = [NSString stringWithFormat:@"translateY(%lfpx)",currentValue / _targetComponent.weexInstance.pixelScaleFactor]; - transformString = [transformString stringByAppendingFormat:@" %@",newString]; - } - [_oldFilterStyles setObject:transformString forKey:@"transform"]; - } - else - { - double currentValue = [info.fromValue doubleValue] + [info.perValue doubleValue] * per; - [_oldFilterStyles setObject:@(currentValue) forKey:info.propertyName]; - } - } - WXPerformBlockOnMainThread(^{ - [_targetComponent _updateViewStyles:_oldFilterStyles]; - }); - [_targetComponent _updateCSSNodeStyles:_oldFilterStyles]; - [_targetComponent.weexInstance.componentManager startComponentTasks]; -} - -#pragma mark CADisplayLink -- (void)_startTransitionDisplayLink -{ - WXAssertComponentThread(); - if (!_transitionDisplayLink) { - _transitionDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_handleTransitionDisplayLink)]; - [_transitionDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; - } - else{ - [self _awakeTransitionDisplayLink]; - } -} - -- (void)_stopTransitionDisplayLink -{ - WXAssertComponentThread(); - if (_transitionDisplayLink) { - [_transitionDisplayLink invalidate]; - _transitionDisplayLink = nil; - } -} - -- (BOOL)_isTransitionRunning -{ - WXAssertComponentThread(); - BOOL yesOrNo = NO; - if (!_transitionDisplayLink.paused && _transitionCount >= 5) { - yesOrNo = YES; - } - return yesOrNo; -} - -- (void)_suspendTransitionDisplayLink -{ - WXAssertComponentThread(); - if(_transitionDisplayLink && !_transitionDisplayLink.paused){ - _transitionDisplayLink.paused = YES; - } -} - -- (void)_awakeTransitionDisplayLink -{ - WXAssertComponentThread(); - if (_transitionDisplayLink && _transitionDisplayLink.paused) { - _transitionDisplayLink.paused = NO; - } -} - -- (void)_handleTransitionDisplayLink -{ - WXAssertComponentThread(); - int count = _transitionDuration * 60 / 1000; - if (_transitionCount >= count) { - [self _suspendTransitionDisplayLink]; - [self _resetProcessAnimationParameter]; - return; - } - else - { - [self _calculatetransitionProcessingStyle]; - } - _transitionCount ++; -} - -- (void)_resetProcessAnimationParameter -{ - _transitionCount = 0; - _transitionDuration = 0; - _propertyArray = nil; - _oldFilterStyles = nil; - _filterStyles= nil; -} - -- (NSMutableDictionary *)_filterStyles -{ - return self.filterStyles; -} - -- (NSMutableDictionary *)_oldFilterStyles -{ - return self.oldFilterStyles; -} - -#pragma mark UnitBezierp -- (void)unitBezierp1x:(double)p1x p1y:(double)p1y p2x:(double)p2x p2y:(double)p2y -{ - cx = 3.0 * p1x; - bx = 3.0 * (p2x - p1x) - cx; - ax = 1.0 - cx -bx; - - cy = 3.0 * p1y; - by = 3.0 * (p2y - p1y) - cy; - ay = 1.0 - cy - by; -} - -- (double)sampleCurveX:(double)t -{ - return ((ax * t + bx) * t + cx) * t; -} - -- (double)sampleCurveY:(double)t -{ - return ((ay * t + by) * t + cy) * t; -} - -- (double)sampleCurveDerivativeX:(double)t -{ - return (3.0 * ax * t + 2.0 * bx) * t + cx; -} - -- (double)solveCurveX:(double)x epsilon:(double)epsilon -{ - double t0; - double t1; - double t2; - double x2; - double d2; - int i; - - for (t2 = x, i = 0; i < 8; i++) { - x2 = [self sampleCurveX:t2] - x; - if (fabs (x2) < epsilon) - return t2; - d2 = [self sampleCurveDerivativeX:t2]; - if (fabs(d2) < 1e-6) - break; - t2 = t2 - x2 / d2; - } - t0 = 0.0; - t1 = 1.0; - t2 = x; - - if (t2 < t0) - return t0; - if (t2 > t1) - return t1; - - while (t0 < t1) { - x2 = [self sampleCurveX:t2]; - if (fabs(x2 - x) < epsilon) - return t2; - if (x > x2) - t0 = t2; - else - t1 = t2; - t2 = (t1 - t0) * .5 + t0; - } - return t2; -} - -- (double)solveWithx:(double)x epsilon:(double)epsilon -{ - return [self sampleCurveY:([self solveCurveX:x epsilon:epsilon])]; -} -@end http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Module/WXTransition.mm ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Module/WXTransition.mm b/ios/sdk/WeexSDK/Sources/Module/WXTransition.mm new file mode 100644 index 0000000..8e982ac --- /dev/null +++ b/ios/sdk/WeexSDK/Sources/Module/WXTransition.mm @@ -0,0 +1,519 @@ +/* + * 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. + */ + +#define SOLVE_EPS(dur) (1. / (1000. * (dur))) + +#import <QuartzCore/CATransaction.h> +#import <QuartzCore/CADisplayLink.h> +#import "WXComponentManager.h" +#import "WXSDKInstance.h" +#import "WXComponent+Layout.h" +#import "WXComponent_internal.h" +#import "WXTransition.h" +#import "WXUtility.h" +#import "WXAssert.h" +#import "WXSDKInstance_private.h" +#import "WXLength.h" + +@implementation WXTransitionInfo +@end + +@interface WXTransition() +{ + WXComponent *_targetComponent; + double ax; + double bx; + double cx; + + double ay; + double by; + double cy; + + float _transitionDuration; + float _transitionDelay; + NSUInteger _transitionCount; + + CAMediaTimingFunction *_transitionTimingFunction; + CADisplayLink *_transitionDisplayLink; + + NSMutableDictionary *_filterStyles; + NSMutableDictionary *_oldFilterStyles; +} + +@end + +@implementation WXTransition + +- (instancetype)initWithStyles:(NSDictionary *)styles +{ + if (self = [super init]) { + NSString *property = styles[kWXTransitionProperty]; + NSArray *properties = [property componentsSeparatedByString:@","]; + for (NSString *string in properties) { + _transitionOptions |= [self transitionOptionsFromString:string]; + } + } + return self; +} + +#pragma mark - HandleStyle +- (WXTransitionOptions)transitionOptionsFromString:(NSString *)string +{ + NSDictionary<NSString*,NSNumber*> *options = @{ + @"width": @(WXTransitionOptionsWidth), + @"height": @(WXTransitionOptionsHeight), + @"right": @(WXTransitionOptionsRight), + @"left": @(WXTransitionOptionsLeft), + @"bottom": @(WXTransitionOptionsBottom), + @"top": @(WXTransitionOptionsTop), + @"backgroundColor": @(WXTransitionOptionsBackgroundColor), + @"transform": @(WXTransitionOptionsTransform), + @"opacity": @(WXTransitionOptionsOpacity), + }; + return options[string].integerValue; +} + +- (void)_handleTransitionWithStyles:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles target:(WXComponent *)targetComponent +{ + BOOL isRunning = [self _isTransitionRunning]; + if (isRunning) { + [self _rollBackTransitionWithStyles:styles]; + } + else + { + [self _suspendTransitionDisplayLink]; + } + + _filterStyles = _filterStyles ?:[NSMutableDictionary new]; + _oldFilterStyles = _oldFilterStyles ?: [NSMutableDictionary new]; + NSMutableDictionary *futileStyles = [NSMutableDictionary new]; + + for (NSString *key in styles) { + if (self.transitionOptions & [self transitionOptionsFromString:key]) { + [_filterStyles setObject:styles[key] forKey:key]; + if (![key isEqualToString:@"transform"]) { + if (!isRunning) { + [_oldFilterStyles setObject:targetComponent.styles[key] forKey:key]; + } + } + } + else + { + [futileStyles setObject:styles[key] forKey:key]; + } + } + [self updateFutileStyles:futileStyles resetStyles:nil target:targetComponent]; + + _targetComponent = targetComponent; + NSMutableDictionary *componentStyles = [NSMutableDictionary dictionaryWithDictionary:styles]; + [componentStyles addEntriesFromDictionary:targetComponent.styles]; + + _transitionDuration = componentStyles[kWXTransitionDuration] ? [WXConvert CGFloat:componentStyles[kWXTransitionDuration]] : 0; + _transitionDelay = componentStyles[kWXTransitionDelay] ? [WXConvert CGFloat:componentStyles[kWXTransitionDelay]] : 0; + _transitionTimingFunction = [WXConvert CAMediaTimingFunction:componentStyles[kWXTransitionTimingFunction]]; + + if (_transitionDuration == 0 ) { + [self updateFutileStyles:_filterStyles resetStyles:nil target:targetComponent]; + return; + } + + if (![[NSString stringWithFormat:@"%@",_transitionTimingFunction] isEqualToString: kCAMediaTimingFunctionLinear]) { + float vec[4] = {0.}; + [_transitionTimingFunction getControlPointAtIndex:1 values:&vec[0]]; + [_transitionTimingFunction getControlPointAtIndex:2 values:&vec[2]]; + [self unitBezierp1x:vec[0] p1y:vec[1] p2x:vec[2] p2y:vec[3]]; + } + + [self _resloveTransitionProperty]; + [self performSelector:@selector(_startTransitionDisplayLink) withObject:self afterDelay:_transitionDelay/1000]; +} + +- (void)updateFutileStyles:(NSDictionary *)styles resetStyles:(NSMutableArray *)resetStyles target:(WXComponent *)targetComponent +{ + [targetComponent _updateCSSNodeStyles:styles]; + [targetComponent _resetCSSNodeStyles:resetStyles]; + WXPerformBlockOnMainThread(^{ + [targetComponent _updateViewStyles:styles]; + }); +} + +- (void)_rollBackTransitionWithStyles:(NSDictionary *)styles +{ + _transitionDuration = _transitionCount * 1000 / 60; + _transitionCount = 0; + _propertyArray = nil; +} + +- (void)_resloveTransitionProperty +{ + if (_filterStyles.count == 0) { + return; + } + for (NSString * name in _filterStyles.allKeys) { + [self _dealTransitionWithProperty:name]; + } +} + +- (void)_dealTransitionWithProperty:(NSString *)singleProperty +{ + if (_filterStyles[singleProperty]) + { + if (!_propertyArray) { + _propertyArray = [NSMutableArray new]; + } + if ([singleProperty isEqualToString:@"backgroundColor"]) { + WXTransitionInfo *info = [WXTransitionInfo new]; + info.fromValue = [self _dealWithColor:[WXConvert UIColor:_oldFilterStyles[singleProperty]]]; + info.toValue = [self _dealWithColor:[WXConvert UIColor:_filterStyles[singleProperty]]]; + info.perValue = [self _calculatePerColorRGB1:info.toValue RGB2:info.fromValue]; + info.propertyName = singleProperty; + [_propertyArray addObject:info]; + } + else if ([singleProperty isEqualToString:@"transform"]) { + NSString *transformOrigin = _filterStyles[@"transformOrigin"]; + WXTransform *wxTransform = [[WXTransform alloc] initWithCSSValue:_filterStyles[singleProperty] origin:transformOrigin instance:_targetComponent.weexInstance]; + WXTransform *oldTransform = _targetComponent->_transform; + if (wxTransform.rotateAngle != oldTransform.rotateAngle) { + WXTransitionInfo *info = [WXTransitionInfo new]; + info.propertyName = @"transform.rotation"; + info.fromValue = @(oldTransform.rotateAngle); + info.toValue = [NSNumber numberWithDouble:wxTransform.rotateAngle]; + info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); + [_propertyArray addObject:info]; + } + if (wxTransform.rotateX != oldTransform.rotateX) + { + WXTransitionInfo *info = [WXTransitionInfo new]; + info.propertyName = @"transform.rotation.x"; + info.fromValue = @(oldTransform.rotateX); + info.toValue = [NSNumber numberWithDouble:wxTransform.rotateX]; + info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); + [_propertyArray addObject:info]; + } + if (wxTransform.rotateY != oldTransform.rotateY) + { + WXTransitionInfo *info = [WXTransitionInfo new]; + info.propertyName = @"transform.rotation.y"; + info.fromValue = @(oldTransform.rotateY); + info.toValue = [NSNumber numberWithDouble:wxTransform.rotateY]; + info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); + [_propertyArray addObject:info]; + } + if (wxTransform.rotateZ != oldTransform.rotateZ) + { + WXTransitionInfo *info = [WXTransitionInfo new]; + info.propertyName = @"transform.rotation.z"; + info.fromValue = @(oldTransform.rotateZ); + info.toValue = [NSNumber numberWithDouble:wxTransform.rotateZ]; + info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); + [_propertyArray addObject:info]; + } + if (wxTransform.scaleX != oldTransform.scaleX) { + WXTransitionInfo *info = [WXTransitionInfo new]; + info.propertyName = @"transform.scale.x"; + info.fromValue = @(oldTransform.scaleX); + info.toValue = @(wxTransform.scaleX); + info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); + [_propertyArray addObject:info]; + } + if (wxTransform.scaleY != oldTransform.scaleY) { + WXTransitionInfo *info = [WXTransitionInfo new]; + info.propertyName = @"transform.scale.y"; + info.fromValue = @(oldTransform.scaleY); + info.toValue = @(wxTransform.scaleY); + info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); + [_propertyArray addObject:info]; + } + if (wxTransform.translateX && [wxTransform.translateX floatValue] !=[oldTransform.translateX floatValue]) { + WXTransitionInfo *info = [WXTransitionInfo new]; + info.propertyName = @"transform.translation.x"; + info.fromValue = @([oldTransform.translateX floatValue]); + info.toValue = @([wxTransform.translateX floatValue]); + info.perValue = @([wxTransform.translateX floatValue] - [oldTransform.translateX floatValue]); + [_propertyArray addObject:info]; + } + if (wxTransform.translateY && [wxTransform.translateY floatValue] !=[oldTransform.translateY floatValue]) { + WXTransitionInfo *info = [WXTransitionInfo new]; + info.propertyName = @"transform.translation.y"; + info.fromValue = @([oldTransform.translateY floatValue]); + info.toValue = @([wxTransform.translateY floatValue]); + info.perValue = @([wxTransform.translateY floatValue] - [oldTransform.translateY floatValue]); + [_propertyArray addObject:info]; + } + _targetComponent->_transform = wxTransform; + } + else + { + WXTransitionInfo *info = [WXTransitionInfo new]; + info.fromValue = @(_oldFilterStyles[singleProperty] ? [WXConvert CGFloat:_oldFilterStyles[singleProperty]] : 0); + info.toValue = @(_filterStyles[singleProperty] ? [WXConvert CGFloat:_filterStyles[singleProperty]] : 0 ); + info.perValue = @([info.toValue doubleValue] - [info.fromValue doubleValue]); + info.propertyName = singleProperty; + [_propertyArray addObject:info]; + } + } +} + +- (NSArray *)_dealWithColor:(UIColor *)color +{ + CGFloat R, G, B, A; + [color getRed:&R green:&G blue:&B alpha:&A]; + return @[@(R),@(G),@(B),@(A)]; +} + +- (NSArray *)_calculatePerColorRGB1:(NSArray *)RGB1 RGB2:(NSArray *)RGB2 +{ + CGFloat R = [RGB1[0] doubleValue] - [RGB2[0] doubleValue]; + CGFloat G = [RGB1[1] doubleValue] - [RGB2[1] doubleValue]; + CGFloat B = [RGB1[2] doubleValue] - [RGB2[2] doubleValue]; + CGFloat A = [RGB1[3] doubleValue] - [RGB2[3] doubleValue]; + return @[@(R),@(G),@(B),@(A)]; +} + +- (void)_calculatetransitionProcessingStyle +{ + if (_propertyArray.count == 0) { + return; + } + double per = 1000 * (_transitionCount + 1 ) / (60 * _transitionDuration);//linear + if (![[NSString stringWithFormat:@"%@",_transitionTimingFunction] isEqualToString: kCAMediaTimingFunctionLinear]) { + per = [self solveWithx:((_transitionCount+2)*16)/_transitionDuration epsilon:SOLVE_EPS(_transitionDuration)]; + } + NSString *transformString = [NSString string]; + for (WXTransitionInfo *info in _propertyArray) { + if ([info.propertyName isEqualToString:@"backgroundColor"]) { + NSArray *array = @[ + @([info.fromValue[0] floatValue] + [info.perValue[0] floatValue] * per), + @([info.fromValue[1] floatValue] + [info.perValue[1] floatValue] * per), + @([info.fromValue[2] floatValue] + [info.perValue[2] floatValue] * per), + @([info.fromValue[3] floatValue] + [info.perValue[3] floatValue] * per)]; + UIColor *color = [UIColor colorWithRed:[array[0] floatValue] green:[array[1] floatValue] blue:[array[2] floatValue] alpha:[array[3] floatValue]]; + WXPerformBlockOnMainThread(^{ + _targetComponent.view.backgroundColor = color; + [_targetComponent.view setNeedsDisplay]; + }); + NSString *colorString = [WXConvert HexWithColor:color]; + [_oldFilterStyles setObject:colorString forKey:info.propertyName]; + } + else if ([info.propertyName hasPrefix:@"transform"]) + { + double currentValue = [info.fromValue doubleValue] + [info.perValue doubleValue] * per; + NSString *newString = [NSString string]; + if ([info.propertyName isEqualToString:@"transform.rotation"]) { + newString = [NSString stringWithFormat:@"rotate(%lfdeg)",currentValue * 180.0 / M_PI]; + transformString = [transformString stringByAppendingFormat:@" %@",newString]; + } + if ([info.propertyName isEqualToString:@"transform.rotation.x"]) { + newString = [NSString stringWithFormat:@"rotateX(%lfdeg)",currentValue * 180.0 / M_PI]; + transformString = [transformString stringByAppendingFormat:@" %@",newString]; + } + if ([info.propertyName isEqualToString:@"transform.rotation.y"]) { + newString = [NSString stringWithFormat:@"rotateY(%lfdeg)",currentValue * 180.0 / M_PI]; + transformString = [transformString stringByAppendingFormat:@" %@",newString]; + } + if ([info.propertyName isEqualToString:@"transform.rotation.z"]) { + newString = [NSString stringWithFormat:@"rotateZ(%lfdeg)",currentValue * 180.0 / M_PI]; + transformString = [transformString stringByAppendingFormat:@" %@",newString]; + } + if ([info.propertyName isEqualToString:@"transform.scale.x"]) { + newString = [NSString stringWithFormat:@"scaleX(%lf)",currentValue]; + transformString = [transformString stringByAppendingFormat:@" %@",newString]; + } + if ([info.propertyName isEqualToString:@"transform.scale.y"]) { + newString = [NSString stringWithFormat:@"scaleY(%lf)",currentValue]; + transformString = [transformString stringByAppendingFormat:@" %@",newString]; + } + if ([info.propertyName isEqualToString:@"transform.translation.x"]) { + newString = [NSString stringWithFormat:@"translateX(%lfpx)",currentValue / _targetComponent.weexInstance.pixelScaleFactor]; + transformString = [transformString stringByAppendingFormat:@" %@",newString]; + } + if ([info.propertyName isEqualToString:@"transform.translation.y"]) { + newString = [NSString stringWithFormat:@"translateY(%lfpx)",currentValue / _targetComponent.weexInstance.pixelScaleFactor]; + transformString = [transformString stringByAppendingFormat:@" %@",newString]; + } + [_oldFilterStyles setObject:transformString forKey:@"transform"]; + } + else + { + double currentValue = [info.fromValue doubleValue] + [info.perValue doubleValue] * per; + [_oldFilterStyles setObject:@(currentValue) forKey:info.propertyName]; + } + } + WXPerformBlockOnMainThread(^{ + [_targetComponent _updateViewStyles:_oldFilterStyles]; + }); + [_targetComponent _updateCSSNodeStyles:_oldFilterStyles]; + [_targetComponent.weexInstance.componentManager startComponentTasks]; +} + +#pragma mark CADisplayLink +- (void)_startTransitionDisplayLink +{ + WXAssertComponentThread(); + if (!_transitionDisplayLink) { + _transitionDisplayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(_handleTransitionDisplayLink)]; + [_transitionDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + } + else{ + [self _awakeTransitionDisplayLink]; + } +} + +- (void)_stopTransitionDisplayLink +{ + WXAssertComponentThread(); + if (_transitionDisplayLink) { + [_transitionDisplayLink invalidate]; + _transitionDisplayLink = nil; + } +} + +- (BOOL)_isTransitionRunning +{ + WXAssertComponentThread(); + BOOL yesOrNo = NO; + if (!_transitionDisplayLink.paused && _transitionCount >= 5) { + yesOrNo = YES; + } + return yesOrNo; +} + +- (void)_suspendTransitionDisplayLink +{ + WXAssertComponentThread(); + if(_transitionDisplayLink && !_transitionDisplayLink.paused){ + _transitionDisplayLink.paused = YES; + } +} + +- (void)_awakeTransitionDisplayLink +{ + WXAssertComponentThread(); + if (_transitionDisplayLink && _transitionDisplayLink.paused) { + _transitionDisplayLink.paused = NO; + } +} + +- (void)_handleTransitionDisplayLink +{ + WXAssertComponentThread(); + int count = _transitionDuration * 60 / 1000; + if (_transitionCount >= count) { + [self _suspendTransitionDisplayLink]; + [self _resetProcessAnimationParameter]; + return; + } + else + { + [self _calculatetransitionProcessingStyle]; + } + _transitionCount ++; +} + +- (void)_resetProcessAnimationParameter +{ + _transitionCount = 0; + _transitionDuration = 0; + _propertyArray = nil; + _oldFilterStyles = nil; + _filterStyles= nil; +} + +- (NSMutableDictionary *)_filterStyles +{ + return self.filterStyles; +} + +- (NSMutableDictionary *)_oldFilterStyles +{ + return self.oldFilterStyles; +} + +#pragma mark UnitBezierp +- (void)unitBezierp1x:(double)p1x p1y:(double)p1y p2x:(double)p2x p2y:(double)p2y +{ + cx = 3.0 * p1x; + bx = 3.0 * (p2x - p1x) - cx; + ax = 1.0 - cx -bx; + + cy = 3.0 * p1y; + by = 3.0 * (p2y - p1y) - cy; + ay = 1.0 - cy - by; +} + +- (double)sampleCurveX:(double)t +{ + return ((ax * t + bx) * t + cx) * t; +} + +- (double)sampleCurveY:(double)t +{ + return ((ay * t + by) * t + cy) * t; +} + +- (double)sampleCurveDerivativeX:(double)t +{ + return (3.0 * ax * t + 2.0 * bx) * t + cx; +} + +- (double)solveCurveX:(double)x epsilon:(double)epsilon +{ + double t0; + double t1; + double t2; + double x2; + double d2; + int i; + + for (t2 = x, i = 0; i < 8; i++) { + x2 = [self sampleCurveX:t2] - x; + if (fabs (x2) < epsilon) + return t2; + d2 = [self sampleCurveDerivativeX:t2]; + if (fabs(d2) < 1e-6) + break; + t2 = t2 - x2 / d2; + } + t0 = 0.0; + t1 = 1.0; + t2 = x; + + if (t2 < t0) + return t0; + if (t2 > t1) + return t1; + + while (t0 < t1) { + x2 = [self sampleCurveX:t2]; + if (fabs(x2 - x) < epsilon) + return t2; + if (x > x2) + t0 = t2; + else + t1 = t2; + t2 = (t1 - t0) * .5 + t0; + } + return t2; +} + +- (double)solveWithx:(double)x epsilon:(double)epsilon +{ + return [self sampleCurveY:([self solveCurveX:x epsilon:epsilon])]; +} +@end http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Utility/WXConvert.m ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXConvert.m b/ios/sdk/WeexSDK/Sources/Utility/WXConvert.m index 2744e60..a303ddb 100644 --- a/ios/sdk/WeexSDK/Sources/Utility/WXConvert.m +++ b/ios/sdk/WeexSDK/Sources/Utility/WXConvert.m @@ -63,6 +63,9 @@ WX_NUMBER_CONVERT(NSUInteger, unsignedIntegerValue) { if ([value isKindOfClass:[NSString class]]) { NSString *valueString = (NSString *)value; + if (valueString.length <=0) { + return NAN; + } if ([valueString hasSuffix:@"px"] || [valueString hasSuffix:@"wx"]) { valueString = [valueString substringToIndex:(valueString.length - 2)]; } @@ -72,12 +75,32 @@ WX_NUMBER_CONVERT(NSUInteger, unsignedIntegerValue) value = [value substringWithRange:NSMakeRange(start, end-start)]; return [self safeAreaInset:value]; } + //value maybe not number ,such as 100% + if (![WXConvert checkStringIsRealNum:valueString]) { + return NAN; + } return [valueString doubleValue]; } return [self double:value]; } ++ (BOOL)checkStringIsRealNum:(NSString *)checkedNumString { + NSScanner* scan = [NSScanner scannerWithString:checkedNumString]; + int intVal; + BOOL isInt = [scan scanInt:&intVal] && [scan isAtEnd]; + if (isInt) { + return YES; + } + float floatVal; + BOOL isFloat = [scan scanFloat:&floatVal] && [scan isAtEnd]; + if (isFloat) { + return YES; + } + + return NO; +} + + (CGFloat)safeAreaInset:(NSString*)value { static NSArray * directionArray = nil; http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b77b4259/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h ---------------------------------------------------------------------- diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h index 0e2bb06..b1b852a 100644 --- a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h +++ b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h @@ -253,6 +253,9 @@ _Nonnull SEL WXSwizzledSelectorForSelector(_Nonnull SEL selector); */ + (CGFloat)defaultPixelScaleFactor; +#if defined __cplusplus +extern "C" { +#endif /** * @abstract Returns the scale of the main screen. * @@ -276,7 +279,11 @@ CGFloat WXFloorPixelValue(CGFloat value); * */ CGFloat WXCeilPixelValue(CGFloat value); - + +#if defined __cplusplus +}; +#endif + /** * @abstract check whether the file is exist * @@ -404,6 +411,10 @@ CGPoint WXPixelPointResize(CGPoint value) DEPRECATED_MSG_ATTRIBUTE("Use WXPixelS */ + (NSDictionary *_Nullable)linearGradientWithBackgroundImage:(NSString *_Nullable)backgroundImage; +#if defined __cplusplus +extern "C" { +#endif + /** * @abstract compare float a and b, if a equal b, return true,or reture false. * @@ -435,6 +446,10 @@ BOOL WXFloatGreaterThan(CGFloat a, CGFloat b); */ BOOL WXFloatGreaterThanWithPrecision(CGFloat a,CGFloat b,double precision); +#if defined __cplusplus +}; +#endif + /** * @abstract convert returnKeyType to type string . *