You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by cx...@apache.org on 2017/03/06 11:10:10 UTC

[04/12] incubator-weex git commit: * [dev] Add Feature Recycler and Waterfall

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m
index 104a8f2..0418ae8 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m
+++ b/ios/sdk/WeexSDK/Sources/Component/WXListComponent.m
@@ -8,6 +8,7 @@
 
 #import "WXListComponent.h"
 #import "WXCellComponent.h"
+#import "WXHeaderComponent.h"
 #import "WXComponent.h"
 #import "WXComponent_internal.h"
 #import "NSArray+Weex.h"
@@ -52,53 +53,6 @@
 
 @end
 
-@interface WXHeaderComponent : WXComponent
-
-@property (nonatomic, weak) WXListComponent *list;
-
-@end
-
-@implementation WXHeaderComponent
-
-//TODO: header remove->need reload
-- (instancetype)initWithRef:(NSString *)ref type:(NSString *)type styles:(NSDictionary *)styles attributes:(NSDictionary *)attributes events:(NSArray *)events weexInstance:(WXSDKInstance *)weexInstance
-{
-    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
-    
-    if (self) {
-        _async = YES;
-        _isNeedJoinLayoutSystem = NO;
-    }
-    
-    return self;
-}
-
-- (void)_frameDidCalculated:(BOOL)isChanged
-{
-    [super _frameDidCalculated:isChanged];
-    
-    if (isChanged) {
-        [self.list headerDidLayout:self];
-    }
-}
-
-- (void)_calculateFrameWithSuperAbsolutePosition:(CGPoint)superAbsolutePosition gatherDirtyComponents:(NSMutableSet<WXComponent *> *)dirtyComponents
-{
-    if (isUndefined(self.cssNode->style.dimensions[CSS_WIDTH]) && self.list) {
-        self.cssNode->style.dimensions[CSS_WIDTH] = self.list.scrollerCSSNode->style.dimensions[CSS_WIDTH];
-    }
-    
-    if ([self needsLayout]) {
-        layoutNode(self.cssNode, CSS_UNDEFINED, CSS_UNDEFINED, CSS_DIRECTION_INHERIT);
-        if ([WXLog logLevel] >= WXLogLevelDebug) {
-            print_css_node(self.cssNode, CSS_PRINT_LAYOUT | CSS_PRINT_STYLE | CSS_PRINT_CHILDREN);
-        }
-    }
-    
-    [super _calculateFrameWithSuperAbsolutePosition:superAbsolutePosition gatherDirtyComponents:dirtyComponents];
-}
-
-@end
 
 @interface WXSection : NSObject<NSCopying>
 
@@ -133,7 +87,7 @@
 }
 @end
 
-@interface WXListComponent () <UITableViewDataSource, UITableViewDelegate>
+@interface WXListComponent () <UITableViewDataSource, UITableViewDelegate, WXCellRenderDelegate, WXHeaderRenderDelegate>
 
 @end
 
@@ -246,9 +200,9 @@
 - (void)_insertSubcomponent:(WXComponent *)subcomponent atIndex:(NSInteger)index
 {
     if ([subcomponent isKindOfClass:[WXCellComponent class]]) {
-        ((WXCellComponent *)subcomponent).list = self;
+        ((WXCellComponent *)subcomponent).delegate = self;
     } else if ([subcomponent isKindOfClass:[WXHeaderComponent class]]) {
-        ((WXHeaderComponent *)subcomponent).list = self;
+        ((WXHeaderComponent *)subcomponent).delegate = self;
     } else if (![subcomponent isKindOfClass:[WXRefreshComponent class]]
                && ![subcomponent isKindOfClass:[WXLoadingComponent class]]
                && subcomponent->_positionType != WXPositionTypeFixed) {
@@ -328,6 +282,13 @@
     }
 }
 
+#pragma mark - WXHeaderRenderDelegate
+
+- (float)headerWidthForLayout:(WXHeaderComponent *)cell
+{
+    return self.scrollerCSSNode->style.dimensions[CSS_WIDTH];
+}
+
 - (void)headerDidLayout:(WXHeaderComponent *)header
 {
     [self.weexInstance.componentManager _addUITask:^{
@@ -335,9 +296,19 @@
         [_tableView beginUpdates];
         [_tableView endUpdates];
     }];
+}
+
+- (void)headerDidRemove:(WXHeaderComponent *)header
+{
     
 }
 
