You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by ky...@apache.org on 2018/11/15 09:24:25 UTC

[incubator-weex] branch master updated: [WEEX-653][android][iOS][core] Android&iOS support rtl direction by CSS "direction:rtl" (#1664)

This is an automated email from the ASF dual-hosted git repository.

kyork pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-weex.git


The following commit(s) were added to refs/heads/master by this push:
     new 3cb8e9e  [WEEX-653][android][iOS][core] Android&iOS support rtl direction by CSS "direction:rtl" (#1664)
3cb8e9e is described below

commit 3cb8e9e7744be99408519bc20a7ab818e24d2cbd
Author: Klueze <hz...@gmail.com>
AuthorDate: Thu Nov 15 17:24:20 2018 +0800

    [WEEX-653][android][iOS][core] Android&iOS support rtl direction by CSS "direction:rtl" (#1664)
    
    Ref https://developer.mozilla.org/en-US/docs/Web/CSS/text-align
---
 .../com/alibaba/weex/extend/component/WXMask.java  |   4 +-
 android/sdk/libs/armeabi-v7a/libweexcore.so        | Bin 1116120 -> 1399344 bytes
 android/sdk/libs/armeabi/libweexcore.so            | Bin 1128400 -> 1407536 bytes
 .../x86/{libweexjss.so => libJavaScriptCore.so}    | Bin 11354824 -> 10159504 bytes
 android/sdk/libs/x86/libweexcore.so                | Bin 2706100 -> 2742964 bytes
 android/sdk/libs/x86/libweexjss.so                 | Bin 11354824 -> 1231736 bytes
 android/sdk/libs/x86/libweexjst.so                 | Bin 0 -> 5548 bytes
 .../main/java/com/taobao/weex/WXEnvironment.java   |  14 +++
 .../main/java/com/taobao/weex/WXSDKInstance.java   |   7 ++
 .../com/taobao/weex/bridge/WXBridgeManager.java    |   1 +
 .../main/java/com/taobao/weex/bridge/WXParams.java |   7 ++
 .../main/java/com/taobao/weex/common/WXConfig.java |   1 +
 .../src/main/java/com/taobao/weex/dom/WXStyle.java |   8 +-
 .../measurefunc/TextContentBoxMeasurement.java     |   2 +-
 .../weex/ui/action/ActionGetLayoutDirection.java   | 117 +++++++++++++++++++++
 .../com/taobao/weex/ui/component/WXComponent.java  |  66 ++++++++++--
 .../com/taobao/weex/ui/component/WXIndicator.java  |   2 +-
 .../com/taobao/weex/ui/component/WXScroller.java   |  89 +++++++++++++++-
 .../com/taobao/weex/ui/component/WXSlider.java     |  29 ++++-
 .../com/taobao/weex/ui/component/WXVContainer.java |   5 +-
 .../weex/ui/component/list/BasicListComponent.java |  42 +++++++-
 .../weex/ui/component/list/GapItemDecoration.java  |  13 ++-
 .../list/template/WXRecyclerTemplateList.java      |   3 +-
 .../template/jni/NativeRenderLayoutDirection.java} |  28 ++---
 .../list/template/jni/NativeRenderObjectUtils.java |   1 +
 .../com/taobao/weex/ui/module/WXDomModule.java     |  12 ++-
 .../taobao/weex/ui/view/WXCirclePageAdapter.java   |  28 ++++-
 .../com/taobao/weex/ui/view/WXCircleViewPager.java |  23 ++--
 .../com/taobao/weex/utils/StaticLayoutProxy.java   |  22 ++--
 android/sdk/src/main/res/values-ldltr/isrtl.xml    |  24 +++++
 android/sdk/src/main/res/values-ldrtl/istrtl.xml   |  24 +++++
 ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m   |  16 +--
 .../Sources/Component/WXComponent_internal.h       |   3 +
 .../Sources/Component/WXCycleSliderComponent.mm    |  33 ++++++
 .../Sources/Component/WXScrollerComponent.mm       |  37 ++++++-
 .../WeexSDK/Sources/Component/WXTextComponent.mm   |   6 +-
 .../WeexSDK/Sources/Layout/WXComponent+Layout.h    |  10 ++
 .../WeexSDK/Sources/Layout/WXComponent+Layout.mm   |  75 ++++++++++++-
 ios/sdk/WeexSDK/Sources/Model/WXComponent.mm       |   5 +-
 ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m      |   3 +
 ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m |   1 +
 ios/sdk/WeexSDK/Sources/Module/WXDomModule.m       |  26 +++++
 .../WeexSDK/Sources/Protocol/WXScrollerProtocol.h  |   6 ++
 ios/sdk/WeexSDK/Sources/Utility/WXType.h           |   6 ++
 ios/sdk/WeexSDK/Sources/Utility/WXUtility.h        |   6 ++
 ios/sdk/WeexSDK/Sources/Utility/WXUtility.m        |  27 ++++-
 .../Sources/View/WXComponent+ViewManagement.mm     |   6 ++
 .../jniheader/NativeRenderObjectUtils_jni.h        |   8 ++
 weex_core/Source/android/utils/params_utils.cpp    |  16 +++
 .../native_render_object_utils_impl_android.cpp    |   7 +-
 weex_core/Source/core/css/constants_name.h         |   1 +
 weex_core/Source/core/css/constants_value.h        |   4 +
 weex_core/Source/core/css/css_value_getter.cpp     |  11 ++
 weex_core/Source/core/css/css_value_getter.h       |   1 +
 weex_core/Source/core/layout/flex_enum.h           |  12 ++-
 weex_core/Source/core/layout/layout.cpp            |  76 ++++++++++---
 weex_core/Source/core/layout/layout.h              |  94 ++++++++++++++---
 weex_core/Source/core/layout/style.h               |   6 +-
 .../Source/core/render/node/render_object.cpp      |   7 ++
 weex_core/Source/core/render/node/render_object.h  |   3 +-
 .../Source/core/render/node/render_scroller.cpp    |   7 ++
 .../Source/core/render/node/render_scroller.h      |  18 ++++
 weex_core/Source/core/render/page/render_page.cpp  |   8 +-
 weex_core/release.sh                               |   0
 64 files changed, 1000 insertions(+), 117 deletions(-)

diff --git a/android/playground/app/src/main/java/com/alibaba/weex/extend/component/WXMask.java b/android/playground/app/src/main/java/com/alibaba/weex/extend/component/WXMask.java
index 778404c..252de1c 100644
--- a/android/playground/app/src/main/java/com/alibaba/weex/extend/component/WXMask.java
+++ b/android/playground/app/src/main/java/com/alibaba/weex/extend/component/WXMask.java
@@ -124,7 +124,9 @@ public class WXMask extends WXVContainer {
     top = get(TOP);
     bottom = get(BOTTOM);
     FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height);
-    params.setMargins(left, top, right, bottom);
+
+    this.setMarginsSupportRTL(params, left, top, right, bottom);
+
     getHostView().setLayoutParams(params);
   }
 
diff --git a/android/sdk/libs/armeabi-v7a/libweexcore.so b/android/sdk/libs/armeabi-v7a/libweexcore.so
old mode 100755
new mode 100644
index 08a3751..4b1cac4
Binary files a/android/sdk/libs/armeabi-v7a/libweexcore.so and b/android/sdk/libs/armeabi-v7a/libweexcore.so differ
diff --git a/android/sdk/libs/armeabi/libweexcore.so b/android/sdk/libs/armeabi/libweexcore.so
old mode 100755
new mode 100644
index a88a0ff..1be8d2b
Binary files a/android/sdk/libs/armeabi/libweexcore.so and b/android/sdk/libs/armeabi/libweexcore.so differ
diff --git a/android/sdk/libs/x86/libweexjss.so b/android/sdk/libs/x86/libJavaScriptCore.so
old mode 100755
new mode 100644
similarity index 53%
copy from android/sdk/libs/x86/libweexjss.so
copy to android/sdk/libs/x86/libJavaScriptCore.so
index ac0dd7f..0e0f9f5
Binary files a/android/sdk/libs/x86/libweexjss.so and b/android/sdk/libs/x86/libJavaScriptCore.so differ
diff --git a/android/sdk/libs/x86/libweexcore.so b/android/sdk/libs/x86/libweexcore.so
old mode 100755
new mode 100644
index 9955dc3..e4c3a3b
Binary files a/android/sdk/libs/x86/libweexcore.so and b/android/sdk/libs/x86/libweexcore.so differ
diff --git a/android/sdk/libs/x86/libweexjss.so b/android/sdk/libs/x86/libweexjss.so
old mode 100755
new mode 100644
index ac0dd7f..3733a2a
Binary files a/android/sdk/libs/x86/libweexjss.so and b/android/sdk/libs/x86/libweexjss.so differ
diff --git a/android/sdk/libs/x86/libweexjst.so b/android/sdk/libs/x86/libweexjst.so
new file mode 100644
index 0000000..84add1e
Binary files /dev/null and b/android/sdk/libs/x86/libweexjst.so differ
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXEnvironment.java b/android/sdk/src/main/java/com/taobao/weex/WXEnvironment.java
index 13564ff..cf4c7b2 100644
--- a/android/sdk/src/main/java/com/taobao/weex/WXEnvironment.java
+++ b/android/sdk/src/main/java/com/taobao/weex/WXEnvironment.java
@@ -157,6 +157,13 @@ public class WXEnvironment {
     configs.put(WXConfig.sysModel, SYS_MODEL);
     configs.put(WXConfig.weexVersion, String.valueOf(WXSDK_VERSION));
     configs.put(WXConfig.logLevel,sLogLevel.getName());
+
+    try {
+      configs.put(WXConfig.layoutDirection, isLayoutDirectionRTL() ? "rtl" : "ltr");
+    } catch (Exception e) {
+      configs.put(WXConfig.layoutDirection, "ltr");
+    }
+
     try {
       if (isApkDebugable()) {
         options.put(WXConfig.debugMode, "true");
@@ -225,6 +232,13 @@ public class WXEnvironment {
     return isHardwareSupport() && isInitialized;
   }
 
+  public static boolean isLayoutDirectionRTL() {
+    // support RTL
+    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+      return sApplication.getApplicationContext().getResources().getBoolean(R.bool.weex_is_right_to_left);
+    }
+    return false;
+  }
   /**
    * Tell whether Weex can run on current hardware.
    * @return true if weex can run on current hardware, otherwise false.
diff --git a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
index cfa87b7..0962db5 100644
--- a/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
+++ b/android/sdk/src/main/java/com/taobao/weex/WXSDKInstance.java
@@ -1664,6 +1664,13 @@ public class WXSDKInstance implements IWXActivityStateListener,View.OnLayoutChan
     return 0;
   }
 
+  public int getRenderContainerPaddingRight() {
+    if(mRenderContainer != null) {
+      return mRenderContainer.getPaddingRight();
+    }
+    return 0;
+  }
+
   public int getRenderContainerPaddingTop() {
     if(mRenderContainer != null) {
       return mRenderContainer.getPaddingTop();
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
index 531b601..cbe68ae 100644
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
+++ b/android/sdk/src/main/java/com/taobao/weex/bridge/WXBridgeManager.java
@@ -1975,6 +1975,7 @@ public class WXBridgeManager implements Callback, BactchExecutor {
     wxParams.setDeviceModel(config.get(WXConfig.sysModel));
     wxParams.setShouldInfoCollect(config.get("infoCollect"));
     wxParams.setLogLevel(config.get(WXConfig.logLevel));
+    wxParams.setLayoutDirection(config.get(WXConfig.layoutDirection));
     wxParams.setUseSingleProcess(isUseSingleProcess ? "true" : "false");
     wxParams.setCrashFilePath(WXEnvironment.getCrashFilePath(WXEnvironment.getApplication().getApplicationContext()));
     wxParams.setLibJssPath(WXEnvironment.getLibJssRealPath());
diff --git a/android/sdk/src/main/java/com/taobao/weex/bridge/WXParams.java b/android/sdk/src/main/java/com/taobao/weex/bridge/WXParams.java
index 8b41a8f..657b21a 100644
--- a/android/sdk/src/main/java/com/taobao/weex/bridge/WXParams.java
+++ b/android/sdk/src/main/java/com/taobao/weex/bridge/WXParams.java
@@ -42,6 +42,7 @@ public class WXParams implements Serializable {
   private String useSingleProcess;
   private String crashFilePath;
   private String libJssPath;
+  private String layoutDirection;
 
   private String libJscPath;
   private String libIcuPath;
@@ -121,6 +122,11 @@ public class WXParams implements Serializable {
   }
 
   @CalledByNative
+  public String getLayoutDirection() {return layoutDirection;}
+
+  public void setLayoutDirection(String direction) { this.layoutDirection = direction; }
+
+  @CalledByNative
   public String getAppName() {
     return appName;
   }
@@ -246,6 +252,7 @@ public class WXParams implements Serializable {
     map.put("deviceHeight", deviceHeight);
     map.put("deviceModel", deviceModel);
     map.put("deviceWidth", deviceWidth);
+    map.put("layoutDirection", layoutDirection);
     map.put("libJssPath", libJssPath);
     map.put("logLevel", logLevel);
     map.put("needInitV8", needInitV8);
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXConfig.java b/android/sdk/src/main/java/com/taobao/weex/common/WXConfig.java
index 11dc820..7bf525c 100644
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXConfig.java
+++ b/android/sdk/src/main/java/com/taobao/weex/common/WXConfig.java
@@ -33,5 +33,6 @@ public interface WXConfig {
   String externalUserAgent="externalUserAgent";
   String logLevel="logLevel";
   String scale = "scale";
+  String layoutDirection = "layoutDirection";
   String debugMode = "debugMode";
 }
diff --git a/android/sdk/src/main/java/com/taobao/weex/dom/WXStyle.java b/android/sdk/src/main/java/com/taobao/weex/dom/WXStyle.java
index a401090..17f549e 100644
--- a/android/sdk/src/main/java/com/taobao/weex/dom/WXStyle.java
+++ b/android/sdk/src/main/java/com/taobao/weex/dom/WXStyle.java
@@ -178,13 +178,17 @@ public class WXStyle implements Map<String, Object>,Cloneable {
   }
 
   public static Layout.Alignment getTextAlignment(Map<String, Object> style){
-    Layout.Alignment alignment= Layout.Alignment.ALIGN_NORMAL;
+    return getTextAlignment(style, false);
+  }
+
+  public static Layout.Alignment getTextAlignment(Map<String, Object> style, boolean isRTL){
+    Layout.Alignment alignment= isRTL ? Layout.Alignment.ALIGN_OPPOSITE : Layout.Alignment.ALIGN_NORMAL;
     String textAlign= (String) style.get(Constants.Name.TEXT_ALIGN);
     if(TextUtils.equals(Constants.Value.LEFT,textAlign)){
       alignment= Layout.Alignment.ALIGN_NORMAL;
     }
     else if(TextUtils.equals(Constants.Value.CENTER,textAlign)){
-      alignment=Layout.Alignment.ALIGN_CENTER;
+      alignment= Layout.Alignment.ALIGN_CENTER;
     }
     else if(TextUtils.equals(Constants.Value.RIGHT,textAlign)){
       alignment= Layout.Alignment.ALIGN_OPPOSITE;
diff --git a/android/sdk/src/main/java/com/taobao/weex/layout/measurefunc/TextContentBoxMeasurement.java b/android/sdk/src/main/java/com/taobao/weex/layout/measurefunc/TextContentBoxMeasurement.java
index 66d0fae..ef0ccb0 100644
--- a/android/sdk/src/main/java/com/taobao/weex/layout/measurefunc/TextContentBoxMeasurement.java
+++ b/android/sdk/src/main/java/com/taobao/weex/layout/measurefunc/TextContentBoxMeasurement.java
@@ -232,7 +232,7 @@ public class TextContentBoxMeasurement extends ContentBoxMeasurement {
       if (style.containsKey(Constants.Name.FONT_FAMILY)) {
         mFontFamily = WXStyle.getFontFamily(style);
       }
-      mAlignment = WXStyle.getTextAlignment(style);
+      mAlignment = WXStyle.getTextAlignment(style, mComponent.isNativeLayoutRTL());
       textOverflow = WXStyle.getTextOverflow(style);
       int lineHeight = WXStyle.getLineHeight(style, mComponent.getViewPortWidth());
       if (lineHeight != UNSET) {
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionGetLayoutDirection.java b/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionGetLayoutDirection.java
new file mode 100644
index 0000000..039bdfc
--- /dev/null
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/action/ActionGetLayoutDirection.java
@@ -0,0 +1,117 @@
+/**
+ * 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.
+ */
+package com.taobao.weex.ui.action;
+
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+import android.view.View;
+
+import com.taobao.weex.WXSDKInstance;
+import com.taobao.weex.WXSDKManager;
+import com.taobao.weex.bridge.JSCallback;
+import com.taobao.weex.bridge.SimpleJSCallback;
+import com.taobao.weex.ui.component.WXComponent;
+import com.taobao.weex.ui.component.list.template.jni.NativeRenderObjectUtils;
+import com.taobao.weex.utils.WXViewUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by listen on 18/09/12.
+ */
+public class ActionGetLayoutDirection extends BasicGraphicAction {
+
+  private final String mCallback;
+
+  public ActionGetLayoutDirection(WXSDKInstance instance, String ref, String callback) {
+    super(instance, ref);
+    this.mCallback = callback;
+  }
+
+  @Override
+  public void executeAction() {
+    WXSDKInstance instance = getWXSDKIntance();
+    if (instance == null || instance.isDestroy()) {
+      return;
+    }
+
+    JSCallback jsCallback = new SimpleJSCallback(instance.getInstanceId(), mCallback);
+
+    if (TextUtils.isEmpty(getRef())) {
+      Map<String, Object> options = new HashMap<>();
+      options.put("result", false);
+      options.put("errMsg", "Illegal parameter");
+      jsCallback.invoke(options);
+    } else if ("viewport".equalsIgnoreCase(getRef())) {
+      callbackViewport(instance, jsCallback);
+    } else {
+      WXComponent component = WXSDKManager.getInstance().getWXRenderManager().getWXComponent(getPageId(), getRef());
+      if (component == null) {
+        return;
+      }
+
+      String directionRet = "ltr";
+      if (component != null) {
+        int direction = NativeRenderObjectUtils.nativeRenderObjectGetLayoutDirectionFromPathNode(component.getRenderObjectPtr());
+        switch (direction) {
+          case 0: {
+            directionRet = "inherit";
+            break;
+          }
+          case 1: {
+            directionRet = "ltr";
+            break;
+          }
+          case 2: {
+            directionRet = "rtl";
+            break;
+          }
+          default: {
+            directionRet = "ltr";
+            break;
+          }
+
+        }
+      }
+      jsCallback.invoke(directionRet);
+    }
+  }
+
+  private void callbackViewport(WXSDKInstance instance, JSCallback jsCallback) {
+    View container;
+    if ((container = instance.getContainerView()) != null) {
+      Map<String, Object> options = new HashMap<>();
+      options.put("direction", "ltr");
+      options.put("result", true);
+      jsCallback.invoke(options);
+    } else {
+      Map<String, Object> options = new HashMap<>();
+      options.put("result", false);
+      options.put("errMsg", "Component does not exist");
+      jsCallback.invoke(options);
+    }
+  }
+
+  @NonNull
+  private float getWebPxValue(int value,int viewport) {
+    return WXViewUtils.getWebPxByWidth(value, viewport);
+  }
+
+}
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
index 7840b9a..fbf8bc3 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXComponent.java
@@ -46,6 +46,7 @@ import android.support.v4.view.ViewCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
 import android.text.TextUtils;
 import android.util.Pair;
+import android.view.Gravity;
 import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup;
@@ -87,6 +88,7 @@ import com.taobao.weex.ui.animation.WXAnimationModule;
 import com.taobao.weex.ui.component.basic.WXBasicComponent;
 import com.taobao.weex.ui.component.binding.Statements;
 import com.taobao.weex.ui.component.list.WXCell;
+import com.taobao.weex.ui.component.list.template.jni.NativeRenderLayoutDirection;
 import com.taobao.weex.ui.component.list.template.jni.NativeRenderObjectUtils;
 import com.taobao.weex.ui.component.pesudo.OnActivePseudoListner;
 import com.taobao.weex.ui.component.pesudo.PesudoStatus;
@@ -153,6 +155,7 @@ public abstract class WXComponent<T extends View> extends WXBasicComponent imple
   private int mPreRealWidth = 0;
   private int mPreRealHeight = 0;
   private int mPreRealLeft = 0;
+  private int mPreRealRight = 0;
   private int mPreRealTop = 0;
   private int mStickyOffset = 0;
   protected WXGesture mGesture;
@@ -233,6 +236,44 @@ public abstract class WXComponent<T extends View> extends WXBasicComponent imple
     WXBridgeManager.getInstance().bindMeasurementToRenderObject(getRenderObjectPtr());
   }
 
+
+  public void setMarginsSupportRTL(ViewGroup.MarginLayoutParams lp, int left, int top, int right, int bottom) {
+      lp.setMargins(left, top, right, bottom);
+      if (lp instanceof FrameLayout.LayoutParams) {
+          FrameLayout.LayoutParams lp_frameLayout = (FrameLayout.LayoutParams) lp;
+          lp_frameLayout.gravity = Gravity.LEFT | Gravity.TOP;
+      }
+  }
+
+  public boolean isNativeLayoutRTL() {
+      return NativeRenderObjectUtils.nativeRenderObjectGetLayoutDirectionFromPathNode(this.getRenderObjectPtr()) == NativeRenderLayoutDirection.rtl;
+  }
+
+  public static boolean isLayoutRTL(WXComponent cmp) {
+    if (cmp == null) return false;
+
+    View view = cmp.getHostView();
+    if (ViewCompat.isLayoutDirectionResolved(view)) {
+      return ViewCompat.getLayoutDirection(view) == View.LAYOUT_DIRECTION_RTL;
+    } else if (cmp.getParent() != null){
+      return isLayoutRTL(cmp.getParent());
+    } else {
+      return isLayoutRTL((ViewGroup) view.getParent());
+    }
+  }
+
+  public static boolean isLayoutRTL(ViewGroup viewGroup) {
+    if (viewGroup == null) return false;
+
+    if (ViewCompat.isLayoutDirectionResolved(viewGroup)) {
+      return ViewCompat.getLayoutDirection(viewGroup) == View.LAYOUT_DIRECTION_RTL;
+    } else if (viewGroup.getParent() instanceof ViewGroup) {
+      return isLayoutRTL((ViewGroup) viewGroup.getParent());
+    } else {
+      return false;
+    }
+  }
+
   public void updateStyles(WXComponent component) {
     if (component != null) {
       updateProperties(component.getStyles());
@@ -881,8 +922,7 @@ public abstract class WXComponent<T extends View> extends WXBasicComponent imple
   /**
    * layout view
    */
-  public final void setLayout(WXComponent component) {
-
+  public void setLayout(WXComponent component) {
     if (TextUtils.isEmpty(component.getComponentType())
             || TextUtils.isEmpty(component.getRef()) || component.getLayoutPosition() == null
             || component.getLayoutSize() == null) {
@@ -910,6 +950,7 @@ public abstract class WXComponent<T extends View> extends WXBasicComponent imple
 
     int realLeft = 0;
     int realTop = 0;
+    int realRight = 0;
 
     if (isFixed()) {
       realLeft = (int) (getLayoutPosition().getLeft() - getInstance().getRenderContainerPaddingLeft());
@@ -921,14 +962,14 @@ public abstract class WXComponent<T extends View> extends WXBasicComponent imple
               parentPadding.get(CSSShorthand.EDGE.TOP) - parentBorder.get(CSSShorthand.EDGE.TOP)) + siblingOffset;
     }
 
-    int realRight = (int) getMargin().get(CSSShorthand.EDGE.RIGHT);
+    realRight = (int) getMargin().get(CSSShorthand.EDGE.RIGHT);
     int realBottom = (int) getMargin().get(CSSShorthand.EDGE.BOTTOM);
 
     Point rawOffset = new Point(
             (int) getLayoutPosition().getLeft(),
             (int) getLayoutPosition().getTop());
 
-    if (mPreRealWidth == realWidth && mPreRealHeight == realHeight && mPreRealLeft == realLeft && mPreRealTop == realTop) {
+    if (mPreRealWidth == realWidth && mPreRealHeight == realHeight && mPreRealLeft == realLeft && mPreRealRight == realRight && mPreRealTop == realTop) {
       return;
     }
 
@@ -994,6 +1035,7 @@ public abstract class WXComponent<T extends View> extends WXBasicComponent imple
       mPreRealWidth = realWidth;
       mPreRealHeight = realHeight;
       mPreRealLeft = realLeft;
+      mPreRealRight = realRight;
       mPreRealTop = realTop;
       onFinishLayout();
       // restore box shadow
@@ -1047,14 +1089,14 @@ public abstract class WXComponent<T extends View> extends WXBasicComponent imple
   protected void setHostLayoutParams(T host, int width, int height, int left, int right, int top, int bottom) {
     ViewGroup.LayoutParams lp;
     if (mParent == null) {
-      FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height);
-      params.setMargins(left, top, right, bottom);
-      lp = params;
+        FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height);
+        this.setMarginsSupportRTL(params, left, top, right, bottom);
+        lp = params;
     } else {
-      lp = mParent.getChildLayoutParams(this, host, width, height, left, right, top, bottom);
+        lp = mParent.getChildLayoutParams(this, host, width, height, left, right, top, bottom);
     }
     if (lp != null) {
-      host.setLayoutParams(lp);
+        host.setLayoutParams(lp);
     }
   }
 
@@ -1063,7 +1105,9 @@ public abstract class WXComponent<T extends View> extends WXBasicComponent imple
 
     params.width = width;
     params.height = height;
-    params.setMargins(left, top, right, bottom);
+
+    this.setMarginsSupportRTL(params, left, top, right, bottom);
+
     host.setLayoutParams(params);
     mInstance.moveFixedView(host);
 
@@ -1844,6 +1888,7 @@ public abstract class WXComponent<T extends View> extends WXBasicComponent imple
   public View detachViewAndClearPreInfo() {
     View original = mHost;
     mPreRealLeft = 0;
+    mPreRealRight = 0;
     mPreRealWidth = 0;
     mPreRealHeight = 0;
     mPreRealTop = 0;
@@ -1853,6 +1898,7 @@ public abstract class WXComponent<T extends View> extends WXBasicComponent imple
 
   public void clearPreLayout() {
     mPreRealLeft = 0;
+    mPreRealRight = 0;
     mPreRealWidth = 0;
     mPreRealHeight = 0;
     mPreRealTop = 0;
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXIndicator.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXIndicator.java
index e8422ca..449c12e 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXIndicator.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXIndicator.java
@@ -54,7 +54,7 @@ public class WXIndicator extends WXComponent<WXCircleIndicator> {
   @Override
   protected void setHostLayoutParams(WXCircleIndicator host, int width, int height, int left, int right, int top, int bottom) {
       FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(width, height);
-      params.setMargins(left, top, right, bottom);
+      this.setMarginsSupportRTL(params, left, top, right, bottom);
       host.setLayoutParams(params);
   }
 
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java
index 81c0e17..bfef86f 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXScroller.java
@@ -33,7 +33,11 @@ import android.os.Build;
 import android.os.Handler;
 import android.os.Looper;
 import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.support.v4.view.ViewCompat;
 import android.text.TextUtils;
+import android.view.Gravity;
+import android.util.Log;
 import android.view.GestureDetector;
 import android.view.MotionEvent;
 import android.view.View;
@@ -378,6 +382,42 @@ public class WXScroller extends WXVContainer<ViewGroup> implements WXScrollViewL
   }
 
   @Override
+  public void setMarginsSupportRTL(ViewGroup.MarginLayoutParams lp, int left, int top, int right, int bottom) {
+    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+      lp.setMargins(left, top, right, bottom);
+      lp.setMarginStart(left);
+      lp.setMarginEnd(right);
+    } else {
+      if (lp instanceof FrameLayout.LayoutParams) {
+        FrameLayout.LayoutParams lp_frameLayout = (FrameLayout.LayoutParams) lp;
+        if (this.isNativeLayoutRTL()) {
+          lp_frameLayout.gravity = Gravity.RIGHT | Gravity.TOP;
+          lp.setMargins(right, top, left, bottom);
+        } else {
+          lp_frameLayout.gravity = Gravity.LEFT | Gravity.TOP;
+          lp.setMargins(left, top, right, bottom);
+        }
+      } else {
+        lp.setMargins(left, top, right, bottom);
+      }
+    }
+  }
+
+  @Override
+  public void setLayout(WXComponent component) {
+    if (TextUtils.isEmpty(component.getComponentType())
+            || TextUtils.isEmpty(component.getRef()) || component.getLayoutPosition() == null
+            || component.getLayoutSize() == null) {
+      return;
+    }
+    if (component.getHostView() != null) {
+      int layoutDirection = component.isNativeLayoutRTL() ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
+      ViewCompat.setLayoutDirection(component.getHostView(), layoutDirection);
+    }
+    super.setLayout(component);
+  }
+
+  @Override
   protected MeasureOutput measure(int width, int height) {
     MeasureOutput measureOutput = new MeasureOutput();
     if (this.mOrientation == Constants.Orientation.HORIZONTAL) {
@@ -437,6 +477,37 @@ public class WXScroller extends WXVContainer<ViewGroup> implements WXScrollViewL
       scrollView.addView(mRealView, layoutParams);
       scrollView.setHorizontalScrollBarEnabled(false);
 
+        final WXScroller component = this;
+        final View.OnLayoutChangeListener listener = new View.OnLayoutChangeListener() {
+          @Override
+          public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
+            final View frameLayout = view;
+            scrollView.post(new Runnable() {
+              @Override
+              public void run() {
+                if (isNativeLayoutRTL()) {
+                  int mw = frameLayout.getMeasuredWidth();
+                  scrollView.scrollTo(mw, component.getScrollY());
+                } else {
+                  scrollView.scrollTo(0, component.getScrollY());
+                }
+              }
+            });
+          }
+        };
+        mRealView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
+          @Override
+          public void onViewAttachedToWindow(View view) {
+            view.addOnLayoutChangeListener(listener);
+          }
+
+          @Override
+          public void onViewDetachedFromWindow(View view) {
+            view.removeOnLayoutChangeListener(listener);
+          }
+        });
+
+
       if(pageEnable) {
         mGestureDetector = new GestureDetector(new MyGestureDetector(scrollView));
         scrollView.setOnTouchListener(new View.OnTouchListener() {
@@ -706,9 +777,21 @@ public class WXScroller extends WXVContainer<ViewGroup> implements WXScrollViewL
       mActiveFeature = mChildren.indexOf(component);
     }
 
-
-    int viewYInScroller=component.getAbsoluteY() - getAbsoluteY();
-    int viewXInScroller=component.getAbsoluteX() - getAbsoluteX();
+    int viewYInScroller = component.getAbsoluteY() - getAbsoluteY();
+    int viewXInScroller = 0;
+    if (this.isNativeLayoutRTL()) {
+      // if layout direction is rtl, we need calculate rtl scroll x;
+      if (getInnerView().getChildCount() > 0) {
+        int totalWidth = getInnerView().getChildAt(0).getWidth();
+        int displayWidth = getInnerView().getMeasuredWidth();
+        viewXInScroller = totalWidth - (component.getAbsoluteX() - getAbsoluteX()) - displayWidth;
+      } else {
+        viewXInScroller = component.getAbsoluteX() - getAbsoluteX();
+      }
+      offsetFloat = - offsetFloat;
+    } else {
+      viewXInScroller = component.getAbsoluteX() - getAbsoluteX();
+    }
 
     scrollBy(viewXInScroller - getScrollX() + (int) offsetFloat, viewYInScroller - getScrollY() + (int) offsetFloat, smooth);
   }
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSlider.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSlider.java
index 196c839..8e94740 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSlider.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXSlider.java
@@ -145,9 +145,9 @@ public class WXSlider extends WXVContainer<FrameLayout> {
     if (lp instanceof ViewGroup.MarginLayoutParams) {
       //expect indicator .
       if (child instanceof WXIndicator) {
-        ((ViewGroup.MarginLayoutParams) lp).setMargins(left, top, right, bottom);
+        this.setMarginsSupportRTL((ViewGroup.MarginLayoutParams) lp, left, top, right, bottom);
       } else {
-        ((ViewGroup.MarginLayoutParams) lp).setMargins(0, 0, 0, 0);
+        this.setMarginsSupportRTL((ViewGroup.MarginLayoutParams) lp, 0, 0, 0, 0);
       }
     }
     return lp;
@@ -193,7 +193,7 @@ public class WXSlider extends WXVContainer<FrameLayout> {
           @Override
           public void run() {
             initIndex = getInitIndex();
-            mViewPager.setCurrentItem(initIndex);
+            mViewPager.setCurrentItem(getRealIndex(initIndex));
             initIndex = -1;
             initRunnable = null;
           }
@@ -203,7 +203,7 @@ public class WXSlider extends WXVContainer<FrameLayout> {
       mViewPager.postDelayed(initRunnable, 50);
     } else {
       if (!keepIndex) {
-        mViewPager.setCurrentItem(0);
+        mViewPager.setCurrentItem(getRealIndex(0));
       }
     }
     if (mIndicator != null) {
@@ -213,6 +213,12 @@ public class WXSlider extends WXVContainer<FrameLayout> {
   }
 
   @Override
+  public void setLayout(WXComponent component) {
+    mAdapter.setLayoutDirectionRTL(this.isNativeLayoutRTL());
+    super.setLayout(component);
+  }
+
+  @Override
   public void remove(WXComponent child, boolean destroy) {
     if (child == null || child.getHostView() == null || mAdapter == null) {
       return;
@@ -274,9 +280,22 @@ public class WXSlider extends WXVContainer<FrameLayout> {
     if(select >= mAdapter.getRealCount()){
       select = select%mAdapter.getRealCount();
     }
+
     return select;
   }
 
+  private int getRealIndex(int idx) {
+    int retIdx = idx;
+
+    if (mAdapter.getRealCount() > 0) {
+      if(idx >= mAdapter.getRealCount()) retIdx = mAdapter.getRealCount() - 1;
+      if (isNativeLayoutRTL()) {
+        retIdx = mAdapter.getRealCount() - 1 - retIdx;
+      }
+    }
+    retIdx = retIdx + 0;
+    return retIdx;
+  }
 
   @Override
   protected boolean setProperty(String key, Object param) {
@@ -383,6 +402,8 @@ public class WXSlider extends WXVContainer<FrameLayout> {
         initIndex = index;
         return;
       }
+
+      index = getRealIndex(index);
       mViewPager.setCurrentItem(index);
       if (mIndicator != null && mIndicator.getHostView() != null
               && mIndicator.getHostView().getRealCurrentItem() != index) {
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
index c9880b5..3d797ed 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/WXVContainer.java
@@ -131,7 +131,7 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
       lp.width = width;
       lp.height = height;
       if(lp instanceof ViewGroup.MarginLayoutParams){
-        ((ViewGroup.MarginLayoutParams) lp).setMargins(left,top,right,bottom);
+        this.setMarginsSupportRTL((ViewGroup.MarginLayoutParams) lp, left, top, right, bottom);
       }
     }
     return lp;
@@ -588,8 +588,7 @@ public abstract class WXVContainer<T extends ViewGroup> extends WXComponent<T> {
           int bottom = (int) (padding.get(CSSShorthand.EDGE.BOTTOM) + border.get(CSSShorthand.EDGE.BOTTOM));
 
           ViewGroup.MarginLayoutParams layoutParams = new ViewGroup.MarginLayoutParams(hostView.getLayoutParams()) ;
-          layoutParams.setMargins(-left, -top, -right, -bottom);
-
+          this.setMarginsSupportRTL(layoutParams, -left, -top, -right, -bottom);
           mBoxShadowHost.setLayoutParams(layoutParams);
 
           hostView.addView(mBoxShadowHost);
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
index e377ad9..a9a2c67 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/BasicListComponent.java
@@ -35,6 +35,7 @@ import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.StaggeredGridLayoutManager;
 import android.text.TextUtils;
 import android.util.SparseArray;
+import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -174,6 +175,42 @@ public abstract class BasicListComponent<T extends ViewGroup & ListComponentView
   }
 
   @Override
+  public void setMarginsSupportRTL(ViewGroup.MarginLayoutParams lp, int left, int top, int right, int bottom) {
+    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
+      lp.setMargins(left, top, right, bottom);
+      lp.setMarginStart(left);
+      lp.setMarginEnd(right);
+    } else {
+      if (lp instanceof FrameLayout.LayoutParams) {
+        FrameLayout.LayoutParams lp_frameLayout = (FrameLayout.LayoutParams) lp;
+        if (this.isNativeLayoutRTL()) {
+          lp_frameLayout.gravity = Gravity.RIGHT | Gravity.TOP;
+          lp.setMargins(right, top, left, bottom);
+        } else {
+          lp_frameLayout.gravity = Gravity.LEFT | Gravity.TOP;
+          lp.setMargins(left, top, right, bottom);
+        }
+      } else {
+        lp.setMargins(left, top, right, bottom);
+      }
+    }
+  }
+
+  @Override
+  public void setLayout(WXComponent component) {
+    if (TextUtils.isEmpty(component.getComponentType())
+            || TextUtils.isEmpty(component.getRef()) || component.getLayoutPosition() == null
+            || component.getLayoutSize() == null) {
+      return;
+    }
+    if (component.getHostView() != null) {
+      int layoutDirection = component.isNativeLayoutRTL() ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR;
+      ViewCompat.setLayoutDirection(component.getHostView(), layoutDirection);
+    }
+    super.setLayout(component);
+  }
+
+  @Override
   protected void onHostViewInitialized(T host) {
     super.onHostViewInitialized(host);
 
@@ -248,7 +285,8 @@ public abstract class BasicListComponent<T extends ViewGroup & ListComponentView
     } else {
       params.width = width;
       params.height = height;
-      params.setMargins(left, 0, right, 0);
+
+      this.setMarginsSupportRTL(params, left, 0, right, 0);
     }
     return params;
   }
@@ -331,8 +369,6 @@ public abstract class BasicListComponent<T extends ViewGroup & ListComponentView
       }
     });
 
-
-
     bounceRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
       @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
       @Override
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/GapItemDecoration.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/GapItemDecoration.java
index 821d7ce..aebb6c3 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/GapItemDecoration.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/GapItemDecoration.java
@@ -64,10 +64,17 @@ public class GapItemDecoration extends RecyclerView.ItemDecoration {
                 if (params.getSpanIndex() >= spanOffsets.length) {
                     return;
                 }
-                float spanOffset = listComponent.getSpanOffsets()[params.getSpanIndex()];
+
+                int index = listComponent.isNativeLayoutRTL() ? spanOffsets.length - params.getSpanIndex() - 1 : params.getSpanIndex();
+                float spanOffset = listComponent.getSpanOffsets()[index];
                 int   spanOffsetPx =  Math.round(WXViewUtils.getRealPxByWidth(spanOffset, listComponent.getViewPortWidth()));
-                outRect.left =  spanOffsetPx;
-                outRect.right = -spanOffsetPx;
+                if (listComponent.isNativeLayoutRTL()) {
+                    outRect.left = -spanOffsetPx;
+                    outRect.right = spanOffsetPx;
+                } else {
+                    outRect.left = spanOffsetPx;
+                    outRect.right = -spanOffsetPx;
+                }
             }
         }
     }
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java
index 916d895..8efcc2f 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/WXRecyclerTemplateList.java
@@ -1283,7 +1283,8 @@ public class WXRecyclerTemplateList extends WXVContainer<BounceRecyclerView> imp
         } else {
             params.width = width;
             params.height = height;
-            params.setMargins(left, 0, right, 0);
+
+            this.setMarginsSupportRTL(params, left, 0, right, 0);
         }
         return params;
     }
diff --git a/android/sdk/src/main/java/com/taobao/weex/common/WXConfig.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/jni/NativeRenderLayoutDirection.java
similarity index 61%
copy from android/sdk/src/main/java/com/taobao/weex/common/WXConfig.java
copy to android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/jni/NativeRenderLayoutDirection.java
index 11dc820..443dcf6 100644
--- a/android/sdk/src/main/java/com/taobao/weex/common/WXConfig.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/jni/NativeRenderLayoutDirection.java
@@ -1,4 +1,4 @@
-/*
+/**
  * 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
@@ -6,9 +6,9 @@
  * 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
@@ -16,22 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package com.taobao.weex.common;
+package com.taobao.weex.ui.component.list.template.jni;
 
-public interface WXConfig {
-
-  String os = "os";
-  String osName = "osName";
-  String appVersion="appVersion";
-  String cacheDir = "cacheDir";
-  String devId="devId";
-  String sysVersion="sysVersion";
-  String sysModel="sysModel";
-  String weexVersion="weexVersion";
-  String appName="appName";
-  String appGroup="appGroup";
-  String externalUserAgent="externalUserAgent";
-  String logLevel="logLevel";
-  String scale = "scale";
-  String debugMode = "debugMode";
+public class NativeRenderLayoutDirection {
+    public static final int inherit = 0;
+    public static final int ltr = 1;
+    public static final int rtl = 2;
 }
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/jni/NativeRenderObjectUtils.java b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/jni/NativeRenderObjectUtils.java
index c477413..f665e8b 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/jni/NativeRenderObjectUtils.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/component/list/template/jni/NativeRenderObjectUtils.java
@@ -51,6 +51,7 @@ public class NativeRenderObjectUtils {
      * */
     public static native int nativeLayoutRenderObject(long ptr, float width, float height);
 
+    public static native int nativeRenderObjectGetLayoutDirectionFromPathNode(long ptr);
     /**
      * get child length
      * */
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXDomModule.java b/android/sdk/src/main/java/com/taobao/weex/ui/module/WXDomModule.java
index 787ae53..8f8c957 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/module/WXDomModule.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/module/WXDomModule.java
@@ -26,6 +26,7 @@ import com.taobao.weex.common.WXModule;
 import com.taobao.weex.dom.binding.JSONUtils;
 import com.taobao.weex.ui.action.ActionAddRule;
 import com.taobao.weex.ui.action.ActionGetComponentRect;
+import com.taobao.weex.ui.action.ActionGetLayoutDirection;
 import com.taobao.weex.ui.action.ActionInvokeMethod;
 import com.taobao.weex.ui.action.GraphicActionBatchBegin;
 import com.taobao.weex.ui.action.GraphicActionBatchEnd;
@@ -47,6 +48,7 @@ public final class WXDomModule extends WXModule {
   public static final String SCROLL_TO_ELEMENT = "scrollToElement";
   public static final String ADD_RULE = "addRule";
   public static final String GET_COMPONENT_RECT = "getComponentRect";
+  public static final String GET_COMPONENT_DIRECTION = "getLayoutDirection";
   public static final String WXDOM = "dom";
   public static final String INVOKE_METHOD = "invokeMethod";
 
@@ -59,7 +61,7 @@ public final class WXDomModule extends WXModule {
    * Methods expose to js. Every method which will be called in js should add to this array.
    */
   public static final String[] METHODS = {SCROLL_TO_ELEMENT, ADD_RULE, GET_COMPONENT_RECT,
-      INVOKE_METHOD, BATCH_BEGIN, BATCH_END};
+      INVOKE_METHOD, GET_COMPONENT_DIRECTION, BATCH_BEGIN, BATCH_END};
 
   public WXDomModule(WXSDKInstance instance){
     mWXSDKInstance = instance;
@@ -82,6 +84,14 @@ public final class WXDomModule extends WXModule {
 
     try {
       switch (method) {
+        case GET_COMPONENT_DIRECTION: {
+          if(args == null){
+            return null;
+          }
+          new ActionGetLayoutDirection(mWXSDKInstance, args.getString(0), args.getString(1))
+                  .executeActionOnRender();
+          break;
+        }
         case SCROLL_TO_ELEMENT:{
           if (args == null) {
             return null;
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCirclePageAdapter.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCirclePageAdapter.java
index 281c4e2..1b5b219 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCirclePageAdapter.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCirclePageAdapter.java
@@ -26,6 +26,7 @@ import com.taobao.weex.WXEnvironment;
 import com.taobao.weex.utils.WXLogUtils;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 public class WXCirclePageAdapter extends PagerAdapter {
@@ -37,12 +38,26 @@ public class WXCirclePageAdapter extends PagerAdapter {
   private List<View> shadow = new ArrayList<>();
   private boolean needLoop = true;
 
+  public boolean isRTL = false;
+  private List<View> originalViews = new ArrayList<>();
+
   public WXCirclePageAdapter(List<View> views, boolean needLoop) {
     super();
     this.views = new ArrayList<>(views);
+    this.originalViews = new ArrayList<>(views);
     this.needLoop = needLoop;
   }
 
+  public void setLayoutDirectionRTL(boolean isRTL) {
+    if (isRTL == this.isRTL) return;
+    this.isRTL = isRTL;
+    this.views = new ArrayList<>(this.originalViews);
+    if (isRTL) {
+      Collections.reverse(this.views);
+    }
+    ensureShadow();
+  }
+
   public WXCirclePageAdapter() {
     this(true);
   }
@@ -56,7 +71,13 @@ public class WXCirclePageAdapter extends PagerAdapter {
     if (WXEnvironment.isApkDebugable()) {
       WXLogUtils.d("onPageSelected >>>> addPageView");
     }
-    views.add(view);
+
+    originalViews.add(view);
+    if (this.isRTL) {
+      views.add(0, view);
+    } else {
+      views.add(view);
+    }
     ensureShadow();
   }
 
@@ -65,6 +86,7 @@ public class WXCirclePageAdapter extends PagerAdapter {
       WXLogUtils.d("onPageSelected >>>> removePageView");
     }
     views.remove(view);
+    originalViews.remove(view);
     ensureShadow();
   }
 
@@ -77,6 +99,10 @@ public class WXCirclePageAdapter extends PagerAdapter {
     views.remove(index);
     views.add(index, newView);
     ensureShadow();
+
+    index = originalViews.indexOf(oldView);
+    originalViews.remove(index);
+    originalViews.add(index, newView);
   }
 
   @Override
diff --git a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCircleViewPager.java b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCircleViewPager.java
index 5c79e5b..6c19615 100644
--- a/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCircleViewPager.java
+++ b/android/sdk/src/main/java/com/taobao/weex/ui/view/WXCircleViewPager.java
@@ -317,13 +317,24 @@ public class WXCircleViewPager extends ViewPager implements WXGestureObservable
   }
 
   private void showNextItem() {
-    if (!needLoop && superGetCurrentItem() == getRealCount() - 1) {
-      return;
-    }
-    if (getRealCount() == 2 && superGetCurrentItem() == 1) {
-      superSetCurrentItem(0, true);
+    if (this.getCirclePageAdapter() != null && this.getCirclePageAdapter().isRTL) {
+      if (!needLoop && superGetCurrentItem() == 0) {
+        return;
+      }
+      if (getRealCount() == 2 && superGetCurrentItem() == 0) {
+        superSetCurrentItem(1, true);
+      } else {
+        superSetCurrentItem(superGetCurrentItem() - 1, true);
+      }
     } else {
-      superSetCurrentItem(superGetCurrentItem() + 1, true);
+      if (!needLoop && superGetCurrentItem() == getRealCount() - 1) {
+        return;
+      }
+      if (getRealCount() == 2 && superGetCurrentItem() == 1) {
+        superSetCurrentItem(0, true);
+      } else {
+        superSetCurrentItem(superGetCurrentItem() + 1, true);
+      }
     }
   }
 }
diff --git a/android/sdk/src/main/java/com/taobao/weex/utils/StaticLayoutProxy.java b/android/sdk/src/main/java/com/taobao/weex/utils/StaticLayoutProxy.java
index a3584ce..ac1d660 100644
--- a/android/sdk/src/main/java/com/taobao/weex/utils/StaticLayoutProxy.java
+++ b/android/sdk/src/main/java/com/taobao/weex/utils/StaticLayoutProxy.java
@@ -31,6 +31,7 @@ import java.lang.reflect.Constructor;
  */
 
 public class StaticLayoutProxy {
+  private static Constructor<StaticLayout> layoutConstructor;
   public static StaticLayout create(CharSequence source, TextPaint paint,
                                     int width,
                                     Layout.Alignment align, float spacingmult, float spacingadd,
@@ -40,6 +41,8 @@ public class StaticLayoutProxy {
       StaticLayout rtlLayout =  createInternal(source, paint, width, align, textDir, spacingmult, spacingadd, includepad);
       if (rtlLayout != null) {
         return rtlLayout;
+      } else {
+        return new StaticLayout(source, paint, width, align, spacingmult, spacingadd, includepad);
       }
     }
     return new StaticLayout(source, paint, width, align, spacingmult, spacingadd, includepad);
@@ -53,16 +56,19 @@ public class StaticLayoutProxy {
       return null;
     } else {
       try {
-        Class<StaticLayout> clazz = StaticLayout.class;
-        Constructor<StaticLayout> constructor = clazz.getConstructor(CharSequence.class, TextPaint.class,
-                int.class, Layout.Alignment.class, TextDirectionHeuristic.class,
-                float.class, float.class,
-                boolean.class);
-
-        if (constructor != null) {
-          return constructor.newInstance(source, paint, width,
+        if (layoutConstructor == null) {
+          Class<StaticLayout> clazz = StaticLayout.class;
+          Constructor<StaticLayout> constructor = clazz.getConstructor(CharSequence.class, TextPaint.class,
+                  int.class, Layout.Alignment.class, TextDirectionHeuristic.class,
+                  float.class, float.class,
+                  boolean.class);
+          layoutConstructor = constructor;
+        }
+        if (layoutConstructor != null) {
+          return layoutConstructor.newInstance(source, paint, width,
                   align, textDir, spacingmult, spacingadd, includepad);
         }
+
       } catch (Throwable e) {
         e.printStackTrace();
       }
diff --git a/android/sdk/src/main/res/values-ldltr/isrtl.xml b/android/sdk/src/main/res/values-ldltr/isrtl.xml
new file mode 100644
index 0000000..5008fea
--- /dev/null
+++ b/android/sdk/src/main/res/values-ldltr/isrtl.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+
+    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.
+
+-->
+<resources>
+    <bool name="weex_is_right_to_left">false</bool>
+</resources>
\ No newline at end of file
diff --git a/android/sdk/src/main/res/values-ldrtl/istrtl.xml b/android/sdk/src/main/res/values-ldrtl/istrtl.xml
new file mode 100644
index 0000000..47d9b1a
--- /dev/null
+++ b/android/sdk/src/main/res/values-ldrtl/istrtl.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!--
+
+    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.
+
+-->
+<resources>
+    <bool name="weex_is_right_to_left">true</bool>
+</resources>
\ No newline at end of file
diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
index dd186de..6d42333 100644
--- a/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
+++ b/ios/sdk/WeexSDK/Sources/Bridge/WXBridgeContext.m
@@ -850,13 +850,17 @@ _Pragma("clang diagnostic pop") \
 {
     if(self.frameworkLoadFinished) {
         WXAssert(script, @"param script required!");
-        NSDictionary* funcInfo = @{
-                                   @"func":@"executeJsService",
-                                   @"arg":name?:@"unsetScriptName"
-                                   };
-        self.jsBridge.javaScriptContext[@"wxExtFuncInfo"] = funcInfo;
+        if ([self.jsBridge respondsToSelector:@selector(javaScriptContext)]) {
+            NSDictionary* funcInfo = @{
+                                       @"func":@"executeJsService",
+                                       @"arg":name?:@"unsetScriptName"
+                                       };
+            self.jsBridge.javaScriptContext[@"wxExtFuncInfo"] = funcInfo;
+        }
         [self.jsBridge executeJavascript:script];
-        self.jsBridge.javaScriptContext[@"wxExtFuncInfo"] = nil;
+        if ([self.jsBridge respondsToSelector:@selector(javaScriptContext)]) {
+            self.jsBridge.javaScriptContext[@"wxExtFuncInfo"] = nil;
+        }
         
         if ([self.jsBridge exception]) {
             NSString *exception = [[self.jsBridge exception] toString];
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h b/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
index fc7658d..3aef1dc 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
+++ b/ios/sdk/WeexSDK/Sources/Component/WXComponent_internal.h
@@ -283,6 +283,9 @@ typedef id (^WXDataBindingBlock)(NSDictionary *data, BOOL *needUpdate);
 
 - (void)_buildViewHierarchyLazily;
 
+
+- (void)_adjustForRTL;
+
 - (BOOL)_isAffineTypeAs:(NSString *)type;
 
 @end
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.mm
index 402e592..b8a25fa 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.mm
+++ b/ios/sdk/WeexSDK/Sources/Component/WXCycleSliderComponent.mm
@@ -458,6 +458,39 @@ typedef NS_ENUM(NSInteger, Direction) {
     _recycleSliderView.currentIndex = _index;
 }
 
+- (void)_buildViewHierarchyLazily {
+    [super _buildViewHierarchyLazily];
+}
+
+- (void)adjustForRTL
+{
+    if (![WXUtility enableRTLLayoutDirection]) return;
+    
+    // this is scroll rtl solution.
+    // scroll layout not use direction, use self tranform
+    if (self.view && _flexCssNode && _flexCssNode->getLayoutDirectionFromPathNode() == WeexCore::kDirectionRTL
+        ) {
+        WXRecycleSliderView *slider = (WXRecycleSliderView *)self.view;
+        CATransform3D transform = CATransform3DScale(CATransform3DIdentity, -1, 1, 1);
+        slider.scrollView.layer.transform = transform ;
+    } else {
+        WXRecycleSliderView *slider = (WXRecycleSliderView *)self.view;
+        slider.scrollView.layer.transform = CATransform3DIdentity ;
+    }
+
+}
+
+- (void)_adjustForRTL {
+    if (![WXUtility enableRTLLayoutDirection]) return;
+    
+    [super _adjustForRTL];
+    [self adjustForRTL];
+}
+
+- (BOOL)shouldTransformSubviewsWhenRTL {
+    return YES;
+}
+
 - (void)viewDidUnload
 {
     [_childrenView removeAllObjects];
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm
index a278202..50256ab 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm
+++ b/ios/sdk/WeexSDK/Sources/Component/WXScrollerComponent.mm
@@ -19,6 +19,7 @@
 
 #import "WXScrollerComponent.h"
 #import "WXComponent_internal.h"
+#import "WXSDKInstance_private.h"
 #import "WXComponent.h"
 #import "WXDefine.h"
 #import "WXConvert.h"
@@ -415,6 +416,33 @@ WX_EXPORT_METHOD(@selector(resetLoadmore))
     }
 }
 
+- (void)adjustForRTL
+{
+    if (![WXUtility enableRTLLayoutDirection]) return;
+    
+    // this is scroll rtl solution.
+    // scroll layout not use direction, use self tranform
+    if (self.view && _flexCssNode && _flexCssNode->getLayoutDirectionFromPathNode() == WeexCore::kDirectionRTL
+        ) {
+        if (_transform) {
+            self.view.layer.transform = CATransform3DConcat(self.view.layer.transform, CATransform3DScale(CATransform3DIdentity, -1, 1, 1));
+        } else {
+            self.view.layer.transform = CATransform3DScale(CATransform3DIdentity, -1, 1, 1);
+        }
+    } else {
+        if (!_transform) {
+            self.view.layer.transform = CATransform3DIdentity;
+        }
+    }
+}
+
+- (void)_adjustForRTL {
+    if (![WXUtility enableRTLLayoutDirection]) return;
+    
+    [super _adjustForRTL];
+    [self adjustForRTL];
+}
+
 - (void)adjustSticky
 {
     if (![self isViewLoaded]) {
@@ -1044,7 +1072,7 @@ WX_EXPORT_METHOD(@selector(resetLoadmore))
             float left = _flexCssNode->getLayoutPositionLeft();
             float width = _flexCssNode->getLayoutWidth();
             float height = _flexCssNode->getLayoutHeight();
-            
+
             if (_scrollDirection == WXScrollDirectionVertical) {
                 _flexCssNode->setFlexDirection(WeexCore::kFlexDirectionColumn, NO);
                 _flexCssNode->setStyleWidth(_flexCssNode->getLayoutWidth(), NO);
@@ -1054,7 +1082,14 @@ WX_EXPORT_METHOD(@selector(resetLoadmore))
                 _flexCssNode->setStyleHeight(_flexCssNode->getLayoutHeight());
                 _flexCssNode->setStyleWidth(FlexUndefined, NO);
             }
+
             _flexCssNode->markAllDirty();
+            
+            // this is scroll rtl solution.
+            // scroll layout not use direction, use self tranform
+            // but we need inherit direction in CSS, so we set children layout diretion manually
+            _flexCssNode->determineChildLayoutDirection(_flexCssNode->getLayoutDirectionFromPathNode());
+            
             std::pair<float, float> renderPageSize;
             renderPageSize.first = self.weexInstance.frame.size.width;
             renderPageSize.second = self.weexInstance.frame.size.height;
diff --git a/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm b/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm
index e8683aa..f4c21a9 100644
--- a/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm
+++ b/ios/sdk/WeexSDK/Sources/Component/WXTextComponent.mm
@@ -139,7 +139,6 @@ CGFloat WXTextDefaultLineThroughWidth = 1.2;
     WXTextStyle _fontStyle;
     NSUInteger _lines;
     NSTextAlignment _textAlign;
-    NSString *_direction;
     WXTextDecoration _textDecoration;
     NSString *_textOverflow;
     CGFloat _lineHeight;
@@ -273,7 +272,6 @@ do {\
     WX_STYLE_FILL_TEXT_PIXEL(lineHeight, lineHeight, YES)
     WX_STYLE_FILL_TEXT_PIXEL(letterSpacing, letterSpacing, YES)
     WX_STYLE_FILL_TEXT(wordWrap, wordWrap, NSString, YES);
-    WX_STYLE_FILL_TEXT(direction, direction, NSString, YES)
     if (_fontFamily && !_observerIconfont) {
         // notification received when custom icon font file download finish
         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(repaintText:) name:WX_ICONFONT_DOWNLOAD_NOTIFICATION object:nil];
@@ -515,7 +513,7 @@ do {\
     NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
     
     // handle text direction style, default ltr
-    BOOL isRtl = [_direction isEqualToString:@"rtl"];
+    BOOL isRtl = [self isDirectionRTL];
     if (isRtl) {
         if (0 == _textAlign) {
             //force text right-align if don't specified any align.
@@ -598,7 +596,7 @@ do {\
     NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
 
     // handle text direction style, default ltr
-    BOOL isRtl = [_direction isEqualToString:@"rtl"];
+    BOOL isRtl = [self isDirectionRTL];
     if (isRtl) {
         if (0 == _textAlign) {
             //force text right-align if don't specified any align.
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.h b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.h
index a338847..518a163 100644
--- a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.h
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.h
@@ -43,6 +43,7 @@ extern "C" {
     CGRect _calculatedFrame;
     CGPoint _absolutePosition;
     WXPositionType _positionType;
+    BOOL _isLastLayoutDirectionRTL;
 }
 
 /**
@@ -69,4 +70,13 @@ extern "C" {
  */
 - (void)removeSubcomponentCssNode:(WXComponent *)subcomponent;
 
+#pragma mark - RTL
+
+@property (nonatomic, assign, readonly) BOOL isDirectionRTL;
+
+// Now we scrollView RTL solution is tranform
+// so scrollView need tranform subviews when RTL by default
+// if your component view is not scrollView but also implement RTL layout by tranform,you need return YES
+- (BOOL)shouldTransformSubviewsWhenRTL;
+
 @end
diff --git a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
index 18cb24d..14246e7 100644
--- a/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
+++ b/ios/sdk/WeexSDK/Sources/Layout/WXComponent+Layout.mm
@@ -153,11 +153,26 @@ bool flexIsUndefined(float value) {
                 [strongSelf->_transform applyTransformForView:strongSelf.view];
             }
             
+            [self _adjustForRTL];
+            
             if (strongSelf->_backgroundImage) {
                 [strongSelf setGradientLayer];
             }
             [strongSelf setNeedsDisplay];
         }];
+    } else {
+        // if frame is not change, we still need check was layoutDirection changed
+        if ([self isDirectionRTL] != _isLastLayoutDirectionRTL) {
+            _isLastLayoutDirectionRTL = [self isDirectionRTL];
+            __weak typeof(self) weakSelf = self;
+            [self.weexInstance.componentManager _addUITask:^{
+                __strong typeof(weakSelf) strongSelf = weakSelf;
+                if (strongSelf->_transform) {
+                    [strongSelf->_transform applyTransformForView:strongSelf.view];
+                }
+                [strongSelf _adjustForRTL];
+            }];
+        }
     }
 }
 
@@ -168,6 +183,7 @@ bool flexIsUndefined(float value) {
     if (_positionType == WXPositionTypeSticky) {
         [self.ancestorScroller adjustSticky];
     }
+
     [self layoutDidFinish];
 }
 
@@ -183,9 +199,15 @@ bool flexIsUndefined(float value) {
     if (_flexCssNode == nullptr) {
         return;
     }
-    
+
     BOOL needLayout = NO;
     
+    // CSS direction for RTL Layout
+    if (styles[@"direction"]) {
+        _flexCssNode->setDirection([self fxDirection:styles[@"direction"]], isUpdate);
+        needLayout = YES;
+    }
+    
     // flex
     if (styles[@"flex"]) {
         _flexCssNode->set_flex([WXConvert CGFloat:styles[@"flex"]]);
@@ -453,7 +475,9 @@ do {\
         if (styles.count<=0) {
             return;
         }
-        
+    
+        WX_FLEX_STYLE_RESET_CSS_NODE(direction, @(WeexCore::kDirectionInherit))
+    
         WX_FLEX_STYLE_RESET_CSS_NODE(flex, @0.0)
         WX_FLEX_STYLE_RESET_CSS_NODE(flexDirection, @(WeexCore::kFlexDirectionColumn))
         WX_FLEX_STYLE_RESET_CSS_NODE(alignItems, @(WeexCore::kAlignItemsStretch))
@@ -563,6 +587,18 @@ static WeexCore::WXCoreSize flexCssNodeMeasure(WeexCore::WXCoreLayoutNode *node,
     return WeexCore::kRelative;
 }
 
+- (WeexCore::WXCoreDirection)fxDirection:(id)value
+{
+    if([value isKindOfClass:[NSString class]]){
+        if ([value isEqualToString:@"rtl"]) {
+            return WeexCore::kDirectionRTL;
+        } else if ([value isEqualToString:@"ltr"]) {
+            return WeexCore::kDirectionLTR;
+        }
+    }
+    return WeexCore::kDirectionInherit;
+}
+
 - (WeexCore::WXCoreFlexDirection)fxFlexDirection:(id)value
 {
     if([value isKindOfClass:[NSString class]]){
@@ -677,4 +713,39 @@ static WeexCore::WXCoreSize flexCssNodeMeasure(WeexCore::WXCoreLayoutNode *node,
     }
 }
 
+#pragma mark - RTL
+
+- (BOOL)isDirectionRTL {
+    if (![WXUtility enableRTLLayoutDirection]) return NO;
+    
+    WeexCore::WXCoreDirection direction = _flexCssNode == nullptr ? WeexCore::WEEXCORE_CSS_DEFAULT_DIRECTION : _flexCssNode->getLayoutDirectionFromPathNode();
+    if (direction != WeexCore::kDirectionInherit) return direction == WeexCore::kDirectionRTL;
+    return NO;
+}
+
+- (void)_adjustForRTL {
+    if (![WXUtility enableRTLLayoutDirection]) return;
+    
+    if (self->_positionType == WXPositionTypeFixed) return;
+    
+    if (self.supercomponent && self.supercomponent->_flexCssNode && self.supercomponent->_flexCssNode->getLayoutDirectionFromPathNode() == WeexCore::kDirectionRTL && [self.supercomponent shouldTransformSubviewsWhenRTL]) {
+        if (_transform) {
+            self.view.layer.transform = CATransform3DConcat(self.view.layer.transform, CATransform3DScale(CATransform3DIdentity, -1, 1, 1));
+        } else {
+            self.view.layer.transform = CATransform3DScale(CATransform3DIdentity, -1, 1, 1);
+        }
+    } else {
+        if (!_transform) {
+            self.view.layer.transform = CATransform3DIdentity;
+        }
+    }
+}
+
+// Now we scrollView RTL solution is tranform
+// so scrollView need tranform subviews when RTL by default
+// if your component view is not scrollView but also implement RTL layout by tranform,you need return YES
+- (BOOL)shouldTransformSubviewsWhenRTL {
+    return [self.view isKindOfClass:[UIScrollView class]];
+}
+
 @end
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm b/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm
index 43fda8b..f69f506 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm
+++ b/ios/sdk/WeexSDK/Sources/Model/WXComponent.mm
@@ -383,11 +383,13 @@ static BOOL bNeedRemoveEvents = YES;
         if (_backgroundImage) {
             [self setGradientLayer];
         }
-        
+
         if (_transform) {
             [_transform applyTransformForView:_view];
         }
         
+        [self _adjustForRTL];
+        
         if (_boxShadow) {
             [self configBoxShadow:_boxShadow];
         }
@@ -801,6 +803,7 @@ static BOOL bNeedRemoveEvents = YES;
     self.transform = [[WXTransform alloc] initWithNativeTransform:CATransform3DMakeAffineTransform(transform) instance:self.weexInstance];
     if (!CGRectEqualToRect(self.calculatedFrame, CGRectZero)) {
         [_transform applyTransformForView:_view];
+        [self _adjustForRTL];
         [_layer setNeedsDisplay];
     }
 }
diff --git a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
index e0cc3b8..4a04c14 100644
--- a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
+++ b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m
@@ -447,6 +447,9 @@ typedef enum : NSUInteger {
         
         BOOL useJSCApiForCreateInstance = [[configCenter configForKey:@"iOS_weex_ext_config.useJSCApiForCreateInstance" defaultValue:@(YES) isDefault:NULL] boolValue];
         [WXUtility setUseJSCApiForCreateInstance:useJSCApiForCreateInstance];
+		
+        BOOL enableRTLLayoutDirection = [[configCenter configForKey:@"iOS_weex_ext_config.enableRTLLayoutDirection" defaultValue:@(YES) isDefault:NULL] boolValue];
+        [WXUtility setEnableRTLLayoutDirection:enableRTLLayoutDirection];
 
         BOOL shoudMultiContext = NO;
         shoudMultiContext = [[configCenter configForKey:@"iOS_weex_ext_config.createInstanceUsingMutliContext" defaultValue:@(YES) isDefault:NULL] boolValue];
diff --git a/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m b/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m
index 75b09d8..3b52110 100644
--- a/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m
+++ b/ios/sdk/WeexSDK/Sources/Module/WXAnimationModule.m
@@ -93,6 +93,7 @@
     if ([_animationInfo.propertyName hasPrefix:@"transform"]) {
         WXTransform *transform = _animationInfo.target->_transform;
         [transform applyTransformForView:_animationInfo.target.view];
+        [_animationInfo.target _adjustForRTL];
     } else if ([_animationInfo.propertyName isEqualToString:@"backgroundColor"]) {
         _animationInfo.target.view.layer.backgroundColor = (__bridge CGColorRef _Nullable)(_animationInfo.toValue);
     } else if ([_animationInfo.propertyName isEqualToString:@"opacity"]) {
diff --git a/ios/sdk/WeexSDK/Sources/Module/WXDomModule.m b/ios/sdk/WeexSDK/Sources/Module/WXDomModule.m
index 312d6f8..a3de95b 100644
--- a/ios/sdk/WeexSDK/Sources/Module/WXDomModule.m
+++ b/ios/sdk/WeexSDK/Sources/Module/WXDomModule.m
@@ -18,6 +18,7 @@
  */
 
 #import "WXDomModule.h"
+#import "WXComponent+Layout.h"
 #import "WXDefine.h"
 #import "WXSDKManager.h"
 #import "WXComponentManager.h"
@@ -54,6 +55,7 @@ WX_EXPORT_METHOD(@selector(updateStyle:styles:))
 WX_EXPORT_METHOD(@selector(updateAttrs:attrs:))
 WX_EXPORT_METHOD(@selector(addRule:rule:))
 WX_EXPORT_METHOD(@selector(getComponentRect:callback:))
+WX_EXPORT_METHOD(@selector(getLayoutDirection:callback:))
 WX_EXPORT_METHOD(@selector(updateComponentData:componentData:callback:))
 WX_EXPORT_METHOD(@selector(beginBatchMark))
 WX_EXPORT_METHOD(@selector(endBatchMark))
@@ -261,6 +263,30 @@ WX_EXPORT_METHOD(@selector(endBatchMark))
     }];
 }
 
+- (void)getLayoutDirection:(NSString*)ref callback:(WXModuleKeepAliveCallback)callback {
+    [self performBlockOnComponentManager:^(WXComponentManager * manager) {
+        if ([ref isEqualToString:@"viewport"]) {
+            dispatch_async(dispatch_get_main_queue(), ^{
+                NSString *direction = [WXUtility getEnvLayoutDirection] == WXLayoutDirectionRTL ? @"rtl" : @"ltr";
+                if (callback) {
+                    callback(direction, false);
+                }
+            });
+        } else {
+            WXComponent *component = [manager componentForRef:ref];
+            dispatch_async(dispatch_get_main_queue(), ^{
+                NSString *direction = @"unknow";
+                if (component) {
+                    direction = [component isDirectionRTL] ? @"rtl" : @"ltr";
+                }
+                if (callback) {
+                    callback(direction, false);
+                }
+            });
+        }
+    }];
+}
+
 - (void)updateComponentData:(NSString*)componentDataId componentData:(NSDictionary*)componentData callback:(NSString*)callbackId
 {
     NSString *recycleListComponentRef = [[componentDataId componentsSeparatedByString:@"@"] objectAtIndex:0];
diff --git a/ios/sdk/WeexSDK/Sources/Protocol/WXScrollerProtocol.h b/ios/sdk/WeexSDK/Sources/Protocol/WXScrollerProtocol.h
index 6cbb245..9b72ba3 100644
--- a/ios/sdk/WeexSDK/Sources/Protocol/WXScrollerProtocol.h
+++ b/ios/sdk/WeexSDK/Sources/Protocol/WXScrollerProtocol.h
@@ -73,7 +73,13 @@
 - (WXScrollDirection)scrollDirection;
 
 @optional
+
 - (NSString*)refreshType;
 - (BOOL)requestGestureShouldStopPropagation:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
+/**
+ * @abstract adjust for RTL
+ */
+- (void)adjustForRTL;
+
 @end
 
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXType.h b/ios/sdk/WeexSDK/Sources/Utility/WXType.h
index a33b9cc..2ef5c84 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXType.h
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXType.h
@@ -20,6 +20,12 @@
 #import <Foundation/Foundation.h>
 #import <UIKit/UIKit.h>
 
+typedef NS_ENUM(NSUInteger, WXLayoutDirection) {
+    WXLayoutDirectionLTR,
+    WXLayoutDirectionRTL,
+    WXLayoutDirectionAuto,
+};
+
 typedef NS_ENUM(NSUInteger, WXComponentType) {
     WXComponentTypeCommon = 0,
     WXComponentTypeVirtual
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h
index 601727a..730c560 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.h
@@ -131,6 +131,8 @@ _Nonnull SEL WXSwizzledSelectorForSelector(_Nonnull SEL selector);
 
 + (NSDictionary *_Nonnull)getDebugEnvironment;
 
++ (WXLayoutDirection)getEnvLayoutDirection;
+
 /**
  * @abstract UserAgent Generation
  *
@@ -489,6 +491,10 @@ BOOL WXFloatGreaterThanWithPrecision(CGFloat a,CGFloat b,double precision);
 
 + (BOOL)useJSCApiForCreateInstance;
 
++ (void)setEnableRTLLayoutDirection:(BOOL)value;
+
++ (BOOL)enableRTLLayoutDirection;
+
 + (long) getUnixFixTimeMillis;
 
 + (NSArray<NSString *> *_Nullable)extractPropertyNamesOfJSValueObject:(JSValue *_Nullable)jsvalue;
diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.m b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.m
index 121a73c..b070a87 100644
--- a/ios/sdk/WeexSDK/Sources/Utility/WXUtility.m
+++ b/ios/sdk/WeexSDK/Sources/Utility/WXUtility.m
@@ -44,6 +44,7 @@
 
 static BOOL unregisterFontWhenCollision = NO;
 static BOOL useJSCApiForCreateInstance = YES;
+static BOOL enableRTLLayoutDirection = YES;
 
 void WXPerformBlockOnMainThread(void (^ _Nonnull block)(void))
 {
@@ -173,6 +174,18 @@ CGFloat WXFloorPixelValue(CGFloat value)
     block();
 }
 
++ (WXLayoutDirection)getEnvLayoutDirection {
+    // We not use the below technique, because your app maybe not support the first preferredLanguages
+    // _sysLayoutDirection = [NSLocale characterDirectionForLanguage:[[NSLocale preferredLanguages] objectAtIndex:0]] == NSLocaleLanguageDirectionRightToLeft ? WXLayoutDirectionRTL : WXLayoutDirectionLTR;
+    if (@available(iOS 9.0, *)) {
+        // The view is shown in right-to-left mode right now.
+        return [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:UISemanticContentAttributeUnspecified] == UIUserInterfaceLayoutDirectionRightToLeft ? WXLayoutDirectionRTL : WXLayoutDirectionLTR;
+    } else {
+        // Use the previous technique
+        return [[UIApplication sharedApplication] userInterfaceLayoutDirection] == UIUserInterfaceLayoutDirectionRightToLeft ? WXLayoutDirectionRTL : WXLayoutDirectionLTR;
+    }
+}
+
 + (NSDictionary *)getEnvironment
 {
     NSString *platform = @"iOS";
@@ -197,7 +210,8 @@ CGFloat WXFloorPixelValue(CGFloat value)
                                     @"deviceWidth":@(deviceWidth * scale),
                                     @"deviceHeight":@(deviceHeight * scale),
                                     @"scale":@(scale),
-                                    @"logLevel":[WXLog logLevelString] ?: @"error"
+                                    @"logLevel":[WXLog logLevelString] ?: @"error",
+                                    @"layoutDirection": [self getEnvLayoutDirection] == WXLayoutDirectionRTL ? @"rtl" : @"ltr"
                                 }];
     
     if ([[[UIDevice currentDevice] systemVersion] integerValue] >= 11) {
@@ -736,6 +750,17 @@ CGFloat WXFloorPixelValue(CGFloat value)
     return defaultScaleFactor;
 }
 
+#pragma mark - RTL
+
++ (void)setEnableRTLLayoutDirection:(BOOL)value
+{
+    enableRTLLayoutDirection = value;
+}
+
++ (BOOL)enableRTLLayoutDirection
+{
+    return enableRTLLayoutDirection;
+}
 
 #pragma mark - get deviceID
 + (NSString *)getDeviceID {
diff --git a/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.mm b/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.mm
index ad17890..98cf737 100644
--- a/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.mm
+++ b/ios/sdk/WeexSDK/Sources/View/WXComponent+ViewManagement.mm
@@ -263,6 +263,7 @@ do {\
         WXTransform* transform = [[WXTransform alloc] initWithCSSValue:[WXConvert NSString:styles[@"transform"]] origin:[WXConvert NSString:transformOrigin] instance:self.weexInstance];
         if (!CGRectEqualToRect(self.calculatedFrame, CGRectZero)) {
             [transform applyTransformForView:_view];
+            [self _adjustForRTL];
             [_layer setNeedsDisplay];
         }
         self.transform = transform;
@@ -270,9 +271,14 @@ do {\
         [_transform setTransformOrigin:[WXConvert NSString:styles[@"transformOrigin"]]];
         if (!CGRectEqualToRect(self.calculatedFrame, CGRectZero)) {
             [_transform applyTransformForView:_view];
+            [self _adjustForRTL];
             [_layer setNeedsDisplay];
         }
     }
+    // for RTL
+    if (styles[@"direction"]) {
+        [self _adjustForRTL];
+    }
 }
 
 - (void)resetBorder:(NSArray *)styles
diff --git a/weex_core/Source/android/jniprebuild/jniheader/NativeRenderObjectUtils_jni.h b/weex_core/Source/android/jniprebuild/jniheader/NativeRenderObjectUtils_jni.h
index 55eefa2..78c51c7 100644
--- a/weex_core/Source/android/jniprebuild/jniheader/NativeRenderObjectUtils_jni.h
+++ b/weex_core/Source/android/jniprebuild/jniheader/NativeRenderObjectUtils_jni.h
@@ -50,6 +50,9 @@ static void AddChildRenderObject(JNIEnv* env, jclass jcaller,
     jlong parent,
     jlong child);
 
+static jint RenderObjectGetLayoutDirectionFromPathNode(JNIEnv* env, jclass jcaller,
+    jlong ptr);
+
 static jboolean RenderObjectHasNewLayout(JNIEnv* env, jclass jcaller,
     jlong ptr);
 
@@ -147,6 +150,11 @@ static const JNINativeMethod kMethodsNativeRenderObjectUtils[] = {
 "J"
 ")"
 "V", reinterpret_cast<void*>(AddChildRenderObject) },
+    { "nativeRenderObjectGetLayoutDirectionFromPathNode",
+"("
+"J"
+")"
+"I", reinterpret_cast<void*>(RenderObjectGetLayoutDirectionFromPathNode) },
     { "nativeRenderObjectHasNewLayout",
 "("
 "J"
diff --git a/weex_core/Source/android/utils/params_utils.cpp b/weex_core/Source/android/utils/params_utils.cpp
index be663ee..47651ef 100644
--- a/weex_core/Source/android/utils/params_utils.cpp
+++ b/weex_core/Source/android/utils/params_utils.cpp
@@ -293,6 +293,22 @@ std::vector<INIT_FRAMEWORK_PARAMS*> initFromParam(
   ADDSTRING(appVersion);
   env->DeleteLocalRef(appVersion);
 
+  jmethodID m_layoutDirection =
+          env->GetMethodID(c_params, "getLayoutDirection", "()Ljava/lang/String;");
+  if (m_layoutDirection == nullptr) {
+    ADDSTRING(nullptr);
+    ReportNativeInitStatus("-1012", "get m_layoutDirection failed");
+    return initFrameworkParams;
+  }
+  jobject layoutDirection = env->CallObjectMethod(params, m_layoutDirection);
+  if (layoutDirection == nullptr) {
+    ADDSTRING(nullptr);
+    ReportNativeInitStatus("-1012", "get layoutDirection failed");
+    return initFrameworkParams;
+  }
+  ADDSTRING(layoutDirection);
+  env->DeleteLocalRef(layoutDirection);
+
   jmethodID m_weexVersion =
       env->GetMethodID(c_params, "getWeexVersion", "()Ljava/lang/String;");
   if (m_weexVersion == nullptr) {
diff --git a/weex_core/Source/android/wrap/native_render_object_utils_impl_android.cpp b/weex_core/Source/android/wrap/native_render_object_utils_impl_android.cpp
index 5565075..8b6d9f1 100644
--- a/weex_core/Source/android/wrap/native_render_object_utils_impl_android.cpp
+++ b/weex_core/Source/android/wrap/native_render_object_utils_impl_android.cpp
@@ -128,8 +128,11 @@ static jint LayoutRenderObject(JNIEnv* env, jclass jcaller,
     return (jint)render->getLayoutHeight();
 }
 
-
-
+static jint RenderObjectGetLayoutDirectionFromPathNode(JNIEnv* env, jclass jcaller,
+                                   jlong ptr){
+    RenderObject* renderObject = convert_long_to_render_object(ptr);
+    return renderObject->getLayoutDirectionFromPathNode();
+}
 
 static jboolean RenderObjectHasNewLayout(JNIEnv* env, jclass jcaller,
                                      jlong ptr){
diff --git a/weex_core/Source/core/css/constants_name.h b/weex_core/Source/core/css/constants_name.h
index 48b8a59..fe282cc 100644
--- a/weex_core/Source/core/css/constants_name.h
+++ b/weex_core/Source/core/css/constants_name.h
@@ -23,6 +23,7 @@
 #include <string>
 
 namespace WeexCore {
+  constexpr char DIRECTION[] = "direction";
 
   constexpr char FLEX[] = "flex";
   constexpr char HORIZONTAL[] = "horizontal";
diff --git a/weex_core/Source/core/css/constants_value.h b/weex_core/Source/core/css/constants_value.h
index d51ebb5..b2a1862 100644
--- a/weex_core/Source/core/css/constants_value.h
+++ b/weex_core/Source/core/css/constants_value.h
@@ -23,6 +23,10 @@
 #include <string>
 
 namespace WeexCore {
+  // direction
+  constexpr char RTL[] = "rtl";
+  constexpr char LTR[] = "ltr";
+  constexpr char INHERIT[] = "inherit";
 
   // flex-direction
   constexpr char ROW[] = "row";
diff --git a/weex_core/Source/core/css/css_value_getter.cpp b/weex_core/Source/core/css/css_value_getter.cpp
index f576245..a60529f 100644
--- a/weex_core/Source/core/css/css_value_getter.cpp
+++ b/weex_core/Source/core/css/css_value_getter.cpp
@@ -24,6 +24,17 @@
 #include "core/layout/style.h"
 
 namespace WeexCore {
+  const WXCoreDirection GetWXCoreDirection(const std::string &value) {
+    const char *c_value = value.c_str();
+    if(strcmp(c_value, INHERIT) == 0) {
+      return WeexCore::kDirectionInherit;
+    } else if (strcmp(c_value, LTR) == 0) {
+      return WeexCore::kDirectionLTR;
+    } else if (strcmp(c_value, RTL) == 0) {
+      return WeexCore::kDirectionRTL;
+    } 
+    return WeexCore::kDirectionLTR;
+  }
 
   const WXCoreFlexDirection GetWXCoreFlexDirection(const std::string &value) {
     const char *c_value = value.c_str();
diff --git a/weex_core/Source/core/css/css_value_getter.h b/weex_core/Source/core/css/css_value_getter.h
index f47abc1..ec630ca 100644
--- a/weex_core/Source/core/css/css_value_getter.h
+++ b/weex_core/Source/core/css/css_value_getter.h
@@ -23,6 +23,7 @@
 #include <string>
 
 namespace WeexCore {
+  const WXCoreDirection GetWXCoreDirection(const std::string &value);
 
   const WXCoreFlexDirection GetWXCoreFlexDirection(const std::string &value);
 
diff --git a/weex_core/Source/core/layout/flex_enum.h b/weex_core/Source/core/layout/flex_enum.h
index 9eb3676..6f63e99 100644
--- a/weex_core/Source/core/layout/flex_enum.h
+++ b/weex_core/Source/core/layout/flex_enum.h
@@ -16,13 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+
 #ifdef __cplusplus
 
 #ifndef WEEXCORE_FLEXLAYOUT_WXCOREFLEXENUM_H
 #define WEEXCORE_FLEXLAYOUT_WXCOREFLEXENUM_H
 
-namespace WeexCore {
+#define WEEXCORE_CSS_DEFAULT_DIRECTION kDirectionLTR
 
+namespace WeexCore {
+    /**
+     * MainAxis direction
+     */
+    enum WXCoreDirection {
+        kDirectionInherit,
+        kDirectionLTR,
+        kDirectionRTL
+    };
   /**
    * MainAxis direction
    */
diff --git a/weex_core/Source/core/layout/layout.cpp b/weex_core/Source/core/layout/layout.cpp
index 6b7a290..8ffdf48 100644
--- a/weex_core/Source/core/layout/layout.cpp
+++ b/weex_core/Source/core/layout/layout.cpp
@@ -645,21 +645,39 @@ namespace WeexCore {
 
   void WXCoreLayoutNode::onLayout(const float left, const float top, const float right, const float bottom,
                                   WXCoreLayoutNode *const absoulteItem, WXCoreFlexLine *const flexLine) {
-    switch (mCssStyle->mFlexDirection) {
-      case kFlexDirectionRow:
-        layoutHorizontal(false, left, top, right, bottom, absoulteItem, flexLine);
-        break;
-      case kFlexDirectionRowReverse:
-        layoutHorizontal(true, left, top, right, bottom, absoulteItem, flexLine);
-        break;
-      case kFlexDirectionColumnReverse:
-        layoutVertical(mCssStyle->mFlexWrap == kWrapReverse, true, left, top, right, bottom, absoulteItem, flexLine);
-        break;
-      case kFlexDirectionColumn:
-      default:
-        layoutVertical(mCssStyle->mFlexWrap == kWrapReverse, false, left, top, right, bottom, absoulteItem, flexLine);
-        break;
-    }
+      // determin direction
+      if (mLayoutResult->mLayoutDirection == kDirectionInherit) {
+          if(mCssStyle->mDirection == kDirectionInherit) {
+              // default direction in css is inherit, inherit direction from parent node
+              mLayoutResult->mLayoutDirection = NULL == mParent ? WEEXCORE_CSS_DEFAULT_DIRECTION : mParent->getLayoutDirection();
+          } else {
+              // specific direction in current Node's style
+              mLayoutResult->mLayoutDirection = mCssStyle->mDirection;
+          }
+      }
+      
+      bool verticalRTL = false;
+      if (mCssStyle->mFlexWrap != kNoWrap && mLayoutResult->mLayoutDirection == kDirectionRTL) {
+          verticalRTL = mCssStyle->mFlexWrap != kWrapReverse;
+      } else {
+          verticalRTL = mCssStyle->mFlexWrap == kWrapReverse;
+      }
+      
+      switch (mCssStyle->mFlexDirection) {
+        case kFlexDirectionRow:
+            layoutHorizontal(mLayoutResult->mLayoutDirection == kDirectionRTL, left, top, right, bottom, absoulteItem, flexLine);
+            break;
+        case kFlexDirectionRowReverse:
+            layoutHorizontal(mLayoutResult->mLayoutDirection != kDirectionRTL, left, top, right, bottom, absoulteItem, flexLine);
+            break;
+          case kFlexDirectionColumnReverse:
+              layoutVertical(verticalRTL, true, left, top, right, bottom, absoulteItem, flexLine);
+              break;
+          case kFlexDirectionColumn:
+          default:
+              layoutVertical(verticalRTL, false, left, top, right, bottom, absoulteItem, flexLine);
+              break;
+      }
   }
 
   /**
@@ -1083,6 +1101,34 @@ namespace WeexCore {
         break;
     }
   }
+    void WXCoreLayoutNode::determineChildLayoutDirection(const WXCoreDirection direction) {
+        for (Index i = 0; i < getChildCount(kBFC); ++i) {
+            WXCoreLayoutNode *child = getChildAt(kBFC, i);
+            // determin direction
+            if (child->mLayoutResult->mLayoutDirection == kDirectionInherit) {
+                if(child->mCssStyle->mDirection == kDirectionInherit) {
+                    // default direction in css is inherit, inherit direction from parent node
+                    child->mLayoutResult->mLayoutDirection = direction;
+                } else {
+                    // specific direction in current Node's style
+                    child->mLayoutResult->mLayoutDirection = child->mCssStyle->mDirection;
+                }
+            }
+        }
+    }
+    
+    WXCoreDirection WXCoreLayoutNode::getLayoutDirectionFromPathNode() {
+        WXCoreLayoutNode *node = this;
+        if (node->getLayoutDirection() != kDirectionInherit) return node->getLayoutDirection();
+        if (node->getDirection() != kDirectionInherit) {
+            node->mLayoutResult->mLayoutDirection = node->getDirection();
+            return node->getLayoutDirection();
+        } else if (nullptr != node->mParent) {
+            node->mLayoutResult->mLayoutDirection = node->mParent->getLayoutDirectionFromPathNode();
+            return node->getLayoutDirection();
+        }
+        return WEEXCORE_CSS_DEFAULT_DIRECTION;
+    }
 }
 
 
diff --git a/weex_core/Source/core/layout/layout.h b/weex_core/Source/core/layout/layout.h
index 9434932..bd748e4 100644
--- a/weex_core/Source/core/layout/layout.h
+++ b/weex_core/Source/core/layout/layout.h
@@ -72,9 +72,10 @@ namespace WeexCore {
   };
 
   /**
-   * layout-result:layout-height、layout-width、position(left、right、top、bottom)
+   * layout-result:layout-height、layout-width、position(left、right、top、bottom)、direction
    */
   struct WXCorelayoutResult {
+    WXCoreDirection mLayoutDirection;
     WXCoreSize mLayoutSize;
     WXCorePosition mLayoutPosition;
 
@@ -83,8 +84,9 @@ namespace WeexCore {
     }
 
     inline void reset() {
-      mLayoutSize.reset();
-      mLayoutPosition.reset();
+        mLayoutSize.reset();
+        mLayoutPosition.reset();
+        mLayoutDirection = kDirectionInherit;
     }
   };
 
@@ -151,7 +153,6 @@ namespace WeexCore {
         mLayoutResult = new WXCorelayoutResult();
       }
 
-
       virtual ~WXCoreLayoutNode() {
         mIsDestroy = true;
         mHasNewLayout = true;
@@ -257,20 +258,22 @@ namespace WeexCore {
     inline void setContext(void * const context) {
       this->context = context;
     }
-
+      
     inline void copyStyle(WXCoreLayoutNode *srcNode) {
-      if (memcmp(mCssStyle, srcNode->mCssStyle, sizeof(WXCoreCSSStyle)) != 0) {
+      if (srcNode != nullptr && memcmp(mCssStyle, srcNode->mCssStyle, sizeof(WXCoreCSSStyle)) != 0) {
         memcpy(mCssStyle, srcNode->mCssStyle, sizeof(WXCoreCSSStyle));
         markDirty();
       }
     }
-
+      
     void copyFrom(WXCoreLayoutNode* srcNode){
-      memcpy(mCssStyle, srcNode->mCssStyle, sizeof(WXCoreCSSStyle));
+        if (srcNode == nullptr) return;
+        
+        memcpy(mCssStyle, srcNode->mCssStyle, sizeof(WXCoreCSSStyle));
     }
 
     inline void copyMeasureFunc(WXCoreLayoutNode *srcNode) {
-      if (memcmp(&measureFunc, &srcNode->measureFunc, sizeof(WXCoreMeasureFunc)) != 0) {
+      if (srcNode != nullptr && memcmp(&measureFunc, &srcNode->measureFunc, sizeof(WXCoreMeasureFunc)) != 0) {
         memcpy(&measureFunc, &srcNode->measureFunc, sizeof(WXCoreMeasureFunc));
         markDirty();
       }
@@ -607,8 +610,6 @@ namespace WeexCore {
 
     void positionAbsoluteFlexItem(float &left, float &top, float &right, float &bottom);
 
-    void onLayout(float left, float top, float right, float bottom, WXCoreLayoutNode* = nullptr, WXCoreFlexLine *const flexLine = nullptr);
-
     void layoutHorizontal(bool isRtl, float left, float top, float right, float bottom,
                           WXCoreLayoutNode*, WXCoreFlexLine *const flexLine);
 
@@ -668,7 +669,7 @@ namespace WeexCore {
 
 
   public:
-
+    virtual void onLayout(float left, float top, float right, float bottom, WXCoreLayoutNode* = nullptr, WXCoreFlexLine *const flexLine = nullptr);
     /** ================================ tree =================================== **/
 
     inline Index getChildCount(FormattingContext formattingContext) const {
@@ -972,7 +973,33 @@ namespace WeexCore {
       return mCssStyle->mMaxHeight;
     }
 
+      inline void setDirection(const WXCoreDirection direction, const bool updating) {
+          if (nullptr == mCssStyle) return;
+          
+          if (mCssStyle->mDirection != direction) {
+              mCssStyle->mDirection = direction;
+              markDirty();
+              if (updating) {
+                  for (auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) {
+                      (*it)->markInheritableDirty();
+                  }
+              }
+          }
+      }
 
+    inline WXCoreDirection getDirection() const {
+        if (mCssStyle == nullptr) {
+            return WEEXCORE_CSS_DEFAULT_DIRECTION;
+        }
+        return mCssStyle->mDirection;
+    }
+    
+    /** ================================ CSS direction For RTL =================================== **/
+      
+    void determineChildLayoutDirection(const WXCoreDirection direction);
+      
+    WXCoreDirection getLayoutDirectionFromPathNode();
+      
     /** ================================ flex-style =================================== **/
 
     inline void setFlexDirection(const WXCoreFlexDirection flexDirection, const bool updating) {
@@ -1070,7 +1097,18 @@ namespace WeexCore {
     inline float getLayoutPositionRight() const  {
       return mLayoutResult->mLayoutPosition.getPosition(kPositionEdgeRight);
     }
+      
+    virtual inline WXCoreDirection getLayoutDirection() const {
+      if (nullptr == mLayoutResult) {
+        return WEEXCORE_CSS_DEFAULT_DIRECTION;
+      }
+      return mLayoutResult->mLayoutDirection;
+    }
 
+    inline void setLayoutDirection(WXCoreDirection direction) {
+        if (nullptr == mLayoutResult) return;
+        mLayoutResult->mLayoutDirection = direction;
+    }
     inline bool hasNewLayout() const {
       return mHasNewLayout;
     }
@@ -1114,6 +1152,38 @@ namespace WeexCore {
       return ret;
     }
 
+    void markInheritableDirty() {
+        if (resetInheritableSet()) {
+            // if some style was inherited from parent, reset those styles
+            // then mark self dirty
+            markDirty(false);
+            
+            // traverse children to mark dirty
+            if(getChildCount() == 0){
+                return;
+            }
+            else {
+                for (auto it = ChildListIterBegin(); it != ChildListIterEnd(); it++) {
+                    (*it)->markInheritableDirty();
+                }
+            }
+        }
+    }
+      
+    /**
+    * if some style was inherited from parent, reset those styles, then return true, eles return false
+    */
+    bool resetInheritableSet() {
+      if (mCssStyle == nullptr || mLayoutResult == nullptr) return false;
+        
+      bool hasInheritedStyle = false;
+      if (mCssStyle->mDirection == kDirectionInherit) {
+          mLayoutResult->mLayoutDirection = kDirectionInherit;
+          hasInheritedStyle = true;
+      }
+      return hasInheritedStyle;
+    }
+      
     inline void setHasNewLayout(const bool hasNewLayout) {
       this->mHasNewLayout = hasNewLayout;
     }
diff --git a/weex_core/Source/core/layout/style.h b/weex_core/Source/core/layout/style.h
index a5c5f7e..5c9ca89 100644
--- a/weex_core/Source/core/layout/style.h
+++ b/weex_core/Source/core/layout/style.h
@@ -201,6 +201,8 @@ namespace WeexCore {
     WXCoreAlignSelf mAlignSelf;
 
     WXCorePositionType mPositionType;
+      
+      WXCoreDirection mDirection;
 
     float mFlexGrow;
 
@@ -242,7 +244,8 @@ namespace WeexCore {
 
     constexpr static WXCorePositionType kWXCorePositionTypeDefault = kRelative;
 
-    WXCoreCSSStyle() : mFlexDirection(kFlexDirectionDefault),
+    WXCoreCSSStyle() : mDirection(kDirectionInherit),
+                       mFlexDirection(kFlexDirectionDefault),
                        mFlexWrap(kFlexWrapDefault),
                        mJustifyContent(kFlexJustifyContentDefault),
                        mAlignItems(kFlexAlignItemsDefault),
@@ -257,6 +260,7 @@ namespace WeexCore {
     }
 
     ~WXCoreCSSStyle() {
+      mDirection = kDirectionInherit;
       mFlexDirection = kFlexDirectionDefault;
       mFlexWrap = kFlexWrapDefault;
       mJustifyContent = kFlexJustifyContentDefault;
diff --git a/weex_core/Source/core/render/node/render_object.cpp b/weex_core/Source/core/render/node/render_object.cpp
index ffc8388..ba547a7 100644
--- a/weex_core/Source/core/render/node/render_object.cpp
+++ b/weex_core/Source/core/render/node/render_object.cpp
@@ -160,6 +160,13 @@ StyleType RenderObject::ApplyStyle(const std::string &key,
       }
     }
     return kTypeLayout;
+  } else if (key == DIRECTION) {
+    WeexCore::WXCoreDirection direction = GetWXCoreDirection(value);
+    if (direction ==  WeexCore::kDirectionInherit && this->is_root_render_ ) {
+        direction = WeexCore::kDirectionLTR;
+    } 
+    setDirection(direction, updating);
+    return kTypeInheritableLayout;
   } else if (key == FLEX_DIRECTION) {
     setFlexDirection(GetWXCoreFlexDirection(value), updating);
     return kTypeLayout;
diff --git a/weex_core/Source/core/render/node/render_object.h b/weex_core/Source/core/render/node/render_object.h
index 5242a64..9522d9d 100644
--- a/weex_core/Source/core/render/node/render_object.h
+++ b/weex_core/Source/core/render/node/render_object.h
@@ -44,7 +44,8 @@ typedef enum StyleType {
   kTypeLayout,
   kTypeMargin,
   kTypePadding,
-  kTypeBorder
+  kTypeBorder,
+  kTypeInheritableLayout
 } StyleType;
 
 class RenderObject : public IRenderObject {
diff --git a/weex_core/Source/core/render/node/render_scroller.cpp b/weex_core/Source/core/render/node/render_scroller.cpp
index 05e67e2..03d0b8d 100644
--- a/weex_core/Source/core/render/node/render_scroller.cpp
+++ b/weex_core/Source/core/render/node/render_scroller.cpp
@@ -52,4 +52,11 @@ void RenderScroller::set_flex(const float flex) {
   this->is_set_flex_ = true;
   WXCoreLayoutNode::set_flex(flex);
 }
+    
+    void RenderScroller::onLayout(const float left, const float top, const float right, const float bottom,
+                                  WXCoreLayoutNode *const absoulteItem, WXCoreFlexLine *const flexLine) {
+        // In scroller only use left to right direction to caculate children frame
+        this->setLayoutDirection(kDirectionLTR);
+        RenderObject::onLayout(left, top, right, bottom, absoulteItem, flexLine);
+    }
 }  // namespace WeexCore
diff --git a/weex_core/Source/core/render/node/render_scroller.h b/weex_core/Source/core/render/node/render_scroller.h
index 59a35df..1cf6fc6 100644
--- a/weex_core/Source/core/render/node/render_scroller.h
+++ b/weex_core/Source/core/render/node/render_scroller.h
@@ -37,6 +37,24 @@ class RenderScroller : public RenderObject {
       const float &current_length) const override {
     return NAN;
   }
+
+protected:
+    void onLayout(const float left, const float top, const float right, const float bottom,
+                                  WXCoreLayoutNode *const absoulteItem, WXCoreFlexLine *const flexLine) override;
+
+    // Since scroll only use ltr to layout children actually,
+    // so we need override this method to return calculated inherit direction as normal render_object do
+    inline WXCoreDirection getLayoutDirection() const override {
+        WXCoreDirection styleDirection = this->getDirection();
+        if (styleDirection != kDirectionInherit) {
+            return styleDirection;
+        } else if (this->getParent() != nullptr) {
+            WXCoreLayoutNode *parent = this->getParent();
+            return parent->getLayoutDirection();
+        }
+        return WEEXCORE_CSS_DEFAULT_DIRECTION;
+    }
+
 };
 }  // namespace WeexCore
 #endif  // CORE_RENDER_NODE_RENDER_SCROLLER_H_
diff --git a/weex_core/Source/core/render/page/render_page.cpp b/weex_core/Source/core/render/page/render_page.cpp
index d54fade..875cd3d 100644
--- a/weex_core/Source/core/render/page/render_page.cpp
+++ b/weex_core/Source/core/render/page/render_page.cpp
@@ -221,7 +221,8 @@ bool RenderPage::UpdateStyle(
   std::vector<std::pair<std::string, std::string>> *margin = nullptr;
   std::vector<std::pair<std::string, std::string>> *padding = nullptr;
   std::vector<std::pair<std::string, std::string>> *border = nullptr;
-
+  bool inheriableLayout = false;
+    
   bool flag = false;
   int result =
       WeexCoreManager::Instance()
@@ -277,13 +278,16 @@ bool RenderPage::UpdateStyle(
                   flag = true;
               });
           break;
+          case kTypeInheritableLayout:
+              inheriableLayout = true;
+              break;
         default: break;
       }
     }
   }
 
   if (style != nullptr || margin != nullptr || padding != nullptr ||
-      border != nullptr)
+      border != nullptr || inheriableLayout)
     SendUpdateStyleAction(render, style, margin, padding, border);
 
   Batch();
diff --git a/weex_core/release.sh b/weex_core/release.sh
old mode 100644
new mode 100755