+#pragma mark - WXCellRenderDelegate
+
+- (float)containerWidthForLayout:(WXCellComponent *)cell
+{
+    return self.scrollerCSSNode->style.dimensions[CSS_WIDTH];
+}
 
 - (void)cellDidRemove:(WXCellComponent *)cell
 {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Component/WXTransform.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXTransform.m b/ios/sdk/WeexSDK/Sources/Component/WXTransform.m
index a72f39b..e5ed68b 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXTransform.m
+++ b/ios/sdk/WeexSDK/Sources/Component/WXTransform.m
@@ -87,7 +87,7 @@
     }
     
     if (_translateX || _translateY) {
-        nativeTransform = CGAffineTransformTranslate(nativeTransform, _translateX ? [_translateX valueForMaximumValue:view.bounds.size.width] : 0,  _translateY ? [_translateY valueForMaximumValue:view.bounds.size.height] : 0);
+        nativeTransform = CGAffineTransformTranslate(nativeTransform, _translateX ? [_translateX valueForMaximum:view.bounds.size.width] : 0,  _translateY ? [_translateY valueForMaximum:view.bounds.size.height] : 0);
     }
     
     nativeTransform = CGAffineTransformScale(nativeTransform, _scaleX, _scaleY);
@@ -131,8 +131,8 @@
           * http://ronnqvi.st/translate-rotate-translate/
           **/
         CGPoint anchorPoint = CGPointMake(
-                                          _originX ? [_originX valueForMaximumValue:view.bounds.size.width] / view.bounds.size.width : 0.5,
-                                          _originY ? [_originY valueForMaximumValue:view.bounds.size.width] / view.bounds.size.height : 0.5);
+                                          _originX ? [_originX valueForMaximum:view.bounds.size.width] / view.bounds.size.width : 0.5,
+                                          _originY ? [_originY valueForMaximum:view.bounds.size.width] / view.bounds.size.height : 0.5);
         [self setAnchorPoint:anchorPoint forView:view];
     }
     
@@ -220,8 +220,8 @@
         }
     }
     
-    _originX = [WXLength lengthWithValue:originX type:typeX];
-    _originY = [WXLength lengthWithValue:originY type:typeY];
+    _originX = [WXLength lengthWithFloat:originX type:typeX];
+    _originY = [WXLength lengthWithFloat:originY type:typeY];
 }
 
 - (void)parseRotate:(NSArray *)value
@@ -235,20 +235,20 @@
     WXLength *translateX;
     double x = [value[0] doubleValue];
     if ([value[0] hasSuffix:@"%"]) {
-        translateX = [WXLength lengthWithValue:x type:WXLengthTypePercent];
+        translateX = [WXLength lengthWithFloat:x type:WXLengthTypePercent];
     } else {
         x = WXPixelScale(x, self.weexInstance.pixelScaleFactor);
-        translateX = [WXLength lengthWithValue:x type:WXLengthTypeFixed];
+        translateX = [WXLength lengthWithFloat:x type:WXLengthTypeFixed];
     }
 
     WXLength *translateY;
     if (value.count > 1) {
         double y = [value[1] doubleValue];
         if ([value[1] hasSuffix:@"%"]) {
-            translateY = [WXLength lengthWithValue:y type:WXLengthTypePercent];
+            translateY = [WXLength lengthWithFloat:y type:WXLengthTypePercent];
         } else {
             y = WXPixelScale(y, self.weexInstance.pixelScaleFactor);
-            translateY = [WXLength lengthWithValue:y type:WXLengthTypeFixed];
+            translateY = [WXLength lengthWithFloat:y type:WXLengthTypeFixed];
         }
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m b/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
index 4103f01..f28f6f1 100644
--- a/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
+++ b/ios/sdk/WeexSDK/Sources/Engine/WXSDKEngine.m
@@ -72,6 +72,8 @@
     [self registerComponent:@"image" withClass:NSClassFromString(@"WXImageComponent") withProperties:nil];
     [self registerComponent:@"scroller" withClass:NSClassFromString(@"WXScrollerComponent") withProperties:nil];
     [self registerComponent:@"list" withClass:NSClassFromString(@"WXListComponent") withProperties:nil];
+    [self registerComponent:@"recycler" withClass:NSClassFromString(@"WXRecyclerComponent") withProperties:nil];
+    [self registerComponent:@"waterfall" withClass:NSClassFromString(@"WXRecyclerComponent") withProperties:nil];
     
     [self registerComponent:@"header" withClass:NSClassFromString(@"WXHeaderComponent")];
     [self registerComponent:@"cell" withClass:NSClassFromString(@"WXCellComponent")];

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Model/WXComponent.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXComponent.m b/ios/sdk/WeexSDK/Sources/Model/WXComponent.m
index c6d5ba6..2feb24c 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXComponent.m
+++ b/ios/sdk/WeexSDK/Sources/Model/WXComponent.m
@@ -168,7 +168,7 @@
 
 - (NSString *)description
 {
-    return [NSString stringWithFormat:@"<%@ ref=%@> %@", _type, _ref, _view];
+    return [NSString stringWithFormat:@"<%@:%p ref=%@> %@", _type, self, _ref, _view];
 }
 
 #pragma mark Property

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m b/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m
index 81e888a..404402e 100644
--- a/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m
+++ b/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m
@@ -176,16 +176,16 @@ WX_EXPORT_METHOD(@selector(transition:args:callback:))
             if ((wxTransform.translateX && ![wxTransform.translateX isEqualToLength:oldTransform.translateX]) || (!wxTransform.translateX && oldTransform.translateX)) {
                 WXAnimationInfo *newInfo = [info copy];
                 newInfo.propertyName = @"transform.translation.x";
-                newInfo.fromValue = @([oldTransform.translateX valueForMaximumValue:view.bounds.size.width]);
-                newInfo.toValue = @([wxTransform.translateX valueForMaximumValue:view.bounds.size.width]);
+                newInfo.fromValue = @([oldTransform.translateX valueForMaximum:view.bounds.size.width]);
+                newInfo.toValue = @([wxTransform.translateX valueForMaximum:view.bounds.size.width]);
                 [infos addObject:newInfo];
             }
             
             if ((wxTransform.translateY && ![wxTransform.translateY isEqualToLength:oldTransform.translateY]) || (!wxTransform.translateY && oldTransform.translateY)) {
                 WXAnimationInfo *newInfo = [info copy];
                 newInfo.propertyName = @"transform.translation.y";
-                newInfo.fromValue = @([oldTransform.translateY valueForMaximumValue:view.bounds.size.height]);
-                newInfo.toValue = @([wxTransform.translateY valueForMaximumValue:view.bounds.size.height]);
+                newInfo.fromValue = @([oldTransform.translateY valueForMaximum:view.bounds.size.height]);
+                newInfo.toValue = @([wxTransform.translateY valueForMaximum:view.bounds.size.height]);
                 [infos addObject:newInfo];
             }
             

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Module/WXMetaModule.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Module/WXMetaModule.m b/ios/sdk/WeexSDK/Sources/Module/WXMetaModule.m
index 3fa4f66..af8c2d0 100644
--- a/ios/sdk/WeexSDK/Sources/Module/WXMetaModule.m
+++ b/ios/sdk/WeexSDK/Sources/Module/WXMetaModule.m
@@ -22,9 +22,9 @@ WX_EXPORT_METHOD(@selector(setViewport:))
     id viewportWidth = viewportArguments[@"width"];
     if ([viewportWidth isKindOfClass:[NSString class]]) {
         if ([viewportWidth isEqualToString:@"device-width"]) {
-            viewportWidthFloat = [WXUtility portraitScreenSize].width * WXScreenScale();
+            viewportWidthFloat = [WXUtility portraitScreenSize].width;
         } else if ([viewportWidth isEqualToString:@"device-height"]) {
-            viewportWidthFloat = [WXUtility portraitScreenSize].height * WXScreenScale();
+            viewportWidthFloat = [WXUtility portraitScreenSize].height;
         } else {
             viewportWidthFloat = [WXConvert CGFloat:viewportWidth];
         }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Utility/WXConvert.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXConvert.h b/ios/sdk/WeexSDK/Sources/Utility/WXConvert.h
index f181700..9703e8c 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXConvert.h
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXConvert.h
@@ -11,6 +11,7 @@
 #import "WXLog.h"
 #import "WXLayoutDefine.h"
 #import "WXType.h"
+#import "WXLength.h"
 
 @class WXBoxShadow;
 @interface WXConvert : NSObject
@@ -69,6 +70,7 @@ typedef BOOL WXClipType;
 
 + (WXGradientType)gradientType:(id)value;
 
++ (WXLength *)WXLength:(id)value isFloat:(BOOL)isFloat scaleFactor:(CGFloat)scaleFactor;
 + (WXBoxShadow *)WXBoxShadow:(id)value scaleFactor:(CGFloat)scaleFactor;
 
 @end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/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 d3ee3b2..c678000 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXConvert.m
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXConvert.m
@@ -9,6 +9,7 @@
 #import "WXConvert.h"
 #import "WXUtility.h"
 #import "WXBoxShadow.h"
+#import "WXAssert.h"
 
 @implementation WXConvert
 
@@ -724,6 +725,34 @@ WX_NUMBER_CONVERT(NSUInteger, unsignedIntegerValue)
     return type;
 }
 
+#pragma mark - Length
+
++ (WXLength *)WXLength:(id)value isFloat:(BOOL)isFloat scaleFactor:(CGFloat)scaleFactor
+{
+    if (!value) {
+        return nil;
+    }
+    
+    WXLengthType type = WXLengthTypeFixed;
+    if ([value isKindOfClass:[NSString class]]) {
+        if ([value isEqualToString:@"auto"]) {
+            type = WXLengthTypeAuto;
+        } else if ([value isEqualToString:@"normal"]){
+            type = WXLengthTypeNormal;
+        } else if ([value hasSuffix:@"%"]) {
+            type = WXLengthTypePercent;
+        }
+    } else if (![value isKindOfClass:[NSNumber class]]) {
+        WXAssert(NO, @"Unsupported type:%@ for WXLength", NSStringFromClass([value class]));
+    }
+    
+    if (isFloat) {
+        return [WXLength lengthWithFloat:([value floatValue] * scaleFactor) type:type];
+    } else {
+        return [WXLength lengthWithInt:([value intValue] * scaleFactor) type:type];
+    }
+}
+
 + (WXBoxShadow *)WXBoxShadow:(id)value scaleFactor:(CGFloat)scaleFactor
 {
     NSString *boxShadow = @"";

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Utility/WXDiffUtil.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXDiffUtil.h b/ios/sdk/WeexSDK/Sources/Utility/WXDiffUtil.h
new file mode 100644
index 0000000..e407469
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXDiffUtil.h
@@ -0,0 +1,38 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import <Foundation/Foundation.h>
+
+@protocol WXDiffable <NSObject>
+
+- (BOOL)isEqualToWXObject:(id<WXDiffable>)object;
+
+@end
+
+@interface WXDiffUpdateIndex : NSObject
+
+@property (nonatomic, assign, readonly) NSUInteger oldIndex;
+@property (nonatomic, assign, readonly) NSUInteger newIndex;
+
+@end
+
+@interface WXDiffResult : NSObject
+
+@property (nonatomic, strong, readonly) NSIndexSet *inserts;
+@property (nonatomic, strong, readonly) NSIndexSet *deletes;
+@property (nonatomic, strong, readonly) NSArray<WXDiffUpdateIndex *> *updates;
+
+- (BOOL)hasChanges;
+
+@end
+
+@interface WXDiffUtil : NSObject
+
++ (WXDiffResult *)diffWithMinimumDistance:(NSArray<id<WXDiffable>> *)newArray oldArray:(NSArray<id<WXDiffable>> *)oldArray;
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Utility/WXDiffUtil.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXDiffUtil.m b/ios/sdk/WeexSDK/Sources/Utility/WXDiffUtil.m
new file mode 100644
index 0000000..01cab02
--- /dev/null
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXDiffUtil.m
@@ -0,0 +1,186 @@
+/**
+ * Created by Weex.
+ * Copyright (c) 2016, Alibaba, Inc. All rights reserved.
+ *
+ * This source code is licensed under the Apache Licence 2.0.
+ * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
+ */
+
+#import "WXDiffUtil.h"
+#import "WXLog.h"
+
+typedef enum : NSUInteger {
+    WXDiffOperationDoNothing,
+    WXDiffOperationUpdate,
+    WXDiffOperationDelete,
+    WXDiffOperationInsert
+} WXDiffOperation;
+
+@implementation WXDiffUpdateIndex
+
+- (instancetype)initWithOldIndex:(NSUInteger)oldIndex newIndex:(NSUInteger)newIndex
+{
+    if (self = [super init]) {
+        _oldIndex = oldIndex;
+        _newIndex = newIndex;
+    }
+    
+    return self;
+}
+
+@end
+
+@implementation WXDiffResult
+
+- (instancetype)initWithInserts:(NSIndexSet *)inserts
+                        deletes:(NSIndexSet *)deletes
+                        updates:(NSArray<WXDiffUpdateIndex *> *)updates
+{
+    if (self = [super init]) {
+        _inserts = [inserts copy];
+        _deletes = [deletes copy];
+        _updates = [updates copy];
+    }
+    
+    return self;
+}
+
+- (BOOL)hasChanges
+{
+    return _updates.count > 0 || _inserts.count > 0 || _deletes.count > 0;
+}
+
+- (NSString *)description
+{
+    return [NSString stringWithFormat:@"<%@: %p; %zi inserts; %zi deletes; %zi updates", NSStringFromClass([self class]), self, _inserts.count, _deletes.count, _updates.count];
+}
+
+
+@end
+
+@implementation WXDiffUtil
+
++ (WXDiffResult *)diffWithMinimumDistance:(NSArray<id<WXDiffable>> *)newArray oldArray:(NSArray<id<WXDiffable>> *)oldArray
+{
+    // Using the levenshtein algorithm
+    // https://en.wikipedia.org/wiki/Levenshtein_distance
+    
+    int oldSize = (int)(oldArray.count + 1);
+    int newSize = (int)(newArray.count + 1);
+    
+    int **matrix = malloc(oldSize * sizeof(int *));
+    for (int i = 0; i < oldSize; i++) {
+        matrix[i] = malloc(newSize * sizeof(int));
+    }
+    
+    matrix[0][0] = 0;
+    
+    for (int i = 1; i < oldSize; i++) {
+        matrix[i][0] = i;
+    }
+    
+    for (int j = 1; j < newSize; j++) {
+        matrix[0][j] = j;
+    }
+    
+    for (int oldIndex = 1; oldIndex < oldSize; oldIndex ++) {
+        for (int newIndex = 1; newIndex < newSize; newIndex ++) {
+            if ([oldArray[oldIndex - 1] isEqualToWXObject:newArray[newIndex - 1]]) {
+                matrix[oldIndex][newIndex] = matrix[oldIndex - 1][newIndex - 1];
+            } else {
+                int updateCost = matrix[oldIndex - 1][newIndex - 1] + 1;
+                int insertCost = matrix[oldIndex][newIndex - 1] + 1;
+                int deleteCost = matrix[oldIndex - 1][newIndex] + 1;
+                matrix[oldIndex][newIndex] = MIN(MIN(insertCost, deleteCost), updateCost);
+            }
+        }
+    }
+    
+    [self _printMatrix:matrix rowSize:oldSize columnSize:newSize];
+    
+    NSMutableArray *updates = [NSMutableArray array];
+    NSMutableIndexSet *inserts = [NSMutableIndexSet indexSet];
+    NSMutableIndexSet *deletes = [NSMutableIndexSet indexSet];
+    int oldIndex = oldSize - 1;
+    int newIndex = newSize - 1;
+    while (oldIndex != 0 || newIndex != 0) {
+        WXDiffOperation operation = [self _operationInMatrix:matrix newIndex:newIndex oldIndex:oldIndex];
+        switch (operation) {
+            case WXDiffOperationUpdate:
+                newIndex --;
+                oldIndex --;
+                [updates addObject:[[WXDiffUpdateIndex alloc] initWithOldIndex:oldIndex newIndex:newIndex]];
+                break;
+            case WXDiffOperationDelete:
+                oldIndex --;
+                [deletes addIndex:oldIndex];
+                break;
+            case WXDiffOperationInsert:
+                newIndex --;
+                [inserts addIndex:newIndex];
+                break;
+            case WXDiffOperationDoNothing:
+                newIndex --;
+                oldIndex --;
+                break;
+        }
+    }
+    
+    for (int i = 0; i < oldSize; i++) {
+        free(matrix[i]);
+    }
+    free(matrix);
+    
+    WXDiffResult *result = [[WXDiffResult alloc] initWithInserts:inserts deletes:deletes updates:updates];
+    return result;
+}
+
++ (WXDiffOperation)_operationInMatrix:(int **)matrix newIndex:(int)newIndex oldIndex:(int)oldIndex
+{
+    if (newIndex == 0) {
+        return WXDiffOperationDelete;
+    }
+    
+    if (oldIndex == 0) {
+        return WXDiffOperationInsert;
+    }
+    
+    int cost = matrix[oldIndex][newIndex];
+    
+    int costBeforeInsert = matrix[oldIndex][newIndex - 1];
+    if (costBeforeInsert + 1 == cost) {
+        return WXDiffOperationInsert;
+    }
+    
+    int costBeforDelete = matrix[oldIndex - 1][newIndex];
+    if (costBeforDelete + 1 == cost) {
+        return WXDiffOperationDelete;
+    }
+    
+    int costBeforUpdate = matrix[oldIndex - 1][newIndex - 1];
+    if (costBeforUpdate + 1 == cost) {
+        return WXDiffOperationUpdate;
+    }
+    
+    return WXDiffOperationDoNothing;
+}
+
++ (void)_printMatrix:(int **)matrix rowSize:(int)rowSize columnSize:(int)columnSize
+{
+    for (int i = 0; i < rowSize; i ++) {
+        NSMutableArray *array = [NSMutableArray array];
+        for (int j = 0; j < columnSize; j ++) {
+            int value = matrix[i][j];
+            NSString *result;
+            if (value < 10) {
+                result = [NSString stringWithFormat:@"0%zi", value];
+            } else {
+                result = [NSString stringWithFormat:@"%zi", value];
+            }
+            [array addObject:result];
+        }
+        WXLogDebug(@"%@", [array componentsJoinedByString:@" "]);
+    }
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Utility/WXLength.h
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXLength.h b/ios/sdk/WeexSDK/Sources/Utility/WXLength.h
index b8480ea..491d2d7 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXLength.h
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXLength.h
@@ -12,13 +12,20 @@ typedef enum : NSUInteger {
     WXLengthTypeFixed,
     WXLengthTypePercent,
     WXLengthTypeAuto,
+    WXLengthTypeNormal
 } WXLengthType;
 
 @interface WXLength : NSObject
 
-+ (instancetype)lengthWithValue:(float)value type:(WXLengthType)type;
++ (instancetype)lengthWithFloat:(float)value type:(WXLengthType)type;
 
-- (float)valueForMaximumValue:(float)maximumValue;
++ (instancetype)lengthWithInt:(int)value type:(WXLengthType)type;
+
+- (float)valueForMaximum:(float)maximumValue;
+
+- (int)intValue;
+
+- (float)floatValue;
 
 - (BOOL)isEqualToLength:(WXLength *)length;
 
@@ -28,4 +35,6 @@ typedef enum : NSUInteger {
 
 - (BOOL)isAuto;
 
+- (BOOL)isNormal;
+
 @end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/Utility/WXLength.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXLength.m b/ios/sdk/WeexSDK/Sources/Utility/WXLength.m
index 30cf57e..e64526d 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXLength.m
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXLength.m
@@ -11,25 +11,38 @@
 
 @implementation WXLength
 {
-    float _value;
+    float _floatValue;
+    int _intValue;
     WXLengthType _type;
+    BOOL _isFloat;
 }
 
-+ (instancetype)lengthWithValue:(float)value type:(WXLengthType)type
++ (instancetype)lengthWithFloat:(float)value type:(WXLengthType)type
 {
     WXLength *length = [WXLength new];
-    length->_value = value;
+    length->_floatValue = value;
     length->_type = type;
+    length->_isFloat = YES;
     return length;
 }
 
-- (float)valueForMaximumValue:(float)maximumValue
++ (instancetype)lengthWithInt:(int)value type:(WXLengthType)type
 {
+    WXLength *length = [WXLength new];
+    length->_intValue = value;
+    length->_type = type;
+    length->_isFloat = NO;
+    return length;
+}
+
+- (float)valueForMaximum:(float)maximumValue
+{
+    
     switch (_type) {
         case WXLengthTypeFixed:
-            return _value;
+            return _isFloat ? _floatValue : _intValue;
         case WXLengthTypePercent:
-            return maximumValue * _value / 100.0;
+            return maximumValue * (_isFloat ? _floatValue : _intValue) / 100.0;
         case WXLengthTypeAuto:
             return maximumValue;
         default:
@@ -38,9 +51,22 @@
     }
 }
 
+- (int)intValue
+{
+    WXAssert(!_isFloat, @"call `intValue` for non-int length");
+    return _intValue;
+}
+
+- (float)floatValue
+{
+    WXAssert(_isFloat,  @"call `floatValue` for non-float length");
+    return _floatValue;
+}
+
 - (BOOL)isEqualToLength:(WXLength *)length
 {
-    return length && _type == length->_type && _value == length->_value;
+    return length && _type == length->_type && _isFloat == length->_isFloat
+    && _floatValue == length->_floatValue && _intValue == length->_intValue;
 }
 
 - (BOOL)isFixed
@@ -58,4 +84,9 @@
     return _type == WXLengthTypeAuto;
 }
 
+- (BOOL)isNormal
+{
+    return _type == WXLengthTypeNormal;
+}
+
 @end

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/c6fddbea/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.m
----------------------------------------------------------------------
diff --git a/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.m b/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.m
index 3e0c7fc..686b341 100644
--- a/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.m
+++ b/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.m
@@ -100,7 +100,7 @@
     _visibility = styles[@"visibility"] ? [WXConvert WXVisibility:styles[@"visibility"]] : WXVisibilityShow;
     _positionType = styles[@"position"] ? [WXConvert WXPositionType:styles[@"position"]] : WXPositionTypeRelative;
     _transform = styles[@"transform"] || styles[@"transformOrigin"] ?
-    [[WXTransform alloc] initWithCSSValue:[WXConvert NSString:styles[@"transform"]] origin:styles[@"transformOrigin"] instance:self.weexInstance] :
+    [[WXTransform alloc] initWithCSSValue:[WXConvert NSString:styles[@"transform"]] origin:[WXConvert NSString:styles[@"transformOrigin"]] instance:self.weexInstance] :
     [[WXTransform alloc] initWithCSSValue:nil origin:nil instance:self.weexInstance];
     _boxShadow = styles[@"boxShadow"]?[WXConvert WXBoxShadow:styles[@"boxShadow"] scaleFactor:self.weexInstance.pixelScaleFactor]:nil;
     if (_boxShadow) {
@@ -172,7 +172,7 @@
     
     if (styles[@"transformOrigin"] || styles[@"transform"]) {
         id transform = styles[@"transform"] ? : self.styles[@"transform"];
-        id transformOrigin = styles[@"transformOrigin"] ? : self.styles[@"transformOrigin"];
+        id transformOrigin = styles[@"transformOrigin"] ? [WXConvert NSString:styles[@"transformOrigin"]] : [WXConvert NSString:self.styles[@"transformOrigin"]];
         _transform = [[WXTransform alloc] initWithCSSValue:[WXConvert NSString:transform] origin:transformOrigin instance:self.weexInstance];
         if (!CGRectEqualToRect(self.calculatedFrame, CGRectZero)) {
             [_transform applyTransformForView:_view];