[dali_1.1.32] Merge branch 'devel/master' 30/67930/1
authorAgnelo Vaz <agnelo.vaz@samsung.com>
Fri, 29 Apr 2016 08:11:23 +0000 (09:11 +0100)
committerAgnelo Vaz <agnelo.vaz@samsung.com>
Fri, 29 Apr 2016 08:11:23 +0000 (09:11 +0100)
Change-Id: Id870d98184d1dd0b6c77ce901dfdf6bf167304d5

177 files changed:
automated-tests/.gitignore
automated-tests/CMakeLists.txt.in [moved from automated-tests/CMakeLists.txt with 65% similarity]
automated-tests/src/dali-toolkit-internal/dali-toolkit-test-utils/toolkit-text-model.cpp
automated-tests/src/dali-toolkit-styling/CMakeLists.txt [new file with mode: 0644]
automated-tests/src/dali-toolkit-styling/tct-dali-toolkit-styling-core.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-styling/utc-Dali-StyleManager.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/CMakeLists.txt [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/facebook-flexbox/layout-test-utils.c [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/facebook-flexbox/layout-test-utils.h [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/tct-dali-toolkit-third-party-core.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit-third-party/utc-Dali-Flexbox-Layout.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/CMakeLists.txt
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/mesh-builder.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-button.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/test-button.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-bitmap-loader.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-color-controller.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-feedback-player.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-file-loader.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-orientation.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-orientation.h [deleted file]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-singleton-service.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-singleton-service.h [deleted file]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-sound-player.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-style-monitor.cpp
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-style-monitor.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-test-application.h
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-abstraction.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-virtual-keyboard.cpp [new file with mode: 0644]
automated-tests/src/dali-toolkit/utc-Dali-Builder.cpp
automated-tests/src/dali-toolkit/utc-Dali-Control.cpp
automated-tests/src/dali-toolkit/utc-Dali-ControlImpl.cpp
automated-tests/src/dali-toolkit/utc-Dali-ControlRenderer.cpp
automated-tests/src/dali-toolkit/utc-Dali-DebugRenderer.cpp
automated-tests/src/dali-toolkit/utc-Dali-ImageView.cpp
automated-tests/src/dali-toolkit/utc-Dali-RendererFactory.cpp
automated-tests/src/dali-toolkit/utc-Dali-StyleManager.cpp [deleted file]
automated-tests/src/dali-toolkit/utc-Dali-TextEditor.cpp
automated-tests/src/dali-toolkit/utc-Dali-TextField.cpp
build/tizen/configure.ac
build/tizen/dali-toolkit/Makefile.am
build/tizen/docs/dali.doxy.in
dali-toolkit/dali-toolkit.h
dali-toolkit/devel-api/builder/builder.cpp
dali-toolkit/devel-api/builder/builder.h
dali-toolkit/devel-api/controls/bloom-view/bloom-view.h
dali-toolkit/devel-api/controls/flex-container/flex-container.h
dali-toolkit/devel-api/controls/popup/popup.h
dali-toolkit/devel-api/controls/renderer-factory/control-renderer.h
dali-toolkit/devel-api/controls/shadow-view/shadow-view.h
dali-toolkit/devel-api/file.list
dali-toolkit/devel-api/image-atlas/image-atlas.h
dali-toolkit/devel-api/shader-effects/dissolve-effect.h
dali-toolkit/devel-api/shader-effects/motion-blur-effect.h
dali-toolkit/devel-api/transition-effects/cube-transition-effect.h
dali-toolkit/internal/builder/builder-actor.cpp
dali-toolkit/internal/builder/builder-animations.cpp
dali-toolkit/internal/builder/builder-impl.cpp
dali-toolkit/internal/builder/builder-impl.h
dali-toolkit/internal/controls/bubble-effect/bubble-emitter-impl.cpp
dali-toolkit/internal/controls/flex-container/flex-container-impl.h
dali-toolkit/internal/controls/image-view/image-view-impl.cpp
dali-toolkit/internal/controls/image-view/image-view-impl.h
dali-toolkit/internal/controls/model3d-view/model3d-view-impl.cpp
dali-toolkit/internal/controls/model3d-view/obj-loader.cpp
dali-toolkit/internal/controls/model3d-view/obj-loader.h
dali-toolkit/internal/controls/page-turn-view/page-turn-book-spine-effect.h
dali-toolkit/internal/controls/renderers/border/border-renderer.cpp
dali-toolkit/internal/controls/renderers/color/color-renderer.cpp
dali-toolkit/internal/controls/renderers/debug/debug-renderer.cpp
dali-toolkit/internal/controls/renderers/gradient/gradient-renderer.cpp
dali-toolkit/internal/controls/renderers/image/image-renderer.cpp
dali-toolkit/internal/controls/renderers/image/image-renderer.h
dali-toolkit/internal/controls/renderers/npatch/npatch-renderer.cpp
dali-toolkit/internal/controls/renderers/renderer-factory-cache.cpp
dali-toolkit/internal/controls/renderers/renderer-factory-impl.cpp
dali-toolkit/internal/controls/renderers/renderer-factory-impl.h
dali-toolkit/internal/controls/renderers/renderer-string-constants.cpp [new file with mode: 0644]
dali-toolkit/internal/controls/renderers/renderer-string-constants.h [new file with mode: 0644]
dali-toolkit/internal/controls/renderers/svg/nanosvg/nanosvg.cc
dali-toolkit/internal/controls/renderers/svg/svg-renderer.cpp
dali-toolkit/internal/controls/scrollable/bouncing-effect-actor.cpp
dali-toolkit/internal/controls/shadow-view/shadow-view-impl.cpp
dali-toolkit/internal/controls/text-controls/text-editor-impl.cpp
dali-toolkit/internal/controls/text-controls/text-field-impl.cpp
dali-toolkit/internal/controls/text-controls/text-label-impl.cpp
dali-toolkit/internal/file.list
dali-toolkit/internal/styling/style-manager-impl.cpp
dali-toolkit/internal/styling/style-manager-impl.h
dali-toolkit/internal/text/color-run.h
dali-toolkit/internal/text/color-segmentation.cpp
dali-toolkit/internal/text/color-segmentation.h
dali-toolkit/internal/text/decorator/text-decorator.cpp
dali-toolkit/internal/text/input-style.h
dali-toolkit/internal/text/logical-model-impl.cpp
dali-toolkit/internal/text/logical-model-impl.h
dali-toolkit/internal/text/multi-language-helper-functions.cpp
dali-toolkit/internal/text/rendering/atlas/atlas-manager.h
dali-toolkit/internal/text/rendering/atlas/atlas-mesh-factory.cpp
dali-toolkit/internal/text/rendering/atlas/text-atlas-renderer.cpp
dali-toolkit/internal/text/rendering/vector-based/glyphy-shader/glyphy-shader.cpp
dali-toolkit/internal/text/rendering/vector-based/vector-based-renderer.cpp
dali-toolkit/internal/text/text-controller-impl.cpp
dali-toolkit/internal/text/text-controller-impl.h
dali-toolkit/internal/text/text-controller.cpp
dali-toolkit/internal/text/text-controller.h
dali-toolkit/internal/text/text-definitions.h
dali-toolkit/internal/text/text-view-interface.h
dali-toolkit/internal/text/text-view.cpp
dali-toolkit/internal/text/text-view.h
dali-toolkit/internal/text/visual-model-impl.h
dali-toolkit/internal/transition-effects/cube-transition-effect-impl.h
dali-toolkit/public-api/controls/buttons/button.h
dali-toolkit/public-api/controls/control-impl.cpp
dali-toolkit/public-api/controls/image-view/image-view.cpp
dali-toolkit/public-api/controls/image-view/image-view.h
dali-toolkit/public-api/controls/table-view/table-view.h
dali-toolkit/public-api/dali-toolkit-version.cpp
dali-toolkit/public-api/file.list
dali-toolkit/public-api/styling/style-manager.cpp [moved from dali-toolkit/devel-api/styling/style-manager.cpp with 61% similarity]
dali-toolkit/public-api/styling/style-manager.h [moved from dali-toolkit/devel-api/styling/style-manager.h with 53% similarity]
dali-toolkit/styles/480x800/dali-toolkit-default-theme.json
dali-toolkit/styles/720x1280/dali-toolkit-default-theme.json
doc/dali-toolkit-doc.h
docs/content/example-code/properties.cpp
docs/content/images/texture-atlas/atlas-size.jpg [deleted file]
docs/content/images/texture-atlas/atlas.jpg [deleted file]
docs/content/images/texture-atlas/compression-example.jpg [deleted file]
docs/content/images/texture-atlas/compression-options.jpg [deleted file]
docs/content/images/texture-atlas/example-code.jpg [deleted file]
docs/content/images/texture-atlas/example-javascript-code.jpg [deleted file]
docs/content/images/texture-atlas/image-wall.jpg [deleted file]
docs/content/images/texture-atlas/texture-packer-add-sprites.jpg [deleted file]
docs/content/images/texture-atlas/texture-packer-preferences.jpg [deleted file]
docs/content/images/texture-atlas/texture-packer-publish.jpg [deleted file]
docs/content/images/texture-atlas/texture-packer-startup.jpg [deleted file]
docs/content/main.md
docs/content/programming-guide/handle-body-idiom.h
docs/content/programming-guide/image-actor.h [deleted file]
docs/content/programming-guide/image-view.h
docs/content/programming-guide/properties.h
docs/content/programming-guide/scroll-view.h
docs/content/programming-guide/shader-intro.h
docs/content/programming-guide/size-negotiation.h
docs/content/programming-guide/type-registration.h
docs/content/shared-javascript-and-cpp-documentation/control-renderers.md
docs/content/shared-javascript-and-cpp-documentation/item-view.md
docs/content/shared-javascript-and-cpp-documentation/popup.md
docs/content/shared-javascript-and-cpp-documentation/resource-image-scaling.md
docs/content/shared-javascript-and-cpp-documentation/resources.md
docs/content/shared-javascript-and-cpp-documentation/script-json-specification.md
docs/content/shared-javascript-and-cpp-documentation/script-overview.md
docs/content/shared-javascript-and-cpp-documentation/texture-atlas.md [deleted file]
docs/content/shared-javascript-and-cpp-documentation/texture-compression.md [deleted file]
node-addon/binding.gyp
node-addon/examples/line-mesh.js
node-addon/examples/mesh-morph.js
node-addon/examples/point-mesh.js
node-addon/examples/scripts/item-template.json
node-addon/examples/texture-mesh.js
node-addon/item-template.json
packaging/dali-toolkit.spec
plugins/dali-script-v8/docs/content/animation.js
plugins/dali-script-v8/docs/content/image-view.js
plugins/dali-script-v8/docs/content/item-factory.js
plugins/dali-script-v8/src/animation/animation-api.cpp
plugins/dali-script-v8/src/rendering/geometry-api.cpp
plugins/dali-script-v8/src/rendering/geometry-wrapper.cpp
plugins/dali-script-v8/src/rendering/geometry-wrapper.h
plugins/dali-script-v8/src/rendering/texture-set-api.cpp
plugins/dali-script-v8/src/rendering/texture-set-wrapper.cpp
plugins/dali-script-v8/src/rendering/texture-set-wrapper.h

index 39d9377..b12e784 100644 (file)
@@ -2,4 +2,5 @@
 build
 build.log
 tct*core.h
+CMakeLists.txt
 results_xml.*
similarity index 65%
rename from automated-tests/CMakeLists.txt
rename to automated-tests/CMakeLists.txt.in
index 9e15203..0a0b958 100644 (file)
@@ -4,8 +4,10 @@ PROJECT(tct_coreapi_utc)
 INCLUDE(FindPkgConfig)
 SET(BIN_DIR "/opt/usr/bin")
 
+ADD_DEFINITIONS(-DDALI_STYLE_DIR="@dataReadOnlyDir@/toolkit/styles/")
+
 INCLUDE_DIRECTORIES(
-       src/common
+  src/common
 )
 
 ADD_SUBDIRECTORY(src)
index 4ec0eba..9f39bd2 100644 (file)
@@ -81,7 +81,6 @@ void ClearModelData( CharacterIndex characterIndex,
   logicalModel->mBidirectionalParagraphInfo.Clear();
   logicalModel->mCharacterDirections.Clear();
   logicalModel->mBidirectionalLineInfo.Clear();
-  logicalModel->mLogicalToVisualMap.Clear();
   logicalModel->mVisualToLogicalMap.Clear();
   visualModel->mGlyphs.Clear();
   visualModel->mGlyphsToCharacters.Clear();
@@ -90,7 +89,6 @@ void ClearModelData( CharacterIndex characterIndex,
   visualModel->mGlyphsPerCharacter.Clear();
   visualModel->mGlyphPositions.Clear();
   visualModel->mLines.Clear();
-  visualModel->mColorRuns.Clear();
 
   visualModel->ClearCaches();
 }
@@ -324,9 +322,7 @@ void CreateTextModel( const std::string& text,
     layoutParameters.numberOfBidirectionalInfoRuns = bidirectionalLineInfo.Count();
 
     // Set the bidirectional info into the model.
-    logicalModel->SetVisualToLogicalMap( layoutParameters.lineBidirectionalInfoRunsBuffer,
-                                         layoutParameters.numberOfBidirectionalInfoRuns,
-                                         0u,
+    logicalModel->SetVisualToLogicalMap( 0u,
                                          numberOfCharacters );
 
     if( options.reorder )
diff --git a/automated-tests/src/dali-toolkit-styling/CMakeLists.txt b/automated-tests/src/dali-toolkit-styling/CMakeLists.txt
new file mode 100644 (file)
index 0000000..92653f1
--- /dev/null
@@ -0,0 +1,83 @@
+SET(PKG_NAME "dali-toolkit-styling")
+
+SET(EXEC_NAME "tct-${PKG_NAME}-core")
+SET(RPM_NAME "core-${PKG_NAME}-tests")
+
+SET(CAPI_LIB "dali-toolkit-styling")
+
+# List of test case sources (Only these get parsed for test cases)
+SET(TC_SOURCES
+   utc-Dali-StyleManager.cpp
+)
+
+# Append list of test harness files (Won't get parsed for test cases)
+LIST(APPEND TC_SOURCES
+   ../dali-toolkit/dali-toolkit-test-utils/test-harness.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-application.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-bitmap-loader.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-color-controller.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-environment-variable.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-feedback-player.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-file-loader.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-imf-manager.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-orientation.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-physical-keyboard.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-style-monitor.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-singleton-service.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-sound-player.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-text-abstraction.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-timer.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard-event-notifier.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-tts-player.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-virtual-keyboard.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-animation-data.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-button.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-application.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-platform-abstraction.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-gesture-manager.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-render-controller.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-trace-call-stack.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-native-image.cpp
+)
+
+
+PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
+  dali-core
+  dali-toolkit
+)
+
+PKG_CHECK_MODULES(DALI_ADAPTOR REQUIRED
+  dali-adaptor
+)
+
+SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} -O0 -ggdb --coverage -Wall -Werror")
+
+ADD_DEFINITIONS(-DTEST_RESOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../resources\" )
+
+FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
+    SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
+ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS})
+
+INCLUDE_DIRECTORIES(
+    ../../../
+    ${${CAPI_LIB}_INCLUDE_DIRS}
+    ${DALI_ADAPTOR_INCLUDE_DIRS}
+    ../dali-toolkit/dali-toolkit-test-utils
+)
+
+ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
+TARGET_LINK_LIBRARIES(${EXEC_NAME}
+  ${${CAPI_LIB}_LIBRARIES}
+  -lpthread -ldl
+)
+
+INSTALL(PROGRAMS ${EXEC_NAME}
+    DESTINATION ${BIN_DIR}/${EXEC_NAME}
+)
diff --git a/automated-tests/src/dali-toolkit-styling/tct-dali-toolkit-styling-core.cpp b/automated-tests/src/dali-toolkit-styling/tct-dali-toolkit-styling-core.cpp
new file mode 100644 (file)
index 0000000..6e99684
--- /dev/null
@@ -0,0 +1,51 @@
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-toolkit-styling-core.h"
+
+int main(int argc, char * const argv[])
+{
+  int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
+
+  const char* optString = "rs";
+  bool optRerunFailed(true);
+  bool optRunSerially(false);
+
+  int nextOpt = 0;
+  do
+  {
+    nextOpt = getopt( argc, argv, optString );
+    switch(nextOpt)
+    {
+      case 'r':
+        optRerunFailed = true;
+        break;
+      case 's':
+        optRunSerially = true;
+        break;
+      case '?':
+        TestHarness::Usage(argv[0]);
+        exit(TestHarness::EXIT_STATUS_BAD_ARGUMENT);
+        break;
+    }
+  } while( nextOpt != -1 );
+
+  if( optind == argc ) // no testcase name in argument list
+  {
+    if( optRunSerially )
+    {
+      result = TestHarness::RunAll( argv[0], tc_array );
+    }
+    else
+    {
+      result = TestHarness::RunAllInParallel( argv[0], tc_array, optRerunFailed );
+    }
+  }
+  else
+  {
+    // optind is index of next argument - interpret as testcase name
+    result = TestHarness::FindAndRunTestCase(tc_array, argv[optind]);
+  }
+  return result;
+}
diff --git a/automated-tests/src/dali-toolkit-styling/utc-Dali-StyleManager.cpp b/automated-tests/src/dali-toolkit-styling/utc-Dali-StyleManager.cpp
new file mode 100644 (file)
index 0000000..d82faf3
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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.
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <dali-toolkit-test-suite-utils.h>
+#include <dali-toolkit/dali-toolkit.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali-toolkit/devel-api/builder/builder.h>
+#include <test-button.h>
+#include <test-animation-data.h>
+#include <toolkit-style-monitor.h>
+
+using namespace Dali;
+using namespace Dali::Toolkit;
+
+namespace
+{
+const char* defaultTheme =
+"{\n"
+"  \"styles\":\n"
+"  {\n"
+"    \"textlabel\":\n"
+"    {\n"
+"      \"pointSize\":18\n"
+"    },\n"
+"\n"
+"    \"textlabelFontSize0\":\n"
+"    {\n"
+"      \"pointSize\":8\n"
+"    },\n"
+"    \"textlabelFontSize1\":\n"
+"    {\n"
+"      \"pointSize\":10\n"
+"    },\n"
+"    \"textlabelFontSize2\":\n"
+"    {\n"
+"      \"pointSize\":15\n"
+"    },\n"
+"    \"textlabelFontSize3\":\n"
+"    {\n"
+"      \"pointSize\":19\n"
+"    },\n"
+"    \"textlabelFontSize4\":\n"
+"    {\n"
+"      \"pointSize\":25\n"
+"    },\n"
+"\n"
+"    \"textfield\":\n"
+"    {\n"
+"      \"pointSize\":18,\n"
+"      \"primaryCursorColor\":[0.0,0.72,0.9,1.0],\n"
+"      \"secondaryCursorColor\":[0.0,0.72,0.9,1.0],\n"
+"      \"cursorWidth\":3,\n"
+"      \"selectionHighlightColor\":[0.75,0.96,1.0,1.0],\n"
+"      \"grabHandleImage\" : \"{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png\",\n"
+"      \"selectionHandleImageLeft\" : {\"filename\":\"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png\" },\n"
+"      \"selectionHandleImageRight\": {\"filename\":\"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png\" }\n"
+"    },\n"
+"\n"
+"    \"textfieldFontSize0\":\n"
+"    {\n"
+"      \"pointSize\":10\n"
+"    },\n"
+"    \"textfieldFontSize1\":\n"
+"    {\n"
+"      \"pointSize\":10\n"
+"    },\n"
+"    \"textfieldFontSize2\":\n"
+"    {\n"
+"      \"pointSize\":10\n"
+"    },\n"
+"    \"textfieldFontSize3\":\n"
+"    {\n"
+"      \"pointSize\":10\n"
+"    },\n"
+"    \"textfieldFontSize4\":\n"
+"    {\n"
+"      \"pointSize\":10\n"
+"    },\n"
+"    \"textselectionpopup\":\n"
+"    {\n"
+"      \"popupMaxSize\":[656,72],\n"
+"      \"optionDividerSize\":[2,0],\n"
+"      \"popupDividerColor\":[0.23,0.72,0.8,0.11],\n"
+"      \"popupIconColor\":[1.0,1.0,1.0,1.0],\n"
+"      \"popupPressedColor\":[0.24,0.72,0.8,0.11],\n"
+"      \"background\": {\n"
+"        \"rendererType\": \"nPatch\",\n"
+"        \"imageUrl\": \"{DALI_IMAGE_DIR}selection-popup-bg.9.png\"\n"
+"        },\n"
+"      \"popupFadeInDuration\":0.25,\n"
+"      \"popupFadeOutDuration\":0.25\n"
+"    },\n"
+"    \"textselectionpopupbutton\":\n"
+"    {\n"
+"      \"label\":\n"
+"      {\n"
+"        \"pointSize\":8,\n"
+"        \"fontStyle\":\"{\\\\""weight\\\\"":\\\\""light\\\\""}\"\n"
+"      }\n"
+"    },\n"
+"    \"textselectiontoolbar\":\n"
+"    {\n"
+"      \"enableOvershoot\":true,\n"
+"      \"scrollView\":\n"
+"      {\n"
+"        \"overshootAnimationSpeed\":360.0,\n"
+"        \"overshootSize\":[720.0,130.0]\n"
+"      }\n"
+"    },\n"
+"    \"scrollview\":\n"
+"    {\n"
+"      \"overshootEffectColor\":\"B018\",\n"
+"      \"overshootAnimationSpeed\":360.0,\n"
+"      \"overshootSize\":[720.0,130.0]\n"
+"    },\n"
+"    \"itemview\":\n"
+"    {\n"
+"      \"overshootEffectColor\":\"B018\",\n"
+"      \"overshootAnimationSpeed\":360.0,\n"
+"      \"overshootSize\":[720.0,130.0]\n"
+"    },\n"
+"    \"texteditor\":\n"
+"    {\n"
+"      \"pointSize\":18,\n"
+"      \"primaryCursorColor\":[0.0,0.72,0.9,1.0],\n"
+"      \"secondaryCursorColor\":[0.0,0.72,0.9,1.0],\n"
+"      \"cursorWidth\":3,\n"
+"      \"selectionHighlightColor\":[0.75,0.96,1.0,1.0],\n"
+"      \"grabHandleImage\" : \"{DALI_STYLE_IMAGE_DIR}cursor_handler_drop_center.png\",\n"
+"      \"selectionHandleImageLeft\" : {\"filename\":\"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_left.png\" },\n"
+"      \"selectionHandleImageRight\": {\"filename\":\"{DALI_STYLE_IMAGE_DIR}selection_handle_drop_right.png\" }\n"
+"    }\n"
+"  }\n"
+"}\n";
+
+} // anonymous namespace
+
+
+
+void dali_style_manager_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void dali_style_manager_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+
+int UtcDaliStyleManagerConstructorP(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliStyleManagerConstructorP");
+  StyleManager styleManager;
+  DALI_TEST_CHECK( !styleManager);
+  END_TEST;
+}
+
+int UtcDaliStyleManagerCopyConstructorP(void)
+{
+  TestApplication application;
+
+  StyleManager styleManager = StyleManager::Get();
+  StyleManager copyOfStyleManager( styleManager );
+
+  DALI_TEST_CHECK( copyOfStyleManager );
+  END_TEST;
+}
+
+int UtcDaliStyleManagerAssignmentOperatorP(void)
+{
+  TestApplication application;
+
+  StyleManager styleManager = StyleManager::Get();
+  StyleManager copyOfStyleManager = styleManager;
+
+  DALI_TEST_CHECK( copyOfStyleManager );
+  DALI_TEST_CHECK( copyOfStyleManager == styleManager );
+  END_TEST;
+}
+
+int UtcDaliStyleManagerGet(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline(" UtcDaliStyleManagerGet");
+
+  // Register Type
+  TypeInfo type;
+  type = TypeRegistry::Get().GetTypeInfo( "StyleManager" );
+  DALI_TEST_CHECK( type );
+  BaseHandle handle = type.CreateInstance();
+  DALI_TEST_CHECK( handle );
+
+  StyleManager manager;
+
+  manager = StyleManager::Get();
+  DALI_TEST_CHECK(manager);
+
+  StyleManager newManager = StyleManager::Get();
+  DALI_TEST_CHECK(newManager);
+
+  // Check that focus manager is a singleton
+  DALI_TEST_CHECK(manager == newManager);
+  END_TEST;
+}
+
+
+namespace
+{
+class StyleChangedSignalChecker : public ConnectionTracker
+{
+public:
+  StyleChangedSignalChecker()
+  : signalCount(0)
+  {
+  }
+
+  void OnStyleChanged(StyleManager styleManager, StyleChange::Type type)
+  {
+    signalCount++;
+  }
+
+  void Reset()
+  {
+    signalCount =0;
+  }
+
+public:
+  int signalCount;
+};
+
+} // anonymous namespace
+
+int UtcDaliStyleManagerApplyTheme(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "Testing StyleManager ApplyTheme" );
+
+  const char* json1 =
+    "{\n"
+    "  \"styles\":\n"
+    "  {\n"
+    "    \"testbutton\":\n"
+    "    {\n"
+    "      \"backgroundColor\":[1.0,1.0,0.0,1.0],\n"
+    "      \"foregroundColor\":[0.0,0.0,1.0,1.0]\n"
+    "    }\n"
+    "  }\n"
+    "}\n";
+
+  const char* json2 =
+    "{\n"
+    "  \"styles\":\n"
+    "  {\n"
+    "    \"testbutton\":\n"
+    "    {\n"
+    "      \"backgroundColor\":[1.0,0.0,0.0,1.0],\n"
+    "      \"foregroundColor\":[0.0,1.0,1.0,1.0]\n"
+    "    }\n"
+    "  }\n"
+    "}\n";
+
+  // Add 2 buttons to test how many times the signal is sent
+  Test::TestButton testButton = Test::TestButton::New();
+  Test::TestButton testButton2 = Test::TestButton::New();
+  Stage::GetCurrent().Add( testButton );
+  Stage::GetCurrent().Add( testButton2 );
+  StyleChangedSignalChecker styleChangedSignalHandler;
+  StyleChangedSignalChecker styleChangedSignalHandler2;
+  StyleManager styleManager = StyleManager::Get();
+
+  styleManager.StyleChangedSignal().Connect(&styleChangedSignalHandler, &StyleChangedSignalChecker::OnStyleChanged);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("Apply the style");
+
+  std::string themeFile("ThemeOne");
+  Test::StyleMonitor::SetThemeFileOutput(themeFile, json1);
+  StyleManager::Get().ApplyTheme(themeFile);
+
+  Property::Value bgColor( testButton.GetProperty(Test::TestButton::Property::BACKGROUND_COLOR) );
+  Property::Value fgColor( testButton.GetProperty(Test::TestButton::Property::FOREGROUND_COLOR) );
+
+  DALI_TEST_EQUALS( bgColor, Property::Value(Color::YELLOW), 0.001, TEST_LOCATION );
+  DALI_TEST_EQUALS( fgColor, Property::Value(Color::BLUE), 0.001, TEST_LOCATION );
+
+  tet_infoline("Testing that the signal handler is called only once");
+  DALI_TEST_EQUALS( styleChangedSignalHandler.signalCount, 1, TEST_LOCATION );
+
+  tet_infoline("Override the background property");
+  testButton.SetProperty( Test::TestButton::Property::BACKGROUND_COLOR, Color::GREEN );
+  bgColor = testButton.GetProperty(Test::TestButton::Property::BACKGROUND_COLOR);
+  fgColor = testButton.GetProperty(Test::TestButton::Property::FOREGROUND_COLOR);
+  DALI_TEST_EQUALS( bgColor, Property::Value(Color::GREEN), 0.001, TEST_LOCATION );
+  DALI_TEST_EQUALS( fgColor, Property::Value(Color::BLUE), 0.001, TEST_LOCATION );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  tet_infoline("Apply the style again");
+
+  styleChangedSignalHandler.signalCount = 0;
+  StyleManager::Get().ApplyTheme(themeFile);
+
+  bgColor = testButton.GetProperty(Test::TestButton::Property::BACKGROUND_COLOR);
+  fgColor = testButton.GetProperty(Test::TestButton::Property::FOREGROUND_COLOR);
+
+  tet_infoline("Check that the property is changed");
+  DALI_TEST_EQUALS( bgColor, Property::Value(Color::YELLOW), 0.001, TEST_LOCATION );
+  DALI_TEST_EQUALS( fgColor, Property::Value(Color::BLUE), 0.001, TEST_LOCATION );
+  tet_infoline("Testing that the signal handler is called only once");
+  DALI_TEST_EQUALS( styleChangedSignalHandler.signalCount, 1, TEST_LOCATION );
+
+  tet_infoline( "Load a different stylesheet");
+
+  tet_infoline("Apply the new style");
+  std::string themeFile2("ThemeTwo");
+  Test::StyleMonitor::SetThemeFileOutput(themeFile2, json2);
+
+  styleChangedSignalHandler.signalCount = 0;
+  StyleManager::Get().ApplyTheme(themeFile2);
+
+  bgColor = testButton.GetProperty(Test::TestButton::Property::BACKGROUND_COLOR);
+  fgColor = testButton.GetProperty(Test::TestButton::Property::FOREGROUND_COLOR);
+
+  tet_infoline("Check that the properties change, but the signal gets sent only once");
+  DALI_TEST_EQUALS( bgColor, Property::Value(Color::RED), 0.001, TEST_LOCATION );
+  DALI_TEST_EQUALS( fgColor, Property::Value(Color::CYAN), 0.001, TEST_LOCATION );
+  DALI_TEST_EQUALS( styleChangedSignalHandler.signalCount, 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliStyleManagerApplyDefaultTheme(void)
+{
+  tet_infoline( "Testing StyleManager ApplyTheme" );
+
+  const char* defaultTheme =
+    "{\n"
+    "  \"styles\":\n"
+    "  {\n"
+    "    \"testbutton\":\n"
+    "    {\n"
+    "      \"backgroundColor\":[1.0,1.0,0.0,1.0],\n"
+    "      \"foregroundColor\":[0.0,0.0,1.0,1.0]\n"
+    "    }\n"
+    "  }\n"
+    "}\n";
+  // Bg: Yellow, Fg: Blue
+
+  const char* appTheme =
+    "{\n"
+    "  \"styles\":\n"
+    "  {\n"
+    "    \"testbutton\":\n"
+    "    {\n"
+    "      \"backgroundColor\":[1.0,0.0,1.0,1.0],\n"
+    "      \"foregroundColor\":[0.0,1.0,0.0,1.0]\n"
+    "    }\n"
+    "  }\n"
+    "}\n";
+  // Bg::Magenta, Fg:Green
+
+  std::string filepath(TEST_RESOURCE_DIR "");
+
+  Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json",
+                                          defaultTheme);
+  ToolkitTestApplication application;
+
+  Test::TestButton testButton = Test::TestButton::New();
+  Stage::GetCurrent().Add( testButton );
+  StyleChangedSignalChecker styleChangedSignalHandler;
+  StyleManager styleManager = StyleManager::Get();
+
+  styleManager.StyleChangedSignal().Connect(&styleChangedSignalHandler, &StyleChangedSignalChecker::OnStyleChanged);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  // Get the default:
+  Property::Value defaultBgColor( testButton.GetProperty(Test::TestButton::Property::BACKGROUND_COLOR) );
+  Property::Value defaultFgColor( testButton.GetProperty(Test::TestButton::Property::FOREGROUND_COLOR) );
+
+  tet_infoline("Apply the style");
+
+  std::string themeFile("ThemeOne");
+  Test::StyleMonitor::SetThemeFileOutput(themeFile, appTheme);
+  StyleManager::Get().ApplyTheme(themeFile);
+
+  Property::Value bgColor( testButton.GetProperty(Test::TestButton::Property::BACKGROUND_COLOR) );
+  Property::Value fgColor( testButton.GetProperty(Test::TestButton::Property::FOREGROUND_COLOR) );
+
+  DALI_TEST_EQUALS( bgColor, Property::Value(Color::MAGENTA), 0.001, TEST_LOCATION );
+  DALI_TEST_EQUALS( fgColor, Property::Value(Color::GREEN), 0.001, TEST_LOCATION );
+
+  tet_infoline("Testing that the signal handler is called only once");
+  DALI_TEST_EQUALS( styleChangedSignalHandler.signalCount, 1, TEST_LOCATION );
+  tet_infoline("Revert the style");
+
+  styleChangedSignalHandler.signalCount = 0;
+  StyleManager::Get().ApplyDefaultTheme();
+
+  bgColor = testButton.GetProperty(Test::TestButton::Property::BACKGROUND_COLOR);
+  fgColor = testButton.GetProperty(Test::TestButton::Property::FOREGROUND_COLOR);
+
+  tet_infoline("Check that the property is reverted");
+  DALI_TEST_EQUALS( bgColor, defaultBgColor, 0.001, TEST_LOCATION );
+  DALI_TEST_EQUALS( fgColor, defaultFgColor, 0.001, TEST_LOCATION );
+  DALI_TEST_EQUALS( bgColor, Property::Value(Color::YELLOW), 0.001, TEST_LOCATION );
+  DALI_TEST_EQUALS( fgColor, Property::Value(Color::BLUE), 0.001, TEST_LOCATION );
+  tet_infoline("Testing that the signal handler is called only once");
+  DALI_TEST_EQUALS( styleChangedSignalHandler.signalCount, 1, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliStyleManagerSetStyleConstantP(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( " UtcDaliStyleManagerSetStyleConstantP" );
+
+  StyleManager manager = StyleManager::Get();
+
+  std::string key( "key" );
+  Property::Value value( 100 );
+
+  manager.SetStyleConstant( key, value );
+
+  Property::Value returnedValue;
+  manager.GetStyleConstant( key, returnedValue );
+
+  DALI_TEST_CHECK( value.Get<int>() == returnedValue.Get<int>() );
+  END_TEST;
+}
+
+
+int UtcDaliStyleManagerGetStyleConstantP(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( " UtcDaliStyleManagerGetStyleConstantP" );
+
+  StyleManager manager = StyleManager::Get();
+
+  std::string key( "key" );
+  Property::Value value( 100 );
+
+  manager.SetStyleConstant( key, value );
+
+  Property::Value returnedValue;
+  manager.GetStyleConstant( key, returnedValue );
+
+  DALI_TEST_CHECK( value.Get<int>() == returnedValue.Get<int>() );
+  END_TEST;
+}
+
+int UtcDaliStyleManagerGetStyleConstantN(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( " UtcDaliStyleManagerGetStyleConstantN" );
+
+  StyleManager manager = StyleManager::Get();
+
+  std::string key2( "key2" );
+  Property::Value returnedValue2;
+  DALI_TEST_CHECK( !manager.GetStyleConstant( key2, returnedValue2 ) );
+
+  END_TEST;
+}
+
+int UtcDaliStyleManagerApplyStyle(void)
+{
+  ToolkitTestApplication application;
+
+  tet_infoline( "UtcDaliStyleManagerApplyStyle - test that a style can be applied to a single button" );
+
+  const char* json1 =
+    "{\n"
+    "  \"styles\":\n"
+    "  {\n"
+    "    \"testbutton\":\n"
+    "    {\n"
+    "      \"backgroundColor\":[1.0,1.0,0.0,1.0],\n"
+    "      \"foregroundColor\":[0.0,0.0,1.0,1.0]\n"
+    "    }\n"
+    "  }\n"
+    "}\n";
+
+  const char* json2 =
+    "{\n"
+    "  \"styles\":\n"
+    "  {\n"
+    "    \"testbutton\":\n"
+    "    {\n"
+    "      \"backgroundColor\":[1.0,0.0,0.0,1.0],\n"
+    "      \"foregroundColor\":[0.0,1.0,1.0,1.0]\n"
+    "    }\n"
+    "  }\n"
+    "}\n";
+
+  // Add 2 buttons
+  Test::TestButton testButton = Test::TestButton::New();
+  Test::TestButton testButton2 = Test::TestButton::New();
+  Stage::GetCurrent().Add( testButton );
+  Stage::GetCurrent().Add( testButton2 );
+  StyleChangedSignalChecker styleChangedSignalHandler;
+  StyleManager styleManager = StyleManager::Get();
+
+  styleManager.StyleChangedSignal().Connect(&styleChangedSignalHandler, &StyleChangedSignalChecker::OnStyleChanged);
+
+  tet_infoline("Apply the style");
+
+  std::string themeFile("ThemeOne");
+  Test::StyleMonitor::SetThemeFileOutput(themeFile, json1);
+  styleManager.ApplyTheme(themeFile);
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Property::Value themedBgColor( testButton.GetProperty(Test::TestButton::Property::BACKGROUND_COLOR) );
+  Property::Value themedFgColor( testButton.GetProperty(Test::TestButton::Property::FOREGROUND_COLOR) );
+
+  // Apply the style to the test button:
+  std::string themeFile2("ThemeTwo");
+  Test::StyleMonitor::SetThemeFileOutput(themeFile2, json2);
+  styleManager.ApplyStyle( testButton, themeFile2, "testbutton" );
+
+  tet_infoline("Check that the properties change for the first button");
+  Property::Value bgColor = testButton.GetProperty(Test::TestButton::Property::BACKGROUND_COLOR);
+  Property::Value fgColor = testButton.GetProperty(Test::TestButton::Property::FOREGROUND_COLOR);
+  DALI_TEST_EQUALS( bgColor, Property::Value(Color::RED), 0.001, TEST_LOCATION );
+  DALI_TEST_EQUALS( fgColor, Property::Value(Color::CYAN), 0.001, TEST_LOCATION );
+
+  DALI_TEST_NOT_EQUALS( bgColor, themedBgColor, 0.001, TEST_LOCATION );
+  DALI_TEST_NOT_EQUALS( fgColor, themedFgColor, 0.001, TEST_LOCATION );
+
+  tet_infoline("Check that the properties remain the same for the second button");
+  bgColor = testButton2.GetProperty(Test::TestButton::Property::BACKGROUND_COLOR);
+  fgColor = testButton2.GetProperty(Test::TestButton::Property::FOREGROUND_COLOR);
+  DALI_TEST_EQUALS( bgColor, themedBgColor, 0.001, TEST_LOCATION );
+  DALI_TEST_EQUALS( fgColor, themedFgColor, 0.001, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliStyleManagerStyleChangedSignal(void)
+{
+  tet_infoline("Test that the StyleChange signal is fired when the font size is altered" );
+  Test::StyleMonitor::SetThemeFileOutput( DALI_STYLE_DIR "dali-toolkit-default-theme.json",
+                                          defaultTheme );
+
+  ToolkitTestApplication application;
+
+  std::string labelStr("Label");
+  Toolkit::TextLabel label = Toolkit::TextLabel::New(labelStr);
+  Stage::GetCurrent().Add( label );
+
+  Toolkit::TextLabel label2 = Toolkit::TextLabel::New(labelStr);
+  Stage::GetCurrent().Add( label2 );
+
+  StyleChangedSignalChecker styleChangedSignalHandler;
+  StyleMonitor styleMonitor = StyleMonitor::Get();
+  StyleManager styleManager = StyleManager::Get();
+
+  styleManager.StyleChangedSignal().Connect(&styleChangedSignalHandler, &StyleChangedSignalChecker::OnStyleChanged);
+
+  Test::StyleMonitor::SetDefaultFontFamily("Times New Roman");
+
+  styleMonitor.StyleChangeSignal().Emit( styleMonitor,  StyleChange::DEFAULT_FONT_CHANGE);
+
+  tet_infoline("Test that the StyleChanged signal is received only once");
+
+  DALI_TEST_EQUALS( styleChangedSignalHandler.signalCount, 1, TEST_LOCATION );
+
+  // Check that the label's font style has been altered
+  Property::Value family = label.GetProperty(TextLabel::Property::FONT_FAMILY);
+  std::string familyStr;
+  family.Get( familyStr );
+
+  DALI_TEST_EQUALS( familyStr, "Times New Roman", TEST_LOCATION);
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/CMakeLists.txt b/automated-tests/src/dali-toolkit-third-party/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ea5ce5c
--- /dev/null
@@ -0,0 +1,73 @@
+SET(PKG_NAME "dali-toolkit-third-party")
+
+SET(EXEC_NAME "tct-${PKG_NAME}-core")
+SET(RPM_NAME "core-${PKG_NAME}-tests")
+
+SET(CAPI_LIB "dali-toolkit-third-party")
+
+# List of test case sources (Only these get parsed for test cases)
+SET(TC_SOURCES
+ utc-Dali-Flexbox-Layout.cpp
+)
+
+# Append list of test harness files (Won't get parsed for test cases)
+LIST(APPEND TC_SOURCES
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-accessibility-adaptor.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-application.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-clipboard-event-notifier.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-event-thread-callback.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-environment-variable.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-imf-manager.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-orientation.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-physical-keyboard.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-style-monitor.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-singleton-service.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-timer.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/toolkit-tts-player.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/dali-test-suite-utils.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/dummy-control.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/mesh-builder.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-actor-utils.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-animation-data.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-application.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-button.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-harness.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-gesture-manager.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-gl-abstraction.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-gl-sync-abstraction.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-platform-abstraction.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-render-controller.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-trace-call-stack.cpp
+   ../dali-toolkit/dali-toolkit-test-utils/test-native-image.cpp
+   facebook-flexbox/layout-test-utils.c
+)
+
+
+PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
+    dali-core
+    dali-adaptor
+    dali-toolkit
+)
+
+SET(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} -O0 -ggdb --coverage -Wall -Werror")
+
+FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
+    SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
+ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS})
+
+INCLUDE_DIRECTORIES(
+    ../../../
+    ${${CAPI_LIB}_INCLUDE_DIRS}
+    ../dali-toolkit/dali-toolkit-test-utils
+)
+
+ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
+TARGET_LINK_LIBRARIES(${EXEC_NAME}
+    ${${CAPI_LIB}_LIBRARIES}
+    -lpthread
+)
+
+INSTALL(PROGRAMS ${EXEC_NAME}
+    DESTINATION ${BIN_DIR}/${EXEC_NAME}
+)
diff --git a/automated-tests/src/dali-toolkit-third-party/facebook-flexbox/layout-test-utils.c b/automated-tests/src/dali-toolkit-third-party/facebook-flexbox/layout-test-utils.c
new file mode 100644 (file)
index 0000000..58c42c4
--- /dev/null
@@ -0,0 +1,8461 @@
+/**
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+#include "layout-test-utils.h"
+#include <stdlib.h>
+
+#ifdef _MSC_VER
+#include <float.h>
+#define isnan _isnan
+
+/* define fmaxf & fminf if < VC12 */
+#if _MSC_VER < 1800
+inline float fmaxf(const float a, const float b) {
+  return (a > b) ? a : b;
+}
+inline float fminf(const float a, const float b) {
+  return (a < b) ? a : b;
+}
+#endif
+#endif
+
+  /** START_GENERATED **/
+#define SMALL_WIDTH 35
+#define SMALL_HEIGHT 18
+#define BIG_WIDTH 172
+#define BIG_HEIGHT 36
+#define BIG_MIN_WIDTH 100
+#define SMALL_TEXT "small"
+#define LONG_TEXT "loooooooooong with space"
+#define MEASURE_WITH_RATIO_2 "measureWithRatio2"
+#define MEASURE_WITH_MATCH_PARENT "measureWithMatchParent"
+  /** END_GENERATED **/
+
+typedef struct failed_test_t {
+  struct failed_test_t *next;
+  const char *name;
+  css_node_t *style;
+  css_node_t *expected;
+} failed_test_t;
+
+static failed_test_t *failed_test_head = NULL;
+static failed_test_t *failed_test_tail = NULL;
+static void add_failed_test(const char *name, css_node_t *style, css_node_t *expected) {
+  failed_test_t *failed_test = (failed_test_t *)malloc(sizeof(failed_test_t));
+  failed_test->next = NULL;
+  failed_test->name = name;
+  failed_test->style = style;
+  failed_test->expected = expected;
+
+  if (!failed_test_head) {
+    failed_test_head = failed_test;
+    failed_test_tail = failed_test;
+  } else {
+    failed_test_tail->next = failed_test;
+    failed_test_tail = failed_test;
+  }
+}
+
+static bool eq(float a, float b) {
+  return fabs(a - b) < 0.0001;
+}
+
+static bool are_layout_equal(css_node_t *a, css_node_t *b) {
+  if (!eq(a->layout.dimensions[CSS_WIDTH], b->layout.dimensions[CSS_WIDTH]) ||
+      !eq(a->layout.dimensions[CSS_HEIGHT], b->layout.dimensions[CSS_HEIGHT]) ||
+      !eq(a->layout.position[CSS_TOP], b->layout.position[CSS_TOP]) ||
+      !eq(a->layout.position[CSS_LEFT], b->layout.position[CSS_LEFT]) ||
+      !eq(a->children_count, b->children_count)) {
+    return false;
+  }
+  int i;
+  for (i = 0; i < a->children_count; ++i) {
+    if (!are_layout_equal(a->get_child(a->context, i), b->get_child(b->context, i))) {
+      return false;
+    }
+  }
+  return true;
+}
+
+css_dim_t measure(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode) {
+  const char *text = (const char *)context;
+  css_dim_t dim;
+  if (strcmp(text, SMALL_TEXT) == 0) {
+    if (widthMode == CSS_MEASURE_MODE_UNDEFINED) {
+      width = 1000000;
+    }
+    dim.dimensions[CSS_WIDTH] = fminf(SMALL_WIDTH, width);
+    dim.dimensions[CSS_HEIGHT] = SMALL_HEIGHT;
+    return dim;
+  }
+  if (strcmp(text, LONG_TEXT) == 0) {
+    if (widthMode == CSS_MEASURE_MODE_UNDEFINED) {
+      width = 1000000;
+    }
+    dim.dimensions[CSS_WIDTH] = width >= BIG_WIDTH ? BIG_WIDTH : fmaxf(BIG_MIN_WIDTH, width);
+    dim.dimensions[CSS_HEIGHT] = width >= BIG_WIDTH ? SMALL_HEIGHT : BIG_HEIGHT;
+    return dim;
+  }
+
+  if (strcmp(text, MEASURE_WITH_RATIO_2) == 0) {
+    if (widthMode != CSS_MEASURE_MODE_UNDEFINED) {
+      dim.dimensions[CSS_WIDTH] = width;
+      dim.dimensions[CSS_HEIGHT] = width * 2;
+    } else if (heightMode != CSS_MEASURE_MODE_UNDEFINED) {
+      dim.dimensions[CSS_WIDTH] = height * 2;
+      dim.dimensions[CSS_HEIGHT] = height;
+    } else {
+      dim.dimensions[CSS_WIDTH] = 99999;
+      dim.dimensions[CSS_HEIGHT] = 99999;
+    }
+    return dim;
+  }
+
+  if (strcmp(text, MEASURE_WITH_MATCH_PARENT) == 0) {
+    if (widthMode == CSS_MEASURE_MODE_UNDEFINED) {
+      width = 99999;
+    }
+    if (heightMode == CSS_MEASURE_MODE_UNDEFINED) {
+      height = 99999;
+    }
+    dim.dimensions[CSS_WIDTH] = width;
+    dim.dimensions[CSS_HEIGHT] = height;
+    return dim;
+  }
+
+  // Should not go here
+  dim.dimensions[CSS_WIDTH] = CSS_UNDEFINED;
+  dim.dimensions[CSS_HEIGHT] = CSS_UNDEFINED;
+  return dim;
+}
+
+static int test_ran_count = 0;
+void test(const char *name, css_node_t *style, css_node_t *expected_layout) {
+  ++test_ran_count;
+  layoutNode(style, CSS_UNDEFINED, CSS_UNDEFINED, (css_direction_t)-1);
+
+  if (!are_layout_equal(style, expected_layout)) {
+    printf("%sF%s", "\x1B[31m", "\x1B[0m");
+    add_failed_test(name, style, expected_layout);
+  } else {
+    printf("%s.%s", "\x1B[32m", "\x1B[0m");
+    free_css_node(style);
+    free_css_node(expected_layout);
+  }
+}
+
+bool tests_finished() {
+  failed_test_t *failed_test = failed_test_head;
+  printf("\n");
+
+  int tests_failed = 0;
+  while (failed_test) {
+    printf("%sFAIL%s %s\n", "\x1B[31m", "\x1B[0m", failed_test->name);
+
+    printf("Input:    ");
+    print_css_node(failed_test->style, (css_print_options_t)(CSS_PRINT_STYLE | CSS_PRINT_CHILDREN));
+    printf("Output:   ");
+    print_css_node(failed_test->style, (css_print_options_t)(CSS_PRINT_LAYOUT | CSS_PRINT_CHILDREN));
+
+    printf("Expected: ");
+    print_css_node(failed_test->expected, (css_print_options_t)(CSS_PRINT_LAYOUT | CSS_PRINT_CHILDREN));
+
+    free_css_node(failed_test->style);
+    free_css_node(failed_test->expected);
+
+    failed_test_t *next_failed_test = failed_test->next;
+    free(failed_test);
+    failed_test = next_failed_test;
+
+    tests_failed++;
+  }
+  printf("\n\n");
+
+  if (tests_failed > 0) {
+    printf("TESTS FAILED: %d\n", tests_failed);
+    return false;
+  } else {
+    printf("ALL TESTS PASSED: %d tests ran.\n", test_ran_count);
+    return true;
+  }
+}
+
+static css_node_t* get_child(void *context, int i) {
+  css_node_t* children = (css_node_t*)context;
+  return &children[i];
+}
+
+static bool is_dirty(void *context) {
+  (void)context; // remove unused warning
+  return true;
+}
+
+static void init_test_css_node(css_node_t *node) {
+  node->get_child = get_child;
+  node->is_dirty = is_dirty;
+}
+
+css_node_t *new_test_css_node(void) {
+  css_node_t *node = new_css_node();
+  init_test_css_node(node);
+  return node;
+}
+
+void init_css_node_children(css_node_t *node, int children_count) {
+  node->context = calloc((size_t)children_count, sizeof(css_node_t));
+  int i;
+  for (i = 0; i < children_count; ++i) {
+    init_css_node(node->get_child(node->context, i));
+    init_test_css_node(node->get_child(node->context, i));
+  }
+  node->children_count = children_count;
+}
+
+// @generated by transpile.html
+
+bool perform_layout_test()
+{
+  /** START_GENERATED **/
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+    }
+
+    test("should layout a single node with width and height", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 500;
+        node_1->style.dimensions[CSS_HEIGHT] = 500;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 250;
+        node_1->style.dimensions[CSS_HEIGHT] = 250;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.dimensions[CSS_WIDTH] = 125;
+        node_1->style.dimensions[CSS_HEIGHT] = 125;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 500;
+        node_1->layout.dimensions[CSS_HEIGHT] = 500;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 500;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 250;
+        node_1->layout.dimensions[CSS_HEIGHT] = 250;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 750;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 125;
+        node_1->layout.dimensions[CSS_HEIGHT] = 125;
+      }
+    }
+
+    test("should layout node with children", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 500;
+        node_1->style.dimensions[CSS_HEIGHT] = 500;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 250;
+        node_1->style.dimensions[CSS_HEIGHT] = 250;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.dimensions[CSS_WIDTH] = 125;
+        node_1->style.dimensions[CSS_HEIGHT] = 125;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 500;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 500;
+        node_1->layout.dimensions[CSS_HEIGHT] = 500;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 250;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 250;
+        node_1->layout.dimensions[CSS_HEIGHT] = 250;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 125;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 125;
+        node_1->layout.dimensions[CSS_HEIGHT] = 125;
+      }
+    }
+
+    test("should layout node with children in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 500;
+        node_1->style.dimensions[CSS_HEIGHT] = 500;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 500;
+        node_1->style.dimensions[CSS_HEIGHT] = 500;
+        init_css_node_children(node_1, 2);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.dimensions[CSS_WIDTH] = 250;
+          node_2->style.dimensions[CSS_HEIGHT] = 250;
+          node_2 = node_1->get_child(node_1->context, 1);
+          node_2->style.dimensions[CSS_WIDTH] = 250;
+          node_2->style.dimensions[CSS_HEIGHT] = 250;
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 500;
+        node_1->layout.dimensions[CSS_HEIGHT] = 500;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 500;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 500;
+        node_1->layout.dimensions[CSS_HEIGHT] = 500;
+        init_css_node_children(node_1, 2);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 250;
+          node_2->layout.dimensions[CSS_HEIGHT] = 250;
+          node_2 = node_1->get_child(node_1->context, 1);
+          node_2->layout.position[CSS_TOP] = 250;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 250;
+          node_2->layout.dimensions[CSS_HEIGHT] = 250;
+        }
+      }
+    }
+
+    test("should layout node with nested children", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 500;
+        node_1->style.dimensions[CSS_HEIGHT] = 500;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+        node_1->style.dimensions[CSS_WIDTH] = 500;
+        node_1->style.dimensions[CSS_HEIGHT] = 500;
+        init_css_node_children(node_1, 2);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.dimensions[CSS_WIDTH] = 250;
+          node_2->style.dimensions[CSS_HEIGHT] = 250;
+          node_2 = node_1->get_child(node_1->context, 1);
+          node_2->style.dimensions[CSS_WIDTH] = 250;
+          node_2->style.dimensions[CSS_HEIGHT] = 250;
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 500;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 500;
+        node_1->layout.dimensions[CSS_HEIGHT] = 500;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 500;
+        node_1->layout.dimensions[CSS_HEIGHT] = 500;
+        init_css_node_children(node_1, 2);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 250;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 250;
+          node_2->layout.dimensions[CSS_HEIGHT] = 250;
+          node_2 = node_1->get_child(node_1->context, 1);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 250;
+          node_2->layout.dimensions[CSS_HEIGHT] = 250;
+        }
+      }
+    }
+
+    test("should layout node with nested children in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      node_0->style.margin[CSS_LEFT] = 10;
+      node_0->style.margin[CSS_TOP] = 10;
+      node_0->style.margin[CSS_RIGHT] = 10;
+      node_0->style.margin[CSS_BOTTOM] = 10;
+      node_0->style.margin[CSS_START] = 10;
+      node_0->style.margin[CSS_END] = 10;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 10;
+      node_0->layout.position[CSS_LEFT] = 10;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+    }
+
+    test("should layout node with margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      node_0->style.margin[CSS_LEFT] = 10;
+      node_0->style.margin[CSS_TOP] = 10;
+      node_0->style.margin[CSS_RIGHT] = 10;
+      node_0->style.margin[CSS_BOTTOM] = 10;
+      node_0->style.margin[CSS_START] = 10;
+      node_0->style.margin[CSS_END] = 10;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.margin[CSS_LEFT] = 50;
+        node_1->style.margin[CSS_TOP] = 50;
+        node_1->style.margin[CSS_RIGHT] = 50;
+        node_1->style.margin[CSS_BOTTOM] = 50;
+        node_1->style.margin[CSS_START] = 50;
+        node_1->style.margin[CSS_END] = 50;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.margin[CSS_LEFT] = 25;
+        node_1->style.margin[CSS_TOP] = 25;
+        node_1->style.margin[CSS_RIGHT] = 25;
+        node_1->style.margin[CSS_BOTTOM] = 25;
+        node_1->style.margin[CSS_START] = 25;
+        node_1->style.margin[CSS_END] = 25;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 10;
+      node_0->layout.position[CSS_LEFT] = 10;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 50;
+        node_1->layout.position[CSS_LEFT] = 50;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 225;
+        node_1->layout.position[CSS_LEFT] = 25;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 360;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with several children", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      node_0->style.margin[CSS_LEFT] = 10;
+      node_0->style.margin[CSS_TOP] = 10;
+      node_0->style.margin[CSS_RIGHT] = 10;
+      node_0->style.margin[CSS_BOTTOM] = 10;
+      node_0->style.margin[CSS_START] = 10;
+      node_0->style.margin[CSS_END] = 10;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.margin[CSS_LEFT] = 50;
+        node_1->style.margin[CSS_TOP] = 50;
+        node_1->style.margin[CSS_RIGHT] = 50;
+        node_1->style.margin[CSS_BOTTOM] = 50;
+        node_1->style.margin[CSS_START] = 50;
+        node_1->style.margin[CSS_END] = 50;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.margin[CSS_LEFT] = 25;
+        node_1->style.margin[CSS_TOP] = 25;
+        node_1->style.margin[CSS_RIGHT] = 25;
+        node_1->style.margin[CSS_BOTTOM] = 25;
+        node_1->style.margin[CSS_START] = 25;
+        node_1->style.margin[CSS_END] = 25;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 10;
+      node_0->layout.position[CSS_LEFT] = 10;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 850;
+        node_1->layout.position[CSS_LEFT] = 50;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 675;
+        node_1->layout.position[CSS_LEFT] = 25;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 540;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with several children in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW_REVERSE;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 300;
+        node_1->style.dimensions[CSS_HEIGHT] = 150;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 100;
+        node_1->layout.dimensions[CSS_WIDTH] = 300;
+        node_1->layout.dimensions[CSS_HEIGHT] = 150;
+      }
+    }
+
+    test("should layout rtl with reverse correctly", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 300;
+        node_1->style.dimensions[CSS_HEIGHT] = 150;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 100;
+        node_1->layout.dimensions[CSS_WIDTH] = 300;
+        node_1->layout.dimensions[CSS_HEIGHT] = 150;
+      }
+    }
+
+    test("should layout node with row flex direction", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 300;
+        node_1->style.dimensions[CSS_HEIGHT] = 150;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 900;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 600;
+        node_1->layout.dimensions[CSS_WIDTH] = 300;
+        node_1->layout.dimensions[CSS_HEIGHT] = 150;
+      }
+    }
+
+    test("should layout node with row flex direction in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 300;
+        node_1->style.dimensions[CSS_HEIGHT] = 150;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 350;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 200;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 300;
+        node_1->layout.dimensions[CSS_HEIGHT] = 150;
+      }
+    }
+
+    test("should layout node based on children main dimensions", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 300;
+        node_1->style.dimensions[CSS_HEIGHT] = 150;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 350;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 150;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 300;
+        node_1->layout.dimensions[CSS_HEIGHT] = 150;
+      }
+    }
+
+    test("should layout node based on children main dimensions in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 200;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 800;
+      }
+    }
+
+    test("should layout node with just flex", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 800;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 800;
+      }
+    }
+
+    test("should layout node with just flex in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1->style.dimensions[CSS_WIDTH] = 1000;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.flex = 1;
+          node_2->style.dimensions[CSS_WIDTH] = 1000;
+          init_css_node_children(node_2, 1);
+          {
+            css_node_t *node_3;
+            node_3 = node_2->get_child(node_2->context, 0);
+            node_3->style.flex = 1;
+            node_3->style.dimensions[CSS_WIDTH] = 1000;
+          }
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 1000;
+        node_1->layout.dimensions[CSS_HEIGHT] = 1000;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 1000;
+          node_2->layout.dimensions[CSS_HEIGHT] = 1000;
+          init_css_node_children(node_2, 1);
+          {
+            css_node_t *node_3;
+            node_3 = node_2->get_child(node_2->context, 0);
+            node_3->layout.position[CSS_TOP] = 0;
+            node_3->layout.position[CSS_LEFT] = 0;
+            node_3->layout.dimensions[CSS_WIDTH] = 1000;
+            node_3->layout.dimensions[CSS_HEIGHT] = 1000;
+          }
+        }
+      }
+    }
+
+    test("should layout node with flex recursively", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+        node_1->style.flex = 1;
+        node_1->style.dimensions[CSS_WIDTH] = 1000;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+          node_2->style.flex = 1;
+          node_2->style.dimensions[CSS_WIDTH] = 1000;
+          init_css_node_children(node_2, 1);
+          {
+            css_node_t *node_3;
+            node_3 = node_2->get_child(node_2->context, 0);
+            node_3->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+            node_3->style.flex = 1;
+            node_3->style.dimensions[CSS_WIDTH] = 1000;
+          }
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 1000;
+        node_1->layout.dimensions[CSS_HEIGHT] = 1000;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 1000;
+          node_2->layout.dimensions[CSS_HEIGHT] = 1000;
+          init_css_node_children(node_2, 1);
+          {
+            css_node_t *node_3;
+            node_3 = node_2->get_child(node_2->context, 0);
+            node_3->layout.position[CSS_TOP] = 0;
+            node_3->layout.position[CSS_LEFT] = 0;
+            node_3->layout.dimensions[CSS_WIDTH] = 1000;
+            node_3->layout.dimensions[CSS_HEIGHT] = 1000;
+          }
+        }
+      }
+    }
+
+    test("should layout node with flex recursively in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      node_0->style.margin[CSS_LEFT] = 5;
+      node_0->style.margin[CSS_TOP] = 10;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.margin[CSS_LEFT] = 15;
+        node_1->style.margin[CSS_TOP] = 50;
+        node_1->style.margin[CSS_BOTTOM] = 20;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.margin[CSS_LEFT] = 30;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 10;
+      node_0->layout.position[CSS_LEFT] = 5;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 50;
+        node_1->layout.position[CSS_LEFT] = 15;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 170;
+        node_1->layout.position[CSS_LEFT] = 30;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with targeted margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      node_0->style.margin[CSS_LEFT] = 5;
+      node_0->style.margin[CSS_TOP] = 10;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.margin[CSS_LEFT] = 15;
+        node_1->style.margin[CSS_TOP] = 50;
+        node_1->style.margin[CSS_BOTTOM] = 20;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.margin[CSS_LEFT] = 30;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 10;
+      node_0->layout.position[CSS_LEFT] = 5;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 880;
+        node_1->layout.position[CSS_LEFT] = 15;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 730;
+        node_1->layout.position[CSS_LEFT] = 30;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with targeted margin in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.justify_content = CSS_JUSTIFY_FLEX_START;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with justifyContent: flex-start", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.justify_content = CSS_JUSTIFY_FLEX_START;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 900;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 800;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with justifyContent: flex-start in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.justify_content = CSS_JUSTIFY_FLEX_END;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 800;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 900;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with justifyContent: flex-end", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.justify_content = CSS_JUSTIFY_FLEX_END;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with justifyContent: flex-end in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.justify_content = CSS_JUSTIFY_SPACE_BETWEEN;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 900;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with justifyContent: space-between", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.justify_content = CSS_JUSTIFY_SPACE_BETWEEN;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 900;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with justifyContent: space-between in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.justify_content = CSS_JUSTIFY_SPACE_AROUND;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 200;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 700;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with justifyContent: space-around", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.justify_content = CSS_JUSTIFY_SPACE_AROUND;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 700;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 200;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with justifyContent: space-around in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.justify_content = CSS_JUSTIFY_CENTER;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 400;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 500;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with justifyContent: center", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.justify_content = CSS_JUSTIFY_CENTER;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 500;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 400;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with justifyContent: center in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 1000;
+      }
+    }
+
+    test("should layout node with flex override height", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.align_items = CSS_ALIGN_FLEX_START;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with alignItems: flex-start", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.align_items = CSS_ALIGN_FLEX_START;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 900;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 800;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with alignItems: flex-start in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.align_items = CSS_ALIGN_CENTER;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 400;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 450;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with alignItems: center", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.align_items = CSS_ALIGN_CENTER;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 900;
+        node_1->layout.position[CSS_LEFT] = 400;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 800;
+        node_1->layout.position[CSS_LEFT] = 450;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with alignItems: center in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.align_items = CSS_ALIGN_FLEX_END;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 800;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 900;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with alignItems: flex-end", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.align_items = CSS_ALIGN_FLEX_END;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 900;
+        node_1->layout.position[CSS_LEFT] = 800;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 800;
+        node_1->layout.position[CSS_LEFT] = 900;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with alignItems: flex-end in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.align_items = CSS_ALIGN_FLEX_END;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.align_self = CSS_ALIGN_CENTER;
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 800;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 450;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with alignSelf overrides alignItems", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.align_items = CSS_ALIGN_FLEX_END;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.align_self = CSS_ALIGN_CENTER;
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 900;
+        node_1->layout.position[CSS_LEFT] = 800;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 800;
+        node_1->layout.position[CSS_LEFT] = 450;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with alignSelf overrides alignItems in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.align_items = CSS_ALIGN_STRETCH;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 1000;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with alignItem: stretch", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.align_items = CSS_ALIGN_STRETCH;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 900;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 1000;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout node with alignItem: stretch in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout empty node", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout empty node in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.margin[CSS_LEFT] = 5;
+        node_1->style.margin[CSS_TOP] = 5;
+        node_1->style.margin[CSS_RIGHT] = 5;
+        node_1->style.margin[CSS_BOTTOM] = 5;
+        node_1->style.margin[CSS_START] = 5;
+        node_1->style.margin[CSS_END] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 10;
+      node_0->layout.dimensions[CSS_HEIGHT] = 10;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 5;
+        node_1->layout.position[CSS_LEFT] = 5;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout child with margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.margin[CSS_LEFT] = 5;
+        node_1->style.margin[CSS_TOP] = 5;
+        node_1->style.margin[CSS_RIGHT] = 5;
+        node_1->style.margin[CSS_BOTTOM] = 5;
+        node_1->style.margin[CSS_START] = 5;
+        node_1->style.margin[CSS_END] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 10;
+      node_0->layout.dimensions[CSS_HEIGHT] = 10;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 5;
+        node_1->layout.position[CSS_LEFT] = 5;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout child with margin in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should not shrink children if not enough space", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = -200;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should not shrink children if not enough space in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.justify_content = CSS_JUSTIFY_CENTER;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+    }
+
+    test("should layout for center", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.justify_content = CSS_JUSTIFY_FLEX_END;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.margin[CSS_TOP] = 10;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout flex-end taking into account margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.justify_content = CSS_JUSTIFY_FLEX_END;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.margin[CSS_TOP] = 10;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 10;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout flex-end taking into account margin in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_items = CSS_ALIGN_FLEX_END;
+        init_css_node_children(node_1, 2);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.margin[CSS_LEFT] = 10;
+          node_2->style.margin[CSS_TOP] = 10;
+          node_2->style.margin[CSS_RIGHT] = 10;
+          node_2->style.margin[CSS_BOTTOM] = 10;
+          node_2->style.margin[CSS_START] = 10;
+          node_2->style.margin[CSS_END] = 10;
+          node_2 = node_1->get_child(node_1->context, 1);
+          node_2->style.dimensions[CSS_HEIGHT] = 100;
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 20;
+      node_0->layout.dimensions[CSS_HEIGHT] = 120;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 20;
+        node_1->layout.dimensions[CSS_HEIGHT] = 120;
+        init_css_node_children(node_1, 2);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 10;
+          node_2->layout.position[CSS_LEFT] = 10;
+          node_2->layout.dimensions[CSS_WIDTH] = 0;
+          node_2->layout.dimensions[CSS_HEIGHT] = 0;
+          node_2 = node_1->get_child(node_1->context, 1);
+          node_2->layout.position[CSS_TOP] = 20;
+          node_2->layout.position[CSS_LEFT] = 20;
+          node_2->layout.dimensions[CSS_WIDTH] = 0;
+          node_2->layout.dimensions[CSS_HEIGHT] = 100;
+        }
+      }
+    }
+
+    test("should layout alignItems with margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+        node_1->style.align_items = CSS_ALIGN_FLEX_END;
+        init_css_node_children(node_1, 2);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.margin[CSS_LEFT] = 10;
+          node_2->style.margin[CSS_TOP] = 10;
+          node_2->style.margin[CSS_RIGHT] = 10;
+          node_2->style.margin[CSS_BOTTOM] = 10;
+          node_2->style.margin[CSS_START] = 10;
+          node_2->style.margin[CSS_END] = 10;
+          node_2 = node_1->get_child(node_1->context, 1);
+          node_2->style.dimensions[CSS_HEIGHT] = 100;
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 20;
+      node_0->layout.dimensions[CSS_HEIGHT] = 120;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 20;
+        node_1->layout.dimensions[CSS_HEIGHT] = 120;
+        init_css_node_children(node_1, 2);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 110;
+          node_2->layout.position[CSS_LEFT] = 10;
+          node_2->layout.dimensions[CSS_WIDTH] = 0;
+          node_2->layout.dimensions[CSS_HEIGHT] = 0;
+          node_2 = node_1->get_child(node_1->context, 1);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 20;
+          node_2->layout.dimensions[CSS_WIDTH] = 0;
+          node_2->layout.dimensions[CSS_HEIGHT] = 100;
+        }
+      }
+    }
+
+    test("should layout alignItems with margin in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout flex inside of an empty element", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.align_items = CSS_ALIGN_STRETCH;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.margin[CSS_LEFT] = 10;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 10;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout alignItems stretch and margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.align_items = CSS_ALIGN_STRETCH;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.margin[CSS_LEFT] = 10;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 10;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout alignItems stretch and margin in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.padding[CSS_LEFT] = 5;
+      node_0->style.padding[CSS_TOP] = 5;
+      node_0->style.padding[CSS_RIGHT] = 5;
+      node_0->style.padding[CSS_BOTTOM] = 5;
+      node_0->style.padding[CSS_START] = 5;
+      node_0->style.padding[CSS_END] = 5;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 10;
+      node_0->layout.dimensions[CSS_HEIGHT] = 10;
+    }
+
+    test("should layout node with padding", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.padding[CSS_LEFT] = 5;
+      node_0->style.padding[CSS_TOP] = 5;
+      node_0->style.padding[CSS_RIGHT] = 5;
+      node_0->style.padding[CSS_BOTTOM] = 5;
+      node_0->style.padding[CSS_START] = 5;
+      node_0->style.padding[CSS_END] = 5;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 10;
+      node_0->layout.dimensions[CSS_HEIGHT] = 10;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 5;
+        node_1->layout.position[CSS_LEFT] = 5;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with padding and a child", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.padding[CSS_LEFT] = 5;
+      node_0->style.padding[CSS_TOP] = 5;
+      node_0->style.padding[CSS_RIGHT] = 5;
+      node_0->style.padding[CSS_BOTTOM] = 5;
+      node_0->style.padding[CSS_START] = 5;
+      node_0->style.padding[CSS_END] = 5;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.margin[CSS_LEFT] = 5;
+        node_1->style.margin[CSS_TOP] = 5;
+        node_1->style.margin[CSS_RIGHT] = 5;
+        node_1->style.margin[CSS_BOTTOM] = 5;
+        node_1->style.margin[CSS_START] = 5;
+        node_1->style.margin[CSS_END] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 20;
+      node_0->layout.dimensions[CSS_HEIGHT] = 20;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 10;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with padding and a child with margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_self = CSS_ALIGN_STRETCH;
+        node_1->style.padding[CSS_LEFT] = 10;
+        node_1->style.padding[CSS_TOP] = 10;
+        node_1->style.padding[CSS_RIGHT] = 10;
+        node_1->style.padding[CSS_BOTTOM] = 10;
+        node_1->style.padding[CSS_START] = 10;
+        node_1->style.padding[CSS_END] = 10;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 20;
+      node_0->layout.dimensions[CSS_HEIGHT] = 20;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 20;
+        node_1->layout.dimensions[CSS_HEIGHT] = 20;
+      }
+    }
+
+    test("should layout node with padding and stretch", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.padding[CSS_LEFT] = 50;
+      node_0->style.padding[CSS_TOP] = 50;
+      node_0->style.padding[CSS_RIGHT] = 50;
+      node_0->style.padding[CSS_BOTTOM] = 50;
+      node_0->style.padding[CSS_START] = 50;
+      node_0->style.padding[CSS_END] = 50;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_self = CSS_ALIGN_STRETCH;
+        node_1->style.padding[CSS_LEFT] = 10;
+        node_1->style.padding[CSS_TOP] = 10;
+        node_1->style.padding[CSS_RIGHT] = 10;
+        node_1->style.padding[CSS_BOTTOM] = 10;
+        node_1->style.padding[CSS_START] = 10;
+        node_1->style.padding[CSS_END] = 10;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 120;
+      node_0->layout.dimensions[CSS_HEIGHT] = 120;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 50;
+        node_1->layout.position[CSS_LEFT] = 50;
+        node_1->layout.dimensions[CSS_WIDTH] = 20;
+        node_1->layout.dimensions[CSS_HEIGHT] = 20;
+      }
+    }
+
+    test("should layout node with inner & outer padding and stretch", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_self = CSS_ALIGN_STRETCH;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.margin[CSS_LEFT] = 16;
+          node_2->style.margin[CSS_TOP] = 16;
+          node_2->style.margin[CSS_RIGHT] = 16;
+          node_2->style.margin[CSS_BOTTOM] = 16;
+          node_2->style.margin[CSS_START] = 16;
+          node_2->style.margin[CSS_END] = 16;
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 32;
+      node_0->layout.dimensions[CSS_HEIGHT] = 32;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 32;
+        node_1->layout.dimensions[CSS_HEIGHT] = 32;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 16;
+          node_2->layout.position[CSS_LEFT] = 16;
+          node_2->layout.dimensions[CSS_WIDTH] = 0;
+          node_2->layout.dimensions[CSS_HEIGHT] = 0;
+        }
+      }
+    }
+
+    test("should layout node with stretch and child with margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.position[CSS_LEFT] = 5;
+      node_0->style.position[CSS_TOP] = 5;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 5;
+      node_0->layout.position[CSS_LEFT] = 5;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+    }
+
+    test("should layout node with top and left", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.justify_content = CSS_JUSTIFY_SPACE_AROUND;
+      node_0->style.dimensions[CSS_HEIGHT] = 10;
+      node_0->style.padding[CSS_TOP] = 5;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 10;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 7.5;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with height, padding and space-around", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.position[CSS_BOTTOM] = 5;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = -5;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+    }
+
+    test("should layout node with bottom", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.position[CSS_TOP] = 10;
+      node_0->style.position[CSS_BOTTOM] = 5;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 10;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+    }
+
+    test("should layout node with both top and bottom", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 500;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.flex = 1;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 500;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 250;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 250;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 250;
+        node_1->layout.dimensions[CSS_WIDTH] = 250;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with position: absolute", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.margin[CSS_RIGHT] = 15;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with child with position: absolute and margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_self = CSS_ALIGN_CENTER;
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.padding[CSS_RIGHT] = 12;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 12;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with position: absolute, padding and alignSelf: center", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_HEIGHT] = 5;
+      node_0->style.padding[CSS_BOTTOM] = 20;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 20;
+    }
+
+    test("should work with height smaller than paddingBottom", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 5;
+      node_0->style.padding[CSS_LEFT] = 20;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 20;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+    }
+
+    test("should work with width smaller than paddingLeft", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.dimensions[CSS_WIDTH] = 400;
+        }
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.align_self = CSS_ALIGN_STRETCH;
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 400;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 400;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 400;
+          node_2->layout.dimensions[CSS_HEIGHT] = 0;
+        }
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with specified width and stretch", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.padding[CSS_LEFT] = 5;
+      node_0->style.padding[CSS_TOP] = 5;
+      node_0->style.padding[CSS_RIGHT] = 5;
+      node_0->style.padding[CSS_BOTTOM] = 5;
+      node_0->style.padding[CSS_START] = 5;
+      node_0->style.padding[CSS_END] = 5;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 10;
+      node_0->layout.dimensions[CSS_HEIGHT] = 10;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 5;
+        node_1->layout.position[CSS_LEFT] = 5;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with padding and child with position absolute", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.position[CSS_LEFT] = 10;
+        node_1->style.position[CSS_TOP] = 10;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 10;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with position absolute, top and left", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.padding[CSS_LEFT] = 20;
+      node_0->style.padding[CSS_TOP] = 20;
+      node_0->style.padding[CSS_RIGHT] = 20;
+      node_0->style.padding[CSS_BOTTOM] = 20;
+      node_0->style.padding[CSS_START] = 20;
+      node_0->style.padding[CSS_END] = 20;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.position[CSS_LEFT] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 40;
+      node_0->layout.dimensions[CSS_HEIGHT] = 40;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 20;
+        node_1->layout.position[CSS_LEFT] = 5;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with padding and child position absolute, left", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.margin[CSS_TOP] = 5;
+        node_1->style.position[CSS_TOP] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 10;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with position: absolute, top and marginTop", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.margin[CSS_LEFT] = 5;
+        node_1->style.position[CSS_LEFT] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with position: absolute, left and marginLeft", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.justify_content = CSS_JUSTIFY_SPACE_AROUND;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1 = node_0->get_child(node_0->context, 1);
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with space-around and child position absolute", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.justify_content = CSS_JUSTIFY_SPACE_AROUND;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1 = node_0->get_child(node_0->context, 1);
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with space-around and child position absolute in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 700;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1->style.margin[CSS_LEFT] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 700;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 5;
+        node_1->layout.dimensions[CSS_WIDTH] = 695;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with flex and main margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 700;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1->style.margin[CSS_RIGHT] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 700;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 695;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with flex and main margin in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 700;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.padding[CSS_RIGHT] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 700;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 347.5;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 347.5;
+        node_1->layout.dimensions[CSS_WIDTH] = 352.5;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with multiple flex and padding", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 700;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.padding[CSS_LEFT] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 700;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 352.5;
+        node_1->layout.dimensions[CSS_WIDTH] = 347.5;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 352.5;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with multiple flex and padding in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 700;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.margin[CSS_LEFT] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 700;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 347.5;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 352.5;
+        node_1->layout.dimensions[CSS_WIDTH] = 347.5;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with multiple flex and margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 700;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.margin[CSS_RIGHT] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 700;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 352.5;
+        node_1->layout.dimensions[CSS_WIDTH] = 347.5;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 347.5;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with multiple flex and margin in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_HEIGHT] = 300;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 600;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 300;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 600;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 600;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with flex and overflow", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 600;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.flex = 1;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 600;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with flex and position absolute", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 600;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.flex = 1;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 600;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 600;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with flex and position absolute in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_HEIGHT] = 500;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.flex = 1;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 500;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 500;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 500;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with double flex and position absolute", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.border[CSS_LEFT] = 5;
+      node_0->style.border[CSS_TOP] = 5;
+      node_0->style.border[CSS_RIGHT] = 5;
+      node_0->style.border[CSS_BOTTOM] = 5;
+      node_0->style.border[CSS_START] = 5;
+      node_0->style.border[CSS_END] = 5;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 10;
+      node_0->layout.dimensions[CSS_HEIGHT] = 10;
+    }
+
+    test("should layout node with borderWidth", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.border[CSS_TOP] = 1;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.position[CSS_TOP] = -1;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with borderWidth and position: absolute, top", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.border[CSS_LEFT] = 1;
+      node_0->style.border[CSS_TOP] = 1;
+      node_0->style.border[CSS_RIGHT] = 1;
+      node_0->style.border[CSS_BOTTOM] = 1;
+      node_0->style.border[CSS_START] = 1;
+      node_0->style.border[CSS_END] = 1;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.position[CSS_LEFT] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 2;
+      node_0->layout.dimensions[CSS_HEIGHT] = 2;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 1;
+        node_1->layout.position[CSS_LEFT] = 6;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with borderWidth and position: absolute, top. cross axis", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 50;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_self = CSS_ALIGN_STRETCH;
+        node_1->style.margin[CSS_LEFT] = 20;
+        node_1->style.padding[CSS_LEFT] = 20;
+        node_1->style.padding[CSS_TOP] = 20;
+        node_1->style.padding[CSS_RIGHT] = 20;
+        node_1->style.padding[CSS_BOTTOM] = 20;
+        node_1->style.padding[CSS_START] = 20;
+        node_1->style.padding[CSS_END] = 20;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 50;
+      node_0->layout.dimensions[CSS_HEIGHT] = 40;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 20;
+        node_1->layout.dimensions[CSS_WIDTH] = 40;
+        node_1->layout.dimensions[CSS_HEIGHT] = 40;
+      }
+    }
+
+    test("should correctly take into account min padding for stretch", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = -31;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.border[CSS_RIGHT] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 5;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 5;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with negative width", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.border[CSS_RIGHT] = 1;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.margin[CSS_RIGHT] = -8;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should handle negative margin and min padding correctly", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.border[CSS_LEFT] = 1;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.margin[CSS_LEFT] = -8;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 1;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should handle negative margin and min padding correctly in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->measure = measure;
+      node_0->context = "small";
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 35;
+      node_0->layout.dimensions[CSS_HEIGHT] = 18;
+    }
+
+    test("should layout node with just text", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->measure = measure;
+      node_0->context = "measureWithRatio2";
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+    }
+
+    test("should layout node with fixed width and custom measure function", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      node_0->measure = measure;
+      node_0->context = "measureWithRatio2";
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+    }
+
+    test("should layout node with fixed height and custom measure function", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      node_0->measure = measure;
+      node_0->context = "measureWithRatio2";
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+    }
+
+    test("should layout node with fixed height and fixed width, ignoring custom measure function", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->measure = measure;
+      node_0->context = "measureWithRatio2";
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 99999;
+      node_0->layout.dimensions[CSS_HEIGHT] = 99999;
+    }
+
+    test("should layout node with no fixed dimension and custom measure function", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN;
+      node_0->style.dimensions[CSS_WIDTH] = 320;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->measure = measure;
+        node_1->context = "measureWithRatio2";
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        init_css_node_children(node_1, 2);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->measure = measure;
+          node_2->context = "measureWithRatio2";
+          node_2 = node_1->get_child(node_1->context, 1);
+          node_2->measure = measure;
+          node_2->context = "measureWithRatio2";
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 320;
+      node_0->layout.dimensions[CSS_HEIGHT] = 740;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 320;
+        node_1->layout.dimensions[CSS_HEIGHT] = 640;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 640;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 320;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        init_css_node_children(node_1, 2);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 200;
+          node_2->layout.dimensions[CSS_HEIGHT] = 100;
+          node_2 = node_1->get_child(node_1->context, 1);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 200;
+          node_2->layout.dimensions[CSS_WIDTH] = 200;
+          node_2->layout.dimensions[CSS_HEIGHT] = 100;
+        }
+      }
+    }
+
+    test("should layout node with nested stacks and custom measure function", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 10;
+      node_0->measure = measure;
+      node_0->context = "small";
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 10;
+      node_0->layout.dimensions[CSS_HEIGHT] = 18;
+    }
+
+    test("should layout node with text and width", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->measure = measure;
+      node_0->context = "loooooooooong with space";
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 172;
+      node_0->layout.dimensions[CSS_HEIGHT] = 18;
+    }
+
+    test("should layout node with text, padding and margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_self = CSS_ALIGN_STRETCH;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.align_self = CSS_ALIGN_STRETCH;
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 300;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 300;
+          node_2->layout.dimensions[CSS_HEIGHT] = 0;
+        }
+      }
+    }
+
+    test("should layout node with nested alignSelf: stretch", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+        node_1->style.dimensions[CSS_WIDTH] = 500;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.flex = 1;
+          node_2->measure = measure;
+          node_2->context = "loooooooooong with space";
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 500;
+      node_0->layout.dimensions[CSS_HEIGHT] = 18;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 500;
+        node_1->layout.dimensions[CSS_HEIGHT] = 18;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 500;
+          node_2->layout.dimensions[CSS_HEIGHT] = 18;
+        }
+      }
+    }
+
+    test("should layout node with text and flex", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.direction = CSS_DIRECTION_RTL;
+        node_1->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+        node_1->style.dimensions[CSS_WIDTH] = 500;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.flex = 1;
+          node_2->measure = measure;
+          node_2->context = "loooooooooong with space";
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 500;
+      node_0->layout.dimensions[CSS_HEIGHT] = 18;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 500;
+        node_1->layout.dimensions[CSS_HEIGHT] = 18;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 500;
+          node_2->layout.dimensions[CSS_HEIGHT] = 18;
+        }
+      }
+    }
+
+    test("should layout node with text and flex in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 130;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_items = CSS_ALIGN_STRETCH;
+        node_1->style.align_self = CSS_ALIGN_STRETCH;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->measure = measure;
+          node_2->context = "loooooooooong with space";
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 130;
+      node_0->layout.dimensions[CSS_HEIGHT] = 36;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 130;
+        node_1->layout.dimensions[CSS_HEIGHT] = 36;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 130;
+          node_2->layout.dimensions[CSS_HEIGHT] = 36;
+        }
+      }
+    }
+
+    test("should layout node with text and stretch", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_items = CSS_ALIGN_STRETCH;
+        node_1->style.align_self = CSS_ALIGN_STRETCH;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.dimensions[CSS_WIDTH] = 130;
+          node_2->measure = measure;
+          node_2->context = "loooooooooong with space";
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 36;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 36;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 130;
+          node_2->layout.dimensions[CSS_HEIGHT] = 36;
+        }
+      }
+    }
+
+    test("should layout node with text stretch and width", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.align_self = CSS_ALIGN_FLEX_START;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_self = CSS_ALIGN_FLEX_START;
+        node_1->measure = measure;
+        node_1->context = "loooooooooong with space";
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 36;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 36;
+      }
+    }
+
+    test("should layout node with text bounded by parent", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.align_self = CSS_ALIGN_FLEX_START;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.padding[CSS_LEFT] = 10;
+      node_0->style.padding[CSS_TOP] = 10;
+      node_0->style.padding[CSS_RIGHT] = 10;
+      node_0->style.padding[CSS_BOTTOM] = 10;
+      node_0->style.padding[CSS_START] = 10;
+      node_0->style.padding[CSS_END] = 10;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_self = CSS_ALIGN_FLEX_START;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->measure = measure;
+          node_2->context = "loooooooooong with space";
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 76;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 20;
+        node_1->layout.position[CSS_LEFT] = 20;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 36;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 100;
+          node_2->layout.dimensions[CSS_HEIGHT] = 36;
+        }
+      }
+    }
+
+    test("should layout node with text bounded by grand-parent", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.justify_content = CSS_JUSTIFY_SPACE_BETWEEN;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 900;
+        node_1 = node_0->get_child(node_0->context, 1);
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 900;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 900;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout space-between when remaining space is negative", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.justify_content = CSS_JUSTIFY_SPACE_BETWEEN;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 900;
+        node_1 = node_0->get_child(node_0->context, 1);
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = -800;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 900;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = -800;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout space-between when remaining space is negative in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.justify_content = CSS_JUSTIFY_FLEX_END;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 900;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = -700;
+        node_1->layout.dimensions[CSS_WIDTH] = 900;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout flex-end when remaining space is negative", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.justify_content = CSS_JUSTIFY_FLEX_END;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 900;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 900;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout flex-end when remaining space is negative in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.margin[CSS_LEFT] = 20;
+          node_2->style.margin[CSS_TOP] = 20;
+          node_2->style.margin[CSS_RIGHT] = 20;
+          node_2->style.margin[CSS_BOTTOM] = 20;
+          node_2->style.margin[CSS_START] = 20;
+          node_2->style.margin[CSS_END] = 20;
+          node_2->measure = measure;
+          node_2->context = "loooooooooong with space";
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 58;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 58;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 20;
+          node_2->layout.position[CSS_LEFT] = 20;
+          node_2->layout.dimensions[CSS_WIDTH] = 172;
+          node_2->layout.dimensions[CSS_HEIGHT] = 18;
+        }
+      }
+    }
+
+    test("should layout text with flexDirection row", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.margin[CSS_LEFT] = 20;
+          node_2->style.margin[CSS_TOP] = 20;
+          node_2->style.margin[CSS_RIGHT] = 20;
+          node_2->style.margin[CSS_BOTTOM] = 20;
+          node_2->style.margin[CSS_START] = 20;
+          node_2->style.margin[CSS_END] = 20;
+          node_2->measure = measure;
+          node_2->context = "loooooooooong with space";
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 58;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 58;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 20;
+          node_2->layout.position[CSS_LEFT] = 8;
+          node_2->layout.dimensions[CSS_WIDTH] = 172;
+          node_2->layout.dimensions[CSS_HEIGHT] = 18;
+        }
+      }
+    }
+
+    test("should layout text with flexDirection row in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.margin[CSS_LEFT] = 20;
+          node_2->style.margin[CSS_TOP] = 20;
+          node_2->style.margin[CSS_RIGHT] = 20;
+          node_2->style.margin[CSS_BOTTOM] = 20;
+          node_2->style.margin[CSS_START] = 20;
+          node_2->style.margin[CSS_END] = 20;
+          node_2->measure = measure;
+          node_2->context = "loooooooooong with space";
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 76;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 76;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 20;
+          node_2->layout.position[CSS_LEFT] = 20;
+          node_2->layout.dimensions[CSS_WIDTH] = 160;
+          node_2->layout.dimensions[CSS_HEIGHT] = 36;
+        }
+      }
+    }
+
+    test("should layout with text and margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.position[CSS_LEFT] = 0;
+        node_1->style.position[CSS_TOP] = 0;
+        node_1->style.position[CSS_RIGHT] = 0;
+        node_1->style.position[CSS_BOTTOM] = 0;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should layout with position absolute, top, left, bottom, right", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.align_self = CSS_ALIGN_FLEX_START;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_self = CSS_ALIGN_FLEX_START;
+        node_1->style.flex = 2.5;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.align_self = CSS_ALIGN_FLEX_START;
+        node_1->style.flex = 7.5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 25;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 25;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 75;
+      }
+    }
+
+    test("should layout with arbitrary flex", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.align_self = CSS_ALIGN_FLEX_START;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_self = CSS_ALIGN_FLEX_START;
+        node_1->style.flex = 2.5;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.align_self = CSS_ALIGN_FLEX_START;
+        node_1->style.flex = 7.5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 75;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 25;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 75;
+      }
+    }
+
+    test("should layout with arbitrary flex in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN_REVERSE;
+      node_0->style.align_self = CSS_ALIGN_FLEX_START;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_self = CSS_ALIGN_FLEX_START;
+        node_1->style.flex = -2.5;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.align_self = CSS_ALIGN_FLEX_START;
+        node_1->style.flex = 0;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout with negative flex in reverse", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.position[CSS_LEFT] = 0;
+        node_1->style.position[CSS_RIGHT] = 0;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 50;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout with position: absolute and another sibling", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.position[CSS_TOP] = 0;
+        node_1->style.position[CSS_BOTTOM] = 20;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 80;
+      }
+    }
+
+    test("should calculate height properly with position: absolute top and bottom", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.justify_content = CSS_JUSTIFY_CENTER;
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.position[CSS_LEFT] = 0;
+        node_1->style.position[CSS_TOP] = 0;
+        node_1->style.position[CSS_RIGHT] = 0;
+        node_1->style.position[CSS_BOTTOM] = 0;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.dimensions[CSS_WIDTH] = 100;
+          node_2->style.dimensions[CSS_HEIGHT] = 100;
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 50;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 100;
+          node_2->layout.dimensions[CSS_HEIGHT] = 100;
+        }
+      }
+    }
+
+    test("should layout with complicated position: absolute and justifyContent: center combo", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.position[CSS_BOTTOM] = 0;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should calculate top properly with position: absolute bottom", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.position[CSS_RIGHT] = 0;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 100;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should calculate left properly with position: absolute right", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.dimensions[CSS_HEIGHT] = 10;
+        node_1->style.position[CSS_BOTTOM] = 0;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 90;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 10;
+      }
+    }
+
+    test("should calculate top properly with position: absolute bottom and height", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.dimensions[CSS_WIDTH] = 10;
+        node_1->style.position[CSS_RIGHT] = 0;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 90;
+        node_1->layout.dimensions[CSS_WIDTH] = 10;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should calculate left properly with position: absolute right and width", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.dimensions[CSS_HEIGHT] = 10;
+        node_1->style.position[CSS_BOTTOM] = 0;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = -10;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 10;
+      }
+    }
+
+    test("should calculate top properly with position: absolute right, width, and no parent dimensions", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.dimensions[CSS_WIDTH] = 10;
+        node_1->style.position[CSS_RIGHT] = 0;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = -10;
+        node_1->layout.dimensions[CSS_WIDTH] = 10;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should calculate left properly with position: absolute right, width, and no parent dimensions", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.justify_content = CSS_JUSTIFY_SPACE_BETWEEN;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.border[CSS_BOTTOM] = 1;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 1;
+      }
+    }
+
+    test("should layout border bottom inside of justify content space between container", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.justify_content = CSS_JUSTIFY_CENTER;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.margin[CSS_TOP] = -6;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = -3;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout negative margin top inside of justify content center container", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.justify_content = CSS_JUSTIFY_CENTER;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.margin[CSS_TOP] = 20;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 20;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 20;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout positive margin top inside of justify content center container", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.justify_content = CSS_JUSTIFY_FLEX_END;
+      node_0->style.border[CSS_BOTTOM] = 5;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 5;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout border bottom and flex end with an empty child", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 800;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position[CSS_LEFT] = 5;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 800;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 5;
+        node_1->layout.dimensions[CSS_WIDTH] = 800;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 800;
+          node_2->layout.dimensions[CSS_HEIGHT] = 0;
+        }
+      }
+    }
+
+    test("should layout with children of a contain with left", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.flex_wrap = CSS_WRAP;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 40;
+        node_1->style.dimensions[CSS_HEIGHT] = 10;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 40;
+        node_1->style.dimensions[CSS_HEIGHT] = 10;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.dimensions[CSS_WIDTH] = 40;
+        node_1->style.dimensions[CSS_HEIGHT] = 10;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 20;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 40;
+        node_1->layout.dimensions[CSS_HEIGHT] = 10;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 40;
+        node_1->layout.dimensions[CSS_WIDTH] = 40;
+        node_1->layout.dimensions[CSS_HEIGHT] = 10;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 10;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 40;
+        node_1->layout.dimensions[CSS_HEIGHT] = 10;
+      }
+    }
+
+    test("should layout flex-wrap", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.flex_wrap = CSS_WRAP;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 40;
+        node_1->style.dimensions[CSS_HEIGHT] = 10;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 40;
+        node_1->style.dimensions[CSS_HEIGHT] = 10;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.dimensions[CSS_WIDTH] = 40;
+        node_1->style.dimensions[CSS_HEIGHT] = 10;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 20;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 60;
+        node_1->layout.dimensions[CSS_WIDTH] = 40;
+        node_1->layout.dimensions[CSS_HEIGHT] = 10;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 20;
+        node_1->layout.dimensions[CSS_WIDTH] = 40;
+        node_1->layout.dimensions[CSS_HEIGHT] = 10;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 10;
+        node_1->layout.position[CSS_LEFT] = 60;
+        node_1->layout.dimensions[CSS_WIDTH] = 40;
+        node_1->layout.dimensions[CSS_HEIGHT] = 10;
+      }
+    }
+
+    test("should layout flex-wrap in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_wrap = CSS_WRAP;
+      node_0->style.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 0;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should layout flex wrap with a line bigger than container", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      node_0->style.maxDimensions[CSS_WIDTH] = 90;
+      node_0->style.maxDimensions[CSS_HEIGHT] = 190;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 90;
+      node_0->layout.dimensions[CSS_HEIGHT] = 190;
+    }
+
+    test("should use max bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      node_0->style.minDimensions[CSS_WIDTH] = 110;
+      node_0->style.minDimensions[CSS_HEIGHT] = 210;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 110;
+      node_0->layout.dimensions[CSS_HEIGHT] = 210;
+    }
+
+    test("should use min bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      node_0->style.maxDimensions[CSS_WIDTH] = 90;
+      node_0->style.maxDimensions[CSS_HEIGHT] = 190;
+      node_0->style.minDimensions[CSS_WIDTH] = 110;
+      node_0->style.minDimensions[CSS_HEIGHT] = 210;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 110;
+      node_0->layout.dimensions[CSS_HEIGHT] = 210;
+    }
+
+    test("should use min bounds over max bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      node_0->style.maxDimensions[CSS_WIDTH] = 80;
+      node_0->style.maxDimensions[CSS_HEIGHT] = 180;
+      node_0->style.minDimensions[CSS_WIDTH] = 90;
+      node_0->style.minDimensions[CSS_HEIGHT] = 190;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 90;
+      node_0->layout.dimensions[CSS_HEIGHT] = 190;
+    }
+
+    test("should use min bounds over max bounds and natural width", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      node_0->style.minDimensions[CSS_WIDTH] = -10;
+      node_0->style.minDimensions[CSS_HEIGHT] = -20;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+    }
+
+    test("should ignore negative min bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      node_0->style.maxDimensions[CSS_WIDTH] = -10;
+      node_0->style.maxDimensions[CSS_HEIGHT] = -20;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+    }
+
+    test("should ignore negative max bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.maxDimensions[CSS_WIDTH] = 30;
+      node_0->style.maxDimensions[CSS_HEIGHT] = 10;
+      node_0->style.padding[CSS_LEFT] = 20;
+      node_0->style.padding[CSS_TOP] = 15;
+      node_0->style.padding[CSS_RIGHT] = 20;
+      node_0->style.padding[CSS_BOTTOM] = 15;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 40;
+      node_0->layout.dimensions[CSS_HEIGHT] = 30;
+    }
+
+    test("should use padded size over max bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.minDimensions[CSS_WIDTH] = 50;
+      node_0->style.minDimensions[CSS_HEIGHT] = 40;
+      node_0->style.padding[CSS_LEFT] = 20;
+      node_0->style.padding[CSS_TOP] = 15;
+      node_0->style.padding[CSS_RIGHT] = 20;
+      node_0->style.padding[CSS_BOTTOM] = 15;
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 50;
+      node_0->layout.dimensions[CSS_HEIGHT] = 40;
+    }
+
+    test("should use min size over padded size", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.minDimensions[CSS_WIDTH] = 200;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.flex = 1;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 50;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 250;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should override flex direction size with min bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.minDimensions[CSS_WIDTH] = 200;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.flex = 1;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 250;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 50;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should override flex direction size with min bounds in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.maxDimensions[CSS_WIDTH] = 110;
+        node_1->style.minDimensions[CSS_WIDTH] = 90;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.flex = 1;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 100;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 200;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should not override flex direction size within bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.maxDimensions[CSS_WIDTH] = 110;
+        node_1->style.minDimensions[CSS_WIDTH] = 90;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.flex = 1;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 200;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 100;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should not override flex direction size within bounds in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.maxDimensions[CSS_WIDTH] = 60;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.flex = 1;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 120;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 120;
+        node_1->layout.dimensions[CSS_WIDTH] = 60;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 180;
+        node_1->layout.dimensions[CSS_WIDTH] = 120;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should override flex direction size with max bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.maxDimensions[CSS_WIDTH] = 60;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.flex = 1;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 180;
+        node_1->layout.dimensions[CSS_WIDTH] = 120;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 120;
+        node_1->layout.dimensions[CSS_WIDTH] = 60;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 120;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should override flex direction size with max bounds in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1->style.maxDimensions[CSS_WIDTH] = 60;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.maxDimensions[CSS_WIDTH] = 60;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.flex = 1;
+        node_1->style.maxDimensions[CSS_WIDTH] = 60;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 60;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 60;
+        node_1->layout.dimensions[CSS_WIDTH] = 60;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 120;
+        node_1->layout.dimensions[CSS_WIDTH] = 60;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should ignore flex size if fully max bound", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1->style.maxDimensions[CSS_WIDTH] = 60;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.maxDimensions[CSS_WIDTH] = 60;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.flex = 1;
+        node_1->style.maxDimensions[CSS_WIDTH] = 60;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 240;
+        node_1->layout.dimensions[CSS_WIDTH] = 60;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 180;
+        node_1->layout.dimensions[CSS_WIDTH] = 60;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 120;
+        node_1->layout.dimensions[CSS_WIDTH] = 60;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should ignore flex size if fully max bound in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1->style.minDimensions[CSS_WIDTH] = 120;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.minDimensions[CSS_WIDTH] = 120;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.flex = 1;
+        node_1->style.minDimensions[CSS_WIDTH] = 120;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 120;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 120;
+        node_1->layout.dimensions[CSS_WIDTH] = 120;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 240;
+        node_1->layout.dimensions[CSS_WIDTH] = 120;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should ignore flex size if fully min bound", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1->style.minDimensions[CSS_WIDTH] = 120;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex = 1;
+        node_1->style.minDimensions[CSS_WIDTH] = 120;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.flex = 1;
+        node_1->style.minDimensions[CSS_WIDTH] = 120;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 180;
+        node_1->layout.dimensions[CSS_WIDTH] = 120;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 60;
+        node_1->layout.dimensions[CSS_WIDTH] = 120;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = -60;
+        node_1->layout.dimensions[CSS_WIDTH] = 120;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should ignore flex size if fully min bound in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1->style.maxDimensions[CSS_WIDTH] = 310;
+        node_1->style.minDimensions[CSS_WIDTH] = 290;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 300;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should pre-fill child size within bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1->style.maxDimensions[CSS_WIDTH] = 290;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 290;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should pre-fill child size within max bound", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1->style.minDimensions[CSS_WIDTH] = 310;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 310;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+      }
+    }
+
+    test("should pre-fill child size within min bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.maxDimensions[CSS_WIDTH] = 300;
+      node_0->style.maxDimensions[CSS_HEIGHT] = 700;
+      node_0->style.minDimensions[CSS_WIDTH] = 100;
+      node_0->style.minDimensions[CSS_HEIGHT] = 500;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        node_1->style.dimensions[CSS_HEIGHT] = 300;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        node_1->style.dimensions[CSS_HEIGHT] = 300;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 600;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 300;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 300;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 300;
+      }
+    }
+
+    test("should set parents size based on bounded children", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.maxDimensions[CSS_WIDTH] = 100;
+      node_0->style.maxDimensions[CSS_HEIGHT] = 500;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        node_1->style.dimensions[CSS_HEIGHT] = 300;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        node_1->style.dimensions[CSS_HEIGHT] = 300;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 500;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 300;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 300;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 300;
+      }
+    }
+
+    test("should set parents size based on max bounded children", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.minDimensions[CSS_WIDTH] = 300;
+      node_0->style.minDimensions[CSS_HEIGHT] = 700;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        node_1->style.dimensions[CSS_HEIGHT] = 300;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 200;
+        node_1->style.dimensions[CSS_HEIGHT] = 300;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 700;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 300;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 300;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 300;
+      }
+    }
+
+    test("should set parents size based on min bounded children", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.align_items = CSS_ALIGN_STRETCH;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.maxDimensions[CSS_WIDTH] = 1100;
+        node_1->style.maxDimensions[CSS_HEIGHT] = 110;
+        node_1->style.minDimensions[CSS_WIDTH] = 900;
+        node_1->style.minDimensions[CSS_HEIGHT] = 90;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 1000;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should keep stretched size within bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.align_items = CSS_ALIGN_STRETCH;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.maxDimensions[CSS_WIDTH] = 900;
+        node_1->style.maxDimensions[CSS_HEIGHT] = 90;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 90;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 900;
+        node_1->layout.dimensions[CSS_HEIGHT] = 90;
+      }
+    }
+
+    test("should keep stretched size within max bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.align_items = CSS_ALIGN_STRETCH;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.minDimensions[CSS_WIDTH] = 1100;
+        node_1->style.minDimensions[CSS_HEIGHT] = 110;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 110;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 1100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 110;
+      }
+    }
+
+    test("should keep stretched size within min bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.minDimensions[CSS_WIDTH] = 100;
+        node_1->style.minDimensions[CSS_HEIGHT] = 110;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 110;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 110;
+      }
+    }
+
+    test("should keep cross axis size within min bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.minDimensions[CSS_WIDTH] = 100;
+        node_1->style.minDimensions[CSS_HEIGHT] = 110;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 110;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 900;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 110;
+      }
+    }
+
+    test("should keep cross axis size within min bounds in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.maxDimensions[CSS_WIDTH] = 500;
+        node_1->style.maxDimensions[CSS_HEIGHT] = 600;
+        node_1->style.position[CSS_LEFT] = 100;
+        node_1->style.position[CSS_TOP] = 100;
+        node_1->style.position[CSS_RIGHT] = 100;
+        node_1->style.position[CSS_BOTTOM] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 100;
+        node_1->layout.dimensions[CSS_WIDTH] = 500;
+        node_1->layout.dimensions[CSS_HEIGHT] = 600;
+      }
+    }
+
+    test("should layout node with position absolute, top and left and max bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 1000;
+      node_0->style.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.minDimensions[CSS_WIDTH] = 900;
+        node_1->style.minDimensions[CSS_HEIGHT] = 1000;
+        node_1->style.position[CSS_LEFT] = 100;
+        node_1->style.position[CSS_TOP] = 100;
+        node_1->style.position[CSS_RIGHT] = 100;
+        node_1->style.position[CSS_BOTTOM] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 1000;
+      node_0->layout.dimensions[CSS_HEIGHT] = 1000;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 100;
+        node_1->layout.dimensions[CSS_WIDTH] = 900;
+        node_1->layout.dimensions[CSS_HEIGHT] = 1000;
+      }
+    }
+
+    test("should layout node with position absolute, top and left and min bounds", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 400;
+      node_0->style.dimensions[CSS_HEIGHT] = 400;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.padding[CSS_LEFT] = 10;
+        node_1->style.padding[CSS_TOP] = 10;
+        node_1->style.padding[CSS_RIGHT] = 10;
+        node_1->style.padding[CSS_BOTTOM] = 10;
+        node_1->style.padding[CSS_START] = 10;
+        node_1->style.padding[CSS_END] = 10;
+        node_1->style.position[CSS_LEFT] = 100;
+        node_1->style.position[CSS_TOP] = 100;
+        node_1->style.position[CSS_RIGHT] = 100;
+        node_1->style.position[CSS_BOTTOM] = 100;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.position_type = CSS_POSITION_ABSOLUTE;
+          node_2->style.position[CSS_LEFT] = 10;
+          node_2->style.position[CSS_TOP] = 10;
+          node_2->style.position[CSS_RIGHT] = 10;
+          node_2->style.position[CSS_BOTTOM] = 10;
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 400;
+      node_0->layout.dimensions[CSS_HEIGHT] = 400;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 100;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 10;
+          node_2->layout.position[CSS_LEFT] = 10;
+          node_2->layout.dimensions[CSS_WIDTH] = 180;
+          node_2->layout.dimensions[CSS_HEIGHT] = 180;
+        }
+      }
+    }
+
+    test("should layout absolutely positioned node with absolutely positioned padded parent", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 400;
+      node_0->style.dimensions[CSS_HEIGHT] = 400;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.position_type = CSS_POSITION_ABSOLUTE;
+        node_1->style.padding[CSS_LEFT] = 10;
+        node_1->style.padding[CSS_TOP] = 10;
+        node_1->style.padding[CSS_RIGHT] = 10;
+        node_1->style.padding[CSS_BOTTOM] = 10;
+        node_1->style.padding[CSS_START] = 10;
+        node_1->style.padding[CSS_END] = 10;
+        node_1->style.border[CSS_LEFT] = 1;
+        node_1->style.border[CSS_TOP] = 1;
+        node_1->style.border[CSS_RIGHT] = 1;
+        node_1->style.border[CSS_BOTTOM] = 1;
+        node_1->style.border[CSS_START] = 1;
+        node_1->style.border[CSS_END] = 1;
+        node_1->style.position[CSS_LEFT] = 100;
+        node_1->style.position[CSS_TOP] = 100;
+        node_1->style.position[CSS_RIGHT] = 100;
+        node_1->style.position[CSS_BOTTOM] = 100;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.position_type = CSS_POSITION_ABSOLUTE;
+          node_2->style.position[CSS_LEFT] = 10;
+          node_2->style.position[CSS_TOP] = 10;
+          node_2->style.position[CSS_RIGHT] = 10;
+          node_2->style.position[CSS_BOTTOM] = 10;
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 400;
+      node_0->layout.dimensions[CSS_HEIGHT] = 400;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 100;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 11;
+          node_2->layout.position[CSS_LEFT] = 11;
+          node_2->layout.dimensions[CSS_WIDTH] = 178;
+          node_2->layout.dimensions[CSS_HEIGHT] = 178;
+        }
+      }
+    }
+
+    test("should layout absolutely positioned node with absolutely positioned padded and bordered parent", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 400;
+      node_0->style.dimensions[CSS_HEIGHT] = 400;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex = 1;
+        node_1->style.padding[CSS_LEFT] = 10;
+        node_1->style.padding[CSS_TOP] = 10;
+        node_1->style.padding[CSS_RIGHT] = 10;
+        node_1->style.padding[CSS_BOTTOM] = 10;
+        node_1->style.padding[CSS_START] = 10;
+        node_1->style.padding[CSS_END] = 10;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.position_type = CSS_POSITION_ABSOLUTE;
+          node_2->style.position[CSS_LEFT] = 10;
+          node_2->style.position[CSS_TOP] = 10;
+          node_2->style.position[CSS_RIGHT] = 10;
+          node_2->style.position[CSS_BOTTOM] = 10;
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 400;
+      node_0->layout.dimensions[CSS_HEIGHT] = 400;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 400;
+        node_1->layout.dimensions[CSS_HEIGHT] = 400;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 10;
+          node_2->layout.position[CSS_LEFT] = 10;
+          node_2->layout.dimensions[CSS_WIDTH] = 380;
+          node_2->layout.dimensions[CSS_HEIGHT] = 380;
+        }
+      }
+    }
+
+    test("should layout absolutely positioned node with padded flex 1 parent", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+        init_css_node_children(node_1, 2);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.dimensions[CSS_WIDTH] = 50;
+          node_2->style.dimensions[CSS_HEIGHT] = 50;
+          node_2 = node_1->get_child(node_1->context, 1);
+          node_2->style.dimensions[CSS_WIDTH] = 50;
+          node_2->style.dimensions[CSS_HEIGHT] = 50;
+        }
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.direction = CSS_DIRECTION_LTR;
+        node_1->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+        init_css_node_children(node_1, 2);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.dimensions[CSS_WIDTH] = 50;
+          node_2->style.dimensions[CSS_HEIGHT] = 50;
+          node_2 = node_1->get_child(node_1->context, 1);
+          node_2->style.dimensions[CSS_WIDTH] = 50;
+          node_2->style.dimensions[CSS_HEIGHT] = 50;
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+        init_css_node_children(node_1, 2);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 150;
+          node_2->layout.dimensions[CSS_WIDTH] = 50;
+          node_2->layout.dimensions[CSS_HEIGHT] = 50;
+          node_2 = node_1->get_child(node_1->context, 1);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 100;
+          node_2->layout.dimensions[CSS_WIDTH] = 50;
+          node_2->layout.dimensions[CSS_HEIGHT] = 50;
+        }
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 50;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+        init_css_node_children(node_1, 2);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 50;
+          node_2->layout.dimensions[CSS_HEIGHT] = 50;
+          node_2 = node_1->get_child(node_1->context, 1);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 50;
+          node_2->layout.dimensions[CSS_WIDTH] = 50;
+          node_2->layout.dimensions[CSS_HEIGHT] = 50;
+        }
+      }
+    }
+
+    test("should layout nested nodes with mixed directions", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.justify_content = CSS_JUSTIFY_SPACE_BETWEEN;
+      node_0->style.flex_wrap = CSS_WRAP;
+      node_0->style.dimensions[CSS_WIDTH] = 320;
+      node_0->style.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 6);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 3);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 4);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 5);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 320;
+      node_0->layout.dimensions[CSS_HEIGHT] = 200;
+      init_css_node_children(node_0, 6);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 110;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 220;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 3);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 4);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 110;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 5);
+        node_1->layout.position[CSS_TOP] = 100;
+        node_1->layout.position[CSS_LEFT] = 220;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+      }
+    }
+
+    test("should correctly space wrapped nodes", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      node_0->style.padding[CSS_LEFT] = 5;
+      node_0->style.padding[CSS_RIGHT] = 5;
+      node_0->style.padding[CSS_START] = 15;
+      node_0->style.padding[CSS_END] = 15;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 50;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 15;
+        node_1->layout.dimensions[CSS_WIDTH] = 170;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    test("should give start/end padding precedence over left/right padding", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_LEFT] = 5;
+        node_1->style.margin[CSS_RIGHT] = 5;
+        node_1->style.margin[CSS_START] = 15;
+        node_1->style.margin[CSS_END] = 15;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 50;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 15;
+        node_1->layout.dimensions[CSS_WIDTH] = 170;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    test("should give start/end margin precedence over left/right margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      node_0->style.border[CSS_LEFT] = 5;
+      node_0->style.border[CSS_RIGHT] = 5;
+      node_0->style.border[CSS_START] = 15;
+      node_0->style.border[CSS_END] = 15;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 50;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 15;
+        node_1->layout.dimensions[CSS_WIDTH] = 170;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    test("should give start/end border precedence over left/right border", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      node_0->style.padding[CSS_START] = 15;
+      node_0->style.padding[CSS_END] = 5;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 50;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 15;
+        node_1->layout.dimensions[CSS_WIDTH] = 180;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    test("should layout node with correct start/end padding", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      node_0->style.padding[CSS_START] = 15;
+      node_0->style.padding[CSS_END] = 5;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 50;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 5;
+        node_1->layout.dimensions[CSS_WIDTH] = 180;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    test("should layout node with correct start/end padding in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_START] = 15;
+        node_1->style.margin[CSS_END] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 50;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 15;
+        node_1->layout.dimensions[CSS_WIDTH] = 180;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    test("should layout node with correct start/end margin", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.direction = CSS_DIRECTION_RTL;
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_START] = 15;
+        node_1->style.margin[CSS_END] = 5;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 50;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 5;
+        node_1->layout.dimensions[CSS_WIDTH] = 180;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    test("should layout node with correct start/end margin in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      node_0->style.border[CSS_START] = 15;
+      node_0->style.border[CSS_END] = 5;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 50;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 15;
+        node_1->layout.dimensions[CSS_WIDTH] = 180;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    test("should layout node with correct start/end border", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.direction = CSS_DIRECTION_RTL;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      node_0->style.border[CSS_START] = 15;
+      node_0->style.border[CSS_END] = 5;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 50;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 5;
+        node_1->layout.dimensions[CSS_WIDTH] = 180;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    test("should layout node with correct start/end border in rtl", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.dimensions[CSS_WIDTH] = 200;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 0;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 0;
+      init_css_node_children(node_0, 1);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+      }
+    }
+
+    test("should layout node with a 0 width", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.align_items = CSS_ALIGN_FLEX_START;
+      node_0->style.dimensions[CSS_WIDTH] = 100;
+      node_0->style.dimensions[CSS_HEIGHT] = 10;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 10;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN;
+        node_1->style.align_items = CSS_ALIGN_FLEX_START;
+        node_1->style.flex = 1;
+        node_1->style.dimensions[CSS_HEIGHT] = 10;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.flex = 1;
+          node_2->style.dimensions[CSS_HEIGHT] = 10;
+          node_2->measure = measure;
+          node_2->context = "measureWithMatchParent";
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 100;
+      node_0->layout.dimensions[CSS_HEIGHT] = 10;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 10;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 50;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 10;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 50;
+          node_2->layout.dimensions[CSS_HEIGHT] = 10;
+        }
+      }
+    }
+
+    test("should correctly progagate size contraints from flexible parents", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.align_items = CSS_ALIGN_STRETCH;
+      node_0->style.dimensions[CSS_WIDTH] = 150;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+          init_css_node_children(node_2, 1);
+          {
+            css_node_t *node_3;
+            node_3 = node_2->get_child(node_2->context, 0);
+            node_3->style.align_self = CSS_ALIGN_CENTER;
+          }
+        }
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_HEIGHT] = 150;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 150;
+      node_0->layout.dimensions[CSS_HEIGHT] = 150;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 10;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 140;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 0;
+          node_2->layout.dimensions[CSS_HEIGHT] = 140;
+          init_css_node_children(node_2, 1);
+          {
+            css_node_t *node_3;
+            node_3 = node_2->get_child(node_2->context, 0);
+            node_3->layout.position[CSS_TOP] = 70;
+            node_3->layout.position[CSS_LEFT] = 0;
+            node_3->layout.dimensions[CSS_WIDTH] = 0;
+            node_3->layout.dimensions[CSS_HEIGHT] = 0;
+          }
+        }
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 150;
+      }
+    }
+
+    test("should layout content of an item which is stretched late", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.dimensions[CSS_WIDTH] = 200;
+          node_2->style.dimensions[CSS_HEIGHT] = 200;
+        }
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 210;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 200;
+        node_1->layout.dimensions[CSS_HEIGHT] = 200;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 200;
+          node_2->layout.dimensions[CSS_HEIGHT] = 200;
+        }
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 210;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 190;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 190;
+          node_2->layout.dimensions[CSS_HEIGHT] = 0;
+        }
+      }
+    }
+
+    test("should layout items whose positioning is determined by sibling tree branches", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.align_self = CSS_ALIGN_FLEX_START;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.align_self = CSS_ALIGN_STRETCH;
+        node_1->style.dimensions[CSS_WIDTH] = 1;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.dimensions[CSS_HEIGHT] = 150;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 11;
+      node_0->layout.dimensions[CSS_HEIGHT] = 150;
+      init_css_node_children(node_0, 3);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 10;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 0;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 1;
+        node_1->layout.dimensions[CSS_HEIGHT] = 150;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 11;
+        node_1->layout.dimensions[CSS_WIDTH] = 0;
+        node_1->layout.dimensions[CSS_HEIGHT] = 150;
+      }
+    }
+
+    test("should layout child whose cross axis is undefined and whose alignSelf is stretch", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.dimensions[CSS_WIDTH] = 100;
+          node_2->style.dimensions[CSS_HEIGHT] = 100;
+        }
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 100;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->style.flex_direction = CSS_FLEX_DIRECTION_COLUMN;
+          node_2->style.align_items = CSS_ALIGN_CENTER;
+          init_css_node_children(node_2, 1);
+          {
+            css_node_t *node_3;
+            node_3 = node_2->get_child(node_2->context, 0);
+            node_3->style.dimensions[CSS_WIDTH] = 50;
+            node_3->style.dimensions[CSS_HEIGHT] = 50;
+          }
+        }
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 200;
+      node_0->layout.dimensions[CSS_HEIGHT] = 100;
+      init_css_node_children(node_0, 2);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 0;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 100;
+          node_2->layout.dimensions[CSS_HEIGHT] = 100;
+        }
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 0;
+        node_1->layout.position[CSS_LEFT] = 100;
+        node_1->layout.dimensions[CSS_WIDTH] = 100;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        init_css_node_children(node_1, 1);
+        {
+          css_node_t *node_2;
+          node_2 = node_1->get_child(node_1->context, 0);
+          node_2->layout.position[CSS_TOP] = 0;
+          node_2->layout.position[CSS_LEFT] = 0;
+          node_2->layout.dimensions[CSS_WIDTH] = 100;
+          node_2->layout.dimensions[CSS_HEIGHT] = 50;
+          init_css_node_children(node_2, 1);
+          {
+            css_node_t *node_3;
+            node_3 = node_2->get_child(node_2->context, 0);
+            node_3->layout.position[CSS_TOP] = 0;
+            node_3->layout.position[CSS_LEFT] = 25;
+            node_3->layout.dimensions[CSS_WIDTH] = 50;
+            node_3->layout.dimensions[CSS_HEIGHT] = 50;
+          }
+        }
+      }
+    }
+
+    test("should center items correctly inside a stretched layout", root_node, root_layout);
+  }
+
+  {
+    css_node_t *root_node = new_test_css_node();
+    {
+      css_node_t *node_0 = root_node;
+      node_0->style.flex_direction = CSS_FLEX_DIRECTION_ROW;
+      node_0->style.align_content = CSS_ALIGN_STRETCH;
+      node_0->style.align_items = CSS_ALIGN_FLEX_START;
+      node_0->style.flex_wrap = CSS_WRAP;
+      node_0->style.dimensions[CSS_WIDTH] = 300;
+      node_0->style.dimensions[CSS_HEIGHT] = 380;
+      init_css_node_children(node_0, 15);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        node_1 = node_0->get_child(node_0->context, 3);
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        node_1 = node_0->get_child(node_0->context, 4);
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        node_1 = node_0->get_child(node_0->context, 5);
+        node_1->style.align_self = CSS_ALIGN_FLEX_START;
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        node_1 = node_0->get_child(node_0->context, 6);
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        node_1 = node_0->get_child(node_0->context, 7);
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 100;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        node_1 = node_0->get_child(node_0->context, 8);
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        node_1 = node_0->get_child(node_0->context, 9);
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        node_1 = node_0->get_child(node_0->context, 10);
+        node_1->style.align_self = CSS_ALIGN_FLEX_START;
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        node_1 = node_0->get_child(node_0->context, 11);
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        node_1 = node_0->get_child(node_0->context, 12);
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        node_1 = node_0->get_child(node_0->context, 13);
+        node_1->style.align_self = CSS_ALIGN_FLEX_START;
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+        node_1 = node_0->get_child(node_0->context, 14);
+        node_1->style.dimensions[CSS_WIDTH] = 50;
+        node_1->style.dimensions[CSS_HEIGHT] = 50;
+        node_1->style.margin[CSS_LEFT] = 10;
+        node_1->style.margin[CSS_TOP] = 10;
+        node_1->style.margin[CSS_RIGHT] = 10;
+        node_1->style.margin[CSS_BOTTOM] = 10;
+        node_1->style.margin[CSS_START] = 10;
+        node_1->style.margin[CSS_END] = 10;
+      }
+    }
+
+    css_node_t *root_layout = new_test_css_node();
+    {
+      css_node_t *node_0 = root_layout;
+      node_0->layout.position[CSS_TOP] = 0;
+      node_0->layout.position[CSS_LEFT] = 0;
+      node_0->layout.dimensions[CSS_WIDTH] = 300;
+      node_0->layout.dimensions[CSS_HEIGHT] = 380;
+      init_css_node_children(node_0, 15);
+      {
+        css_node_t *node_1;
+        node_1 = node_0->get_child(node_0->context, 0);
+        node_1->layout.position[CSS_TOP] = 10;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+        node_1 = node_0->get_child(node_0->context, 1);
+        node_1->layout.position[CSS_TOP] = 10;
+        node_1->layout.position[CSS_LEFT] = 80;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+        node_1 = node_0->get_child(node_0->context, 2);
+        node_1->layout.position[CSS_TOP] = 10;
+        node_1->layout.position[CSS_LEFT] = 150;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+        node_1 = node_0->get_child(node_0->context, 3);
+        node_1->layout.position[CSS_TOP] = 10;
+        node_1->layout.position[CSS_LEFT] = 220;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+        node_1 = node_0->get_child(node_0->context, 4);
+        node_1->layout.position[CSS_TOP] = 92.5;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 5);
+        node_1->layout.position[CSS_TOP] = 92.5;
+        node_1->layout.position[CSS_LEFT] = 80;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+        node_1 = node_0->get_child(node_0->context, 6);
+        node_1->layout.position[CSS_TOP] = 92.5;
+        node_1->layout.position[CSS_LEFT] = 150;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+        node_1 = node_0->get_child(node_0->context, 7);
+        node_1->layout.position[CSS_TOP] = 92.5;
+        node_1->layout.position[CSS_LEFT] = 220;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 100;
+        node_1 = node_0->get_child(node_0->context, 8);
+        node_1->layout.position[CSS_TOP] = 225;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+        node_1 = node_0->get_child(node_0->context, 9);
+        node_1->layout.position[CSS_TOP] = 225;
+        node_1->layout.position[CSS_LEFT] = 80;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+        node_1 = node_0->get_child(node_0->context, 10);
+        node_1->layout.position[CSS_TOP] = 225;
+        node_1->layout.position[CSS_LEFT] = 150;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+        node_1 = node_0->get_child(node_0->context, 11);
+        node_1->layout.position[CSS_TOP] = 225;
+        node_1->layout.position[CSS_LEFT] = 220;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+        node_1 = node_0->get_child(node_0->context, 12);
+        node_1->layout.position[CSS_TOP] = 307.5;
+        node_1->layout.position[CSS_LEFT] = 10;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+        node_1 = node_0->get_child(node_0->context, 13);
+        node_1->layout.position[CSS_TOP] = 307.5;
+        node_1->layout.position[CSS_LEFT] = 80;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+        node_1 = node_0->get_child(node_0->context, 14);
+        node_1->layout.position[CSS_TOP] = 307.5;
+        node_1->layout.position[CSS_LEFT] = 150;
+        node_1->layout.dimensions[CSS_WIDTH] = 50;
+        node_1->layout.dimensions[CSS_HEIGHT] = 50;
+      }
+    }
+
+    test("should layout with alignContent: stretch, and alignItems: flex-start", root_node, root_layout);
+  }
+  /** END_GENERATED **/
+  return tests_finished();
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/facebook-flexbox/layout-test-utils.h b/automated-tests/src/dali-toolkit-third-party/facebook-flexbox/layout-test-utils.h
new file mode 100644 (file)
index 0000000..9c8a903
--- /dev/null
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2014, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <dali-toolkit/internal/controls/flex-container/layout.h>
+
+void test(const char *name, css_node_t *style, css_node_t *expected_layout);
+bool tests_finished(void);
+css_dim_t measure(void *context, float width, css_measure_mode_t widthMode, float height, css_measure_mode_t heightMode);
+void init_css_node_children(css_node_t *node, int children_count);
+css_node_t *new_test_css_node(void);
+bool perform_layout_test(void);
diff --git a/automated-tests/src/dali-toolkit-third-party/tct-dali-toolkit-third-party-core.cpp b/automated-tests/src/dali-toolkit-third-party/tct-dali-toolkit-third-party-core.cpp
new file mode 100644 (file)
index 0000000..df212a2
--- /dev/null
@@ -0,0 +1,51 @@
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-toolkit-third-party-core.h"
+
+int main(int argc, char * const argv[])
+{
+  int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
+
+  const char* optString = "rs";
+  bool optRerunFailed(true);
+  bool optRunSerially(false);
+
+  int nextOpt = 0;
+  do
+  {
+    nextOpt = getopt( argc, argv, optString );
+    switch(nextOpt)
+    {
+      case 'r':
+        optRerunFailed = true;
+        break;
+      case 's':
+        optRunSerially = true;
+        break;
+      case '?':
+        TestHarness::Usage(argv[0]);
+        exit(TestHarness::EXIT_STATUS_BAD_ARGUMENT);
+        break;
+    }
+  } while( nextOpt != -1 );
+
+  if( optind == argc ) // no testcase name in argument list
+  {
+    if( optRunSerially )
+    {
+      result = TestHarness::RunAll( argv[0], tc_array );
+    }
+    else
+    {
+      result = TestHarness::RunAllInParallel( argv[0], tc_array, optRerunFailed );
+    }
+  }
+  else
+  {
+    // optind is index of next argument - interpret as testcase name
+    result = TestHarness::FindAndRunTestCase(tc_array, argv[optind]);
+  }
+  return result;
+}
diff --git a/automated-tests/src/dali-toolkit-third-party/utc-Dali-Flexbox-Layout.cpp b/automated-tests/src/dali-toolkit-third-party/utc-Dali-Flexbox-Layout.cpp
new file mode 100644 (file)
index 0000000..83f932e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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.
+ *
+ */
+
+#include <dali-toolkit-test-suite-utils.h>
+
+extern "C"
+{
+#include "facebook-flexbox/layout-test-utils.h"
+}
+
+//////////////////////////////////////////////////////////
+
+int UtcDaliFlexboxLayoutTest(void)
+{
+  ToolkitTestApplication application;
+  tet_infoline("UtcDaliFlexboxLayoutTest");
+
+  // The test function is a 3rd party function that should return true if the test passes
+  if( perform_layout_test() )
+  {
+    tet_result(TET_PASS);
+  }
+  else
+  {
+    tet_result(TET_FAIL);
+  }
+
+  END_TEST;
+}
index 15ffd4c..4d63fee 100644 (file)
@@ -45,7 +45,6 @@ SET(TC_SOURCES
    utc-Dali-PushButton.cpp
    utc-Dali-RadioButton.cpp
    utc-Dali-ScrollViewEffect.cpp
-   utc-Dali-StyleManager.cpp
    utc-Dali-SuperBlurView.cpp
    utc-Dali-Toolkit.cpp
    utc-Dali-Model3dView.cpp
index 0a90c8e..467bb52 100644 (file)
@@ -233,12 +233,27 @@ void DALI_TEST_EQUALS( const std::string &str1, const char* str2, const char* lo
   DALI_TEST_EQUALS(str1.c_str(), str2, location);
 }
 
-/**
- * Test whether two strings are equal.
- * @param[in] str1 The first string
- * @param[in] str2 The second string
- * @param[in] location The TEST_LOCATION macro should be used here
- */
+void DALI_TEST_EQUALS( Property::Value& str1, const char* str2, const char* location)
+{
+  bool result = false;
+
+  if( str1.GetType() == Property::STRING )
+  {
+    std::string string;
+    str1.Get(string);
+    result = !string.compare(str2);
+  }
+
+  if( result )
+  {
+    tet_result(TET_PASS);
+  }
+  else
+  {
+    tet_result(TET_FAIL);
+  }
+}
+
 void DALI_TEST_EQUALS( const char* str1, const std::string &str2, const char* location)
 {
   DALI_TEST_EQUALS(str1, str2.c_str(), location);
index baeaa6a..7f81872 100644 (file)
@@ -153,6 +153,82 @@ inline bool CompareType<Degree>(Degree q1, Degree q2, float epsilon)
   return CompareType<float>(q1.degree, q2.degree, epsilon);
 }
 
+template <>
+inline bool CompareType<Property::Value>(Property::Value q1, Property::Value q2, float epsilon)
+{
+  Property::Type type = q1.GetType();
+  if( type != q2.GetType() )
+  {
+    return false;
+  }
+
+  switch(type)
+  {
+    case Property::BOOLEAN:
+    {
+      bool a, b;
+      q1.Get(a);
+      q2.Get(b);
+      return a == b;
+      break;
+    }
+    case Property::INTEGER:
+    {
+      int a, b;
+      q1.Get(a);
+      q2.Get(b);
+      return a == b;
+      break;
+    }
+    case Property::FLOAT:
+    {
+      float a, b;
+      q1.Get(a);
+      q2.Get(b);
+      return CompareType<float>(a, b, epsilon);
+      break;
+    }
+    case Property::VECTOR2:
+    {
+      Vector2 a, b;
+      q1.Get(a);
+      q2.Get(b);
+      return CompareType<Vector2>(a, b, epsilon);
+      break;
+    }
+    case Property::VECTOR3:
+    {
+      Vector3 a, b;
+      q1.Get(a);
+      q2.Get(b);
+      return CompareType<Vector3>(a, b, epsilon);
+      break;
+    }
+    case Property::RECTANGLE:
+    case Property::VECTOR4:
+    {
+      Vector4 a, b;
+      q1.Get(a);
+      q2.Get(b);
+      return CompareType<Vector4>(a, b, epsilon);
+      break;
+    }
+    case Property::ROTATION:
+    {
+      Quaternion a, b;
+      q1.Get(a);
+      q2.Get(b);
+      return CompareType<Quaternion>(a, b, epsilon);
+      break;
+    }
+    default:
+      return false;
+  }
+
+  return false;
+}
+
+
 bool operator==(TimePeriod a, TimePeriod b);
 std::ostream& operator<<( std::ostream& ostream, TimePeriod value );
 std::ostream& operator<<( std::ostream& ostream, Radian angle );
@@ -196,6 +272,23 @@ inline void DALI_TEST_EQUALS(Type value1, Type value2, float epsilon, const char
   }
 }
 
+template<typename Type>
+inline void DALI_TEST_NOT_EQUALS(Type value1, Type value2, float epsilon, const char* location)
+{
+  if( CompareType<Type>(value1, value2, epsilon) )
+  {
+    std::ostringstream o;
+    o << value1 << " !=  " << value2 << std::endl;
+    fprintf(stderr, "%s, checking %s", location, o.str().c_str());
+    tet_result(TET_FAIL);
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+
 /**
  * Test whether two TimePeriods are within a certain distance of each other.
  * @param[in] value1 The first value
@@ -316,6 +409,14 @@ inline void DALI_TEST_EQUALS<const std::string&>( const std::string &str1, const
  * @param[in] str2 The second string
  * @param[in] location The TEST_LOCATION macro should be used here
  */
+void DALI_TEST_EQUALS( Property::Value& str1, const char* str2, const char* location);
+
+/**
+ * Test whether two strings are equal.
+ * @param[in] str1 The first string
+ * @param[in] str2 The second string
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
 void DALI_TEST_EQUALS( const std::string &str1, const char* str2, const char* location);
 
 /**
index c4dac4e..873c8d2 100644 (file)
@@ -17,7 +17,7 @@
 
 #include "dummy-control.h"
 
-#include <dali-toolkit/devel-api/styling/style-manager.h>
+#include <dali-toolkit/dali-toolkit.h>
 
 namespace Dali
 {
index 304e567..5b127c7 100644 (file)
@@ -62,15 +62,11 @@ Geometry CreateQuadGeometryFromBuffer( PropertyBuffer vertexData )
     { Vector2( halfQuadSize,  halfQuadSize), Vector2(1.f, 1.f) } };
   vertexData.SetData(texturedQuadVertexData, 4);
 
-  unsigned int indexData[6] = { 0, 3, 1, 0, 2, 3 };
-  Property::Map indexFormat;
-  indexFormat["indices"] = Property::INTEGER;
-  PropertyBuffer indices = PropertyBuffer::New( indexFormat );
-  indices.SetData( indexData, sizeof(indexData)/sizeof(indexData[0]) );
+  unsigned short indexData[6] = { 0, 3, 1, 0, 2, 3 };
 
   Geometry geometry = Geometry::New();
   geometry.AddVertexBuffer( vertexData );
-  geometry.SetIndexBuffer( indices );
+  geometry.SetIndexBuffer( indexData, sizeof(indexData)/sizeof(indexData[0]) );
 
   return geometry;
 }
index cbecb9b..a83f3e3 100644 (file)
@@ -72,6 +72,7 @@ void TestButton::SetProperty( BaseObject* object, Property::Index index, const P
 
   if ( button )
   {
+    TestButton& buttonImpl = GetImpl(button);
     switch ( index )
     {
       case Test::TestButton::Property::PRESS_TRANSITION:
@@ -79,19 +80,28 @@ void TestButton::SetProperty( BaseObject* object, Property::Index index, const P
         if( value.GetType() == Property::MAP )
         {
           Property::Map* valueMap = value.GetMap();
-          TestButton& buttonImpl = GetImpl(button);
           buttonImpl.mPressTransitionData.Clear();
           NewAnimation( *valueMap, buttonImpl.mPressTransitionData );
         }
         else if( value.GetType() == Property::ARRAY )
         {
           Property::Array* valueArray = value.GetArray();
-          TestButton& buttonImpl = GetImpl(button);
           buttonImpl.mPressTransitionData.Clear();
           NewAnimation( *valueArray, buttonImpl.mPressTransitionData );
         }
         break;
       }
+      case Test::TestButton::Property::BACKGROUND_COLOR:
+      {
+        buttonImpl.mBackgroundColor = value.Get<Vector4>();
+        break;
+      }
+
+      case Test::TestButton::Property::FOREGROUND_COLOR:
+      {
+        buttonImpl.mForegroundColor = value.Get<Vector4>();
+        break;
+      }
     }
   }
 }
@@ -100,6 +110,8 @@ Property::Value TestButton::GetProperty( BaseObject* object, Property::Index pro
 {
   Test::TestButton button = Test::TestButton::DownCast( Dali::BaseHandle( object ) );
 
+  Property::Value value;
+
   if ( button )
   {
     TestButton& buttonImpl = GetImpl(button);
@@ -108,22 +120,26 @@ Property::Value TestButton::GetProperty( BaseObject* object, Property::Index pro
       case Test::TestButton::Property::PRESS_TRANSITION:
       {
         return ConvertAnimationMap(buttonImpl.mPressTransitionData);
-        break;
       }
       case Test::TestButton::Property::RELEASE_TRANSITION:
       {
         return ConvertAnimationMap(buttonImpl.mReleaseTransitionData);
-        break;
       }
       case Test::TestButton::Property::DISABLED_TRANSITION:
       {
         return ConvertAnimationMap(buttonImpl.mDisabledTransitionData);
-        break;
       }
       case Test::TestButton::Property::ENABLED_TRANSITION:
       {
         return ConvertAnimationMap(buttonImpl.mEnabledTransitionData);
-        break;
+      }
+      case Test::TestButton::Property::BACKGROUND_COLOR:
+      {
+        return Property::Value(buttonImpl.mBackgroundColor);
+      }
+      case Test::TestButton::Property::FOREGROUND_COLOR:
+      {
+        return Property::Value(buttonImpl.mForegroundColor);
       }
     }
   }
@@ -142,6 +158,8 @@ DALI_PROPERTY_REGISTRATION( Test, TestButton, "pressTransition", ARRAY, PRESS_TR
 DALI_PROPERTY_REGISTRATION( Test, TestButton, "releaseTransition", ARRAY, RELEASE_TRANSITION)
 DALI_PROPERTY_REGISTRATION( Test, TestButton, "disabledTransition", ARRAY, DISABLED_TRANSITION )
 DALI_PROPERTY_REGISTRATION( Test, TestButton, "enabledTransition", ARRAY, ENABLED_TRANSITION )
+DALI_PROPERTY_REGISTRATION( Test, TestButton, "backgroundColor", VECTOR4, BACKGROUND_COLOR )
+DALI_PROPERTY_REGISTRATION( Test, TestButton, "foregroundColor", VECTOR4, FOREGROUND_COLOR )
 
 DALI_TYPE_REGISTRATION_END()
 
index 5dd5ac3..c9a29e4 100644 (file)
@@ -42,7 +42,9 @@ public:
       PRESS_TRANSITION = PROPERTY_START_INDEX,
       RELEASE_TRANSITION,
       DISABLED_TRANSITION,
-      ENABLED_TRANSITION
+      ENABLED_TRANSITION,
+      BACKGROUND_COLOR,
+      FOREGROUND_COLOR
     };
   };
   TestButton();
@@ -79,6 +81,8 @@ public:
   Test::TestAnimationData mReleaseTransitionData;
   Test::TestAnimationData mDisabledTransitionData;
   Test::TestAnimationData mEnabledTransitionData;
+  Dali::Vector4 mBackgroundColor;
+  Dali::Vector4 mForegroundColor;
 };
 
 inline TestButton& GetImpl( Test::TestButton& handle )
index a69b323..5820806 100644 (file)
@@ -394,6 +394,12 @@ static Internal::Adaptor::AccessibilityAdaptor& GetImplementation(Dali::Accessib
   return static_cast<Internal::Adaptor::AccessibilityAdaptor&>(handle);
 }
 
+static const Internal::Adaptor::AccessibilityAdaptor& GetImplementation(const Dali::AccessibilityAdaptor& adaptor)
+{
+  const BaseObject& handle = adaptor.GetBaseObject();
+  return static_cast<const Internal::Adaptor::AccessibilityAdaptor&>(handle);
+}
+
 
 } // namespace Adaptor
 } // namespace Internal
@@ -422,7 +428,7 @@ void AccessibilityAdaptor::MockSetReadPosition( Vector2& position )
 
 // Methods:
 
-Vector2 AccessibilityAdaptor::GetReadPosition()
+Vector2 AccessibilityAdaptor::GetReadPosition() const
 {
   return Internal::Adaptor::GetImplementation(*this).GetReadPosition();
 }
index 900f374..2975c33 100644 (file)
@@ -56,7 +56,7 @@ public: // Getters
 
   static AccessibilityAdaptor Get();
 
-  Vector2 GetReadPosition();
+  Vector2 GetReadPosition() const;
   bool IsEnabled() const;
   void SetActionHandler(AccessibilityActionHandler& handler);
   void SetGestureHandler(AccessibilityGestureHandler& handler);
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-bitmap-loader.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-bitmap-loader.cpp
new file mode 100644 (file)
index 0000000..00c1204
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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.
+ */
+
+#include <dali/public-api/object/base-object.h>
+#include <dali/devel-api/adaptor-framework/bitmap-loader.h>
+#include <cstring>
+
+using namespace Dali;
+
+namespace Dali
+{
+class Adaptor;
+
+namespace Internal
+{
+
+class BitmapLoader : public BaseObject
+{
+public:
+  static IntrusivePtr<BitmapLoader> New( const std::string& url,
+                                         ImageDimensions size,
+                                         FittingMode::Type fittingMode,
+                                         SamplingMode::Type samplingMode,
+                                         bool orientationCorrection)
+  {
+    IntrusivePtr<BitmapLoader> internal = new BitmapLoader( url, size, fittingMode, samplingMode, orientationCorrection );
+    return internal;
+  }
+
+  BitmapLoader(const std::string& url,
+               ImageDimensions size,
+               FittingMode::Type fittingMode,
+               SamplingMode::Type samplingMode,
+               bool orientationCorrection)
+  : mSize(size),
+    mPixelData(),
+    mUrl(url)
+  {
+  }
+
+  ~BitmapLoader(){}
+
+  void Load()
+  {
+    size_t bufferSize  = mSize.GetWidth() * mSize.GetHeight() * 4;
+    unsigned char* buffer = static_cast<unsigned char*>(malloc(bufferSize));
+    memset(buffer, 0, bufferSize);
+
+    mPixelData = PixelData::New( buffer, mSize.GetWidth(), mSize.GetHeight(), Pixel::RGBA8888, PixelData::FREE);
+  }
+
+  PixelDataPtr GetPixelData() const
+  {
+    return mPixelData;
+  }
+
+  const std::string& GetUrl() const
+  {
+    return mUrl;
+  }
+
+  bool IsLoaded()
+  {
+    return mPixelData ? true : false;
+  }
+
+  ImageDimensions mSize;
+  PixelDataPtr mPixelData;
+  const std::string mUrl;
+};
+
+} // internal
+
+inline Internal::BitmapLoader& GetImplementation(Dali::BitmapLoader& handle)
+{
+  DALI_ASSERT_ALWAYS( handle && "handle is empty" );
+  BaseObject& object = handle.GetBaseObject();
+  return static_cast<Internal::BitmapLoader&>(object);
+}
+
+inline const Internal::BitmapLoader& GetImplementation(const Dali::BitmapLoader& handle)
+{
+  DALI_ASSERT_ALWAYS( handle && "handle is empty" );
+  const BaseObject& object = handle.GetBaseObject();
+  return static_cast<const Internal::BitmapLoader&>(object);
+}
+
+Dali::BitmapLoader Dali::BitmapLoader::New(std::string const&url, Dali::Uint16Pair size, Dali::FittingMode::Type fittingMode, Dali::SamplingMode::Type samplingMode, bool orientationCorrection)
+{
+  IntrusivePtr<Internal::BitmapLoader> internal = Internal::BitmapLoader::New(url, size, fittingMode, samplingMode, orientationCorrection);
+  return BitmapLoader( internal.Get() );
+}
+
+Dali::BitmapLoader::BitmapLoader(Dali::BitmapLoader const& handle)
+:BaseHandle(handle)
+{
+}
+Dali::BitmapLoader::BitmapLoader(Internal::BitmapLoader* internal)
+:BaseHandle(internal)
+{
+}
+Dali::BitmapLoader::~BitmapLoader()
+{
+}
+void Dali::BitmapLoader::Load()
+{
+  GetImplementation(*this).Load();
+}
+PixelDataPtr Dali::BitmapLoader::GetPixelData() const
+{
+  return GetImplementation(*this).GetPixelData();
+}
+std::string Dali::BitmapLoader::GetUrl() const
+{
+  return GetImplementation(*this).GetUrl();
+}
+bool Dali::BitmapLoader::IsLoaded()
+{
+  return GetImplementation(*this).IsLoaded();
+}
+
+} // Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-color-controller.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-color-controller.cpp
new file mode 100644 (file)
index 0000000..f24bc44
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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.
+ */
+
+#include <dali/devel-api/adaptor-framework/color-controller.h>
+
+#include <dali/public-api/object/base-object.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class ColorController : public BaseObject
+{
+public:
+  ColorController(){}
+  static Dali::ColorController Get()
+  {
+    return Dali::ColorController( new ColorController() );
+  }
+
+  bool RetrieveColor( const std::string& colorCode, Vector4& colorValue )
+  {
+    return false;
+  }
+
+  bool RetrieveColor( const std::string& colorCode ,
+                      Vector4&           textColor,
+                      Vector4&           textOutlineColor,
+                      Vector4&           textShadowColor)
+  {
+    return false;
+  }
+protected:
+  virtual ~ColorController(){}
+};
+
+} // Adaptor
+} // Internal
+
+inline Internal::Adaptor::ColorController& GetImplementation(Dali::ColorController& controller)
+{
+  DALI_ASSERT_ALWAYS(controller && "ColorController handle is empty");
+  BaseObject& handle = controller.GetBaseObject();
+  return static_cast<Internal::Adaptor::ColorController&>(handle);
+}
+
+inline const Internal::Adaptor::ColorController& GetImplementation(const Dali::ColorController& controller)
+{
+  DALI_ASSERT_ALWAYS(controller && "ColorController handle is empty");
+  const BaseObject& handle = controller.GetBaseObject();
+  return static_cast<const Internal::Adaptor::ColorController&>(handle);
+}
+
+ColorController ColorController::Get()
+{
+  return Internal::Adaptor::ColorController::Get();
+}
+
+ColorController::ColorController(Internal::Adaptor::ColorController* internal)
+: BaseHandle(internal)
+{
+}
+
+ColorController::~ColorController()
+{
+}
+
+bool ColorController::RetrieveColor( const std::string& colorCode, Vector4& colorValue )
+{
+  return GetImplementation(*this).RetrieveColor( colorCode, colorValue );
+}
+
+} // Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-feedback-player.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-feedback-player.cpp
new file mode 100644 (file)
index 0000000..999249a
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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.
+ */
+
+#include <dali/devel-api/adaptor-framework/feedback-player.h>
+#include <dali/devel-api/adaptor-framework/singleton-service.h>
+#include <dali/public-api/object/base-object.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+class Adaptor;
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+class FeedbackPlayer : public Dali::BaseObject
+{
+public:
+  static Dali::FeedbackPlayer New()
+  {
+    Dali::FeedbackPlayer player = Dali::FeedbackPlayer( new FeedbackPlayer() );
+    return player;
+  }
+
+  static Dali::FeedbackPlayer Get()
+  {
+    Dali::FeedbackPlayer player;
+    Dali::SingletonService service( Dali::SingletonService::Get() );
+    if( service )
+    {
+      // Check whether the singleton is already created
+      Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::FeedbackPlayer ) );
+      if( handle )
+      {
+        player = Dali::FeedbackPlayer( dynamic_cast< FeedbackPlayer* >( handle.GetObjectPtr() ) );
+      }
+      else
+      {
+        player = Dali::FeedbackPlayer( New() );
+        service.Register( typeid( player ), player );
+      }
+    }
+    return player;
+  }
+  void PlayMonotone(unsigned int duration)
+  {
+  }
+
+  void PlayFile( const std::string& filePath )
+  {
+  }
+
+  void Stop()
+  {
+  }
+
+  int PlaySound( const std::string& fileName )
+  {
+    return 0;
+  }
+
+  void StopSound( int handle )
+  {
+  }
+
+  void PlayFeedbackPattern( int type, int pattern )
+  {
+  }
+
+  bool LoadFile(const std::string& filename, std::string& data)
+  {
+    return true;
+  }
+
+private:
+  FeedbackPlayer()
+  {
+  }
+
+  virtual ~FeedbackPlayer()
+  {
+  }
+
+  FeedbackPlayer(const FeedbackPlayer&)
+  {
+  }
+
+  FeedbackPlayer& operator=(FeedbackPlayer&)
+  {
+    return *this;
+  }
+};
+
+} // Adaptor
+} // Internal
+
+inline Internal::Adaptor::FeedbackPlayer& GetImplementation(Dali::FeedbackPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "FeedbackPlayer handle is empty" );
+  BaseObject& handle = player.GetBaseObject();
+  return static_cast<Internal::Adaptor::FeedbackPlayer&>(handle);
+}
+
+inline const Internal::Adaptor::FeedbackPlayer& GetImplementation(const Dali::FeedbackPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "FeedbackPlayer handle is empty" );
+  const BaseObject& handle = player.GetBaseObject();
+  return static_cast<const Internal::Adaptor::FeedbackPlayer&>(handle);
+}
+
+FeedbackPlayer::FeedbackPlayer()
+{
+}
+
+FeedbackPlayer FeedbackPlayer::Get()
+{
+  return Internal::Adaptor::FeedbackPlayer::Get();
+}
+
+FeedbackPlayer::~FeedbackPlayer()
+{
+}
+
+void FeedbackPlayer::PlayMonotone(unsigned int duration)
+{
+  GetImplementation(*this).PlayMonotone(duration);
+}
+
+void FeedbackPlayer::PlayFile(const std::string filePath)
+{
+  GetImplementation(*this).PlayFile(filePath);
+}
+
+void FeedbackPlayer::Stop()
+{
+  GetImplementation(*this).Stop();
+}
+
+int FeedbackPlayer::PlaySound( const std::string& fileName )
+{
+  return GetImplementation(*this).PlaySound(fileName);
+}
+
+void FeedbackPlayer::StopSound( int handle )
+{
+  GetImplementation(*this).StopSound(handle);
+}
+
+void FeedbackPlayer::PlayFeedbackPattern( int type, int pattern )
+{
+  GetImplementation(*this).PlayFeedbackPattern(type, pattern);
+}
+
+bool FeedbackPlayer::LoadFile(const std::string& filename, std::string& data)
+{
+  return GetImplementation(*this).LoadFile(filename, data);
+}
+
+FeedbackPlayer::FeedbackPlayer( Internal::Adaptor::FeedbackPlayer* player )
+: BaseHandle( player )
+{
+}
+
+} // Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-file-loader.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-file-loader.cpp
new file mode 100644 (file)
index 0000000..5cc6ad1
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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.
+ */
+
+#include <string>
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/devel-api/adaptor-framework/file-loader.h>
+
+namespace Dali
+{
+
+namespace FileLoader
+{
+
+int ReadFile(
+  const std::string& filename,
+  Dali::Vector<char> & memblock,
+  FileLoader::FileType fileType)
+{
+  return 0;
+}
+
+int ReadFile(
+  const std::string& filename,
+  std::streampos& fileSize,
+  Dali::Vector<char> & memblock,
+  FileLoader::FileType fileType)
+{
+  return 0;
+}
+
+std::streampos GetFileSize(const std::string& filename)
+{
+  return 0;
+}
+
+}
+}
index 30dd65f..b1b5660 100644 (file)
  *
  */
 
-#include "toolkit-orientation.h"
+#include <dali/devel-api/adaptor-framework/orientation.h>
 
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/object/base-object.h>
 #include <dali/public-api/signals/dali-signal.h>
 
-namespace Dali
-{
+using namespace Dali;
 
-namespace
+namespace Dali
 {
-ToolkitOrientation* gToolkitOrientation(NULL);
-} // unnamed namespace
+class Adaptor;
 
 namespace Internal
 {
-
 namespace Adaptor
 {
+class Window;
+
+
+struct RotationEvent
+{
+  int angle;     ///< one of 0, 90, 180, 270
+  int winResize; ///< true if the window should be resized
+  int width;     ///< new window width
+  int height;    ///< new window height
+};
 
 /**
- * Stub for the Orientation
+ * The RotationObserver can be overridden in order to listen to rotation events.
  */
-class Orientation : public BaseObject
+class RotationObserver
 {
-public: // Creation & Destruction
+public:
+  virtual void OnRotationPrepare( const RotationEvent& rotation ) = 0;
+  virtual void OnRotationRequest( ) = 0;
 
-  Orientation();
-  Orientation(ToolkitOrientation *orientation);
-  ~Orientation();
+protected:
+  RotationObserver(){}
+  virtual ~RotationObserver(){}
+};
 
-public: // Setters & Getters
+class Orientation : public BaseObject, public RotationObserver
+{
+public:
+  typedef Dali::Orientation::OrientationSignalType OrientationSignalType;
 
-  void SetDegrees( int degrees )
+  static Orientation* New(Window* window)
+  {
+    Orientation* orientation = new Orientation(window);
+    return orientation;
+  }
+  Orientation(Window* window)
   {
-    mOrientation = degrees;
   }
 
-  int GetDegrees() const;
-  float GetRadians() const;
-
-public: // Signals
-
-  Dali::Orientation::OrientationSignalType& ChangedSignal();
-
-  void EmitChangedSignal()
+protected:
+  virtual ~Orientation()
+  {
+  }
+public:
+  void SetAdaptor(Dali::Adaptor& adaptor)
+  {
+  }
+  int GetDegrees() const
+  {
+    return 0;
+  }
+  float GetRadians() const
+  {
+    return 0.0f;
+  }
+  OrientationSignalType& ChangedSignal()
   {
-    mChangedSignal.Emit(Dali::Orientation(this));
+    return mChangedSignal;
   }
+  virtual void OnRotationPrepare( const RotationEvent& rotation )
+  {
+  };
+  virtual void OnRotationRequest( )
+  {
+  };
 
 private:
-
-  Dali::Orientation::OrientationSignalType mChangedSignal;
-
-  ToolkitOrientation* mToolkitOrientation;
-
-  int mOrientation;
+  Orientation(const Orientation&);
+  Orientation& operator=(Orientation&);
+  OrientationSignalType mChangedSignal;
 };
 
-Orientation::Orientation()
-: mToolkitOrientation(NULL),
-  mOrientation(0)
-{
-}
+} // Adaptor namespace
+} // Internal namespace
 
-Orientation::Orientation(ToolkitOrientation *orientation)
-: mToolkitOrientation(orientation),
-  mOrientation(0)
+inline Internal::Adaptor::Orientation& GetImplementation (Dali::Orientation& orientation)
 {
+  DALI_ASSERT_ALWAYS(orientation && "Orientation handle is empty");
+  BaseObject& handle = orientation.GetBaseObject();
+  return static_cast<Internal::Adaptor::Orientation&>(handle);
 }
-
-Orientation::~Orientation()
+inline const Internal::Adaptor::Orientation& GetImplementation(const Dali::Orientation& orientation)
 {
+  DALI_ASSERT_ALWAYS(orientation && "Orientation handle is empty");
+  const BaseObject& handle = orientation.GetBaseObject();
+  return static_cast<const Internal::Adaptor::Orientation&>(handle);
 }
 
-int Orientation::GetDegrees() const
+Orientation::Orientation()
 {
-  mToolkitOrientation->mFunctionsCalled.GetDegrees = true;
-  return mOrientation;
 }
-
-float Orientation::GetRadians() const
+Orientation::~Orientation()
 {
-  mToolkitOrientation->mFunctionsCalled.GetRadians = true;
-  return Math::PI * (float)mOrientation / 180.0f;
 }
-
-Dali::Orientation::OrientationSignalType& Orientation::ChangedSignal()
+Orientation::Orientation(const Orientation& handle)
+: BaseHandle(handle)
 {
-  mToolkitOrientation->mFunctionsCalled.ChangedSignal = true;
-  return mChangedSignal;
 }
 
-} // namespace Adaptor
-
-} // namespace Internal
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-ToolkitOrientation::ToolkitOrientation()
-: mOrientationStub(new Internal::Adaptor::Orientation(this)),
-  mOrientation( mOrientationStub )
+Orientation& Orientation::operator=(const Orientation& rhs)
 {
-  gToolkitOrientation = this;
+  BaseHandle::operator=(rhs);
+  return *this;
 }
 
-ToolkitOrientation::~ToolkitOrientation()
+int Orientation::GetDegrees() const
 {
-  gToolkitOrientation = NULL;
+  return GetImplementation(*this).GetDegrees();
 }
 
-Orientation ToolkitOrientation::GetHandle()
+float Orientation::GetRadians() const
 {
-  return mOrientation;
+  return GetImplementation(*this).GetRadians();
 }
 
-void ToolkitOrientation::SetDegrees( int degrees )
+Orientation::OrientationSignalType& Orientation::ChangedSignal()
 {
-  mOrientationStub->SetDegrees( degrees );
+  return GetImplementation(*this).ChangedSignal();
 }
 
-void ToolkitOrientation::EmitChangedSignal()
+Orientation::Orientation( Internal::Adaptor::Orientation* orientation )
+: BaseHandle(orientation)
 {
-  mOrientationStub->EmitChangedSignal();
 }
 
-} // namespace Dali
+} // Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-orientation.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-orientation.h
deleted file mode 100644 (file)
index 007f70f..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef __DALI_TOOLKIT_TOOLKIT_ORIENTATION_H__
-#define __DALI_TOOLKIT_TOOLKIT_ORIENTATION_H__
-
-/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- *
- * Licensed 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.
- *
- */
-
-// EXTERNAL INCLUDES
-#include <string>
-#include <dali/devel-api/adaptor-framework/orientation.h>
-
-namespace Dali
-{
-
-namespace Internal
-{
-namespace Adaptor
-{
-class Orientation;
-}
-}
-
-/**
- * This creates a stubbed Orientation so that internal Toolkit Adaptor calls work.
- * Furthermore, it provides an interface to see if certain methods were invoked.
- */
-class ToolkitOrientation
-{
-public: // Construction & Destruction
-
-  ToolkitOrientation();
-  ~ToolkitOrientation();
-
-public: // Getters
-
-  Orientation GetHandle();
-
-public: // Setters
-
-  void SetDegrees( int degrees );
-
-public: // Signal Emissions
-
-  void EmitChangedSignal();
-
-public: // TEST FUNCTIONS
-
-  // Enumeration of Adaptor methods
-  enum TestFuncEnum
-  {
-    GetDegrees,
-    GetRadians,
-    ChangedSignal,
-  };
-
-  void Reset()
-  {
-    mFunctionsCalled.Reset();
-  }
-
-  bool WasCalled(TestFuncEnum func)
-  {
-    switch(func)
-    {
-      case GetDegrees:          return mFunctionsCalled.GetDegrees;
-      case GetRadians:          return mFunctionsCalled.GetRadians;
-      case ChangedSignal:       return mFunctionsCalled.ChangedSignal;
-    }
-    return false;
-  }
-
-  void ResetCallStatistics(TestFuncEnum func)
-  {
-    switch(func)
-    {
-      case GetDegrees:          mFunctionsCalled.GetDegrees = false; break;
-      case GetRadians:          mFunctionsCalled.GetRadians = false; break;
-      case ChangedSignal:       mFunctionsCalled.ChangedSignal = false; break;
-    }
-  }
-
-private:
-
-  struct TestFunctions
-  {
-    TestFunctions()
-    : GetDegrees(false),
-      GetRadians(false),
-      ChangedSignal(false)
-    {
-    }
-
-    void Reset()
-    {
-      GetDegrees = false;
-      GetRadians = false;
-      ChangedSignal = false;
-    }
-
-    bool GetDegrees;
-    bool GetRadians;
-    bool ChangedSignal;
-  };
-
-  TestFunctions mFunctionsCalled;
-
-  // The stub
-  Internal::Adaptor::Orientation* mOrientationStub;
-  friend class Internal::Adaptor::Orientation;
-  Orientation mOrientation; // Hold a handle ourselves.
-};
-
-} // namespace Dali
-
-#endif // __DALI_TOOLKIT_TOOLKIT_ORIENTATION_H__
index 8ac2d0f..d8efd70 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
  *
  */
 
-#include "toolkit-singleton-service.h"
+#include <dali/devel-api/adaptor-framework/singleton-service.h>
 
 #include <dali/public-api/common/dali-common.h>
 #include <dali/public-api/object/base-object.h>
@@ -31,108 +31,125 @@ namespace Internal
 namespace Adaptor
 {
 
-/**
- * Stub for the SingletonService
- */
-class SingletonService : public Dali::BaseObject
+namespace
 {
-public:
-  static Dali::SingletonService New();
-  static Dali::SingletonService Get();
-  void Register( const std::type_info& info, BaseHandle singleton );
-  void UnregisterAll();
-  BaseHandle GetSingleton( const std::type_info& info ) const;
-
-private:
-  SingletonService();
-  virtual ~SingletonService();
+Dali::IntrusivePtr<SingletonService> gSingletonService;
+} // unnamed namespace
 
-  // Undefined
-  SingletonService( const SingletonService& );
-  SingletonService& operator=( SingletonService& );
 
-private:
-
-  typedef std::pair<std::string, BaseHandle> SingletonPair;
-  typedef std::map<std::string, BaseHandle>  SingletonContainer;
-  typedef SingletonContainer::const_iterator SingletonConstIter;
-
-  SingletonContainer mSingletonContainer; ///< The container to look up singleton by its type name
+class SingletonService : public Dali::BaseObject
+{
+public:
 
-  static Dali::SingletonService mToolkitSingletonService;
-};
+  /**
+   * Create a SingletonService.
+   * This should only be called once by the Application class.
+   * @return A newly created SingletonService.
+   */
+  static Dali::SingletonService New()
+  {
+    DALI_ASSERT_ALWAYS( 0 && "SingletonService New method used");
+    gSingletonService = Dali::IntrusivePtr<SingletonService>( new SingletonService() );
+    return Dali::SingletonService( gSingletonService.Get() );
+  }
 
-Dali::SingletonService SingletonService::mToolkitSingletonService;
+  /**
+   * @copydoc Dali::SingletonService::Get()
+   */
+  static Dali::SingletonService Get()
+  {
+    Dali::SingletonService singletonService;
+    if ( !gSingletonService )
+    {
+      gSingletonService = Dali::IntrusivePtr<SingletonService>( new SingletonService() );
+    }
+    return Dali::SingletonService( gSingletonService.Get() );
+  }
 
-Dali::SingletonService SingletonService::New()
-{
-  return Get();
-}
+  /**
+   * @copydoc Dali::SingletonService::Register()
+   */
+  void Register( const std::type_info& info, BaseHandle singleton )
+  {
+    if( singleton )
+    {
+      mSingletonContainer.insert( SingletonPair( info.name(), singleton ) );
+    }
+  }
 
-Dali::SingletonService SingletonService::Get()
-{
-  if( ! mToolkitSingletonService )
+  /**
+   * @copydoc Dali::SingletonService::UnregisterAll()
+   */
+  void UnregisterAll()
   {
-    mToolkitSingletonService = Dali::SingletonService( new Dali::Internal::Adaptor::SingletonService );
+    mSingletonContainer.clear();
   }
-  return mToolkitSingletonService;
-}
 
-void SingletonService::Register( const std::type_info& info, BaseHandle singleton )
-{
-  if( singleton )
+  /**
+   * @copydoc Dali::SingletonService::GetSingleton()
+   */
+  BaseHandle GetSingleton( const std::type_info& info ) const
   {
-    mSingletonContainer.insert( SingletonPair( info.name(), singleton ) );
+    BaseHandle object;
+
+    SingletonConstIter iter = mSingletonContainer.find(info.name());
+    if( iter != mSingletonContainer.end() )
+    {
+      object = ( *iter ).second;
+    }
+    return object;
   }
-}
 
-void SingletonService::UnregisterAll()
-{
-  mSingletonContainer.clear();
-}
+private:
 
-BaseHandle SingletonService::GetSingleton( const std::type_info& info ) const
-{
-  BaseHandle object;
+  /**
+   * Private Constructor
+   * @see SingletonService::New()
+   */
+  SingletonService()
+  : mSingletonContainer()
+  {
+    // Can only have one instance of SingletonService
+    DALI_ASSERT_ALWAYS( !gSingletonService && "Only one instance of SingletonService is allowed");
+    gSingletonService = this;
+  }
 
-  SingletonConstIter iter = mSingletonContainer.find(info.name());
-  if( iter != mSingletonContainer.end() )
+  /**
+   * Virtual Destructor
+   */
+  virtual ~SingletonService()
   {
-    object = ( *iter ).second;
+    gSingletonService = 0;
   }
 
-  return object;
-}
+  // Undefined
+  SingletonService( const SingletonService& );
+  SingletonService& operator=( SingletonService& );
 
-SingletonService::SingletonService()
-: mSingletonContainer()
-{
-}
+private:
+  typedef std::pair<std::string, BaseHandle> SingletonPair;
+  typedef std::map<std::string, BaseHandle>  SingletonContainer;
+  typedef SingletonContainer::const_iterator SingletonConstIter;
 
-SingletonService::~SingletonService()
-{
-}
+  SingletonContainer mSingletonContainer; ///< The container to look up singleton by its type name
+};
 
 } // namespace Adaptor
 } // namespace Internal
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 
-Internal::Adaptor::SingletonService& GetImplementation(Dali::SingletonService& player)
+inline Internal::Adaptor::SingletonService& GetImplementation(Dali::SingletonService& player)
 {
   DALI_ASSERT_ALWAYS( player && "SingletonService handle is empty" );
-
   BaseObject& handle = player.GetBaseObject();
-
   return static_cast<Internal::Adaptor::SingletonService&>(handle);
 }
 
-const Internal::Adaptor::SingletonService& GetImplementation(const Dali::SingletonService& player)
+inline const Internal::Adaptor::SingletonService& GetImplementation(const Dali::SingletonService& player)
 {
   DALI_ASSERT_ALWAYS( player && "SingletonService handle is empty" );
-
   const BaseObject& handle = player.GetBaseObject();
-
   return static_cast<const Internal::Adaptor::SingletonService&>(handle);
 }
 
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-singleton-service.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-singleton-service.h
deleted file mode 100644 (file)
index 68e4ecc..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef __DALI_TOOLKIT_TOOLKIT_SINGLETON_SERVICE_H__
-#define __DALI_TOOLKIT_TOOLKIT_SINGLETON_SERVICE_H__
-
-/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- *
- * Licensed 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.
- *
- */
-
-// EXTERNAL INCLUDES
-
-#define __DALI_SINGELTON_SERVICE_H__
-#include <typeinfo>
-#include <dali/public-api/object/base-handle.h>
-
-// INTERNAL INCLUDES
-
-namespace Dali
-{
-
-namespace Internal DALI_INTERNAL
-{
-namespace Adaptor
-{
-class SingletonService;
-}
-}
-
-class SingletonService : public BaseHandle
-{
-public:
-  SingletonService();
-  static Dali::SingletonService New();
-  static SingletonService Get();
-  ~SingletonService();
-  void Register( const std::type_info& info, BaseHandle singleton );
-  void UnregisterAll();
-  BaseHandle GetSingleton( const std::type_info& info ) const;
-
-public: // Not intended for application developers
-  SingletonService( Internal::Adaptor::SingletonService* singletonService );
-};
-
-} // namespace Dali
-
-#endif // __DALI_TOOLKIT_TOOLKIT_SINGLETON_SERVICE_H__
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-sound-player.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-sound-player.cpp
new file mode 100644 (file)
index 0000000..8eefcfa
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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.
+ */
+
+#include <dali/public-api/object/base-object.h>
+#include <dali/devel-api/adaptor-framework/singleton-service.h>
+#include <dali/devel-api/adaptor-framework/sound-player.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+class Adaptor;
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+
+class SoundPlayer : public Dali::BaseObject
+{
+public:
+  static Dali::SoundPlayer New()
+  {
+    Dali::SoundPlayer player = Dali::SoundPlayer( new SoundPlayer() );
+    return player;
+  }
+
+  static Dali::SoundPlayer Get()
+  {
+    Dali::SoundPlayer player;
+
+    Dali::SingletonService service( Dali::SingletonService::Get() );
+    if ( service )
+    {
+      // Check whether the singleton is already created
+      Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::SoundPlayer ) );
+      if ( handle )
+      {
+        // If so, downcast the handle
+        player = Dali::SoundPlayer( dynamic_cast< SoundPlayer* >( handle.GetObjectPtr() ) );
+      }
+      else
+      {
+        player = Dali::SoundPlayer( New() );
+        service.Register( typeid( player ), player );
+      }
+    }
+    return player;
+  }
+
+  int PlaySound(const std::string fileName)
+  {
+    return 0;
+  }
+
+  void Stop(int handle)
+  {
+  }
+
+private:
+  SoundPlayer()
+  {
+  }
+
+  virtual ~SoundPlayer()
+  {
+  }
+
+  SoundPlayer(const SoundPlayer&);
+  SoundPlayer& operator=(SoundPlayer&);
+};
+
+} // Adaptor namespace
+} // Internal namespace
+
+inline Internal::Adaptor::SoundPlayer& GetImplementation(Dali::SoundPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "SoundPlayer handle is empty" );
+  BaseObject& handle = player.GetBaseObject();
+  return static_cast<Internal::Adaptor::SoundPlayer&>(handle);
+}
+
+inline const Internal::Adaptor::SoundPlayer& GetImplementation(const Dali::SoundPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "SoundPlayer handle is empty" );
+  const BaseObject& handle = player.GetBaseObject();
+  return static_cast<const Internal::Adaptor::SoundPlayer&>(handle);
+}
+
+SoundPlayer SoundPlayer::Get()
+{
+  return Internal::Adaptor::SoundPlayer::Get();
+}
+
+SoundPlayer::SoundPlayer()
+{
+}
+
+SoundPlayer::SoundPlayer(Internal::Adaptor::SoundPlayer*player)
+:BaseHandle(player)
+{
+}
+
+SoundPlayer::~SoundPlayer()
+{
+}
+
+int SoundPlayer::PlaySound(const std::string fileName)
+{
+  return GetImplementation(*this).PlaySound(fileName);
+}
+
+} // Dali
index 65750c1..3d85457 100644 (file)
 
 namespace Dali
 {
+const std::string Dali::StyleMonitor::DEFAULT_FONT_FAMILY("DefaultFont");
+const std::string Dali::StyleMonitor::DEFAULT_FONT_STYLE("Regular");
+const float       Dali::StyleMonitor::DEFAULT_FONT_SIZE(1.0f);
+}
+
+namespace
+{
+const char* DEFAULT_THEME=
+  "{\"styles\":{\n"
+  "  \"textlabel\":\n"
+  "    {\n"
+  "      \"fontStyle\":\"Regular\",\n"
+  "      \"pointSize\":18\n"
+  "    }\n"
+  "  }\n"
+  "}\n";
+
+struct NamedTheme
+{
+  NamedTheme( const std::string& name, const std::string& theme )
+  : name(name), theme(theme)
+  {
+  }
+
+  std::string name;
+  std::string theme;
+};
+typedef std::vector< NamedTheme > NamedThemes;
+NamedThemes gThemes;
 
+std::string gTheme;
+std::string gFontFamily = Dali::StyleMonitor::DEFAULT_FONT_FAMILY;
+std::string gFontStyle  = Dali::StyleMonitor::DEFAULT_FONT_STYLE;
+float       gFontSize   = Dali::StyleMonitor::DEFAULT_FONT_SIZE;
+}
 
+namespace Dali
+{
 namespace Internal
 {
 namespace Adaptor
@@ -41,9 +77,11 @@ public: // Creation & Destruction
 
 public: // Style Information
   std::string GetDefaultFontFamily() const;
+  std::string GetDefaultFontStyle() const;
   float GetDefaultFontSize() const;
   const std::string& GetTheme() const;
   void SetTheme(std::string theme);
+  bool LoadThemeFile( const std::string& filename, std::string& output );
 
 public: // Signals
   Dali::StyleMonitor::StyleChangeSignalType& StyleChangeSignal();
@@ -56,7 +94,8 @@ public: // Signals
 private:
   Dali::StyleMonitor::StyleChangeSignalType mStyleChangeSignal;
   static Dali::StyleMonitor mToolkitStyleMonitor;
-  std::string mTheme;
+
+  std::string mTheme;  ///<< Current theme name
 };
 
 Dali::StyleMonitor StyleMonitor::mToolkitStyleMonitor;
@@ -81,12 +120,18 @@ StyleMonitor::~StyleMonitor()
 
 std::string StyleMonitor::GetDefaultFontFamily() const
 {
-  return Dali::StyleMonitor::DEFAULT_FONT_FAMILY;
+  return gFontFamily;
+}
+
+std::string StyleMonitor::GetDefaultFontStyle() const
+{
+  return gFontStyle;
 }
 
 float StyleMonitor::GetDefaultFontSize() const
 {
-  return Dali::StyleMonitor::DEFAULT_FONT_SIZE;
+  return gFontSize;
+
 }
 
 const std::string& StyleMonitor::GetTheme() const
@@ -100,6 +145,29 @@ void StyleMonitor::SetTheme(std::string path)
   EmitStyleChangeSignal( StyleChange::THEME_CHANGE );
 }
 
+bool StyleMonitor::LoadThemeFile( const std::string& filename, std::string& output )
+{
+  for( NamedThemes::iterator iter = gThemes.begin(); iter != gThemes.end(); ++iter )
+  {
+    NamedTheme& theme = *iter;
+    if( theme.name == filename )
+    {
+      output = theme.theme;
+      return true;
+    }
+  }
+
+  if( !gTheme.empty() )
+  {
+    output = gTheme;
+  }
+  else
+  {
+    output = DEFAULT_THEME;
+  }
+  return true;
+}
+
 Dali::StyleMonitor::StyleChangeSignalType& StyleMonitor::StyleChangeSignal()
 {
   return mStyleChangeSignal;
@@ -121,9 +189,6 @@ const Internal::Adaptor::StyleMonitor& GetImplementation(const Dali::StyleMonito
   return static_cast<const Internal::Adaptor::StyleMonitor&>(object);
 }
 
-const std::string Dali::StyleMonitor::DEFAULT_FONT_FAMILY("DefaultFont");
-const float       Dali::StyleMonitor::DEFAULT_FONT_SIZE(1.0f);
-
 StyleMonitor::StyleMonitor()
 {
 }
@@ -147,6 +212,11 @@ std::string StyleMonitor::GetDefaultFontFamily() const
   return GetImplementation(*this).GetDefaultFontFamily();
 }
 
+std::string StyleMonitor::GetDefaultFontStyle() const
+{
+  return GetImplementation(*this).GetDefaultFontStyle();
+}
+
 float StyleMonitor::GetDefaultFontSize() const
 {
   return GetImplementation(*this).GetDefaultFontSize();
@@ -172,6 +242,11 @@ void StyleMonitor::EmitStyleChangeSignal(StyleChange::Type styleChange)
   GetImplementation(*this).EmitStyleChangeSignal(styleChange);
 }
 
+bool StyleMonitor::LoadThemeFile( const std::string& filename, std::string& output )
+{
+  return GetImplementation(*this).LoadThemeFile(filename, output);
+}
+
 StyleMonitor& StyleMonitor::operator=(const StyleMonitor& monitor)
 {
   if( *this != monitor )
@@ -187,3 +262,41 @@ StyleMonitor::StyleMonitor(Internal::Adaptor::StyleMonitor* internal)
 }
 
 } // namespace Dali
+
+namespace Test
+{
+namespace StyleMonitor
+{
+
+void SetThemeFileOutput( const std::string& name, const std::string& output )
+{
+  for( NamedThemes::iterator iter = gThemes.begin(); iter != gThemes.end(); ++iter )
+  {
+    NamedTheme& theme = *iter;
+    if( theme.name == name )
+    {
+      theme.theme = output;
+      return;
+    }
+  }
+
+  gThemes.push_back( NamedTheme( name, output ) );
+}
+
+void SetDefaultFontFamily(const std::string& family)
+{
+  gFontFamily = family;
+}
+
+void SetDefaultFontStyle(const std::string& style)
+{
+  gFontStyle = style;
+}
+
+void SetDefaultFontSize( float size )
+{
+  gFontSize = size;
+}
+
+} // StyleMonitor
+} // Test
index 8aa55e5..b69a7db 100644 (file)
@@ -43,6 +43,7 @@ class StyleMonitor : public BaseHandle
 public: // Typedefs
   typedef Signal< void (StyleMonitor, StyleChange::Type) > StyleChangeSignalType;
   static const std::string DEFAULT_FONT_FAMILY;
+  static const std::string DEFAULT_FONT_STYLE;
   static const float       DEFAULT_FONT_SIZE;
 
 public: // Creation & Destruction
@@ -54,9 +55,11 @@ public: // Creation & Destruction
 
 public: // Style Information
   std::string GetDefaultFontFamily() const;
+  std::string GetDefaultFontStyle() const;
   float GetDefaultFontSize() const;
   const std::string& GetTheme() const;
   void SetTheme(std::string themeFilePath);
+  bool LoadThemeFile( const std::string& filename, std::string& output );
 
 public: // Signals
   StyleChangeSignalType& StyleChangeSignal();
@@ -72,4 +75,16 @@ public:
 
 } // namespace Dali
 
+namespace Test
+{
+namespace StyleMonitor
+{
+void SetThemeFileOutput( const std::string& name, const std::string& output );
+void SetDefaultFontFamily(const std::string& family);
+void SetDefaultFontStyle(const std::string& style);
+void SetDefaultFontSize( float size );
+
+}
+}
+
 #endif // __DALI_TOOLKIT_TOOLKIT_STYLE_MONITOR_H__
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-abstraction.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-text-abstraction.cpp
new file mode 100644 (file)
index 0000000..cd0c19d
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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.
+ */
+
+#include <dali/devel-api/text-abstraction/bidirectional-support.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/text-abstraction/font-metrics.h>
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+#include <dali/devel-api/text-abstraction/script.h>
+#include <dali/devel-api/text-abstraction/segmentation.h>
+#include <dali/devel-api/text-abstraction/shaping.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/devel-api/adaptor-framework/singleton-service.h>
+#include <cstring>
+
+using namespace Dali;
+
+namespace Dali
+{
+class Adaptor;
+
+namespace TextAbstraction
+{
+namespace Internal
+{
+
+class BidirectionalSupport : public BaseObject
+{
+public:
+  BidirectionalSupport()
+  {
+  }
+
+  ~BidirectionalSupport()
+  {
+  }
+
+  static TextAbstraction::BidirectionalSupport Get()
+  {
+    TextAbstraction::BidirectionalSupport bidirectionalSupportHandle;
+
+    Dali::SingletonService service( Dali::SingletonService::Get() );
+    if( service )
+    {
+      // Check whether the singleton is already created
+      BaseHandle handle = service.GetSingleton( typeid( TextAbstraction::BidirectionalSupport ) );
+      if(handle)
+      {
+        // If so, downcast the handle
+        BidirectionalSupport* impl = dynamic_cast< Internal::BidirectionalSupport* >( handle.GetObjectPtr() );
+        bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( impl );
+      }
+      else // create and register the object
+      {
+        bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( new BidirectionalSupport );
+        service.Register( typeid( bidirectionalSupportHandle ), bidirectionalSupportHandle );
+      }
+    }
+    return bidirectionalSupportHandle;
+  }
+  BidiInfoIndex CreateInfo( const Character* const paragraph, Length numberOfCharacters ){return 0;}
+
+  void DestroyInfo( BidiInfoIndex bidiInfoIndex )
+  {
+  }
+
+  void Reorder( BidiInfoIndex bidiInfoIndex,CharacterIndex firstCharacterIndex,Length numberOfCharacters,CharacterIndex* visualToLogicalMap )
+  {
+  }
+
+  bool GetMirroredText( Character* text,CharacterDirection* directions,Length numberOfCharacters )
+  {
+    return true;
+  }
+
+  bool GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const
+  {
+    return true;
+  }
+
+  void GetCharactersDirection( BidiInfoIndex bidiInfoIndex, CharacterDirection* directions, Length numberOfCharacters )
+  {
+  }
+}; // class BidirectionalSupport
+
+
+class FontClient : public BaseObject
+{
+public:
+  FontClient()
+  : mDpiHorizontal( 0 ),
+    mDpiVertical( 0 )
+  {
+  }
+
+  ~FontClient(){}
+
+  static Dali::TextAbstraction::FontClient Get()
+  {
+    Dali::TextAbstraction::FontClient fontClientHandle;
+
+    Dali::SingletonService service( SingletonService::Get() );
+    if ( service )
+    {
+      // Check whether the singleton is already created
+      Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::TextAbstraction::FontClient ) );
+      if(handle)
+      {
+        // If so, downcast the handle
+        FontClient* impl = dynamic_cast< Dali::TextAbstraction::Internal::FontClient* >( handle.GetObjectPtr() );
+        fontClientHandle = Dali::TextAbstraction::FontClient( impl );
+      }
+      else // create and register the object
+      {
+        fontClientHandle = Dali::TextAbstraction::FontClient( new FontClient );
+        service.Register( typeid( fontClientHandle ), fontClientHandle );
+      }
+    }
+
+    return fontClientHandle;
+  }
+
+  void SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi ){}
+  void GetDpi( unsigned int& horizontalDpi, unsigned int& verticalDpi ){horizontalDpi=verticalDpi=96;}
+
+  void ResetSystemDefaults(){}
+  void GetDefaultFonts( FontList& defaultFonts ){}
+  void GetDefaultPlatformFontDescription( FontDescription& fontDescription ){}
+  void GetSystemFonts( FontList& systemFonts ){}
+  void GetDescription( FontId id, FontDescription& fontDescription ){}
+  PointSize26Dot6 GetPointSize( FontId id ){return 9;}
+  FontId FindDefaultFont( Character charcode, PointSize26Dot6 pointSize, bool preferColor ){return 0;}
+  FontId FindFallbackFont( FontId preferredFont, Character charcode, PointSize26Dot6 pointSize, bool preferColor ){return 0;}
+  FontId GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex ){return 0;}
+  FontId GetFontId( const FontDescription& fontDescription,PointSize26Dot6 pointSize, FaceIndex faceIndex ){return 0;}
+  bool IsScalable( const FontPath& path ){return true;}
+  bool IsScalable( const FontDescription& fontDescription ){return true;}
+  void GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes ){}
+  void GetFixedSizes( const FontDescription& fontDescription, Dali::Vector< PointSize26Dot6 >& sizes ){}
+  void GetFontMetrics( FontId fontId, FontMetrics& metrics, int desiredFixedSize ){}
+  GlyphIndex GetGlyphIndex( FontId fontId, Character charcode ){return 0;}
+  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, bool horizontal, int desiredFixedSize ){return true;}
+  BufferImage CreateBitmap( FontId fontId, GlyphIndex glyphIndex ){return BufferImage();}
+  void CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob,
+                         unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
+  {
+    blobLength = 0;
+  }
+  const GlyphInfo& GetEllipsisGlyph( PointSize26Dot6 pointSize ){return mGlyphInfo;}
+private:
+  unsigned int mDpiHorizontal;
+  unsigned int mDpiVertical;
+  GlyphInfo    mGlyphInfo;
+}; // class FontClient
+
+
+class Shaping : public BaseObject
+{
+public:
+  Shaping() : mText(NULL)
+  {}
+
+  ~Shaping()
+  {
+    delete [] mText;
+  }
+
+  static Dali::TextAbstraction::Shaping Get()
+  {
+    Dali::TextAbstraction::Shaping shapingHandle;
+
+    Dali::SingletonService service( SingletonService::Get() );
+    if ( service )
+    {
+      // Check whether the singleton is already created
+      Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::TextAbstraction::Shaping ) );
+      if(handle)
+      {
+        // If so, downcast the handle
+        Shaping* impl = dynamic_cast< Dali::TextAbstraction::Internal::Shaping* >( handle.GetObjectPtr() );
+        shapingHandle = Dali::TextAbstraction::Shaping( impl );
+      }
+      else // create and register the object
+      {
+        shapingHandle = Dali::TextAbstraction::Shaping( new Shaping );
+        service.Register( typeid( shapingHandle ), shapingHandle );
+      }
+    }
+    return shapingHandle;
+  }
+
+  void GetGlyphs(GlyphInfo* glyphStore, unsigned int*mappingTable)
+  {
+    // Return store & mapping table (0, 1, 2, 3... N-1))
+    if( glyphStore )
+    {
+      memcpy( glyphStore, mText, mNumChars );
+    }
+    for( unsigned int i=0; i<mNumChars ; ++i )
+    {
+      mappingTable[i] = i;
+    }
+  }
+
+  Length Shape(unsigned int const* text, unsigned int numChars, unsigned int fontId, Script script)
+  {
+    mText = new unsigned char[numChars];
+    mNumChars = numChars;
+
+    memcpy( mText, text, numChars );
+
+    return numChars;
+  }
+private:
+  unsigned char* mText;
+  unsigned int mNumChars;
+};
+
+} // Internal
+} // TextAbstraction
+
+inline static TextAbstraction::Internal::BidirectionalSupport& GetImplementation( TextAbstraction::BidirectionalSupport& bidirectionalSupport )
+{
+  DALI_ASSERT_ALWAYS( bidirectionalSupport && "bidirectional support handle is empty" );
+  BaseObject& object = bidirectionalSupport.GetBaseObject();
+  return static_cast<TextAbstraction::Internal::BidirectionalSupport&>(object);
+}
+
+inline static const TextAbstraction::Internal::BidirectionalSupport& GetImplementation( const TextAbstraction::BidirectionalSupport& bidirectionalSupport )
+{
+  DALI_ASSERT_ALWAYS( bidirectionalSupport && "bidirectional support handle is empty" );
+  const BaseObject& object = bidirectionalSupport.GetBaseObject();
+  return static_cast<const TextAbstraction::Internal::BidirectionalSupport&>(object);
+}
+
+inline static TextAbstraction::Internal::FontClient& GetImplementation(TextAbstraction::FontClient& fontClient)
+{
+  DALI_ASSERT_ALWAYS( fontClient && "fontClient handle is empty" );
+  BaseObject& handle = fontClient.GetBaseObject();
+  return static_cast<TextAbstraction::Internal::FontClient&>(handle);
+}
+
+inline static const TextAbstraction::Internal::FontClient& GetImplementation(const TextAbstraction::FontClient& fontClient)
+{
+  DALI_ASSERT_ALWAYS( fontClient && "fontClient handle is empty" );
+  const BaseObject& handle = fontClient.GetBaseObject();
+  return static_cast<const TextAbstraction::Internal::FontClient&>(handle);
+}
+
+inline static TextAbstraction::Internal::Shaping& GetImplementation(TextAbstraction::Shaping& shaping)
+{
+  DALI_ASSERT_ALWAYS( shaping && "shaping handle is empty" );
+  BaseObject& handle = shaping.GetBaseObject();
+  return static_cast<TextAbstraction::Internal::Shaping&>(handle);
+}
+
+inline static const TextAbstraction::Internal::Shaping& GetImplementation(const TextAbstraction::Shaping& shaping)
+{
+  DALI_ASSERT_ALWAYS( shaping && "shaping handle is empty" );
+  const BaseObject& handle = shaping.GetBaseObject();
+  return static_cast<const TextAbstraction::Internal::Shaping&>(handle);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+/******************************************************************************/
+
+namespace TextAbstraction
+{
+const PointSize26Dot6 FontClient::DEFAULT_POINT_SIZE = 768u; // 12*64
+
+BidirectionalSupport::BidirectionalSupport()
+{
+}
+
+BidirectionalSupport::~BidirectionalSupport()
+{
+}
+
+BidirectionalSupport::BidirectionalSupport( Internal::BidirectionalSupport* implementation )
+: BaseHandle( implementation )
+{
+}
+
+BidirectionalSupport BidirectionalSupport::Get()
+{
+  return Internal::BidirectionalSupport::Get();
+}
+
+BidiInfoIndex BidirectionalSupport::CreateInfo( const Character* const paragraph,
+                                                Length numberOfCharacters )
+{
+  return GetImplementation( *this ).CreateInfo( paragraph, numberOfCharacters );
+}
+
+void BidirectionalSupport::DestroyInfo( BidiInfoIndex bidiInfoIndex )
+{
+  GetImplementation( *this ).DestroyInfo( bidiInfoIndex );
+}
+
+void BidirectionalSupport::Reorder( BidiInfoIndex bidiInfoIndex,
+                                    CharacterIndex firstCharacterIndex,
+                                    Length numberOfCharacters,
+                                    CharacterIndex* visualToLogicalMap )
+{
+  GetImplementation( *this ).Reorder( bidiInfoIndex, firstCharacterIndex, numberOfCharacters, visualToLogicalMap );
+}
+
+bool BidirectionalSupport::GetMirroredText( Character* text,
+                                            CharacterDirection* directions,
+                                            Length numberOfCharacters )
+{
+  return GetImplementation( *this ).GetMirroredText( text, directions, numberOfCharacters );
+}
+
+bool BidirectionalSupport::GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const
+{
+  return GetImplementation( *this ).GetParagraphDirection( bidiInfoIndex );
+}
+
+void BidirectionalSupport::GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
+                                                   CharacterDirection* directions,
+                                                   Length numberOfCharacters )
+{
+  GetImplementation( *this ).GetCharactersDirection( bidiInfoIndex, directions, numberOfCharacters );
+}
+
+
+FontClient FontClient::Get()
+{
+  return Internal::FontClient::Get();
+}
+
+FontClient::FontClient()
+{
+}
+
+FontClient::~FontClient()
+{
+}
+
+FontClient::FontClient( const FontClient& handle )
+: BaseHandle( handle )
+{
+}
+
+FontClient& FontClient::operator=( const FontClient& handle )
+{
+  BaseHandle::operator=( handle );
+  return *this;
+}
+
+void FontClient::SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi  )
+{
+  GetImplementation(*this).SetDpi( horizontalDpi, verticalDpi );
+}
+
+void FontClient::GetDpi( unsigned int& horizontalDpi, unsigned int& verticalDpi )
+{
+  GetImplementation(*this).GetDpi( horizontalDpi, verticalDpi );
+}
+
+void FontClient::ResetSystemDefaults()
+{
+  GetImplementation(*this).ResetSystemDefaults();
+}
+
+void FontClient::GetDefaultFonts( FontList& defaultFonts )
+{
+  GetImplementation(*this).GetDefaultFonts( defaultFonts );
+}
+
+void FontClient::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
+{
+  GetImplementation(*this).GetDefaultPlatformFontDescription( fontDescription );
+}
+
+void FontClient::GetSystemFonts( FontList& systemFonts )
+{
+  GetImplementation(*this).GetSystemFonts( systemFonts );
+}
+
+void FontClient::GetDescription( FontId id, FontDescription& fontDescription )
+{
+  GetImplementation(*this).GetDescription( id, fontDescription );
+}
+
+PointSize26Dot6 FontClient::GetPointSize( FontId id )
+{
+  return GetImplementation(*this).GetPointSize( id );
+}
+
+FontId FontClient::FindDefaultFont( Character charcode, PointSize26Dot6 pointSize, bool preferColor )
+{
+  return GetImplementation(*this).FindDefaultFont( charcode, pointSize, preferColor );
+}
+
+FontId FontClient::FindFallbackFont( FontId preferredFont, Character charcode, PointSize26Dot6 pointSize, bool preferColor )
+{
+  return GetImplementation(*this).FindFallbackFont( preferredFont, charcode, pointSize, preferColor );
+}
+
+FontId FontClient::GetFontId( const FontPath& path, PointSize26Dot6 pointSize, FaceIndex faceIndex )
+{
+  return GetImplementation(*this).GetFontId( path, pointSize, faceIndex );
+}
+
+FontId FontClient::GetFontId( const FontDescription& fontDescription,
+                              PointSize26Dot6 pointSize,
+                              FaceIndex faceIndex )
+{
+  return GetImplementation(*this).GetFontId( fontDescription,
+                                             pointSize,
+                                             faceIndex );
+}
+
+bool FontClient::IsScalable( const FontPath& path )
+{
+  return GetImplementation(*this).IsScalable( path );
+}
+
+bool FontClient::IsScalable( const FontDescription& fontDescription )
+{
+  return GetImplementation(*this).IsScalable( fontDescription );
+}
+
+void FontClient::GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes )
+{
+  GetImplementation(*this).GetFixedSizes( path, sizes );
+}
+
+void FontClient::GetFixedSizes( const FontDescription& fontDescription,
+                                Dali::Vector< PointSize26Dot6 >& sizes )
+{
+  GetImplementation(*this).GetFixedSizes( fontDescription, sizes );
+}
+
+void FontClient::GetFontMetrics( FontId fontId, FontMetrics& metrics, int desiredFixedSize )
+{
+  GetImplementation(*this).GetFontMetrics( fontId, metrics, desiredFixedSize );
+}
+
+GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
+{
+  return GetImplementation(*this).GetGlyphIndex( fontId, charcode );
+}
+
+bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal, int desiredFixedSize )
+{
+  return GetImplementation(*this).GetGlyphMetrics( array, size, horizontal, desiredFixedSize );
+}
+
+BufferImage FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex )
+{
+  return GetImplementation(*this).CreateBitmap( fontId, glyphIndex );
+}
+
+
+void FontClient::CreateVectorBlob( FontId fontId,
+                                   GlyphIndex glyphIndex,
+                                   VectorBlob*& blob,
+                                   unsigned int& blobLength,
+                                   unsigned int& nominalWidth,
+                                   unsigned int& nominalHeight )
+{
+  GetImplementation(*this).CreateVectorBlob( fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
+}
+
+const GlyphInfo& FontClient::GetEllipsisGlyph( PointSize26Dot6 pointSize )
+{
+  return GetImplementation(*this).GetEllipsisGlyph( pointSize );
+}
+
+FontClient::FontClient( Internal::FontClient* internal )
+: BaseHandle( internal )
+{
+}
+
+FontMetrics::FontMetrics()
+: ascender( 0.f ),
+  descender( 0.f ),
+  height( 0.f ),
+  underlinePosition( 0.f ),
+  underlineThickness( 0.f )
+{
+}
+
+GlyphInfo::GlyphInfo()
+{
+}
+
+Script GetCharacterScript(unsigned int x)
+{
+  return LATIN;
+}
+bool HasLigatureMustBreak(Script x){return false;}
+bool IsCommonScript(unsigned int character){ return false;}
+bool IsNewParagraph(unsigned int character){return false;}
+bool IsRightToLeftScript(Script){return false;}
+bool IsWhiteSpace(unsigned int character)
+{
+  return character < 0x21;
+}
+
+Segmentation Segmentation::Get(){ return Segmentation();}
+Segmentation::Segmentation(){}
+Segmentation::~Segmentation(){}
+void Segmentation::GetLineBreakPositions(unsigned int const*, unsigned int, char*){}
+void Segmentation::GetWordBreakPositions(unsigned int const*, unsigned int, char*){}
+
+Shaping Shaping::Get()
+{
+  return TextAbstraction::Internal::Shaping::Get();
+}
+
+Shaping::Shaping()
+{
+}
+
+Shaping::Shaping( Internal::Shaping* internal )
+: BaseHandle( internal )
+{
+}
+
+Shaping::~Shaping()
+{
+}
+
+void Shaping::GetGlyphs(GlyphInfo* glyphStore, unsigned int*mappingTable)
+{
+  // Return store & mapping table (0, 1, 2, 3... N-1))
+  GetImplementation(*this).GetGlyphs(glyphStore, mappingTable);
+}
+
+Length Shaping::Shape(unsigned int const* text, unsigned int numChars, unsigned int fontId, Script script)
+{
+  return GetImplementation(*this).Shape( text, numChars, fontId, script );
+}
+
+} // TextAbstraction
+} // Dali
diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-virtual-keyboard.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-virtual-keyboard.cpp
new file mode 100644 (file)
index 0000000..e3f3ce5
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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.
+ */
+
+#include <dali/devel-api/adaptor-framework/virtual-keyboard.h>
+#include <dali/public-api/adaptor-framework/key.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+class Adaptor;
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+namespace VirtualKeyboard
+{
+Dali::VirtualKeyboard::StatusSignalType gKeyboardStatusSignal;
+}
+
+} // Adaptor
+} // Internal
+
+
+bool IsKey( const Dali::KeyEvent& keyEvent, Dali::KEY daliKey)
+{
+  return true;
+}
+
+namespace VirtualKeyboard
+{
+
+void ApplySettings( Dali::Property::Map const& )
+{
+}
+
+bool IsVisible()
+{
+  return false;
+}
+
+void Show()
+{
+}
+
+StatusSignalType& StatusChangedSignal()
+{
+  return Internal::Adaptor::VirtualKeyboard::gKeyboardStatusSignal;
+}
+
+} // VirtualKeyboard
+} // Dali
index 2fb0f0c..3dae0c1 100644 (file)
@@ -432,7 +432,7 @@ int UtcDaliBuilderConstantsP(void)
       "  \"parentOrigin\": \"TOP_LEFT\","
       "  \"anchorPoint\": \"{ANCHOR}\","
       "  \"padding\": \"{PADDING}\","
-      "  \"image\": { \"imageUrl\": \"dir/{IMAGE_PATH}\" },"
+      "  \"image\": { \"url\": \"dir/{IMAGE_PATH}\" },"
       "  \"sizeWidth\": \"{WIDTH}\","
       "  \"signals\": [{"
       "    \"name\": \"touched\","
@@ -863,9 +863,12 @@ int UtcDaliBuilderCustomPropertyP(void)
       "      \"name\": \"touched\",\n"
       "      \"action\": \"quit\"\n"
       "    }],\n"
-      "    \"customProperties\": {\n"
+      "    \"properties\": {\n"
       "      \"newproperty\": true\n"
       "    },\n"
+      "    \"animatableProperties\": {\n"
+      "      \"newAnimatableproperty\": 3\n"
+      "    },\n"
       "    \"actors\": [\n"
       "      {\n"
       "        \"type\":\"ImageView\",\n"
@@ -889,10 +892,15 @@ int UtcDaliBuilderCustomPropertyP(void)
   Property::Value value = actor.GetProperty(index);
   DALI_TEST_CHECK( value.Get<bool>() == true );
 
+  index = actor.GetPropertyIndex("newAnimatableproperty");
+  DALI_TEST_CHECK( Property::INVALID_INDEX != index );
+  value = actor.GetProperty(index);
+  DALI_TEST_CHECK( value.Get<int>() == 3 );
+
   END_TEST;
 }
 
-int UtcDaliBuilderShaderEffectP(void)
+int UtcDaliBuilderCustomShaderP(void)
 {
   ToolkitTestApplication application;
 
@@ -912,11 +920,16 @@ int UtcDaliBuilderShaderEffectP(void)
     "      \"size\": [200, 200, 0],\n"
     "      \"effect\": \"Ripple2D\",\n"
     "      \"image\": {\n"
-    "        \"filename\": \"{DALI_IMAGE_DIR}gallery-medium-25.jpg\",\n"
-    "        \"width\": 200,\n"
-    "        \"height\": 80,\n"
-    "        \"loadPolicy\": \"IMMEDIATE\",\n"
-    "        \"releasePolicy\": \"NEVER\"\n"
+    "        \"url\": \"{DALI_IMAGE_DIR}gallery-medium-25.jpg\",\n"
+    "        \"desiredWidth\": 200,\n"
+    "        \"desiredHeight\": 80,\n"
+    "        \"shader\": {\n"
+    "           \"fragmentShader\": \"precision mediump float;\\nuniform sampler2D sTexture;\\nuniform vec4 uColor;\\nuniform float uAmplitude;\\nuniform float uTime;\\nvarying vec2 vTexCoord;\\nvoid main()\\n{\\n  highp vec2 pos = -1.0 + 2.0 * vTexCoord;\\n  highp float len = length(pos);\\n  highp vec2 texCoord = vTexCoord + pos/len * sin( len * 12.0 - uTime * 4.0 ) * uAmplitude;\\n  gl_FragColor = texture2D(sTexture, texCoord) * uColor;}\\n\\n\"\n"
+    "        }\n"
+    "      },\n"
+    "      \"customAnimatableProperties\": {\n"
+    "         \"uAmplitude\": 0.02,\n"
+    "         \"uTime\": 0.0\n"
     "      },\n"
     "      \"signals\": [\n"
     "        {\n"
@@ -927,7 +940,6 @@ int UtcDaliBuilderShaderEffectP(void)
     "      ]\n"
     "    }\n"
     "  ],\n"
-    "  \"paths\": {},\n"
     "  \"animations\": {\n"
     "    \"Animation_1\": {\n"
     "      \"loop\":true,\n"
@@ -940,27 +952,10 @@ int UtcDaliBuilderShaderEffectP(void)
     "          \"timePeriod\": {\n"
     "            \"delay\": 0,\n"
     "            \"duration\": 10.0\n"
-    "          },\n"
-    "          \"gui-builder-timeline-color\": \"#8dc0da\"\n"
+    "          }\n"
     "        }\n"
     "      ]\n"
     "    }\n"
-    "  },\n"
-    "  \"shaderEffects\": {\n"
-    "    \"Ripple2D\": {\n"
-    "      \"program\": {\n"
-    "        \"vertexPrefix\": \"\",\n"
-    "        \"vertex\": \"void main(void)\\n{\\n  gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\\n  vTexCoord = aTexCoord;\\n}\\n\\n\",\n"
-    "        \"fragmentPrefix\": \"\",\n"
-    "        \"fragment\": \"precision mediump float;\\nuniform float uAmplitude; // 0.02; (< 1)\\nuniform float uTime;\\nvoid main()\\n{\\n  highp vec2 textureSize = sTextureRect.zw - sTextureRect.xy;\\n  highp vec2 pos = -1.0 + 2.0 * vTexCoord.st/textureSize;\\n  highp float len = length(pos);\\n  highp vec2 texCoord = vTexCoord.st/textureSize + pos/len * sin( len * 12.0 - uTime * 4.0 ) * uAmplitude; \\n  gl_FragColor = texture2D(sTexture, texCoord) * uColor;\\n}\\n\\n\\n\",\n"
-    "        \"geometryType\": \"GEOMETRY_TYPE_IMAGE\"\n"
-    "      },\n"
-    "      \"geometryHints\": \"HINT_NONE\",\n"
-    "      \"gridDensity\": 0,\n"
-    "      \"loop\": true,\n"
-    "      \"uAmplitude\": 0.02,\n"
-    "      \"uTime\": 0.0\n"
-    "    }\n"
     "  }\n"
     "}\n"
 
@@ -969,10 +964,16 @@ int UtcDaliBuilderShaderEffectP(void)
   Builder builder = Builder::New();
   builder.LoadFromString( json );
 
-  ShaderEffect effect = builder.GetShaderEffect("Ripple2D");
+  builder.AddActors ( "stage", Stage::GetCurrent().GetRootLayer() );
+
+  // Render and notify
+  application.SendNotification();
+  application.Render();
+
+  Actor actor = Stage::GetCurrent().GetRootLayer().FindChildByName("Image1");
 
   // coverage
-  DALI_TEST_CHECK( effect );
+  DALI_TEST_CHECK( actor );
 
   END_TEST;
 }
@@ -1018,80 +1019,6 @@ int UtcDaliBuilderLoadFromStringN(void)
   END_TEST;
 }
 
-int UtcDaliBuilderShaderEffect2P(void)
-{
-  ToolkitTestApplication application;
-
-  // JSON with a quit event when the actor is touched
-  std::string json(
-    "{\n"
-    "\"templates\":\n"
-    "{\n"
-    "  \"imageTree\": { \n"
-    "    \"type\": \"ImageView\",\n"
-    "    \"size\": [100,100,1],\n"
-    "    \"parentOrigin\": [0.5, 0.5, 0.5],\n"
-    "    \"position\": [\n"
-    "      0.40461349487305,\n"
-    "      0.9150390625,\n"
-    "      0.0\n"
-    "    ],\n"
-    "    \"signals\": [{\n"
-    "      \"name\": \"touched\",\n"
-    "      \"action\": \"quit\"\n"
-    "    }],\n"
-    "    \"actors\": [\n"
-    "      {\n"
-    "        \"type\":\"ImageView\",\n"
-    "        \"name\":\"childImage\" \n"
-    "      }\n"
-    "    ]\n"
-    "  }\n"
-    "},\n"
-    "  \"stage\": [\n"
-    "    {\n"
-    "      \"type\": \"imageTree\",\n"
-    "      \"name\": \"Image1\",\n"
-    "      \"effect\": \"Ripple2D\",\n"
-    "      \"image\": \"offscreen\""
-    "    }\n"
-    "  ],\n"
-    "  \"shaderEffects\": {\n"
-    "    \"Ripple2D\": {\n"
-    "      \"program\": {\n"
-    "        \"vertexPrefix\": \"\",\n"
-    "        \"vertex\": \"void main(void)\\n{\\n  gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\\n  vTexCoord = aTexCoord;\\n}\\n\\n\",\n"
-    "        \"fragmentPrefix\": \"\",\n"
-    "        \"fragment\": \"precision mediump float;\\nuniform float uAmplitude; // 0.02; (< 1)\\nuniform float uTime;\\nvoid main()\\n{\\n  highp vec2 textureSize = sTextureRect.zw - sTextureRect.xy;\\n  highp vec2 pos = -1.0 + 2.0 * vTexCoord.st/textureSize;\\n  highp float len = length(pos);\\n  highp vec2 texCoord = vTexCoord.st/textureSize + pos/len * sin( len * 12.0 - uTime * 4.0 ) * uAmplitude; \\n  gl_FragColor = texture2D(sTexture, texCoord) * uColor;\\n}\\n\\n\\n\",\n"
-    "        \"geometryType\": \"GEOMETRY_TYPE_IMAGE\"\n"
-    "      },\n"
-    "      \"geometryHints\": \"HINT_NONE\",\n"
-    "      \"gridDensity\": 0,\n"
-    "      \"loop\": true,\n"
-    "      \"uAmplitude\": 0.02,\n"
-    "      \"uTime\": 0.0\n"
-    "    }\n"
-    "  },\n"
-    "  \"frameBufferImages\": {\n"
-    "    \"offscreen\": {\n"
-    "      \"type\": \"FrameBufferImage\","
-    "      \"pixelFormat\":\"RGBA8888\","
-    "      \"width\": 400,"
-    "      \"height\": 400"
-    "    }"
-    "   }"
-    "}\n"
-
-  );
-
-  Builder builder = Builder::New();
-  builder.LoadFromString( json );
-
-  // coverage
-  DALI_TEST_CHECK( true );
-
-  END_TEST;
-}
 
 int UtcDaliBuilderAddActorsP(void)
 {
@@ -1173,7 +1100,7 @@ int UtcDaliBuilderFrameBufferP(void)
     "      \"parentOrigin\": [0.5, 0.5, 0.5],\n"
     "      \"effect\": \"Ripple2D\",\n"
     "      \"image\": {\n"
-    "        \"imageUrl\": \"{DALI_IMAGE_DIR}gallery-medium-25.jpg\"\n"
+    "        \"url\": \"{DALI_IMAGE_DIR}gallery-medium-25.jpg\"\n"
     "      },\n"
     "      \"signals\": [\n"
     "        {\n"
@@ -1296,7 +1223,7 @@ int UtcDaliBuilderPathConstraintsP(void)
     "      \"parentOrigin\": [0.5, 0.5, 0.5],\n"
     "      \"effect\": \"Ripple2D\",\n"
     "      \"image\": {\n"
-    "        \"imageUrl\": \"{DALI_IMAGE_DIR}gallery-medium-25.jpg\"\n"
+    "        \"url\": \"{DALI_IMAGE_DIR}gallery-medium-25.jpg\"\n"
     "      },\n"
     "      \"signals\": [\n"
     "        {\n"
index 588c7c5..9a7e6ff 100644 (file)
@@ -428,16 +428,16 @@ int UtcDaliControlBackgroundImage(void)
   Property::Map* resultMap = propValue.GetMap();
   DALI_TEST_CHECK( resultMap->Find( "rendererType" ) );
   DALI_TEST_CHECK( resultMap->Find( "rendererType" )->Get<std::string>() == "image" );
-  DALI_TEST_CHECK( resultMap->Find( "imageUrl" ) );
-  DALI_TEST_CHECK( resultMap->Find( "imageUrl" )->Get<std::string>() == "TestImage" );
+  DALI_TEST_CHECK( resultMap->Find( "url" ) );
+  DALI_TEST_CHECK( resultMap->Find( "url" )->Get<std::string>() == "TestImage" );
 
   image = ResourceImage::New("TestImage2");
   control.SetBackgroundImage( image );
 
   propValue = control.GetProperty( Control::Property::BACKGROUND );
   resultMap = propValue.GetMap();
-  DALI_TEST_CHECK( resultMap->Find( "imageUrl" ) );
-  DALI_TEST_CHECK( resultMap->Find( "imageUrl" )->Get<std::string>() == "TestImage2" );
+  DALI_TEST_CHECK( resultMap->Find( "url" ) );
+  DALI_TEST_CHECK( resultMap->Find( "url" )->Get<std::string>() == "TestImage2" );
 
   END_TEST;
 }
@@ -452,14 +452,14 @@ int UtcDaliControlBackgroundProperties(void)
 
   Property::Map imageMap;
   imageMap[ "rendererType" ] = "image";
-  imageMap[ "imageUrl" ] = "TestImage";
+  imageMap[ "url" ] = "TestImage";
   control.SetProperty( Control::Property::BACKGROUND, imageMap );
   Property::Value propValue = control.GetProperty( Control::Property::BACKGROUND );
   Property::Map* resultMap = propValue.GetMap();
   DALI_TEST_CHECK( resultMap->Find( "rendererType" ) );
   DALI_TEST_CHECK( resultMap->Find( "rendererType" )->Get<std::string>() == "image" );
-  DALI_TEST_CHECK( resultMap->Find( "imageUrl" ) );
-  DALI_TEST_CHECK( resultMap->Find( "imageUrl" )->Get<std::string>() == "TestImage" );
+  DALI_TEST_CHECK( resultMap->Find( "url" ) );
+  DALI_TEST_CHECK( resultMap->Find( "url" )->Get<std::string>() == "TestImage" );
 
   Property::Map rendererMap;
   rendererMap["rendererType"] = "color";
@@ -487,7 +487,7 @@ int UtcDaliControlBackgroundProperties(void)
   control.SetProperty( Control::Property::BACKGROUND_IMAGE, deprecatedImageMap );
   propValue = control.GetProperty( Control::Property::BACKGROUND_IMAGE );
   resultMap = propValue.GetMap();
-  DALI_TEST_CHECK( resultMap->Find( "imageUrl" )->Get< std::string >() == "TestImage" );
+  DALI_TEST_CHECK( resultMap->Find( "url" )->Get< std::string >() == "TestImage" );
   control.SetProperty( Control::Property::BACKGROUND_IMAGE, emptyMap );
   DALI_TEST_CHECK( control.GetProperty( Control::Property::BACKGROUND_IMAGE ).Get< Property::Map >().Empty() );
 
index 7eb5f48..264a125 100644 (file)
@@ -34,7 +34,6 @@
 #include <dali/integration-api/events/touch-event-integ.h>
 #include <dali/integration-api/events/hover-event-integ.h>
 
-#include <dali-toolkit/devel-api/styling/style-manager.h>
 
 #include "dummy-control.h"
 
@@ -934,7 +933,3 @@ int UtcDaliControlImplGetNextKeyboardFocusableActorP(void)
 
   END_TEST;
 }
-
-
-
-
index 9a89c9c..55fa608 100644 (file)
@@ -321,7 +321,7 @@ int UtcDaliControlRendererGetPropertyMap2(void)
   DALI_TEST_CHECK( typeValue );
   DALI_TEST_CHECK( typeValue->Get<std::string>() == "border" );
 
-   colorValue = resultMap.Find( "borderColor",  Property::VECTOR4 );
+  colorValue = resultMap.Find( "borderColor",  Property::VECTOR4 );
   DALI_TEST_CHECK( colorValue );
   DALI_TEST_CHECK( colorValue->Get<Vector4>() == Color::CYAN );
 
@@ -478,11 +478,11 @@ int UtcDaliControlRendererGetPropertyMap5(void)
   RendererFactory factory = RendererFactory::Get();
   Property::Map propertyMap;
   propertyMap.Insert( "rendererType",  "image" );
-  propertyMap.Insert( "imageUrl",  TEST_IMAGE_FILE_NAME );
-  propertyMap.Insert( "imageDesiredWidth",   20 );
-  propertyMap.Insert( "imageDesiredHeight",   30 );
-  propertyMap.Insert( "imageFittingMode",   "fitHeight" );
-  propertyMap.Insert( "imageSamplingMode",   "boxThenNearest" );
+  propertyMap.Insert( "url",  TEST_IMAGE_FILE_NAME );
+  propertyMap.Insert( "desiredWidth",   20 );
+  propertyMap.Insert( "desiredHeight",   30 );
+  propertyMap.Insert( "fittingMode",   "FIT_HEIGHT" );
+  propertyMap.Insert( "samplingMode",   "BOX_THEN_NEAREST" );
 
   ControlRenderer imageRenderer = factory.GetControlRenderer(propertyMap);
   DALI_TEST_CHECK( imageRenderer );
@@ -495,23 +495,23 @@ int UtcDaliControlRendererGetPropertyMap5(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<std::string>() == "image" );
 
-  value = resultMap.Find( "imageUrl",  Property::STRING );
+  value = resultMap.Find( "url",  Property::STRING );
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<std::string>() == TEST_IMAGE_FILE_NAME );
 
-  value = resultMap.Find( "imageFittingMode",   Property::STRING );
+  value = resultMap.Find( "fittingMode",   Property::STRING );
   DALI_TEST_CHECK( value );
-  DALI_TEST_CHECK( value->Get<std::string>() == "fitHeight" );
+  DALI_TEST_CHECK( value->Get<std::string>() == "FIT_HEIGHT" );
 
-  value = resultMap.Find( "imageSamplingMode",   Property::STRING );
+  value = resultMap.Find( "samplingMode",   Property::STRING );
   DALI_TEST_CHECK( value );
-  DALI_TEST_CHECK( value->Get<std::string>() == "boxThenNearest" );
+  DALI_TEST_CHECK( value->Get<std::string>() == "BOX_THEN_NEAREST" );
 
-  value = resultMap.Find( "imageDesiredWidth",   Property::INTEGER );
+  value = resultMap.Find( "desiredWidth",   Property::INTEGER );
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<int>() == 20 );
 
-  value = resultMap.Find( "imageDesiredHeight",   Property::INTEGER );
+  value = resultMap.Find( "desiredHeight",   Property::INTEGER );
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<int>() == 30 );
 
@@ -524,23 +524,23 @@ int UtcDaliControlRendererGetPropertyMap5(void)
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<std::string>() == "image" );
 
-  value = resultMap.Find( "imageUrl",  Property::STRING );
+  value = resultMap.Find( "url",  Property::STRING );
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<std::string>() == TEST_IMAGE_FILE_NAME );
 
-  value = resultMap.Find( "imageFittingMode",   Property::STRING );
+  value = resultMap.Find( "fittingMode",   Property::STRING );
   DALI_TEST_CHECK( value );
-  DALI_TEST_CHECK( value->Get<std::string>() == "shrinkToFit" );
+  DALI_TEST_CHECK( value->Get<std::string>() == "SHRINK_TO_FIT" );
 
-  value = resultMap.Find( "imageSamplingMode",   Property::STRING );
+  value = resultMap.Find( "samplingMode",   Property::STRING );
   DALI_TEST_CHECK( value );
-  DALI_TEST_CHECK( value->Get<std::string>() == "box" );
+  DALI_TEST_CHECK( value->Get<std::string>() == "BOX" );
 
-  value = resultMap.Find( "imageDesiredWidth",   Property::INTEGER );
+  value = resultMap.Find( "desiredWidth",   Property::INTEGER );
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<int>() == 100 );
 
-  value = resultMap.Find( "imageDesiredHeight",   Property::INTEGER );
+  value = resultMap.Find( "desiredHeight",   Property::INTEGER );
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<int>() == 200 );
 
@@ -554,8 +554,8 @@ int UtcDaliControlRendererGetPropertyMap6(void)
 
   RendererFactory factory = RendererFactory::Get();
   Property::Map propertyMap;
-  propertyMap.Insert( "rendererType",  "nPatch" );
-  propertyMap.Insert( "imageUrl",  TEST_NPATCH_FILE_NAME );
+  propertyMap.Insert( "rendererType",  "image" );
+  propertyMap.Insert( "url",  TEST_NPATCH_FILE_NAME );
   propertyMap.Insert( "borderOnly",  true );
   ControlRenderer nPatchRenderer = factory.GetControlRenderer( propertyMap );
 
@@ -565,9 +565,9 @@ int UtcDaliControlRendererGetPropertyMap6(void)
   // check the property values from the returned map from control renderer
   Property::Value* value = resultMap.Find( "rendererType",  Property::STRING );
   DALI_TEST_CHECK( value );
-  DALI_TEST_CHECK( value->Get<std::string>() == "nPatch" );
+  DALI_TEST_CHECK( value->Get<std::string>() == "image" );
 
-  value = resultMap.Find( "imageUrl",  Property::STRING );
+  value = resultMap.Find( "url",  Property::STRING );
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<std::string>() == TEST_NPATCH_FILE_NAME );
 
@@ -586,8 +586,8 @@ int UtcDaliControlRendererGetPropertyMap7(void)
   // request SvgRenderer with a property map
   RendererFactory factory = RendererFactory::Get();
   Property::Map propertyMap;
-  propertyMap.Insert( "rendererType",  "svg" );
-  propertyMap.Insert( "imageUrl",  TEST_SVG_FILE_NAME );
+  propertyMap.Insert( "rendererType",  "image" );
+  propertyMap.Insert( "url",  TEST_SVG_FILE_NAME );
   ControlRenderer svgRenderer = factory.GetControlRenderer( propertyMap );
 
   Property::Map resultMap;
@@ -595,9 +595,9 @@ int UtcDaliControlRendererGetPropertyMap7(void)
   // check the property values from the returned map from control renderer
   Property::Value* value = resultMap.Find( "rendererType",  Property::STRING );
   DALI_TEST_CHECK( value );
-  DALI_TEST_CHECK( value->Get<std::string>() == "svg" );
+  DALI_TEST_CHECK( value->Get<std::string>() == "image" );
 
-  value = resultMap.Find( "imageUrl",  Property::STRING );
+  value = resultMap.Find( "url",  Property::STRING );
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<std::string>() == TEST_SVG_FILE_NAME );
 
@@ -608,9 +608,9 @@ int UtcDaliControlRendererGetPropertyMap7(void)
   // check the property values from the returned map from control renderer
   value = resultMap.Find( "rendererType",  Property::STRING );
   DALI_TEST_CHECK( value );
-  DALI_TEST_CHECK( value->Get<std::string>() == "svg" );
+  DALI_TEST_CHECK( value->Get<std::string>() == "image" );
 
-  value = resultMap.Find( "imageUrl",  Property::STRING );
+  value = resultMap.Find( "url",  Property::STRING );
   DALI_TEST_CHECK( value );
   DALI_TEST_CHECK( value->Get<std::string>() == TEST_SVG_FILE_NAME );
 
index 1429161..28999a0 100644 (file)
@@ -110,15 +110,15 @@ int UtcDaliDebugRendererGetRenderer1(void)
   // Test that image renderer is replaced with debug renderer
   Property::Map propertyMap4;
   propertyMap4.Insert( "rendererType",  "image" );
-  propertyMap4.Insert( "imageUrl",  TEST_IMAGE_FILE_NAME );
+  propertyMap4.Insert( "url",  TEST_IMAGE_FILE_NAME );
   ControlRenderer imageRenderer = factory.GetControlRenderer( propertyMap4 );
   DALI_TEST_CHECK( imageRenderer );
   DALI_TEST_CHECK( IsDebugRenderer( imageRenderer ) );
 
   // Test that n patch renderer is replaced with debug renderer
   Property::Map propertyMap5;
-  propertyMap5.Insert( "rendererType",  "nPatch" );
-  propertyMap5.Insert( "imageUrl",  TEST_NPATCH_FILE_NAME );
+  propertyMap5.Insert( "rendererType",  "image" );
+  propertyMap5.Insert( "url",  TEST_NPATCH_FILE_NAME );
   ControlRenderer nPatchRenderer = factory.GetControlRenderer( propertyMap4 );
   DALI_TEST_CHECK( nPatchRenderer );
   DALI_TEST_CHECK( IsDebugRenderer( nPatchRenderer ) );
index 36a42dd..cbba3e0 100644 (file)
@@ -968,3 +968,46 @@ int UtcDaliImageViewSetImageBufferImageWithCustomShaderToNativeImage(void)
 
   END_TEST;
 }
+
+int UtcDaliImageViewGetImageP1(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New();
+  DALI_TEST_CHECK( ! imageView.GetImage() );
+
+  Image image = CreateBufferImage();
+  imageView.SetImage( image );
+  DALI_TEST_CHECK( imageView.GetImage() == image );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewGetImageP2(void)
+{
+  ToolkitTestApplication application;
+
+  BufferImage image = CreateBufferImage();
+  ImageView imageView = ImageView::New( image );
+  DALI_TEST_CHECK( imageView.GetImage() == image );
+
+  END_TEST;
+}
+
+int UtcDaliImageViewGetImageN(void)
+{
+  ToolkitTestApplication application;
+
+  ImageView imageView = ImageView::New( TEST_IMAGE_FILE_NAME );
+  DALI_TEST_CHECK( ! imageView.GetImage() );
+
+  Image image = CreateBufferImage();
+  imageView.SetImage( image );
+  DALI_TEST_CHECK( imageView.GetImage() == image );
+
+  imageView.SetImage( TEST_IMAGE_FILE_NAME );
+  DALI_TEST_CHECK( ! imageView.GetImage() );
+
+  END_TEST;
+}
+
index 6e22042..f37298c 100644 (file)
@@ -561,7 +561,7 @@ int UtcDaliRendererFactoryGetImageRenderer1(void)
 
   Property::Map propertyMap;
   propertyMap.Insert( "rendererType",  "image" );
-  propertyMap.Insert( "imageUrl",  TEST_IMAGE_FILE_NAME );
+  propertyMap.Insert( "url",  TEST_IMAGE_FILE_NAME );
 
   ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
   DALI_TEST_CHECK( controlRenderer );
@@ -642,8 +642,8 @@ int UtcDaliRendererFactoryGetNPatchRenderer1(void)
   Integration::ResourcePointer ninePatchResource = CustomizeNinePatch( application, ninePatchImageWidth, ninePatchImageHeight, stretchRangesX, stretchRangesY );
 
   Property::Map propertyMap;
-  propertyMap.Insert( "rendererType",  "nPatch" );
-  propertyMap.Insert( "imageUrl",  TEST_NPATCH_FILE_NAME );
+  propertyMap.Insert( "rendererType",  "image" );
+  propertyMap.Insert( "url",  TEST_NPATCH_FILE_NAME );
   {
     tet_infoline( "whole grid" );
     ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
@@ -706,8 +706,8 @@ int UtcDaliRendererFactoryGetNPatchRenderer2(void)
   Integration::ResourcePointer ninePatchResource = CustomizeNinePatch( application, ninePatchImageWidth, ninePatchImageHeight, stretchRangesX, stretchRangesY );
 
   Property::Map propertyMap;
-  propertyMap.Insert( "rendererType",  "nPatch" );
-  propertyMap.Insert( "imageUrl",  TEST_NPATCH_FILE_NAME );
+  propertyMap.Insert( "rendererType",  "image" );
+  propertyMap.Insert( "url",  TEST_NPATCH_FILE_NAME );
   {
     ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
     DALI_TEST_CHECK( controlRenderer );
@@ -868,8 +868,8 @@ int UtcDaliRendererFactoryGetNPatchRendererN2(void)
   DALI_TEST_CHECK( factory );
 
   Property::Map propertyMap;
-  propertyMap.Insert( "rendererType",  "nPatch" );
-  propertyMap.Insert( "imageUrl",  111 );
+  propertyMap.Insert( "rendererType",  111 );
+  propertyMap.Insert( "url",  "ERROR.9.jpg" );
 
   ControlRenderer controlRenderer = factory.GetControlRenderer( propertyMap );
   DALI_TEST_CHECK( controlRenderer );
diff --git a/automated-tests/src/dali-toolkit/utc-Dali-StyleManager.cpp b/automated-tests/src/dali-toolkit/utc-Dali-StyleManager.cpp
deleted file mode 100644 (file)
index 98a4d0b..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
- *
- * Licensed 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.
- */
-
-#include <iostream>
-#include <stdlib.h>
-#include <dali-toolkit-test-suite-utils.h>
-#include <dali-toolkit/dali-toolkit.h>
-#include <dali/integration-api/events/touch-event-integ.h>
-#include <dali-toolkit/devel-api/styling/style-manager.h>
-
-
-using namespace Dali;
-using namespace Dali::Toolkit;
-
-void dali_style_manager_startup(void)
-{
-  test_return_value = TET_UNDEF;
-}
-
-void dali_style_manager_cleanup(void)
-{
-  test_return_value = TET_PASS;
-}
-
-int UtcDaliStyleManagerGet(void)
-{
-  ToolkitTestApplication application;
-
-  tet_infoline(" UtcDaliStyleManagerGet");
-
-  // Register Type
-  TypeInfo type;
-  type = TypeRegistry::Get().GetTypeInfo( "StyleManager" );
-  DALI_TEST_CHECK( type );
-  BaseHandle handle = type.CreateInstance();
-  DALI_TEST_CHECK( handle );
-
-  StyleManager manager;
-
-  manager = StyleManager::Get();
-  DALI_TEST_CHECK(manager);
-
-  StyleManager newManager = StyleManager::Get();
-  DALI_TEST_CHECK(newManager);
-
-  // Check that focus manager is a singleton
-  DALI_TEST_CHECK(manager == newManager);
-  END_TEST;
-}
-
-int UtcDaliStyleManagerSetOrientationValue(void)
-{
-  ToolkitTestApplication application;
-
-  tet_infoline( " UtcDaliStyleManagerSetOrientationValue" );
-
-  StyleManager manager = StyleManager::Get();
-
-  int orientation1 = 0;
-  manager.SetOrientationValue( orientation1 );
-  DALI_TEST_CHECK( manager.GetOrientationValue() == orientation1 );
-
-  int orientation2 = 180;
-  manager.SetOrientationValue( orientation2 );
-  DALI_TEST_CHECK( manager.GetOrientationValue() == orientation2 );
-
-  END_TEST;
-}
-
-int UtcDaliStyleManagerSetOrientation(void)
-{
-  ToolkitTestApplication application;
-
-  tet_infoline( " UtcDaliStyleManagerSetOrientation" );
-
-  StyleManager manager = StyleManager::Get();
-
-  Orientation orientation;
-
-  manager.SetOrientation( orientation );
-
-  DALI_TEST_CHECK( manager.GetOrientation() == orientation );
-
-  END_TEST;
-}
-
-int UtcDaliStyleManagerSetStyleConstant(void)
-{
-  ToolkitTestApplication application;
-
-  tet_infoline( " UtcDaliStyleManagerSetStyleConstant" );
-
-  StyleManager manager = StyleManager::Get();
-
-  std::string key( "key" );
-  Property::Value value( 100 );
-
-  manager.SetStyleConstant( key, value );
-
-  Property::Value returnedValue;
-  manager.GetStyleConstant( key, returnedValue );
-
-  DALI_TEST_CHECK( value.Get<int>() == returnedValue.Get<int>() );
-
-  std::string key2( "key2" );
-  Property::Value returnedValue2;
-  DALI_TEST_CHECK( !manager.GetStyleConstant( key2, returnedValue2 ) );
-
-  END_TEST;
-}
index 4bb5f56..809b07b 100644 (file)
@@ -23,7 +23,6 @@
 #include <dali-toolkit-test-suite-utils.h>
 #include <dali-toolkit/dali-toolkit.h>
 #include <dali-toolkit/devel-api/controls/text-controls/text-editor.h> ///< @todo to be removed when text-editor is added to the dali-toolkit.h
-#include <dali-toolkit/devel-api/styling/style-manager.h>
 
 using namespace Dali;
 using namespace Toolkit;
@@ -372,7 +371,7 @@ int utcDaliTextEditorAtlasRenderP(void)
   ToolkitTestApplication application;
   tet_infoline(" UtcDaliToolkitTextEditorAtlasRenderP");
   StyleManager styleManager = StyleManager::Get();
-  styleManager.RequestDefaultTheme();
+  styleManager.ApplyDefaultTheme();
   TextEditor editor = TextEditor::New();
   DALI_TEST_CHECK( editor );
 
index 982dffe..2498c57 100644 (file)
@@ -22,7 +22,6 @@
 #include <dali/integration-api/events/tap-gesture-event.h>
 #include <dali-toolkit-test-suite-utils.h>
 #include <dali-toolkit/dali-toolkit.h>
-#include <dali-toolkit/devel-api/styling/style-manager.h>
 
 using namespace Dali;
 using namespace Toolkit;
@@ -425,7 +424,7 @@ int utcDaliTextFieldAtlasRenderP(void)
   ToolkitTestApplication application;
   tet_infoline(" UtcDaliToolkitTextFieldAtlasRenderP");
   StyleManager styleManager = StyleManager::Get();
-  styleManager.RequestDefaultTheme();
+  styleManager.ApplyDefaultTheme();
   TextField field = TextField::New();
   DALI_TEST_CHECK( field );
 
index a861a17..67156bb 100644 (file)
@@ -168,6 +168,7 @@ AC_CONFIG_FILES([
  dali-toolkit.pc
  docs/Makefile
  docs/dali.doxy
+ ../../automated-tests/CMakeLists.txt
 ])
 
 AC_OUTPUT
index f803a93..f967eb5 100644 (file)
@@ -110,7 +110,6 @@ develapiimageatlasdir =         $(develapidir)/image-atlas
 develapiscriptingdir =          $(develapidir)/scripting
 develapishadereffectsdir =      $(develapidir)/shader-effects
 develapitransitioneffectsdir =  $(develapidir)/transition-effects
-develapistylingdir =            $(develapidir)/styling
 develapitoolbardir =            $(develapicontrolsdir)/tool-bar
 develapitextselectionpopupdir = $(develapicontrolsdir)/text-controls
 
@@ -130,7 +129,6 @@ develapiscripting_HEADERS =         $(devel_api_scripting_header_files)
 develapishadowview_HEADERS =        $(devel_api_shadow_view_header_files)
 develapishadereffects_HEADERS =     $(devel_api_shader_effects_header_files)
 develapislider_HEADERS =            $(devel_api_slider_header_files)
-develapistyling_HEADERS =           $(devel_api_styling_header_files)
 develapisuperblurview_HEADERS =     $(devel_api_super_blur_view_header_files)
 develapitoolbar_HEADERS =           $(devel_api_tool_bar_header_files)
 develapitransitioneffects_HEADERS = $(devel_api_transition_effects_header_files)
@@ -151,6 +149,7 @@ publicapiscrollbardir =            $(publicapicontrolsdir)/scroll-bar
 publicapiscrollabledir =           $(publicapicontrolsdir)/scrollable
 publicapiscrollviewdir =           $(publicapicontrolsdir)/scrollable/scroll-view
 publicapiitemviewdir =             $(publicapicontrolsdir)/scrollable/item-view
+publicapistylingdir =              $(publicapidir)/styling
 publicapitableviewdir =            $(publicapicontrolsdir)/table-view
 publicapitextcontrolsdir =         $(publicapicontrolsdir)/text-controls
 publicapifocusmanagerdir =         $(publicapidir)/focus-manager
@@ -171,6 +170,7 @@ publicapipageturnview_HEADERS =         $(public_api_page_turn_view_header_files
 publicapiscrollbar_HEADERS =            $(public_api_scroll_bar_header_files)
 publicapiscrollable_HEADERS =           $(public_api_scrollable_header_files)
 publicapiscrollview_HEADERS =           $(public_api_scroll_view_header_files)
+publicapistyling_HEADERS =              $(public_api_styling_header_files)
 publicapitableview_HEADERS =            $(public_api_table_view_header_files)
 publicapitextcontrols_HEADERS =         $(public_api_text_controls_header_files)
 publicapifocusmanager_HEADERS =         $(public_api_focus_manager_header_files)
index 72ed846..b14f125 100644 (file)
@@ -891,9 +891,11 @@ WARN_LOGFILE           =
 INPUT                  = @DOXYGEN_DOCS_DIR@/content \
                          @prefix@/include/dali/doc/dali-core-doc.h \
                          @prefix@/include/dali/doc/dali-adaptor-doc.h \
-                         ../../../../dali-toolkit/doc/dali-toolkit-doc.h \
+                         ../../../doc/dali-toolkit-doc.h \
                          @prefix@/include/dali/public-api \
-                         ../../../../dali-toolkit/dali-toolkit/public-api \
+                         @prefix@/include/dali/devel-api \
+                         ../../../dali-toolkit/public-api \
+                         ../../../dali-toolkit/devel-api \
                          ../../../automated-tests/README.md
 
 # This tag can be used to specify the character encoding of the source files
index 19a1993..36484f1 100644 (file)
@@ -51,6 +51,7 @@
 #include <dali-toolkit/public-api/controls/text-controls/text-label.h>
 #include <dali-toolkit/public-api/accessibility-manager/accessibility-manager.h>
 #include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
+#include <dali-toolkit/public-api/styling/style-manager.h>
 #include <dali-toolkit/public-api/text/rendering-backend.h>
 #include <dali-toolkit/public-api/dali-toolkit-version.h>
 #include <dali-toolkit/public-api/enums.h>
index f89b622..4270b1e 100644 (file)
@@ -134,11 +134,6 @@ void Builder::CreateRenderTask( const std::string &name )
   GetImpl(*this).CreateRenderTask( name );
 }
 
-ShaderEffect Builder::GetShaderEffect( const std::string &name )
-{
-  return GetImpl(*this).GetShaderEffect( name );
-}
-
 FrameBufferImage Builder::GetFrameBufferImage( const std::string &name )
 {
   return GetImpl(*this).GetFrameBufferImage( name );
index 39fed86..0526510 100644 (file)
@@ -384,15 +384,6 @@ class DALI_IMPORT_API Builder : public BaseHandle
   void CreateRenderTask( const std::string &name );
 
   /**
-   * Get or create ShaderEffect from the ShaderEffect instance library.
-   * An empty handle is returned otherwise.
-   * @pre The Builder has been initialized.
-   * @param name The name of a ShaderEffect in the loaded representation
-   * @return A handle to a ShaderEffect if found, otherwise empty
-   */
-  ShaderEffect GetShaderEffect( const std::string &name );
-
-  /**
    * Get or create FrameBufferImage from the FrameBufferImage instance library.
    * An empty handle is returned otherwise.
    * @pre The Builder has been initialized.
index 9353f13..50ae2a8 100644 (file)
@@ -69,8 +69,8 @@ class BloomView;
  *
  *  // create and add some visible actors to the BloomView, all these child actors will therefore get bloomed\n
  *  Image image = Image::New(...);\n
- *  ImageActor imageActor = ImageActor::New(image);\n
- *  bloomView.Add(imageActor);\n
+ *  ImageView imageView = ImageView::New(image);\n
+ *  bloomView.Add(imageView);\n
  *  ...\n
  *
  *  // Start rendering the BloomView\n
index b8540e9..97a9bdb 100644 (file)
@@ -53,12 +53,13 @@ class FlexContainer;
  * Below is an illustration of the various directions and terms as applied to a flex
  * container with the "flex direction" defined as "row".
  *
+ * @code
  *     flex container
  *    --------------------------------------------------------------- cross start
  *    | ------------------ --------|--------------------------- |
  *    | |                | |       |                          | |
  *    | |                | |       |                          | |
- *    | |  flex item 1   | |       |    flex item 2           | |  main axis
+ *    | |  flex item 1   | |       |    flex item 2           | | main axis
  *    |-|----------------|-|-------|--------------------------|-|------------>
  *    | |                | |       |                          | |
  *    | |                | |       |                          | |
@@ -69,6 +70,7 @@ class FlexContainer;
  *    | main start                 | cross axis                 | main end
  *    |                            |                            |
  *                                 v
+ * @endcode
  *
  * @nosubgrouping
  * <h3>Per-child Custom properties for script supporting:</h3>
index b0bf93d..6251c01 100644 (file)
@@ -215,7 +215,7 @@ public:
   /**
    * @brief Sets the actor to use for a footer in this Popup.
    *
-   * @param[in] control The footer actor to be added to this Popup
+   * @param[in] footer The footer actor to be added to this Popup
    */
   void SetFooter( Actor footer );
 
index be5db96..fe31a7e 100644 (file)
@@ -99,7 +99,7 @@ public:
    * Depth-index controls draw-order for overlapping renderers.
    * Renderer with higher depth indices are rendered in front of other renderer with smaller values
    *
-   * @param[in] depthIndex The depth index of this renderer.
+   * @param[in] index The depth index of this renderer.
    */
   void SetDepthIndex( float index );
 
index 188c3c3..2df4978 100644 (file)
@@ -66,17 +66,17 @@ class ShadowView;
  *
  *  // create and add some visible actors to the ShadowView, all these child actors will therefore cast a shadow.
  *  Image image = Image::New(...);
- *  ImageActor imageActor = ImageActor::New(image);
- *  imageActor.SetParentOrigin( ParentOrigin::CENTER );
- *  imageActor.SetAnchorPoint( AnchorPoint::CENTER );
- *  shadowView.Add(imageActor);\n Add the renderable actor to the shadow view
- *
- *  ImageActor shadowPlane = ImageActor::New(); //This will be the shadow plane
- *  shadowPlane.SetParentOrigin( ParentOrigin::CENTER );
- *  shadowPlane.SetAnchorPoint( AnchorPoint::CENTER );
- *  shadowPlane.SetSize(700.0f, 700.0f);
- *  shadowPlane.SetPosition( Vector3(0.0f, 0.0f, -30.0f) ); //Just behind the image actor.
- *  shadowPlane.SetShadowPlane(ShadowPlane);
+ *  ImageView imageView = ImageView::New(image);
+ *  imageView.SetParentOrigin( ParentOrigin::CENTER );
+ *  imageView.SetAnchorPoint( AnchorPoint::CENTER );
+ *  shadowView.Add(imageView);\n Add the renderable actor to the shadow view
+ *
+ *  ImageView shadowPlaneBg = ImageView::New(); //This will be the shadow plane
+ *  shadowPlaneBg.SetParentOrigin( ParentOrigin::CENTER );
+ *  shadowPlaneBg.SetAnchorPoint( AnchorPoint::CENTER );
+ *  shadowPlaneBg.SetSize(700.0f, 700.0f);
+ *  shadowPlaneBg.SetPosition( Vector3(0.0f, 0.0f, -30.0f) ); //Just behind the image actor.
+ *  shadowView.SetShadowPlaneBackground(ShadowPlane);
  *
  *  Actor pointLight = Actor::New(); // This will be the light source
  *  pointLight.SetPosition(300.0f, 250.0f, 600.0f);
index 8987002..f28fa71 100755 (executable)
@@ -22,7 +22,6 @@ devel_api_src_files = \
   $(devel_api_src_dir)/controls/tool-bar/tool-bar.cpp \
   $(devel_api_src_dir)/focus-manager/keyinput-focus-manager.cpp \
   $(devel_api_src_dir)/image-atlas/image-atlas.cpp \
-  $(devel_api_src_dir)/styling/style-manager.cpp \
   $(devel_api_src_dir)/scripting/script.cpp \
   $(devel_api_src_dir)/transition-effects/cube-transition-cross-effect.cpp \
   $(devel_api_src_dir)/transition-effects/cube-transition-effect.cpp \
@@ -74,9 +73,6 @@ devel_api_focus_manager_header_files = \
 devel_api_image_atlas_header_files = \
   $(devel_api_src_dir)/image-atlas/image-atlas.h
 
-devel_api_styling_header_files = \
-  $(devel_api_src_dir)/styling/style-manager.h
-
 devel_api_scripting_header_files = \
   $(devel_api_src_dir)/scripting/script.h \
   $(devel_api_src_dir)/scripting/script-plugin.h
@@ -123,4 +119,3 @@ devel_api_transition_effects_header_files = \
   $(devel_api_src_dir)/transition-effects/cube-transition-cross-effect.h \
   $(devel_api_src_dir)/transition-effects/cube-transition-fold-effect.h \
   $(devel_api_src_dir)/transition-effects/cube-transition-wave-effect.h
-
index 315584a..395615d 100644 (file)
@@ -83,7 +83,7 @@ public:
   /**
    * @brief This assignment operator is required for (smart) pointer semantics.
    *
-   * @param [in] rhs  A reference to the copied handle
+   * @param [in] handle  A reference to the copied handle
    * @return A reference to this
    */
   ImageAtlas& operator=( const ImageAtlas& handle );
index 0825a5d..5c929b9 100644 (file)
@@ -35,9 +35,10 @@ namespace Toolkit
  * As we use the texture coordinate as pixel position to calculate random offset,
  * the line should passing through rectangle {(0,0),(0,1),(1,0),(1,1)},
  * so make the position parameter with two component values between 0.0 to 1.0
+ * @param[in] actor The actor that registers the uniform properties
  * @param[in] position The point ( locates within rectangle {(0,0),(0,1),(1,0),(1,1)} ) passed through by the central line
  * @param[in] displacement The direction of the central line
- * @param[in] initialProgress, the normalised initial progress of the shader
+ * @param[in] initialProgress The normalised initial progress of the shader
  */
 inline void DissolveEffectSetCentralLine( Actor& actor, const Vector2& position, const Vector2& displacement, float initialProgress )
 {
index 310e3ce..8e71791 100644 (file)
@@ -30,7 +30,8 @@ namespace Toolkit
 /**
  * @brief Set the properties for the motion blur
  *
- * @param numBlurSamples Number of samples used by the shader
+ * @param[in] actor The actor that registers the uniform properties
+ * @param[in] numBlurSamples Number of samples used by the shader
  */
 inline void SetMotionBlurProperties( Actor& actor, unsigned int numBlurSamples = 8 )
 {
index 9c30573..05546a9 100644 (file)
@@ -190,7 +190,7 @@ public: //Signal
    * Signal emitted when the transition has completed animation
    * A callback of the following type may be connected
    * @code
-   *   void YourCallbackName( CubeTransitionEffect cubeEffect, ImageActor currentImage );
+   *   void YourCallbackName( CubeTransitionEffect cubeEffect, Image currentImage );
    * @endcode
    * @return The Signal to connect to.
    */
index 3807b08..8369c62 100644 (file)
@@ -71,23 +71,6 @@ Actor SetupActor( const TreeNode& child, Actor& actor, const Replacement& consta
     }
   }
 
-  // Add custom properties
-  if( OptionalChild customPropertiesChild = IsChild(child,  "customProperties") )
-  {
-    const TreeNode& customPropertiesNode = *customPropertiesChild;
-    const TreeConstIter endIter = customPropertiesNode.CEnd();
-    for( TreeConstIter iter = customPropertiesNode.CBegin(); endIter != iter; ++iter )
-    {
-      const TreeNode::KeyNodePair& keyChild = *iter;
-      std::string key( keyChild.first );
-
-      Property::Value value;
-      DeterminePropertyFromNode( keyChild.second, value, constant );
-      // Register/Set property.
-      actor.RegisterProperty( key, value, Property::READ_WRITE );
-    }
-  }
-
   return actor;
 }
 
index 980fc90..beec9eb 100644 (file)
@@ -229,31 +229,8 @@ Animation CreateAnimation( const TreeNode& child, const Replacement& constant, D
         // to allow animating shader uniforms
         if( propIndex == Property::INVALID_INDEX )
         {
-          ImageActor imageActor = ImageActor::DownCast( targetHandle );
-          if( imageActor )
-          {
-            // A limitation here is that its possible that between creation of animation
-            // and running it the ShaderEffect of the actor has been changed.
-            // However this is a unlikely use case especially when using scripts.
-            if( ShaderEffect effect = imageActor.GetShaderEffect() )
-            {
-              propIndex = effect.GetPropertyIndex( *property );
-              if(propIndex != Property::INVALID_INDEX)
-              {
-                targetHandle = effect;
-              }
-              else
-              {
-                DALI_SCRIPT_WARNING( "Cannot find property on object or ShaderEffect\n" );
-                continue;
-              }
-            }
-          }
-          else
-          {
-            DALI_SCRIPT_WARNING( "Cannot find property on object or ShaderEffect\n" );
+            DALI_SCRIPT_WARNING( "Cannot find property on object\n" );
             continue;
-          }
         }
 
         if( propIndex == Property::INVALID_INDEX)
index 2cf23db..f31bf5f 100644 (file)
@@ -79,6 +79,9 @@ const std::string KEYNAME_TEMPLATES = "templates";
 const std::string KEYNAME_INCLUDES  = "includes";
 const std::string KEYNAME_MAPPINGS  = "mappings";
 
+const std::string PROPERTIES = "properties";
+const std::string ANIMATABLE_PROPERTIES = "animatableProperties";
+
 typedef std::vector<const TreeNode*> TreeNodeList;
 
 
@@ -153,68 +156,10 @@ void Builder::SetProperties( const TreeNode& node, Handle& handle, const Replace
         continue;
       }
 
-      // special field 'image' usually contains an json object description
-      // although sometimes refers to a framebuffer
-      if( key == "image" )
-      {
-        if( 0 == keyChild.second.Size() )
-        {
-          ImageActor imageActor = ImageActor::DownCast(handle);
-          if(imageActor)
-          {
-            if( OptionalString s = constant.IsString( keyChild.second ) )
-            {
-              FrameBufferImage fb = GetFrameBufferImage(*s, constant);
-              if(fb)
-              {
-                imageActor.SetImage( fb );
-              }
-            }
-          }
-        }
-      }
-
-      // special field 'effect' references the shader effect instances
-      if( key == "effect" )
-      {
-        ImageActor actor = ImageActor::DownCast(handle);
-        if( actor )
-        {
-          OptionalString str = constant.IsString( keyChild.second );
-          if( str )
-          {
-            ShaderEffect effect = GetShaderEffect( *str, constant );
-            actor.SetShaderEffect(effect);
-          }
-        }
-        else
-        {
-          DALI_SCRIPT_WARNING("Could not find or set shader effect\n");
-        }
-
-        continue;
-      }
-
       Handle propertyObject( handle );
 
       Dali::Property::Index index = propertyObject.GetPropertyIndex( key );
 
-      if( Property::INVALID_INDEX == index )
-      {
-        ImageActor actor = ImageActor::DownCast(handle);
-        if( actor )
-        {
-          if( ShaderEffect effect = actor.GetShaderEffect() )
-          {
-            index = effect.GetPropertyIndex( key );
-            if(index != Property::INVALID_INDEX)
-            {
-              propertyObject = effect;
-            }
-          }
-        }
-      }
-
       if( Property::INVALID_INDEX != index )
       {
         Property::Type type = propertyObject.GetPropertyType(index);
@@ -253,6 +198,10 @@ void Builder::SetProperties( const TreeNode& node, Handle& handle, const Replace
         DALI_SCRIPT_VERBOSE("SetProperty INVALID '%s' Index=:%d\n", key.c_str(), index);
       }
 
+      // Add custom properties
+      SetCustomProperties(node, handle, constant, PROPERTIES, Property::READ_WRITE);
+      SetCustomProperties(node, handle, constant, ANIMATABLE_PROPERTIES, Property::ANIMATABLE);
+
     } // for property nodes
   }
   else
@@ -261,6 +210,27 @@ void Builder::SetProperties( const TreeNode& node, Handle& handle, const Replace
   }
 }
 
+void Builder::SetCustomProperties( const TreeNode& node, Handle& handle, const Replacement& constant,
+                          const std::string& childName, Property::AccessMode accessMode )
+{
+  // Add custom properties
+  if( OptionalChild customPropertiesChild = IsChild(node, childName) )
+  {
+    const TreeNode& customPropertiesNode = *customPropertiesChild;
+    const TreeConstIter endIter = customPropertiesNode.CEnd();
+    for( TreeConstIter iter = customPropertiesNode.CBegin(); endIter != iter; ++iter )
+    {
+      const TreeNode::KeyNodePair& keyChild = *iter;
+      std::string key( keyChild.first );
+
+      Property::Value value;
+      DeterminePropertyFromNode( keyChild.second, value, constant );
+      // Register/Set property.
+      handle.RegisterProperty( key, value, accessMode );
+    }
+  }
+}
+
 // Set properties from node on handle.
 void Builder::ApplyProperties( const TreeNode& root, const TreeNode& node,
                                Dali::Handle& handle, const Replacement& constant )
@@ -590,42 +560,6 @@ void Builder::CreateRenderTask( const std::string &name )
   }
 }
 
-ShaderEffect Builder::GetShaderEffect( const std::string &name)
-{
-  Replacement constant( mReplacementMap );
-  return GetShaderEffect( name, constant );
-}
-
-ShaderEffect Builder::GetShaderEffect( const std::string &name, const Replacement& constant )
-{
-  DALI_ASSERT_ALWAYS(mParser.GetRoot() && "Builder script not loaded");
-
-  ShaderEffect ret;
-
-  ShaderEffectLut::const_iterator iter( mShaderEffectLut.find( name ) );
-  if( iter != mShaderEffectLut.end() )
-  {
-    ret = iter->second;
-  }
-  else
-  {
-    if( OptionalChild effects = IsChild( *mParser.GetRoot(), "shaderEffects") )
-    {
-      if( OptionalChild effect = IsChild( *effects, name ) )
-      {
-        Dali::Property::Value propertyMap(Property::MAP);
-        if( DeterminePropertyFromNode( *effect, Property::MAP, propertyMap, constant ) )
-        {
-          ret = Dali::Scripting::NewShaderEffect( propertyMap );
-          mShaderEffectLut[ name ] = ret;
-        }
-      }
-    }
-  }
-
-  return ret;
-}
-
 FrameBufferImage Builder::GetFrameBufferImage( const std::string &name )
 {
   Replacement constant( mReplacementMap );
index a5d6f06..dc0ab41 100644 (file)
@@ -163,16 +163,6 @@ public:
   void CreateRenderTask( const std::string &name );
 
   /**
-   * @copydoc Toolkit::Builder::GetShaderEffect
-   */
-  ShaderEffect GetShaderEffect( const std::string &name );
-
-  /**
-   * @copydoc Toolkit::Builder::GetShaderEffect
-   */
-  ShaderEffect GetShaderEffect( const std::string &name, const Replacement& constant );
-
-  /**
    * @copydoc Toolkit::Builder::GetFrameBufferImage
    */
   FrameBufferImage GetFrameBufferImage( const std::string &name );
@@ -234,15 +224,14 @@ private:
 
   void SetupTask( RenderTask& task, const Toolkit::TreeNode& node, const Replacement& replacement );
 
+  void SetCustomProperties( const TreeNode& node, Handle& handle, const Replacement& constant, const std::string& childName, Property::AccessMode accessMode );
+
 private:
   Toolkit::JsonParser mParser;
 
   typedef std::map<const std::string, FrameBufferImage> ImageLut;
   ImageLut mFrameBufferImageLut;
 
-  typedef std::map<const std::string, ShaderEffect> ShaderEffectLut;
-  ShaderEffectLut mShaderEffectLut;
-
   typedef std::map<const std::string, Path> PathLut;
   PathLut mPathLut;
 
index 836a26d..5126408 100644 (file)
@@ -276,7 +276,7 @@ Geometry BubbleEmitter::CreateGeometry( unsigned int numOfPatch )
   vertexData.reserve( numVertex );
 
   unsigned int numIndex = numOfPatch*6u;
-  Vector<unsigned int> indexData;
+  Vector<unsigned short> indexData;
   indexData.Reserve( numIndex );
 
   for(unsigned int i = 0; i < numOfPatch; i++)
@@ -289,7 +289,7 @@ Geometry BubbleEmitter::CreateGeometry( unsigned int numOfPatch )
     vertexData.push_back( Vertex( index, Vector2(curSize,curSize), Vector2(1.f,1.f)  ) );
     vertexData.push_back( Vertex( index, Vector2(curSize,0.f),     Vector2(1.f,0.f)  ) );
 
-    unsigned int idx = index * 4;
+    unsigned short idx = index * 4;
     indexData.PushBack( idx );
     indexData.PushBack( idx+1 );
     indexData.PushBack( idx+2 );
@@ -305,14 +305,9 @@ Geometry BubbleEmitter::CreateGeometry( unsigned int numOfPatch )
   PropertyBuffer vertices = PropertyBuffer::New( vertexFormat );
   vertices.SetData( &vertexData[0], numVertex );
 
-  Property::Map indexFormat;
-  indexFormat["indices"] = Property::INTEGER;
-  PropertyBuffer indices = PropertyBuffer::New( indexFormat );
-  indices.SetData( &indexData[0], numIndex );
-
   Geometry geometry = Geometry::New();
   geometry.AddVertexBuffer( vertices );
-  geometry.SetIndexBuffer( indices );
+  geometry.SetIndexBuffer( &indexData[0], numIndex );
 
   return geometry;
 }
index 58c25b6..17ea2b6 100644 (file)
@@ -250,20 +250,20 @@ private: // Data
 
 // Helpers for public-api forwarding methods
 
-inline Toolkit::Internal::FlexContainer& GetImpl( Toolkit::FlexContainer& tableView )
+inline Toolkit::Internal::FlexContainer& GetImpl( Toolkit::FlexContainer& flexContainer )
 {
-  DALI_ASSERT_ALWAYS(tableView);
+  DALI_ASSERT_ALWAYS(flexContainer);
 
-  Dali::RefObject& handle = tableView.GetImplementation();
+  Dali::RefObject& handle = flexContainer.GetImplementation();
 
   return static_cast<Toolkit::Internal::FlexContainer&>(handle);
 }
 
-inline const Toolkit::Internal::FlexContainer& GetImpl( const Toolkit::FlexContainer& tableView )
+inline const Toolkit::Internal::FlexContainer& GetImpl( const Toolkit::FlexContainer& flexContainer )
 {
-  DALI_ASSERT_ALWAYS(tableView);
+  DALI_ASSERT_ALWAYS(flexContainer);
 
-  const Dali::RefObject& handle = tableView.GetImplementation();
+  const Dali::RefObject& handle = flexContainer.GetImplementation();
 
   return static_cast<const Toolkit::Internal::FlexContainer&>(handle);
 }
index 3eb0144..5843804 100644 (file)
@@ -142,6 +142,11 @@ void ImageView::SetImage( const std::string& url, ImageDimensions size )
   }
 }
 
+Image ImageView::GetImage() const
+{
+  return mImage;
+}
+
 void ImageView::EnablePreMultipliedAlpha( bool preMultipled )
 {
   if( mRenderer )
index b517994..c598c26 100644 (file)
@@ -76,6 +76,11 @@ public:
   void SetImage( const std::string& imageUrl, ImageDimensions size );
 
   /**
+   * @copydoc Dali::Toolkit::GetImage
+   */
+  Image GetImage() const;
+
+  /**
    * @brief Set whether the Pre-multiplied Alpha Blending is required
    *
    * @param[in] preMultipled whether alpha is pre-multiplied.
index 75af670..6d05a50 100644 (file)
@@ -553,13 +553,13 @@ void Model3dView::UpdateShaderUniforms()
 
 void Model3dView::CreateMaterial()
 {
-  if( mObjLoader.IsMaterialLoaded() && (mTexture0Url != ""))
+  if( mObjLoader.IsMaterialLoaded() && (mTexture0Url != "") && mObjLoader.IsTexturePresent() )
   {
-    if( (mTexture2Url != "") && (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP))
+    if( (mTexture2Url != "") && (mTexture1Url != "") && (mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP) && mObjLoader.IsNormalMapPresent() )
     {
       mShader = Shader::New( NRMMAP_VERTEX_SHADER, NRMMAP_FRAGMENT_SHADER, (Shader::ShaderHints)(Shader::HINT_REQUIRES_SELF_DEPTH_TEST | Shader::HINT_MODIFIES_GEOMETRY) );
     }
-    else if(mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE)
+    else if( mIlluminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE )
     {
       mShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER, (Shader::ShaderHints)(Shader::HINT_REQUIRES_SELF_DEPTH_TEST | Shader::HINT_MODIFIES_GEOMETRY) );
     }
index 5e67b1e..dd9c25d 100644 (file)
@@ -68,10 +68,10 @@ void ObjLoader::CalculateTangentArray(const Dali::Vector<Vector3>& vertex,
 
   Vector3 *tan1 = new Vector3[vertex.Size() * 2];
 
-  memset(tan1, 0, normal.Size() * sizeof(Vector3) * 2);
-  memset(&normal[0], 0, normal.Size() * sizeof(Vector3) * 2);
+  memset( tan1, 0, normal.Size() * sizeof(Vector3) * 2 );
+  memset( &normal[0], 0, normal.Size() * sizeof(Vector3) * 2 );
 
-  for (unsigned long a = 0; a < triangle.Size(); a++)
+  for ( unsigned long a = 0; a < triangle.Size(); a++ )
   {
     Vector3 Tangent, Bitangent, Normal;
 
@@ -95,9 +95,9 @@ void ObjLoader::CalculateTangentArray(const Dali::Vector<Vector3>& vertex,
 
     float f = 1.0f / (DeltaU1 * DeltaV2 - DeltaU2 * DeltaV1);
 
-    Tangent.x = f * (DeltaV2 * Edge1.x - DeltaV1 * Edge2.x);
-    Tangent.y = f * (DeltaV2 * Edge1.y - DeltaV1 * Edge2.y);
-    Tangent.z = f * (DeltaV2 * Edge1.z - DeltaV1 * Edge2.z);
+    Tangent.x = f * ( DeltaV2 * Edge1.x - DeltaV1 * Edge2.x );
+    Tangent.y = f * ( DeltaV2 * Edge1.y - DeltaV1 * Edge2.y );
+    Tangent.z = f * ( DeltaV2 * Edge1.z - DeltaV1 * Edge2.z );
 
     tan1[triangle[a].pntIndex[0]] += Tangent;
     tan1[triangle[a].pntIndex[1]] += Tangent;
@@ -108,15 +108,15 @@ void ObjLoader::CalculateTangentArray(const Dali::Vector<Vector3>& vertex,
     normal[triangle[a].pntIndex[2]] += Normal;
   }
 
-  for (unsigned long a = 0; a < triangle.Size(); a++)
+  for ( unsigned long a = 0; a < triangle.Size(); a++ )
   {
-    for (unsigned long j = 0; j < 3; j++)
+    for ( unsigned long j = 0; j < 3; j++ )
     {
       triangle[a].nrmIndex[j] = triangle[a].pntIndex[j];
     }
   }
 
-  for (unsigned long a = 0; a < normal.Size(); a++)
+  for ( unsigned long a = 0; a < normal.Size(); a++ )
   {
     normal[a].Normalize();
 
@@ -126,14 +126,14 @@ void ObjLoader::CalculateTangentArray(const Dali::Vector<Vector3>& vertex,
     // Gram-Schmidt orthogonalize
     Vector3 calc = t - n * n.Dot(t);
     calc.Normalize();
-    tangent[a] = Vector3(calc.x,calc.y,calc.z);
+    tangent[a] = Vector3( calc.x,calc.y,calc.z );
   }
 
   delete[] tan1;
 }
 
 
-void ObjLoader::CenterAndScale(bool center, Dali::Vector<Vector3>& points)
+void ObjLoader::CenterAndScale( bool center, Dali::Vector<Vector3>& points )
 {
   BoundingVolume newAABB;
 
@@ -151,7 +151,7 @@ void ObjLoader::CenterAndScale(bool center, Dali::Vector<Vector3>& points)
 
 
   newAABB.Init();
-  for( unsigned int ui = 0; ui < points.Size(); ++ui)
+  for( unsigned int ui = 0; ui < points.Size(); ++ui )
   {
     points[ui] = points[ui] - GetCenter();
     points[ui] = points[ui] / biggestDimension;
@@ -164,76 +164,122 @@ void ObjLoader::CenterAndScale(bool center, Dali::Vector<Vector3>& points)
 void ObjLoader::CreateGeometryArray(Dali::Vector<Vertex> & vertices,
                                     Dali::Vector<Vector2> & textures,
                                     Dali::Vector<VertexExt> & verticesExt,
-                                    Dali::Vector<int> & indices)
+                                    Dali::Vector<unsigned short> & indices)
 {
   //If we don't have tangents, calculate them
   //we need to recalculate the normals too, because we need just one normal,tangent, bitangent per vertex
+  //In the case of a textureless object, we don't need tangents and so we skip this step
   //TODO: Use a better function to calculate tangents
-  if( mTangents.Size() == 0 )
+  if( mTangents.Size() == 0 && mHasTexture && mHasNormalMap )
   {
-    mTangents.Resize(mNormals.Size());
-    mBiTangents.Resize(mNormals.Size());
-    CalculateTangentArray(mPoints, mTextures, mTriangles, mNormals, mTangents);
-    for (unsigned int ui = 0 ; ui < mNormals.Size() ; ++ui )
+    mTangents.Resize( mNormals.Size() );
+    mBiTangents.Resize( mNormals.Size() );
+    CalculateTangentArray( mPoints, mTextures, mTriangles, mNormals, mTangents );
+    for ( unsigned int ui = 0 ; ui < mNormals.Size() ; ++ui )
     {
       mBiTangents[ui] = mNormals[ui].Cross(mTangents[ui]);
     }
   }
 
+  bool mapsCorrespond; //True if the sizes of the arrays necessary for the object agree.
+
+  if ( mHasTexture )
+  {
+    mapsCorrespond = ( mPoints.Size() == mTextures.Size() ) && ( mTextures.Size() == mNormals.Size() );
+  }
+  else
+  {
+    mapsCorrespond = ( mPoints.Size() == mNormals.Size() );
+  }
+
   //Check the number of points textures and normals
-  if ((mPoints.Size() == mTextures.Size()) && (mTextures.Size() == mNormals.Size()))
+  if ( mapsCorrespond )
   {
+    int numPoints = mPoints.Size();
+    int numIndices = 3 * mTriangles.Size();
+    vertices.Resize( numPoints );
+    textures.Resize( numPoints );
+    verticesExt.Resize( numPoints );
+    indices.Resize( numIndices );
+
     //We create the vertices array. For now we just copy points info
     for (unsigned int ui = 0 ; ui < mPoints.Size() ; ++ui )
     {
       Vertex vertex;
       vertex.position = mPoints[ui];
-      vertices.PushBack(vertex);
+      vertices[ui] = vertex;
 
-      textures.PushBack(Vector2());
-      verticesExt.PushBack(VertexExt());
+      if ( mHasTexture )
+      {
+        textures[ui] = Vector2();
+        verticesExt[ui] = VertexExt();
+      }
     }
 
+    int indiceIndex = 0;
+
     //We copy the indices
-    for (unsigned int ui = 0 ; ui < mTriangles.Size() ; ++ui )
+    for ( unsigned int ui = 0 ; ui < mTriangles.Size() ; ++ui )
     {
-      for (int j = 0 ; j < 3 ; ++j)
+      for ( int j = 0 ; j < 3 ; ++j )
       {
-        indices.PushBack(mTriangles[ui].pntIndex[j]);
+        indices[indiceIndex] = mTriangles[ui].pntIndex[j];
+        indiceIndex++;
 
         vertices[mTriangles[ui].pntIndex[j]].normal = mNormals[mTriangles[ui].nrmIndex[j]];
 
-        textures[mTriangles[ui].pntIndex[j]] = mTextures[mTriangles[ui].texIndex[j]];
+        if ( mHasTexture )
+        {
+          textures[mTriangles[ui].pntIndex[j]] = mTextures[mTriangles[ui].texIndex[j]];
+        }
 
-        verticesExt[mTriangles[ui].pntIndex[j]].tangent = mTangents[mTriangles[ui].nrmIndex[j]];
-        verticesExt[mTriangles[ui].pntIndex[j]].bitangent = mBiTangents[mTriangles[ui].nrmIndex[j]];
+        if ( mHasNormalMap && mHasTexture )
+        {
+          verticesExt[mTriangles[ui].pntIndex[j]].tangent = mTangents[mTriangles[ui].nrmIndex[j]];
+          verticesExt[mTriangles[ui].pntIndex[j]].bitangent = mBiTangents[mTriangles[ui].nrmIndex[j]];
+        }
       }
     }
   }
   else
   {
+    int numVertices = 3 * mTriangles.Size();
+    vertices.Resize( numVertices );
+    textures.Resize( numVertices );
+    verticesExt.Resize( numVertices );
+
+    int index = 0;
+
     //We have to normalize the arrays so we can draw we just one index array
-    for (unsigned int ui = 0 ; ui < mTriangles.Size() ; ++ui )
+    for ( unsigned int ui = 0 ; ui < mTriangles.Size() ; ++ui )
     {
-      for (int j = 0 ; j < 3 ; ++j)
+      for ( int j = 0 ; j < 3 ; ++j )
       {
         Vertex vertex;
         vertex.position = mPoints[mTriangles[ui].pntIndex[j]];
         vertex.normal = mNormals[mTriangles[ui].nrmIndex[j]];
-        vertices.PushBack(vertex);
+        vertices[index] = vertex;
 
-        textures.PushBack(mTextures[mTriangles[ui].texIndex[j]]);
+        if ( mHasTexture )
+        {
+          textures[index] = mTextures[mTriangles[ui].texIndex[j]];
+        }
+
+        if ( mHasNormalMap && mHasTexture )
+        {
+          VertexExt vertexExt;
+          vertexExt.tangent = mTangents[mTriangles[ui].nrmIndex[j]];
+          vertexExt.bitangent = mBiTangents[mTriangles[ui].nrmIndex[j]];
+          verticesExt[index] = vertexExt;
+        }
 
-        VertexExt vertexExt;
-        vertexExt.tangent = mTangents[mTriangles[ui].nrmIndex[j]];
-        vertexExt.bitangent = mBiTangents[mTriangles[ui].nrmIndex[j]];
-        verticesExt.PushBack(vertexExt);
+        index++;
       }
     }
   }
 }
 
-bool ObjLoader::Load(char* objBuffer, std::streampos fileSize, std::string& materialFile)
+bool ObjLoader::Load( char* objBuffer, std::streampos fileSize, std::string& materialFile )
 {
   Vector3 point;
   Vector2 texture;
@@ -244,6 +290,8 @@ bool ObjLoader::Load(char* objBuffer, std::streampos fileSize, std::string& mate
   TriIndex triangle,triangle2;
   int pntAcum = 0, texAcum = 0, nrmAcum = 0;
   bool iniObj = false;
+  bool hasTexture = false;
+  bool hasNormalMap = false;
   int face = 0;
 
   //Init AABB for the file
@@ -253,75 +301,77 @@ bool ObjLoader::Load(char* objBuffer, std::streampos fileSize, std::string& mate
 
   std::string input = objBuffer;
   std::istringstream ss(input);
-  ss.imbue(std::locale("C"));
+  ss.imbue( std::locale( "C" ) );
 
 
   std::string line;
-  std::getline(ss, line);
+  std::getline( ss, line );
 
-  while (std::getline(ss, line))
+  while ( std::getline( ss, line ) )
   {
-    std::istringstream isline(line, std::istringstream::in);
+    std::istringstream isline( line, std::istringstream::in );
     std::string tag;
 
     isline >> tag;
 
-    if (tag == "v")
+    if ( tag == "v" )
     {
       //Two different objects in the same file
       isline >> point.x;
       isline >> point.y;
       isline >> point.z;
-      mPoints.PushBack(point);
+      mPoints.PushBack( point );
 
-      mSceneAABB.ConsiderNewPointInVolume(point);
+      mSceneAABB.ConsiderNewPointInVolume( point );
     }
-    else if (tag == "vn")
+    else if ( tag == "vn" )
     {
       isline >> point.x;
       isline >> point.y;
       isline >> point.z;
 
-      mNormals.PushBack(point);
+      mNormals.PushBack( point );
     }
-    else if (tag == "#_#tangent")
+    else if ( tag == "#_#tangent" )
     {
       isline >> point.x;
       isline >> point.y;
       isline >> point.z;
 
-      mTangents.PushBack(point);
+      mTangents.PushBack( point );
+      hasNormalMap = true;
     }
-    else if (tag == "#_#binormal")
+    else if ( tag == "#_#binormal" )
     {
       isline >> point.x;
       isline >> point.y;
       isline >> point.z;
 
-      mBiTangents.PushBack(point);
+      mBiTangents.PushBack( point );
+      hasNormalMap = true;
     }
-    else if (tag == "vt")
+    else if ( tag == "vt" )
     {
       isline >> texture.x;
       isline >> texture.y;
 
       texture.y = 1.0-texture.y;
-      mTextures.PushBack(texture);
+      mTextures.PushBack( texture );
     }
-    else if (tag == "#_#vt1")
+    else if ( tag == "#_#vt1" )
     {
       isline >> texture.x;
       isline >> texture.y;
 
       texture.y = 1.0-texture.y;
-      mTextures2.PushBack(texture);
+      mTextures2.PushBack( texture );
     }
-    else if (tag == "s")
+    else if ( tag == "s" )
     {
     }
-    else if (tag == "f")
+    else if ( tag == "f" )
     {
-      if (!iniObj)
+      if ( !iniObj )
       {
         //name assign
 
@@ -336,29 +386,30 @@ bool ObjLoader::Load(char* objBuffer, std::streampos fileSize, std::string& mate
 
       char separator;
       char separator2;
-      //File could not have texture Coordinates
-      if (strstr(vet[0].c_str(),"//"))
+
+      if ( strstr( vet[0].c_str(),"//" ) ) //No texture coordinates.
       {
         for( int i = 0 ; i < numIndices; i++)
         {
-          std::istringstream isindex(vet[i]);
-          isindex >> ptIdx[i] >> separator >> nrmIdx[i];
+          std::istringstream isindex( vet[i] );
+          isindex >> ptIdx[i] >> separator >> separator2 >> nrmIdx[i];
           texIdx[i] = 0;
         }
       }
-      else if (strstr(vet[0].c_str(),"/"))
+      else if ( strstr( vet[0].c_str(),"/" ) ) //Has texture coordinates, and possibly also normals.
       {
-        for( int i = 0 ; i < numIndices; i++)
+        for( int i = 0 ; i < numIndices; i++ )
         {
-          std::istringstream isindex(vet[i]);
+          std::istringstream isindex( vet[i] );
           isindex >> ptIdx[i] >> separator >> texIdx[i] >> separator2 >> nrmIdx[i];
+          hasTexture = true;
         }
       }
-      else
+      else //Has just points.
       {
-        for( int i = 0 ; i < numIndices; i++)
+        for( int i = 0 ; i < numIndices; i++ )
         {
-          std::istringstream isindex(vet[i]);
+          std::istringstream isindex( vet[i] );
           isindex >> ptIdx[i];
           texIdx[i] = 0;
           nrmIdx[i] = 0;
@@ -368,47 +419,47 @@ bool ObjLoader::Load(char* objBuffer, std::streampos fileSize, std::string& mate
       //If it is a triangle
       if( numIndices == 3 )
       {
-        for( int i = 0 ; i < 3; i++)
+        for( int i = 0 ; i < 3; i++ )
         {
           triangle.pntIndex[i] = ptIdx[i] - 1 - pntAcum;
           triangle.nrmIndex[i] = nrmIdx[i] - 1 - nrmAcum;
           triangle.texIndex[i] = texIdx[i] - 1 - texAcum;
         }
-        mTriangles.PushBack(triangle);
+        mTriangles.PushBack( triangle );
         face++;
       }
       //If on the other hand it is a quad, we will create two triangles
       else if( numIndices == 4 )
       {
-        for( int i = 0 ; i < 3; i++)
+        for( int i = 0 ; i < 3; i++ )
         {
           triangle.pntIndex[i] = ptIdx[i] - 1 - pntAcum;
           triangle.nrmIndex[i] = nrmIdx[i] - 1 - nrmAcum;
           triangle.texIndex[i] = texIdx[i] - 1 - texAcum;
         }
-        mTriangles.PushBack(triangle);
+        mTriangles.PushBack( triangle );
         face++;
 
-        for( int i = 0 ; i < 3; i++)
+        for( int i = 0 ; i < 3; i++ )
         {
-          int idx = (i+2) % numIndices;
+          int idx = ( i + 2 ) % numIndices;
           triangle2.pntIndex[i] = ptIdx[idx] - 1 - pntAcum;
           triangle2.nrmIndex[i] = nrmIdx[idx] - 1 - nrmAcum;
           triangle2.texIndex[i] = texIdx[idx] - 1 - texAcum;
         }
-        mTriangles.PushBack(triangle2);
+        mTriangles.PushBack( triangle2 );
         face++;
       }
     }
-    else if (tag == "usemtl")
+    else if ( tag == "usemtl" )
     {
       isline >> strMatActual;
     }
-    else if (tag == "mtllib")
+    else if ( tag == "mtllib" )
     {
       isline >> strMatActual;
     }
-    else if (tag == "g")
+    else if ( tag == "g" )
     {
       isline >> name;
     }
@@ -417,10 +468,12 @@ bool ObjLoader::Load(char* objBuffer, std::streampos fileSize, std::string& mate
     }
   }
 
-  if (iniObj)
+  if ( iniObj )
   {
-    CenterAndScale(true, mPoints);
+    CenterAndScale( true, mPoints );
     mSceneLoaded = true;
+    mHasTexture = hasTexture;
+    mHasNormalMap = hasNormalMap;
     return true;
   }
 
@@ -428,7 +481,8 @@ bool ObjLoader::Load(char* objBuffer, std::streampos fileSize, std::string& mate
 
 }
 
-void ObjLoader::LoadMaterial(char* objBuffer, std::streampos fileSize, std::string& texture0Url, std::string& texture1Url, std::string& texture2Url)
+void ObjLoader::LoadMaterial( char* objBuffer, std::streampos fileSize, std::string& texture0Url,
+                              std::string& texture1Url, std::string& texture2Url )
 {
   float fR,fG,fB;
 
@@ -439,44 +493,45 @@ void ObjLoader::LoadMaterial(char* objBuffer, std::streampos fileSize, std::stri
   ss.imbue(std::locale("C"));
 
   std::string line;
-  std::getline(ss, line);
+  std::getline( ss, line );
 
-  while (std::getline(ss, line))
+  while ( std::getline( ss, line ) )
   {
-    std::istringstream isline(line, std::istringstream::in);
+    std::istringstream isline( line, std::istringstream::in );
     std::string tag;
 
     isline >> tag;
 
-    if (tag == "newmtl")  //name of the material
+    if ( tag == "newmtl" )  //name of the material
     {
       isline >> info;
     }
-    else if (tag == "Kd") //diffuse color
+    else if ( tag == "Kd" ) //diffuse color
     {
       isline >> fR >> fG >> fB;
     }
-    else if (tag == "Kd") //Ambient color
+    else if ( tag == "Kd" ) //Ambient color
     {
       isline >> fR >> fG >> fB;
     }
-    else if (tag == "Tf") //color
+    else if ( tag == "Tf" ) //color
     {
     }
-    else if (tag == "Ni")
+    else if ( tag == "Ni" )
     {
     }
-    else if (tag == "map_Kd")
+    else if ( tag == "map_Kd" )
     {
       isline >> info;
       texture0Url = info;
     }
-    else if (tag == "bump")
+    else if ( tag == "bump" )
     {
       isline >> info;
       texture1Url = info;
+      mHasNormalMap = true;
     }
-    else if (tag == "map_Ks")
+    else if ( tag == "map_Ks" )
     {
       isline >> info;
       texture2Url = info;
@@ -486,14 +541,14 @@ void ObjLoader::LoadMaterial(char* objBuffer, std::streampos fileSize, std::stri
   mMaterialLoaded = true;
 }
 
-Geometry ObjLoader::CreateGeometry(Toolkit::Model3dView::IlluminationType illuminationType)
+Geometry ObjLoader::CreateGeometry( Toolkit::Model3dView::IlluminationType illuminationType )
 {
   Dali::Vector<Vertex> vertices;
   Dali::Vector<Vector2> textures;
   Dali::Vector<VertexExt> verticesExt;
-  Dali::Vector<int> indices;
+  Dali::Vector<unsigned short> indices;
 
-  CreateGeometryArray(vertices, textures, verticesExt, indices);
+  CreateGeometryArray( vertices, textures, verticesExt, indices );
 
   //All vertices need at least Position and Normal
   Property::Map vertexFormat;
@@ -506,7 +561,8 @@ Geometry ObjLoader::CreateGeometry(Toolkit::Model3dView::IlluminationType illumi
   surface.AddVertexBuffer( surfaceVertices );
 
   //Some need texture coordinates
-  if( (illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP ) || (illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ) )
+  if( ( (illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP ) ||
+        (illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_TEXTURE ) ) && mHasTexture )
   {
     Property::Map textureFormat;
     textureFormat["aTexCoord"] = Property::VECTOR2;
@@ -517,7 +573,7 @@ Geometry ObjLoader::CreateGeometry(Toolkit::Model3dView::IlluminationType illumi
   }
 
   //Some need tangent and bitangent
-  if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP )
+  if( illuminationType == Toolkit::Model3dView::DIFFUSE_WITH_NORMAL_MAP && mHasNormalMap && mHasTexture )
   {
     Property::Map vertexExtFormat;
     vertexExtFormat["aTangent"] = Property::VECTOR3;
@@ -528,18 +584,12 @@ Geometry ObjLoader::CreateGeometry(Toolkit::Model3dView::IlluminationType illumi
     surface.AddVertexBuffer( extraVertices );
   }
 
-  if (indices.Size())
+  if ( indices.Size() )
   {
-    //Indices
-    Property::Map indicesVertexFormat;
-    indicesVertexFormat["aIndices"] = Property::INTEGER;
-    PropertyBuffer indicesToVertices = PropertyBuffer::New( indicesVertexFormat );
-    indicesToVertices.SetData( &indices[0], indices.Size() );
-
-    surface.SetIndexBuffer ( indicesToVertices );
+    surface.SetIndexBuffer ( &indices[0], indices.Size() );
   }
 
-  surface.SetRequiresDepthTesting(true);
+  surface.SetRequiresDepthTesting( true );
 
   vertices.Clear();
   verticesExt.Clear();
@@ -573,6 +623,16 @@ void ObjLoader::ClearArrays()
   mSceneLoaded = false;
 }
 
+bool ObjLoader::IsTexturePresent()
+{
+  return mHasTexture;
+}
+
+bool ObjLoader::IsNormalMapPresent()
+{
+  return mHasNormalMap;
+}
+
 } // namespace Internal
 } // namespace Toolkit
 } // namespace Dali
index eac63c3..72967a6 100644 (file)
@@ -112,12 +112,17 @@ public:
 
   void      ClearArrays();
 
+  bool      IsTexturePresent();
+  bool      IsNormalMapPresent();
+
 private:
 
   BoundingVolume mSceneAABB;
 
   bool mSceneLoaded;
   bool mMaterialLoaded;
+  bool mHasTexture;
+  bool mHasNormalMap;
 
   Dali::Vector<Vector3> mPoints;
   Dali::Vector<Vector2> mTextures;
@@ -139,7 +144,7 @@ private:
   void CreateGeometryArray(Dali::Vector<Vertex> & vertices,
                            Dali::Vector<Vector2> & textures,
                            Dali::Vector<VertexExt> & verticesExt,
-                           Dali::Vector<int> & indices);
+                           Dali::Vector<unsigned short> & indices);
 
 };
 
index f9e87fb..73e8537 100644 (file)
@@ -35,7 +35,7 @@ namespace Internal
  *
  * When the page is turned over in landscape, call
  * SetIsBackImageVisible(true), this effect can display the back image
- * correctly after the imageActor been rotated 180 degrees.  To
+ * correctly after the page been rotated 180 degrees.  To
  * display the pages visually consistent with its turning state,
  * please set the uniforms with the same values as the PageTurnEffect.
  *
index 9ae46a1..3594538 100644 (file)
@@ -24,6 +24,7 @@
 //INTERNAL INCLUDES
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-impl.h>
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
+#include <dali-toolkit/internal/controls/renderers/renderer-string-constants.h>
 #include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
 
 namespace Dali
@@ -37,9 +38,6 @@ namespace Internal
 
 namespace
 {
-const char * const RENDERER_TYPE("rendererType");
-const char * const RENDERER_TYPE_VALUE("border");
-
 const char * const COLOR_NAME("borderColor");
 const char * const SIZE_NAME("borderSize");
 const char * const ANTI_ALIASING("antiAliasing");
@@ -160,7 +158,7 @@ void BorderRenderer::DoSetOnStage( Actor& actor )
 void BorderRenderer::DoCreatePropertyMap( Property::Map& map ) const
 {
   map.Clear();
-  map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
+  map.Insert( RENDERER_TYPE, BORDER_RENDERER );
   map.Insert( COLOR_NAME, mBorderColor );
   map.Insert( SIZE_NAME, mBorderSize );
 }
@@ -297,16 +295,12 @@ Geometry BorderRenderer::CreateBorderGeometry()
   borderVertices.SetData( borderVertexData, 16 );
 
   // Create indices
-  unsigned int indexData[24] = { 1,5,2,6,3,7,7,6,11,10,15,14,14,10,13,9,12,8,8,9,4,5,0,1};
-  Property::Map indexFormat;
-  indexFormat[INDEX_NAME] = Property::INTEGER;
-  PropertyBuffer indices = PropertyBuffer::New( indexFormat );
-  indices.SetData( indexData, 24 );
+  unsigned short indexData[24] = { 1,5,2,6,3,7,7,6,11,10,15,14,14,10,13,9,12,8,8,9,4,5,0,1};
 
   // Create the geometry object
   Geometry geometry = Geometry::New();
   geometry.AddVertexBuffer( borderVertices );
-  geometry.SetIndexBuffer( indices );
+  geometry.SetIndexBuffer( indexData, sizeof(indexData)/sizeof(indexData[0]) );
   geometry.SetGeometryType( Geometry::TRIANGLE_STRIP );
 
   return geometry;
index abdee4e..c054a5e 100644 (file)
@@ -24,6 +24,7 @@
 //INTERNAL INCLUDES
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-impl.h>
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
+#include <dali-toolkit/internal/controls/renderers/renderer-string-constants.h>
 #include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
 
 namespace Dali
@@ -37,8 +38,6 @@ namespace Internal
 
 namespace
 {
-const char * const RENDERER_TYPE("rendererType");
-const char * const RENDERER_TYPE_VALUE("color");
 const char * const COLOR_NAME("blendColor");
 
 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
@@ -111,7 +110,7 @@ void ColorRenderer::DoSetOnStage( Actor& actor )
 void ColorRenderer::DoCreatePropertyMap( Property::Map& map ) const
 {
   map.Clear();
-  map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
+  map.Insert( RENDERER_TYPE, COLOR_RENDERER );
   map.Insert( COLOR_NAME, mBlendColor );
 }
 
index 6c3c58a..1fc45ca 100644 (file)
@@ -117,16 +117,12 @@ Geometry DebugRenderer::CreateQuadWireframeGeometry()
   quadVertices.SetData( quadVertexData, 4 );
 
   // Create indices
-  unsigned int indexData[10] = { 0, 1, 1, 2, 2, 3, 3, 0 };
-  Property::Map indexFormat;
-  indexFormat[INDEX_NAME] = Property::INTEGER;
-  PropertyBuffer indices = PropertyBuffer::New( indexFormat );
-  indices.SetData( indexData, sizeof(indexData)/sizeof(indexData[0]) );
+  unsigned short indexData[10] = { 0, 1, 1, 2, 2, 3, 3, 0 };
 
   // Create the geometry object
   Geometry geometry = Geometry::New();
   geometry.AddVertexBuffer( quadVertices );
-  geometry.SetIndexBuffer( indices );
+  geometry.SetIndexBuffer( indexData, sizeof(indexData)/sizeof(indexData[0]) );
   geometry.SetGeometryType( Geometry::LINES );
 
   return geometry;
index f1838ae..eec8029 100644 (file)
@@ -29,6 +29,7 @@
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-impl.h>
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
 #include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
+#include <dali-toolkit/internal/controls/renderers/renderer-string-constants.h>
 #include <dali-toolkit/internal/controls/renderers/gradient/linear-gradient.h>
 #include <dali-toolkit/internal/controls/renderers/gradient/radial-gradient.h>
 
@@ -43,9 +44,6 @@ namespace Internal
 
 namespace
 {
-const char * const RENDERER_TYPE("rendererType");
-const char * const RENDERER_TYPE_VALUE("gradient");
-
 // properties: linear gradient
 const char * const START_POSITION_NAME("startPosition"); // Property::VECTOR2
 const char * const END_POSITION_NAME("endPosition"); // Property::VECTOR2
@@ -245,7 +243,7 @@ void GradientRenderer::DoSetOnStage( Actor& actor )
 void GradientRenderer::DoCreatePropertyMap( Property::Map& map ) const
 {
   map.Clear();
-  map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
+  map.Insert( RENDERER_TYPE, GRADIENT_RENDERER );
 
   Gradient::GradientUnits units = mGradient->GetGradientUnits();
   if( units == Gradient::USER_SPACE_ON_USE )
index c2bec85..d0c6c91 100644 (file)
@@ -25,6 +25,7 @@
 #include <dali/integration-api/debug.h>
 
 // INTERNAL HEADER
+#include <dali-toolkit/internal/controls/renderers/renderer-string-constants.h>
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-impl.h>
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
 #include <dali-toolkit/internal/controls/renderers/control-renderer-impl.h>
@@ -45,33 +46,28 @@ namespace
 const char HTTP_URL[] = "http://";
 const char HTTPS_URL[] = "https://";
 
-const char * const RENDERER_TYPE("rendererType");
-const char * const RENDERER_TYPE_VALUE("image");
-
 // property names
-const char * const IMAGE_URL_NAME( "imageUrl" );
-const char * const IMAGE_FITTING_MODE( "imageFittingMode" );
-const char * const IMAGE_SAMPLING_MODE( "imageSamplingMode" );
-const char * const IMAGE_DESIRED_WIDTH( "imageDesiredWidth" );
-const char * const IMAGE_DESIRED_HEIGHT( "imageDesiredHeight" );
+const char * const IMAGE_FITTING_MODE( "fittingMode" );
+const char * const IMAGE_SAMPLING_MODE( "samplingMode" );
+const char * const IMAGE_DESIRED_WIDTH( "desiredWidth" );
+const char * const IMAGE_DESIRED_HEIGHT( "desiredHeight" );
 
 // fitting modes
-const char * const SHRINK_TO_FIT("shrinkToFit");
-const char * const SCALE_TO_FILL("scaleToFill");
-const char * const FIT_WIDTH("fitWidth");
-const char * const FIT_HEIGHT("fitHeight");
-const char * const DEFAULT("default");
+const char * const SHRINK_TO_FIT("SHRINK_TO_FIT");
+const char * const SCALE_TO_FILL("SCALE_TO_FILL");
+const char * const FIT_WIDTH("FIT_WIDTH");
+const char * const FIT_HEIGHT("FIT_HEIGHT");
+const char * const DEFAULT("DEFAULT");
 
 // sampling modes
-const char * const BOX("box");
-const char * const NEAREST("nearest");
-const char * const LINEAR("linear");
-const char * const BOX_THEN_NEAREST("boxThenNearest");
-const char * const BOX_THEN_LINEAR("boxThenLinear");
-const char * const NO_FILTER("noFilter");
-const char * const DONT_CARE("dontCare");
-
-const std::string ATLAS_RECT_UNIFORM_NAME = "uAtlasRect";
+const char * const BOX("BOX");
+const char * const NEAREST("NEAREST");
+const char * const LINEAR("LINEAR");
+const char * const BOX_THEN_NEAREST("BOX_THEN_NEAREST");
+const char * const BOX_THEN_LINEAR("BOX_THEN_LINEAR");
+const char * const NO_FILTER("NO_FILTER");
+const char * const DONT_CARE("DONT_CARE");
+
 const std::string PIXEL_AREA_UNIFORM_NAME = "pixelArea";
 
 const Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
@@ -505,7 +501,7 @@ void ImageRenderer::DoSetOffStage( Actor& actor )
 void ImageRenderer::DoCreatePropertyMap( Property::Map& map ) const
 {
   map.Clear();
-  map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
+  map.Insert( RENDERER_TYPE, IMAGE_RENDERER );
   if( !mImageUrl.empty() )
   {
     map.Insert( IMAGE_URL_NAME, mImageUrl );
index 1ae3e50..da7e100 100644 (file)
@@ -48,28 +48,28 @@ typedef IntrusivePtr< ImageRenderer > ImageRendererPtr;
  *
  * | %Property Name          | Type             |
  * |-------------------------|------------------|
- * | imageUrl                | STRING           |
- * | imageFittingMode        | STRING           |
- * | imageSamplingMode       | STRING           |
- * | imageDesiredWidth       | INT              |
- * | imageDesiredHeight      | INT              |
+ * | url                | STRING           |
+ * | fittingMode        | STRING           |
+ * | samplingMode       | STRING           |
+ * | desiredWidth       | INT              |
+ * | desiredHeight      | INT              |
  *
  * where imageFittingMode should be one of the following fitting modes:
- *   "shrinkToFit"
- *   "scaleToFill"
- *   "fitWidth"
- *   "fitHeight"
- *   "default"
+ *   "SHRINK_TO_FIT"
+ *   "SCALE_TO_FIT"
+ *   "FIT_WIDTH"
+ *   "FIT_HEIGHT"
+ *   "DEFAULT"
  *
  * where imageSamplingMode should be one of the following sampling modes:
- *   "box"
- *   "nearest"
- *   "linear"
- *   "boxThenNearest"
- *   "boxThenLinear"
- *   "noFilter"
- *   "dontCare"
- *   "default"
+ *   "BOX"
+ *   "NEAREST"
+ *   "LINEAR"
+ *   "BOX_THEN_NEAREST"
+ *   "BOX_THEN_LINEAR"
+ *   "NO_FILTER"
+ *   "DONT_CARE"
+ *   "DEFAULT"
  *
  */
 class ImageRenderer: public ControlRenderer, public ConnectionTracker
index df0e8f5..3f91eeb 100644 (file)
@@ -26,6 +26,7 @@
 // INTERNAL IINCLUDES
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-impl.h>
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
+#include <dali-toolkit/internal/controls/renderers/renderer-string-constants.h>
 #include <dali-toolkit/internal/controls/renderers/control-renderer-impl.h>
 #include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
 
@@ -41,10 +42,6 @@ namespace Internal
 
 namespace
 {
-const char * const RENDERER_TYPE("rendererType");
-const char * const RENDERER_TYPE_VALUE("nPatch");
-
-const char * const IMAGE_URL_NAME("imageUrl");
 const char * const BORDER_ONLY("borderOnly");
 
 const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
@@ -121,7 +118,7 @@ const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
  * @param[in]  indices              The indices to generate the geometry from
  * @return The geometry formed from the vertices and indices
  */
-Geometry GenerateGeometry( const Vector< Vector2 >& vertices, const Vector< unsigned int >& indices )
+Geometry GenerateGeometry( const Vector< Vector2 >& vertices, const Vector< unsigned short >& indices )
 {
   Property::Map vertexFormat;
   vertexFormat[ "aPosition" ] = Property::VECTOR2;
@@ -131,18 +128,14 @@ Geometry GenerateGeometry( const Vector< Vector2 >& vertices, const Vector< unsi
     vertexPropertyBuffer.SetData( &vertices[ 0 ], vertices.Size() );
   }
 
-  Property::Map indexFormat;
-  indexFormat[ "indices" ] = Property::INTEGER;
-  PropertyBuffer indexPropertyBuffer = PropertyBuffer::New( indexFormat );
+  // Create the geometry object
+  Geometry geometry = Geometry::New();
+  geometry.AddVertexBuffer( vertexPropertyBuffer );
   if( indices.Size() > 0 )
   {
-    indexPropertyBuffer.SetData( &indices[ 0 ], indices.Size() );
+    geometry.SetIndexBuffer( &indices[ 0 ], indices.Size() );
   }
 
-  // Create the geometry object
-  Geometry geometry = Geometry::New();
-  geometry.AddVertexBuffer( vertexPropertyBuffer );
-  geometry.SetIndexBuffer( indexPropertyBuffer );
 
   return geometry;
 }
@@ -154,7 +147,7 @@ Geometry GenerateGeometry( const Vector< Vector2 >& vertices, const Vector< unsi
  * @param[in]  rowIdx      The row index to start the quad
  * @param[in]  nextRowIdx  The index to the next row
  */
-void AddQuadIndices( Vector< unsigned int >& indices, unsigned int rowIdx, unsigned int nextRowIdx )
+void AddQuadIndices( Vector< unsigned short >& indices, unsigned int rowIdx, unsigned int nextRowIdx )
 {
   indices.PushBack( rowIdx );
   indices.PushBack( nextRowIdx + 1 );
@@ -170,7 +163,7 @@ void AddVertex( Vector< Vector2 >& vertices, unsigned int x, unsigned int y )
   vertices.PushBack( Vector2( x, y ) );
 }
 
-void RegisterStretchProperties( TextureSet& textureSet, const char * uniformName, const NinePatchImage::StretchRanges& stretchPixels, uint16_t imageExtent)
+void RegisterStretchProperties( Renderer& renderer, const char * uniformName, const NinePatchImage::StretchRanges& stretchPixels, uint16_t imageExtent)
 {
   uint16_t prevEnd = 0;
   uint16_t prevFix = 0;
@@ -186,7 +179,7 @@ void RegisterStretchProperties( TextureSet& textureSet, const char * uniformName
 
     std::stringstream uniform;
     uniform << uniformName << "[" << i << "]";
-    textureSet.RegisterProperty( uniform.str(), Vector2( fix, stretch ) );
+    renderer.RegisterProperty( uniform.str(), Vector2( fix, stretch ) );
 
     prevEnd = end;
     prevFix = fix;
@@ -197,7 +190,7 @@ void RegisterStretchProperties( TextureSet& textureSet, const char * uniformName
     prevFix += imageExtent - prevEnd;
     std::stringstream uniform;
     uniform << uniformName << "[" << i << "]";
-    textureSet.RegisterProperty( uniform.str(), Vector2( prevFix, prevStretch ) );
+    renderer.RegisterProperty( uniform.str(), Vector2( prevFix, prevStretch ) );
   }
 }
 
@@ -407,7 +400,7 @@ void NPatchRenderer::DoSetOffStage( Actor& actor )
 void NPatchRenderer::DoCreatePropertyMap( Property::Map& map ) const
 {
   map.Clear();
-  map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
+  map.Insert( RENDERER_TYPE, IMAGE_RENDERER );
   if( !mImageUrl.empty() )
   {
     map.Insert( IMAGE_URL_NAME, mImageUrl );
@@ -552,18 +545,18 @@ void NPatchRenderer::ApplyImageToSampler()
       uint16_t stretchWidth = stretchX.GetY() - stretchX.GetX();
       uint16_t stretchHeight = stretchY.GetY() - stretchY.GetX();
 
-      textureSet.RegisterProperty( "uFixed[0]", Vector2::ZERO );
-      textureSet.RegisterProperty( "uFixed[1]", Vector2( stretchX.GetX(), stretchY.GetX()) );
-      textureSet.RegisterProperty( "uFixed[2]", Vector2( mImageSize.GetWidth() - stretchWidth, mImageSize.GetHeight() - stretchHeight ) );
-      textureSet.RegisterProperty( "uStretchTotal", Vector2( stretchWidth, stretchHeight ) );
+      mImpl->mRenderer.RegisterProperty( "uFixed[0]", Vector2::ZERO );
+      mImpl->mRenderer.RegisterProperty( "uFixed[1]", Vector2( stretchX.GetX(), stretchY.GetX()) );
+      mImpl->mRenderer.RegisterProperty( "uFixed[2]", Vector2( mImageSize.GetWidth() - stretchWidth, mImageSize.GetHeight() - stretchHeight ) );
+      mImpl->mRenderer.RegisterProperty( "uStretchTotal", Vector2( stretchWidth, stretchHeight ) );
     }
     else
     {
-      textureSet.RegisterProperty( "uNinePatchFactorsX[0]", Vector2::ZERO );
-      textureSet.RegisterProperty( "uNinePatchFactorsY[0]", Vector2::ZERO );
+      mImpl->mRenderer.RegisterProperty( "uNinePatchFactorsX[0]", Vector2::ZERO );
+      mImpl->mRenderer.RegisterProperty( "uNinePatchFactorsY[0]", Vector2::ZERO );
 
-      RegisterStretchProperties( textureSet, "uNinePatchFactorsX", mStretchPixelsX, mImageSize.GetWidth() );
-      RegisterStretchProperties( textureSet, "uNinePatchFactorsY", mStretchPixelsY, mImageSize.GetHeight() );
+      RegisterStretchProperties( mImpl->mRenderer, "uNinePatchFactorsX", mStretchPixelsX, mImageSize.GetWidth() );
+      RegisterStretchProperties( mImpl->mRenderer, "uNinePatchFactorsY", mStretchPixelsY, mImageSize.GetHeight() );
     }
   }
 }
@@ -587,7 +580,7 @@ Geometry NPatchRenderer::CreateGeometry( Uint16Pair gridSize )
 
   // Create indices
   //TODO: compare performance with triangle strip when Geometry supports it
-  Vector< unsigned int > indices;
+  Vector< unsigned short > indices;
   indices.Reserve( gridWidth * gridHeight * 6 );
 
   unsigned int rowIdx     = 0;
@@ -644,7 +637,7 @@ Geometry NPatchRenderer::CreateGeometryBorder( Uint16Pair gridSize )
 
   // Create indices
   //TODO: compare performance with triangle strip when Geometry supports it
-  Vector< unsigned int > indices;
+  Vector< unsigned short > indices;
   indices.Reserve( gridWidth * gridHeight * 6 );
 
   //top
index 3a6b79f..4fd7424 100644 (file)
@@ -215,7 +215,7 @@ Geometry RendererFactoryCache::CreateGridGeometry( Uint16Pair gridSize )
   }
 
   // Create indices
-  Vector< unsigned int > indices;
+  Vector< unsigned short > indices;
   indices.Reserve( (gridWidth+2)*gridHeight*2 - 2);
 
   for( unsigned int row = 0u; row < gridHeight; ++row )
@@ -251,15 +251,16 @@ Geometry RendererFactoryCache::CreateGridGeometry( Uint16Pair gridSize )
   Property::Map indexFormat;
   indexFormat[ "indices" ] = Property::INTEGER;
   PropertyBuffer indexPropertyBuffer = PropertyBuffer::New( indexFormat );
-  if( indices.Size() > 0 )
-  {
-    indexPropertyBuffer.SetData( &indices[ 0 ], indices.Size() );
-  }
+
 
   // Create the geometry object
   Geometry geometry = Geometry::New();
   geometry.AddVertexBuffer( vertexPropertyBuffer );
-  geometry.SetIndexBuffer( indexPropertyBuffer );
+  if( indices.Size() > 0 )
+  {
+    geometry.SetIndexBuffer( &indices[ 0 ], indices.Size() );
+  }
+
   geometry.SetGeometryType( Geometry::TRIANGLE_STRIP );
 
   return geometry;
index 2c88562..8ac1b74 100644 (file)
 #include <dali-toolkit/internal/controls/renderers/image/image-renderer.h>
 #include <dali-toolkit/internal/controls/renderers/svg/svg-renderer.h>
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
+#include <dali-toolkit/internal/controls/renderers/renderer-string-constants.h>
 #include <dali-toolkit/internal/controls/renderers/image-atlas-manager.h>
 
 namespace
 {
-const char * const RENDERER_TYPE_NAME( "rendererType" );
-
-const char * const COLOR_RENDERER("color");
-const char * const BORDER_RENDERER("border");
-const char * const GRADIENT_RENDERER("gradient");
-const char * const IMAGE_RENDERER("image");
-const char * const N_PATCH_RENDERER("nPatch");
-const char * const SVG_RENDERER("svg");
-
 const char * const BROKEN_RENDERER_IMAGE_URL( DALI_IMAGE_DIR "broken.png");
-
 }
 
 namespace Dali
@@ -83,14 +74,64 @@ RendererFactory::~RendererFactory()
 {
 }
 
-Toolkit::ControlRenderer RendererFactory::GetControlRenderer( const Property::Map& propertyMap )
+RendererFactory::RendererType RendererFactory::GetRendererType( const Property::Map& propertyMap )
 {
-  ControlRenderer* rendererPtr = NULL;
+  RendererType rendererType = UNDEFINED;
 
-  Property::Value* type = propertyMap.Find( RENDERER_TYPE_NAME );
+  Property::Value* type = propertyMap.Find( RENDERER_TYPE );
   std::string typeValue ;
   if( type && type->Get( typeValue ))
   {
+    if( typeValue ==  COLOR_RENDERER )
+    {
+      rendererType = COLOR;
+    }
+    else if( typeValue == BORDER_RENDERER )
+    {
+      rendererType = BORDER;
+    }
+    else if( typeValue ==  GRADIENT_RENDERER )
+    {
+      rendererType = GRADIENT;
+    }
+    else if( typeValue ==  IMAGE_RENDERER )
+    {
+      rendererType = IMAGE;
+    }
+  }
+
+  // check the url if exist, to decide the renderer type
+  if( rendererType == IMAGE || rendererType == UNDEFINED )
+  {
+    Property::Value* imageURLValue = propertyMap.Find( IMAGE_URL_NAME );
+    std::string imageUrl;
+    if( imageURLValue && imageURLValue->Get( imageUrl ))
+    {
+      if( NinePatchImage::IsNinePatchUrl( imageUrl ) )
+      {
+        rendererType = N_PATCH;
+      }
+      else if( SvgRenderer::IsSvgUrl( imageUrl ) )
+      {
+        rendererType = SVG;
+      }
+      else
+      {
+        rendererType = IMAGE;
+      }
+    }
+  }
+
+  return rendererType;
+}
+
+Toolkit::ControlRenderer RendererFactory::GetControlRenderer( const Property::Map& propertyMap )
+{
+  ControlRenderer* rendererPtr = NULL;
+
+  RendererType type = GetRendererType( propertyMap );
+  if( type != UNDEFINED)
+  {
     if( !mFactoryCache )
     {
       mFactoryCache = new RendererFactoryCache();
@@ -100,32 +141,46 @@ Toolkit::ControlRenderer RendererFactory::GetControlRenderer( const Property::Ma
     {
       return Toolkit::ControlRenderer( new DebugRenderer( *( mFactoryCache.Get() ) ) );
     }
+  }
 
-    if( typeValue ==  COLOR_RENDERER )
+  switch( type )
+  {
+    case COLOR:
     {
       rendererPtr = new ColorRenderer( *( mFactoryCache.Get() ) );
+      break;
     }
-    else if( typeValue ==  GRADIENT_RENDERER )
+     case GRADIENT:
+     {
+       rendererPtr = new GradientRenderer( *( mFactoryCache.Get() ) );
+       break;
+     }
+    case BORDER:
     {
-      rendererPtr = new GradientRenderer( *( mFactoryCache.Get() ) );
+      rendererPtr = new BorderRenderer( *( mFactoryCache.Get() ) );
+      break;
     }
-    else if( typeValue ==  IMAGE_RENDERER )
+    case IMAGE:
     {
       CreateAtlasManager();
       rendererPtr = new ImageRenderer( *( mFactoryCache.Get() ), *( mAtlasManager.Get() ) );
+      break;
     }
-    else if( typeValue ==  N_PATCH_RENDERER )
+    case N_PATCH:
     {
       rendererPtr = new NPatchRenderer( *( mFactoryCache.Get() ) );
+      break;
     }
-    else if( typeValue == BORDER_RENDERER )
-    {
-      rendererPtr = new BorderRenderer( *( mFactoryCache.Get() ) );
-    }
-    else if( typeValue == SVG_RENDERER )
+    case SVG:
     {
       CreateAtlasManager();
       rendererPtr = new SvgRenderer( *( mFactoryCache.Get() ), *( mAtlasManager.Get() ) );
+      break;
+    }
+    case UNDEFINED:
+    default:
+    {
+      break;
     }
   }
 
@@ -385,17 +440,16 @@ void RendererFactory::ResetRenderer( Toolkit::ControlRenderer& renderer, Actor&
   {
     ControlRenderer& controlRenderer = GetImplementation( renderer );
 
-    Property::Value* type = propertyMap.Find( RENDERER_TYPE_NAME );
-    std::string typeValue ;
+    RendererType type = GetRendererType( propertyMap );
 
     //If there's no renderer type specified or if there hasn't been a renderer type change then we can reuse the renderer
-    if( !type || !type->Get( typeValue ) ||
-        ( typeValue == IMAGE_RENDERER    && typeid( controlRenderer ) == typeid( ImageRenderer ) ) ||
-        ( typeValue == N_PATCH_RENDERER  && typeid( controlRenderer ) == typeid( NPatchRenderer ) ) ||
-        ( typeValue == COLOR_RENDERER    && typeid( controlRenderer ) == typeid( ColorRenderer ) )||
-        ( typeValue == GRADIENT_RENDERER && typeid( controlRenderer ) == typeid( GradientRenderer ) ) ||
-        ( typeValue == BORDER_RENDERER   && typeid( controlRenderer ) == typeid( BorderRenderer ) ) ||
-        ( typeValue == SVG_RENDERER      && typeid( controlRenderer ) == typeid( SvgRenderer ) ) )
+    if( type == UNDEFINED ||
+        ( type == IMAGE    && typeid( controlRenderer ) == typeid( ImageRenderer ) ) ||
+        ( type == N_PATCH  && typeid( controlRenderer ) == typeid( NPatchRenderer ) ) ||
+        ( type == COLOR    && typeid( controlRenderer ) == typeid( ColorRenderer ) )||
+        ( type == GRADIENT && typeid( controlRenderer ) == typeid( GradientRenderer ) ) ||
+        ( type == BORDER   && typeid( controlRenderer ) == typeid( BorderRenderer ) ) ||
+        ( type == SVG      && typeid( controlRenderer ) == typeid( SvgRenderer ) ) )
     {
       controlRenderer.Initialize( actor, propertyMap );
       return;
index e129aef..b9d5cf1 100644 (file)
@@ -44,9 +44,19 @@ typedef IntrusivePtr<ImageAtlasManager> ImageAtlasManagerPtr;
  */
 class RendererFactory : public BaseObject
 {
-
 public:
 
+  enum RendererType
+  {
+    COLOR,
+    BORDER,
+    GRADIENT,
+    IMAGE,
+    N_PATCH,
+    SVG,
+    UNDEFINED
+  };
+
   /**
    * @brief Constructor
    *
@@ -115,6 +125,14 @@ protected:
 private:
 
   /**
+   * Get the renderer type from the property map.
+   *
+   * @param[in] propertyMap The map contains the properties of the control renderer
+   * @return The rendererType
+   */
+  RendererType GetRendererType( const Property::Map& propertyMap );
+
+  /**
    * Prepare the atlas manager
    */
   void CreateAtlasManager();
diff --git a/dali-toolkit/internal/controls/renderers/renderer-string-constants.cpp b/dali-toolkit/internal/controls/renderers/renderer-string-constants.cpp
new file mode 100644 (file)
index 0000000..ef01bd1
--- /dev/null
@@ -0,0 +1,43 @@
+ /*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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.
+ *
+ */
+
+// CLASS HEADER
+#include "renderer-string-constants.h"
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+const char * const RENDERER_TYPE("rendererType");
+const char * const COLOR_RENDERER("color");
+const char * const BORDER_RENDERER("border");
+const char * const GRADIENT_RENDERER("gradient");
+const char * const IMAGE_RENDERER("image");
+
+const char * const IMAGE_URL_NAME("url");
+const char * const ATLAS_RECT_UNIFORM_NAME ( "uAtlasRect" );
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
diff --git a/dali-toolkit/internal/controls/renderers/renderer-string-constants.h b/dali-toolkit/internal/controls/renderers/renderer-string-constants.h
new file mode 100644 (file)
index 0000000..ebaf29f
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __DALI_TOOLKIT_INTERNAL_RENDERER_STRING_CONSTANTS_H__
+#define __DALI_TOOLKIT_INTERNAL_RENDERER_STRING_CONSTANTS_H__
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed 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.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Toolkit
+{
+
+namespace Internal
+{
+
+extern const char * const RENDERER_TYPE;
+extern const char * const COLOR_RENDERER;
+extern const char * const BORDER_RENDERER;
+extern const char * const GRADIENT_RENDERER;
+extern const char * const IMAGE_RENDERER;
+
+extern const char * const IMAGE_URL_NAME;
+extern const char * const ATLAS_RECT_UNIFORM_NAME;
+
+} // namespace Internal
+
+} // namespace Toolkit
+
+} // namespace Dali
+
+#endif /* __DALI_TOOLKIT_INTERNAL_RENDERER_STRING_CONSTANTS_H__ */
index 820e619..e52cb15 100644 (file)
@@ -1244,7 +1244,12 @@ static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str)
 {
     NSVGcoordinate coord = {0, NSVG_UNITS_USER};
     char units[32]="";
-    sscanf(str, "%f%s", &coord.value, units);
+
+    /**
+     * In the original file, the formatted data reading did not specify the string with width limitation.
+     * To prevent the possible overflow, we replace '%s' with '%32s' here.
+     */
+    sscanf(str, "%f%32s", &coord.value, units);
     coord.units = nsvg__parseUnits(units);
     return coord;
 }
index 2642c74..d6619d3 100644 (file)
 #include "svg-rasterize-thread.h"
 #include <dali-toolkit/internal/controls/renderers/image/image-renderer.h>
 #include <dali-toolkit/internal/controls/renderers/renderer-factory-cache.h>
+#include <dali-toolkit/internal/controls/renderers/renderer-string-constants.h>
 #include <dali-toolkit/internal/controls/renderers/control-renderer-data-impl.h>
 
 
 namespace
 {
-const char * const RENDERER_TYPE("rendererType");
-const char * const RENDERER_TYPE_VALUE("svg");
-const char * const IMAGE_URL_NAME("imageUrl");
 const char * const UNITS("px");
 
-const std::string TEXTURE_UNIFORM_NAME = "sTexture";
-const std::string ATLAS_RECT_UNIFORM_NAME = "uAtlasRect";
-
 const Dali::Vector4 FULL_TEXTURE_RECT(0.f, 0.f, 1.f, 1.f);
 }
 
@@ -147,7 +142,7 @@ void SvgRenderer::SetSize( const Vector2& size )
 void SvgRenderer::DoCreatePropertyMap( Property::Map& map ) const
 {
   map.Clear();
-  map.Insert( RENDERER_TYPE, RENDERER_TYPE_VALUE );
+  map.Insert( RENDERER_TYPE, IMAGE_RENDERER );
   if( !mImageUrl.empty() )
   {
     map.Insert( IMAGE_URL_NAME, mImageUrl );
index 91e556f..c06e400 100644 (file)
@@ -117,15 +117,11 @@ Actor CreateBouncingEffectActor( Property::Index& bouncePropertyIndex )
   PropertyBuffer vertices = PropertyBuffer::New( vertexFormat );
   vertices.SetData( vertexData, 20u );
 
-  unsigned int indexData[30] = { 0,3,1,0,2,3,4,7,5,4,6,7,8,11,9,8,10,11,12,15,13,12,14,15,16,19,17,16,18,19};
-  Property::Map indexFormat;
-  indexFormat["indices"] = Property::INTEGER;
-  PropertyBuffer indices = PropertyBuffer::New( indexFormat );
-  indices.SetData( indexData, 30u );
+  unsigned short indexData[30] = { 0,3,1,0,2,3,4,7,5,4,6,7,8,11,9,8,10,11,12,15,13,12,14,15,16,19,17,16,18,19};
 
   Geometry meshGeometry = Geometry::New();
   meshGeometry.AddVertexBuffer( vertices );
-  meshGeometry.SetIndexBuffer( indices );
+  meshGeometry.SetIndexBuffer( indexData, sizeof(indexData)/sizeof(indexData[0]) );
 
   // Create the shader
   Shader shader = Shader::New( MESH_VERTEX_SHADER, MESH_FRAGMENT_SHADER );
index 7ae8fa4..28bae71 100644 (file)
@@ -275,6 +275,7 @@ void ShadowView::OnInitialize()
 
   // Turn off inheritance to ensure filter renders properly
   mBlurRootActor.SetParentOrigin( ParentOrigin::CENTER );
+  mBlurRootActor.SetInheritPosition(false);
   mBlurRootActor.SetInheritOrientation(false);
   mBlurRootActor.SetInheritScale(false);
   mBlurRootActor.SetColorMode(USE_OWN_COLOR);
index f0c3fc6..660e823 100644 (file)
@@ -802,34 +802,34 @@ void TextEditor::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange:
 {
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnStyleChange\n");
 
-   switch ( change )
-   {
-     case StyleChange::DEFAULT_FONT_CHANGE:
-     {
-       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnStyleChange DEFAULT_FONT_CHANGE\n");
-       std::string newFont = styleManager.GetDefaultFontFamily();
-       // Property system did not set the font so should update it.
-       mController->UpdateAfterFontChange( newFont );
-       break;
-     }
-
-     case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
-     {
-       DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor::OnStyleChange StyleChange::DEFAULT_FONT_SIZE_CHANGE (%f)\n", mController->GetDefaultPointSize() );
-
-       if ( (mController->GetDefaultPointSize() <= 0.0f) ) // If DefaultPointSize not set by Property system it will be 0.0f
-       {
-         // Property system did not set the PointSize so should update it.
-         // todo instruct text-controller to update model
-       }
-       break;
-     }
-     case StyleChange::THEME_CHANGE:
-     {
-       GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
-       break;
-     }
-   }
+  switch ( change )
+  {
+    case StyleChange::DEFAULT_FONT_CHANGE:
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextEditor::OnStyleChange DEFAULT_FONT_CHANGE\n");
+      const std::string& newFont = GetImpl( styleManager ).GetDefaultFontFamily();
+      // Property system did not set the font so should update it.
+      mController->UpdateAfterFontChange( newFont );
+      break;
+    }
+
+    case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "TextEditor::OnStyleChange StyleChange::DEFAULT_FONT_SIZE_CHANGE (%f)\n", mController->GetDefaultPointSize() );
+
+      if ( (mController->GetDefaultPointSize() <= 0.0f) ) // If DefaultPointSize not set by Property system it will be 0.0f
+      {
+        // Property system did not set the PointSize so should update it.
+        // todo instruct text-controller to update model
+      }
+      break;
+    }
+    case StyleChange::THEME_CHANGE:
+    {
+      GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
+      break;
+    }
+  }
 }
 
 Vector3 TextEditor::GetNaturalSize()
index 082e7e5..efec327 100644 (file)
@@ -1024,34 +1024,34 @@ void TextField::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::
 {
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnStyleChange\n");
 
-   switch ( change )
-   {
-     case StyleChange::DEFAULT_FONT_CHANGE:
-     {
-       DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnStyleChange DEFAULT_FONT_CHANGE\n");
-       std::string newFont = styleManager.GetDefaultFontFamily();
-       // Property system did not set the font so should update it.
-       mController->UpdateAfterFontChange( newFont );
-       break;
-     }
-
-     case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
-     {
-       DALI_LOG_INFO( gLogFilter, Debug::General, "TextField::OnStyleChange StyleChange::DEFAULT_FONT_SIZE_CHANGE (%f)\n", mController->GetDefaultPointSize() );
-
-       if ( (mController->GetDefaultPointSize() <= 0.0f) ) // If DefaultPointSize not set by Property system it will be 0.0f
-       {
-         // Property system did not set the PointSize so should update it.
-         // todo instruct text-controller to update model
-       }
-       break;
-     }
-     case StyleChange::THEME_CHANGE:
-     {
-       GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
-       break;
-     }
-   }
+  switch ( change )
+  {
+    case StyleChange::DEFAULT_FONT_CHANGE:
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextField::OnStyleChange DEFAULT_FONT_CHANGE\n");
+      const std::string& newFont = GetImpl( styleManager ).GetDefaultFontFamily();
+      // Property system did not set the font so should update it.
+      mController->UpdateAfterFontChange( newFont );
+      break;
+    }
+
+    case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "TextField::OnStyleChange StyleChange::DEFAULT_FONT_SIZE_CHANGE (%f)\n", mController->GetDefaultPointSize() );
+
+      if ( (mController->GetDefaultPointSize() <= 0.0f) ) // If DefaultPointSize not set by Property system it will be 0.0f
+      {
+        // Property system did not set the PointSize so should update it.
+        // todo instruct text-controller to update model
+      }
+      break;
+    }
+    case StyleChange::THEME_CHANGE:
+    {
+      GetImpl( styleManager ).ApplyThemeStyle( Toolkit::Control( GetOwner() ) );
+      break;
+    }
+  }
 }
 
 Vector3 TextField::GetNaturalSize()
index 9d3fd45..e7bac78 100644 (file)
@@ -486,7 +486,6 @@ void TextLabel::OnInitialize()
 
 void TextLabel::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::Type change )
 {
-
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "TextLabel::OnStyleChange\n");
 
   switch ( change )
@@ -494,7 +493,7 @@ void TextLabel::OnStyleChange( Toolkit::StyleManager styleManager, StyleChange::
     case StyleChange::DEFAULT_FONT_CHANGE:
     {
       // Property system did not set the font so should update it.
-      std::string newFont = styleManager.GetDefaultFontFamily();
+      const std::string& newFont = GetImpl( styleManager ).GetDefaultFontFamily();
       DALI_LOG_INFO( gLogFilter, Debug::General, "TextLabel::OnStyleChange StyleChange::DEFAULT_FONT_CHANGE newFont(%s)\n", newFont.c_str() );
       mController->UpdateAfterFontChange( newFont );
       break;
index 758160f..cd24d24 100644 (file)
@@ -16,6 +16,7 @@ toolkit_src_files = \
    $(toolkit_src_dir)/controls/renderers/image-atlas-manager.cpp \
    $(toolkit_src_dir)/controls/renderers/renderer-factory-cache.cpp \
    $(toolkit_src_dir)/controls/renderers/renderer-factory-impl.cpp \
+   $(toolkit_src_dir)/controls/renderers/renderer-string-constants.cpp \
    $(toolkit_src_dir)/controls/renderers/border/border-renderer.cpp \
    $(toolkit_src_dir)/controls/renderers/color/color-renderer.cpp \
    $(toolkit_src_dir)/controls/renderers/debug/debug-renderer.cpp \
index 85aa069..a550a11 100644 (file)
@@ -26,7 +26,7 @@
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/controls/control.h>
 #include <dali-toolkit/public-api/controls/control-impl.h>
-#include <dali-toolkit/devel-api/styling/style-manager.h>
+#include <dali-toolkit/public-api/styling/style-manager.h>
 #include <dali-toolkit/internal/feedback/feedback-style.h>
 
 namespace
@@ -98,8 +98,7 @@ Toolkit::StyleManager StyleManager::Get()
 }
 
 StyleManager::StyleManager()
-: mOrientationDegrees( 0 ),  // Portrait
-  mDefaultFontSize( -1 ),
+: mDefaultFontSize( -1 ),
   mDefaultFontFamily(""),
   mFeedbackStyle( NULL )
 {
@@ -123,43 +122,18 @@ StyleManager::~StyleManager()
   delete mFeedbackStyle;
 }
 
-void StyleManager::SetOrientationValue( int orientation )
+void StyleManager::ApplyTheme( const std::string& themeFile )
 {
-  if( orientation !=  mOrientationDegrees )
-  {
-    mOrientationDegrees = orientation;
-    // TODO: if orientation changed, apply the new style to all controls
-    // dont want to really do the whole load from file again if the bundle contains both portrait & landscape
-    SetTheme( mThemeFile );
-  }
-}
-
-int StyleManager::GetOrientationValue()
-{
-  return mOrientationDegrees;
-}
-
-void StyleManager::SetOrientation( Orientation orientation )
-{
-  if( mOrientation )
-  {
-    mOrientation.ChangedSignal().Disconnect( this, &StyleManager::OnOrientationChanged );
-  }
-
-  OnOrientationChanged( orientation );
-
-  if( mOrientation )
-  {
-    mOrientation.ChangedSignal().Connect( this, &StyleManager::OnOrientationChanged );
-  }
+  SetTheme( themeFile );
 }
 
-Orientation StyleManager::GetOrientation()
+void StyleManager::ApplyDefaultTheme()
 {
-  return mOrientation;
+  std::string empty;
+  SetTheme( empty );
 }
 
-std::string StyleManager::GetDefaultFontFamily() const
+const std::string& StyleManager::GetDefaultFontFamily() const
 {
   return mDefaultFontFamily;
 }
@@ -181,22 +155,11 @@ bool StyleManager::GetStyleConstant( const std::string& key, Property::Value& va
   return false;
 }
 
-void StyleManager::RequestThemeChange( const std::string& themeFile )
-{
-  SetTheme( themeFile );
-}
-
-void StyleManager::RequestDefaultTheme()
-{
-  std::string empty;
-  SetTheme( empty );
-}
-
 void StyleManager::ApplyThemeStyle( Toolkit::Control control )
 {
   if( !mThemeBuilder )
   {
-    RequestDefaultTheme();
+    ApplyDefaultTheme();
   }
 
   if( mThemeBuilder )
@@ -248,9 +211,14 @@ void StyleManager::ApplyStyle( Toolkit::Control control, const std::string& json
   }
 }
 
-Toolkit::StyleManager::StyleChangeSignalType& StyleManager::StyleChangeSignal()
+Toolkit::StyleManager::StyleChangedSignalType& StyleManager::StyleChangedSignal()
 {
-  return mStyleChangeSignal;
+  return mStyleChangedSignal;
+}
+
+Toolkit::StyleManager::StyleChangedSignalType& StyleManager::ControlStyleChangeSignal()
+{
+  return mControlStyleChangeSignal;
 }
 
 void StyleManager::SetTheme( const std::string& themeFile )
@@ -275,7 +243,7 @@ void StyleManager::SetTheme( const std::string& themeFile )
       mFeedbackStyle->StyleChanged( mThemeFile, StyleChange::THEME_CHANGE );
     }
 
-    mStyleChangeSignal.Emit( Toolkit::StyleManager::Get(), StyleChange::THEME_CHANGE );
+    EmitStyleChangeSignals(StyleChange::THEME_CHANGE);
   }
   else
   {
@@ -323,13 +291,7 @@ bool StyleManager::LoadJSON( Toolkit::Builder builder, const std::string& jsonFi
 void StyleManager::CollectQualifiers( StringList& qualifiersOut )
 {
   // Append the relevant qualifier for orientation
-  int orientation = mOrientationDegrees;
-
-  if( mOrientation )
-  {
-    orientation = mOrientation.GetDegrees();
-  }
-
+  int orientation = 0; // Get the orientation from the system
   switch( orientation )
   {
     case 90:
@@ -400,15 +362,6 @@ void StyleManager::ApplyStyle( Toolkit::Builder builder, Toolkit::Control contro
   }
 }
 
-void StyleManager::OnOrientationChanged( Orientation orientation )
-{
-  mOrientation = orientation;
-  // TODO: if orientation changed, apply the new style to all controls
-  // dont want to really do the whole load from file again if the bundle contains both portrait & landscape
-  SetTheme( mThemeFile );
-}
-
-
 Toolkit::Builder StyleManager::FindCachedBuilder( const std::string& key )
 {
   BuilderMap::iterator builderIt = mBuilderCache.find( key );
@@ -447,10 +400,21 @@ void StyleManager::StyleMonitorChange( StyleMonitor styleMonitor, StyleChange::T
       break;
     }
   }
+  EmitStyleChangeSignals( styleChange );
+}
+
+void StyleManager::EmitStyleChangeSignals( StyleChange::Type styleChange )
+{
+  Toolkit::StyleManager styleManager = StyleManager::Get();
 
-  mStyleChangeSignal.Emit( Toolkit::StyleManager::Get(), styleChange );
+  // Update Controls first
+  mControlStyleChangeSignal.Emit( styleManager, styleChange );
+
+  // Inform application last
+  mStyleChangedSignal.Emit( styleManager, styleChange );
 }
 
+
 } // namespace Internal
 
 } // namespace Toolkit
index 294e601..f0c217c 100644 (file)
@@ -27,7 +27,7 @@
 #include <dali/public-api/signals/connection-tracker.h>
 
 // INTERNAL INCLUDES
-#include <dali-toolkit/devel-api/styling/style-manager.h>
+#include <dali-toolkit/public-api/styling/style-manager.h>
 #include <dali-toolkit/devel-api/builder/builder.h>
 
 namespace Dali
@@ -67,30 +67,20 @@ protected:
 
 public: // Public API
 
-  /**
-   * @copydoc Toolkit::StyleManager::SetOrientationValue
-   */
-  void SetOrientationValue( int orientation );
-
-  /**
-   * @copydoc Toolkit::StyleManager::GetOrientationValue
-   */
-  int GetOrientationValue();
-
-  /**
-   * @copydoc Toolkit::StyleManager::SetOrientation( Orientation orientation )
+/**
+   * @copydoc Toolkit::StyleManager::ApplyTheme
    */
-  void SetOrientation( Orientation orientation );
+  void ApplyTheme( const std::string& themeFile );
 
   /**
-   * @copydoc Toolkit::StyleManager::GetOrientation
+   * @copydoc Toolkit::StyleManager::ApplyDefaultTheme
    */
-  Orientation GetOrientation();
+  void ApplyDefaultTheme();
 
   /**
    * @copydoc Toolkit::StyleManager::GetDefaultFontFamily
    */
-  std::string GetDefaultFontFamily() const;
+  const std::string& GetDefaultFontFamily() const;
 
   /**
    * @copydoc Toolkit::StyleManager::SetStyleConstant
@@ -103,16 +93,6 @@ public: // Public API
   bool GetStyleConstant( const std::string& key, Property::Value& valueOut );
 
   /**
-   * @copydoc Toolkit::StyleManager::RequestThemeChange
-   */
-  void RequestThemeChange( const std::string& themeFile );
-
-  /**
-   * @copydoc Toolkit::StyleManager::RequestDefaultTheme
-   */
-  void RequestDefaultTheme();
-
-  /**
    * @brief Apply the theme style to a control.
    *
    * @param[in] control The control to apply style.
@@ -136,8 +116,16 @@ public:
 
   /**
    * @copydoc Toolkit::StyleManager::StyleChangeSignal
+   * This signal is sent after all the controls have been updated
+   * due to style change
+   */
+  Toolkit::StyleManager::StyleChangedSignalType& StyleChangedSignal();
+
+  /**
+   * This signal is sent to the controls following a style change.
+   * It should not be exposed in the public API
    */
-  Toolkit::StyleManager::StyleChangeSignalType& StyleChangeSignal();
+  Toolkit::StyleManager::StyleChangedSignalType& ControlStyleChangeSignal();
 
 private:
   typedef std::vector<std::string> StringList;
@@ -202,13 +190,6 @@ private:
   void ApplyStyle( Toolkit::Builder builder, Toolkit::Control control );
 
   /**
-   * @brief Callback for orientation changes
-   *
-   * @param[in] orientation The orientation object
-   */
-  void OnOrientationChanged( Orientation orientation );
-
-  /**
    * Search for a builder in the cache
    *
    * @param[in] key The key the builder was cached under
@@ -232,6 +213,12 @@ private:
    */
   void StyleMonitorChange( StyleMonitor styleMonitor, StyleChange::Type styleChange );
 
+  /**
+   * Emit signals to controls first, app second
+   */
+  void EmitStyleChangeSignals( StyleChange::Type styleChange );
+
+
   // Undefined
   StyleManager(const StyleManager&);
 
@@ -245,9 +232,6 @@ private:
   Toolkit::Builder mThemeBuilder;     ///< Builder for all default theme properties
   StyleMonitor mStyleMonitor;         ///< Style monitor handle
 
-  Orientation mOrientation;           ///< Handle to application orientation object
-  int mOrientationDegrees;            ///< Directly set value of orientation
-
   int mDefaultFontSize;               ///< Logical size, not a point-size
   std::string mDefaultFontFamily;
   std::string mThemeFile;             ///< The full path of the current theme file
@@ -260,7 +244,8 @@ private:
   Toolkit::Internal::FeedbackStyle* mFeedbackStyle; ///< Feedback style
 
   // Signals
-  Toolkit::StyleManager::StyleChangeSignalType       mStyleChangeSignal;         ///< Emitted when the style( theme/font ) changes
+  Toolkit::StyleManager::StyleChangedSignalType mControlStyleChangeSignal; ///< Emitted when the style( theme/font ) changes for the controls to style themselves
+  Toolkit::StyleManager::StyleChangedSignalType mStyleChangedSignal; ///< Emitted after the controls have been styled
 };
 
 } // namespace Internal
index 860ec7b..73a9a1c 100644 (file)
@@ -43,12 +43,6 @@ struct ColorRun
   Vector4      color;        ///< The color of the characters.
 };
 
-struct ColorGlyphRun
-{
-  GlyphRun glyphRun; ///< The initial glyph index and the number of glyphs of the run.
-  Vector4  color;    ///< The color of the glyphs.
-};
-
 } // namespace Text
 
 } // namespace Toolkit
index 9169225..3c2f76a 100644 (file)
@@ -33,52 +33,103 @@ namespace Toolkit
 namespace Text
 {
 
-void SetColorSegmentationInfo( const Vector<ColorRun>& characterColorRuns,
+/**
+ * @brief Finds a color in the vector of colors.
+ *        It inserts the color in the vector if it's not in.
+ *
+ * @param[in,out] colors The vector of colors.
+ * @param[in] color The color to find.
+ *
+ * @return The index + 1 where the color is in the vector. The index zero is reserved for the default color.
+ */
+ColorIndex FindColor( Vector<Vector4>& colors,
+                      const Vector4& color )
+{
+  ColorIndex index = 1u; // The index zero is reserved for the default color.
+  for( Vector<Vector4>::Iterator it = colors.Begin(),
+         endIt = colors.End();
+       it != endIt;
+       ++it )
+  {
+    if( color == *it )
+    {
+      return index;
+    }
+
+    ++index;
+  }
+
+  colors.PushBack( color );
+
+  return index;
+}
+
+void SetColorSegmentationInfo( const Vector<ColorRun>& colorRuns,
                                const Vector<GlyphIndex>& charactersToGlyph,
                                const Vector<Length>& glyphsPerCharacter,
-                               Vector<ColorGlyphRun>& glyphColorRuns )
+                               CharacterIndex startCharacterIndex,
+                               GlyphIndex startGlyphIndex,
+                               Length numberOfCharacters,
+                               Vector<Vector4>& colors,
+                               Vector<ColorIndex>& colorIndices )
 {
-  const VectorBase::SizeType numberOfColorRuns = characterColorRuns.Count();
-
-  if( 0u == numberOfColorRuns )
+  if( 0u == charactersToGlyph.Count() )
   {
-    // Nothing to do.
+    // Nothing to do if there is no text.
     return;
   }
 
-  // Resize the color runs for the glyphs.
-  glyphColorRuns.Resize( numberOfColorRuns );
-
   // Get pointers to the buffers.
-  ColorGlyphRun* glyphColorRunsBuffer = glyphColorRuns.Begin();
   const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin();
   const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin();
 
+  // Calculate the number of glyphs to insert.
+  const CharacterIndex lastCharacterIndex = startCharacterIndex + numberOfCharacters - 1u;
+  const Length numberOfNewGlyphs = *( charactersToGlyphBuffer + lastCharacterIndex ) + *( glyphsPerCharacterBuffer + lastCharacterIndex ) - *( charactersToGlyphBuffer + startCharacterIndex );
+
+  // Reserve space for the new color indices.
+  Vector<ColorIndex> newColorIndices;
+  newColorIndices.Resize( numberOfNewGlyphs );
+
+  ColorIndex* newColorIndicesBuffer = newColorIndices.Begin();
+
   // Convert from characters to glyphs.
   Length index = 0u;
-  for( Vector<ColorRun>::ConstIterator it = characterColorRuns.Begin(),
-         endIt = characterColorRuns.End();
+  for( Vector<ColorRun>::ConstIterator it = colorRuns.Begin(),
+         endIt = colorRuns.End();
        it != endIt;
        ++it, ++index )
   {
     const ColorRun& colorRun = *it;
 
-    if( 0u < colorRun.characterRun.numberOfCharacters )
+    if( ( startCharacterIndex < colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters ) &&
+        ( colorRun.characterRun.characterIndex < startCharacterIndex + numberOfCharacters ) )
     {
-      // Get the next color glyph run.
-      ColorGlyphRun& colorGlyphRun = *( glyphColorRunsBuffer + index );
-      colorGlyphRun.color = colorRun.color;
-
-      // Convert the color run index from character to glyph.
-      colorGlyphRun.glyphRun.glyphIndex = *( charactersToGlyphBuffer + colorRun.characterRun.characterIndex );
-
-      // Get the index to the last character of the run.
-      const CharacterIndex lastIndex = colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters - 1u;
-
-      // Calculate the number of glyphs.
-      colorGlyphRun.glyphRun.numberOfGlyphs = *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - colorGlyphRun.glyphRun.glyphIndex;
+      if( 0u < colorRun.characterRun.numberOfCharacters )
+      {
+        // Find the color index.
+        const ColorIndex colorIndex = FindColor( colors, colorRun.color );
+
+        // Get the index to the last character of the run.
+        const CharacterIndex lastIndex = colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters - 1u;
+
+        const GlyphIndex glyphIndex = std::max( startGlyphIndex, *( charactersToGlyphBuffer + colorRun.characterRun.characterIndex ) ) - startGlyphIndex;
+        // Get the number of glyphs of the run.
+        const Length lastGlyphIndexPlusOne = std::min( numberOfNewGlyphs, *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - startGlyphIndex );
+
+        // Set the indices.
+        for( GlyphIndex i = glyphIndex; i < lastGlyphIndexPlusOne; ++i )
+        {
+          *( newColorIndicesBuffer + i ) = colorIndex;
+        }
+      }
     }
   }
+
+  // Insert the new indices.
+  colorIndices.Insert( colorIndices.Begin() + startGlyphIndex,
+                       newColorIndices.Begin(),
+                       newColorIndices.End() );
 }
 
 } // namespace Text
index 9e52de1..0a816ab 100644 (file)
@@ -38,15 +38,23 @@ class LogicalModel;
 /**
  * @brief Creates color glyph runs.
  *
- * @param[in] characterColorRuns The color runs in characters (set in the mark-up string).
+ * @param[in] colorRuns The color runs in characters (set in the mark-up string).
  * @param[in] charactersToGlyph Conversion table from characters to glyphs.
  * @param[in] glyphsPerCharacter Table with the number of glyphs for each character.
- * @param[out] glyphColorRuns The color runs in glyphs.
+ * @param[in] startCharacterIndex The character from where the text is shaped.
+ * @param[in] startGlyphIndex The glyph from where the text is shaped.
+ * @param[in] numberOfCharacters The number of characters to be shaped.
+ * @param[out] colors The vector of colors.
+ * @param[out] colorIndices Indices to the vector of colors.
  */
-void SetColorSegmentationInfo( const Vector<ColorRun>& characterColorRuns,
+void SetColorSegmentationInfo( const Vector<ColorRun>& colorRuns,
                                const Vector<GlyphIndex>& charactersToGlyph,
                                const Vector<Length>& glyphsPerCharacter,
-                               Vector<ColorGlyphRun>& glyphColorRuns );
+                               CharacterIndex startCharacterIndex,
+                               GlyphIndex startGlyphIndex,
+                               Length numberOfCharacters,
+                               Vector<Vector4>& colors,
+                               Vector<ColorIndex>& colorIndices );
 
 } // namespace Text
 
index bb393ff..47e3694 100644 (file)
@@ -283,7 +283,6 @@ struct Decorator::Impl : public ConnectionTracker
     mNotifyEndOfScroll( false )
   {
     mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
-    mQuadIndexFormat[ "indices" ] = Property::INTEGER;
     mHighlightShader = Shader::New( VERTEX_SHADER, FRAGMENT_SHADER );
     SetupTouchEvents();
   }
@@ -1005,7 +1004,7 @@ struct Decorator::Impl : public ConnectionTracker
       if( !mHighlightQuadList.empty() )
       {
         Vector< Vector2 > vertices;
-        Vector< unsigned int> indices;
+        Vector< unsigned short> indices;
         Vector2 vertex;
 
         std::vector<QuadCoordinates>::iterator iter = mHighlightQuadList.begin();
@@ -1051,20 +1050,14 @@ struct Decorator::Impl : public ConnectionTracker
           mQuadVertices = PropertyBuffer::New( mQuadVertexFormat );
         }
 
-        if( ! mQuadIndices )
-        {
-          mQuadIndices = PropertyBuffer::New( mQuadIndexFormat );
-        }
-
         mQuadVertices.SetData( &vertices[ 0 ], vertices.Size() );
-        mQuadIndices.SetData( &indices[ 0 ], indices.Size() );
 
         if( !mQuadGeometry )
         {
           mQuadGeometry = Geometry::New();
           mQuadGeometry.AddVertexBuffer( mQuadVertices );
         }
-        mQuadGeometry.SetIndexBuffer( mQuadIndices );
+        mQuadGeometry.SetIndexBuffer( &indices[ 0 ], indices.Size() );
 
         if( !mHighlightRenderer )
         {
@@ -1654,7 +1647,6 @@ struct Decorator::Impl : public ConnectionTracker
   Renderer            mHighlightRenderer;
   Shader              mHighlightShader;           ///< Shader used for highlight
   Property::Map       mQuadVertexFormat;
-  Property::Map       mQuadIndexFormat;
   PopupImpl           mCopyPastePopup;
   TextSelectionPopup::Buttons mEnabledPopupButtons; /// Bit mask of currently enabled Popup buttons
   TextSelectionPopupCallbackInterface& mTextSelectionPopupCallbackInterface;
@@ -1666,7 +1658,6 @@ struct Decorator::Impl : public ConnectionTracker
   HandleImpl          mHandle[HANDLE_TYPE_COUNT];
 
   PropertyBuffer      mQuadVertices;
-  PropertyBuffer      mQuadIndices;
   Geometry            mQuadGeometry;
   QuadContainer       mHighlightQuadList;         ///< Sub-selections that combine to create the complete selection highlight
 
index a9e6eab..5d7aead 100644 (file)
@@ -46,6 +46,7 @@ struct InputStyle
     width( TextAbstraction::FontWidth::NORMAL ),
     slant( TextAbstraction::FontSlant::NORMAL ),
     size( 0.f ),
+    isDefaultColor( true ),
     familyDefined( false ),
     weightDefined( false ),
     widthDefined( false ),
@@ -64,11 +65,12 @@ struct InputStyle
   FontSlant   slant;      ///< The font's slant.
   float       size;       ///< The font's size.
 
-  bool        familyDefined : 1; ///< Whether the font's family is defined.
-  bool        weightDefined : 1; ///< Whether the font's weight is defined.
-  bool        widthDefined  : 1; ///< Whether the font's width is defined.
-  bool        slantDefined  : 1; ///< Whether the font's slant is defined.
-  bool        sizeDefined   : 1; ///< Whether the font's size is defined.
+  bool        isDefaultColor : 1; ///< Whether the text's color is the default.
+  bool        familyDefined  : 1; ///< Whether the font's family is defined.
+  bool        weightDefined  : 1; ///< Whether the font's weight is defined.
+  bool        widthDefined   : 1; ///< Whether the font's width is defined.
+  bool        slantDefined   : 1; ///< Whether the font's slant is defined.
+  bool        sizeDefined    : 1; ///< Whether the font's size is defined.
 };
 
 } // namespace Text
index 239a2f8..b64ae2b 100644 (file)
@@ -78,21 +78,15 @@ CharacterDirection LogicalModel::GetCharacterDirection( CharacterIndex character
   return *( mCharacterDirections.Begin() + characterIndex );
 }
 
-void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
-                                          Length numberOfRuns,
-                                          CharacterIndex startIndex,
+void LogicalModel::SetVisualToLogicalMap( CharacterIndex startIndex,
                                           Length numberOfCharacters )
 {
   mVisualToLogicalMap.Resize( numberOfCharacters );
-  mLogicalToVisualMap.Resize( numberOfCharacters );
-
-  const Length numberOfCharactersPlus = numberOfCharacters + 1u;
-  mVisualToLogicalCursorMap.Resize( numberOfCharactersPlus );
 
   CharacterIndex* modelVisualToLogicalMapBuffer = mVisualToLogicalMap.Begin();
-  CharacterIndex* modelLogicalToVisualMapBuffer = mLogicalToVisualMap.Begin();
 
-  CharacterIndex* modelVisualToLogicalCursorMap = mVisualToLogicalCursorMap.Begin();
+  const BidirectionalLineInfoRun* const bidirectionalInfo = mBidirectionalLineInfo.Begin();
+  const Length numberOfRuns = mBidirectionalLineInfo.Count();
 
   CharacterIndex lastIndex = startIndex;
   for( unsigned int bidiIndex = 0u; bidiIndex < numberOfRuns; ++bidiIndex )
@@ -129,13 +123,11 @@ void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const
     *( modelVisualToLogicalMapBuffer + lastIndex ) = lastIndex;
   }
 
-  // Sets the logical to visual conversion map.
-  for( CharacterIndex index = startIndex; index < numberOfCharacters; ++index )
-  {
-    *( modelLogicalToVisualMapBuffer + *( modelVisualToLogicalMapBuffer + index ) ) = index;
-  }
-
   // Sets the visual to logical conversion map for cursor positions.
+  const Length numberOfCharactersPlusOne = numberOfCharacters + 1u;
+  mVisualToLogicalCursorMap.Resize( numberOfCharactersPlusOne );
+
+  CharacterIndex* modelVisualToLogicalCursorMap = mVisualToLogicalCursorMap.Begin();
 
   const Length numberOfBidirectionalParagraphs = mBidirectionalParagraphInfo.Count();
   BidirectionalParagraphInfoRun* bidirectionalParagraphInfoBuffer = mBidirectionalParagraphInfo.Begin();
@@ -145,7 +137,7 @@ void LogicalModel::SetVisualToLogicalMap( const BidirectionalLineInfoRun* const
 
   Length bidirectionalParagraphIndex = 0u;
   bool isRightToLeftParagraph = false;
-  for( CharacterIndex index = startIndex; index < numberOfCharactersPlus; ++index )
+  for( CharacterIndex index = startIndex; index < numberOfCharactersPlusOne; ++index )
   {
     if( bidirectionalParagraph &&
         ( bidirectionalParagraph->characterRun.characterIndex == index ) )
@@ -307,6 +299,7 @@ void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style )
   if( colorOverriden )
   {
     style.textColor = ( *( colorRunsBuffer + colorIndex ) ).color;
+    style.isDefaultColor = false;
   }
 
   // Reset the run index.
@@ -410,9 +403,6 @@ void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style )
     style.size = static_cast<float>( fontDescriptionRun.size ) / 64.f;
     style.sizeDefined = true;
   }
-
-  // Reset the run index.
-  runIndex = 0u;
 }
 
 void LogicalModel::ClearFontDescriptionRuns()
index e41f0fa..089af8e 100644 (file)
@@ -95,14 +95,10 @@ public:
    *
    * @note If the number of runs is zero the bidirectional info buffer is cleared.
    *
-   * @param[in] bidirectionalInfo Pointer to a buffer with all the bidirectional info runs.
-   * @param[in] numberOfRuns The number of bidirectional info runs.
    * @param[in] startIndex Character index from where the conversion tables are set.
    * @param[in] numberOfCharacters The number of characters.
    */
-  void SetVisualToLogicalMap( const BidirectionalLineInfoRun* const bidirectionalInfo,
-                              Length numberOfRuns,
-                              CharacterIndex startIndex,
+  void SetVisualToLogicalMap( CharacterIndex startIndex,
                               Length numberOfCharacters );
 
   /**
@@ -194,7 +190,6 @@ public:
   Vector<BidirectionalParagraphInfoRun> mBidirectionalParagraphInfo;
   Vector<CharacterDirection>            mCharacterDirections;        ///< For each character, whether is right to left. ( @e flase is left to right, @e true right to left ).
   Vector<BidirectionalLineInfoRun>      mBidirectionalLineInfo;
-  Vector<CharacterIndex>                mLogicalToVisualMap;         ///< Bidirectional logical to visual conversion table.
   Vector<CharacterIndex>                mVisualToLogicalMap;         ///< Bidirectional visual to logical conversion table.
   Vector<CharacterIndex>                mVisualToLogicalCursorMap;   ///< Bidirectional visual to logical cursor conversion table.
 };
index a5feaef..06b0f10 100644 (file)
@@ -43,19 +43,36 @@ void MergeFontDescriptions( const Vector<FontDescriptionRun>& fontDescriptions,
   // Pointer to the font id buffer.
   FontId* fontIdsBuffer = fontIds.Begin();
 
+  // Used to temporarily store the style per character.
+  TextAbstraction::FontDescription fontDescription;
+  TextAbstraction::PointSize26Dot6 fontSize;
+
+  Length familyIndex = 0u;
+  Length weightIndex = 0u;
+  Length widthIndex = 0u;
+  Length slantIndex = 0u;
+  Length sizeIndex = 0u;
+
   // Traverse all the characters.
-  for( CharacterIndex index = startIndex; index < numberOfCharacters; ++index )
+  const CharacterIndex lastCharacterPlusOne = startIndex + numberOfCharacters;
+  for( CharacterIndex index = startIndex; index < lastCharacterPlusOne; ++index )
   {
-    // The default font description and font point size.
-    TextAbstraction::FontDescription fontDescription = defaultFontDescription;
-    TextAbstraction::PointSize26Dot6 fontSize = defaultPointSize;
     bool defaultFont = true;
 
+    Length runIndex = 0u;
+
+    bool familyOverriden = false;
+    bool weightOverriden = false;
+    bool widthOverriden = false;
+    bool slantOverriden = false;
+    bool sizeOverriden = false;
+
     // Traverse all the font descriptions.
-    for( Vector<FontDescriptionRun>::ConstIterator it = fontDescriptions.Begin(),
+    const FontDescriptionRun* const fontDescriptionsBuffer = fontDescriptions.Begin();
+    for( Vector<FontDescriptionRun>::ConstIterator it = fontDescriptionsBuffer,
            endIt = fontDescriptions.End();
          it != endIt;
-         ++it )
+         ++it, ++runIndex )
     {
       // Check whether the character's font is modified by the current font description.
       const FontDescriptionRun& fontRun = *it;
@@ -64,28 +81,33 @@ void MergeFontDescriptions( const Vector<FontDescriptionRun>& fontDescriptions,
       {
         if( fontRun.familyDefined )
         {
-          fontDescription.family = std::string( fontRun.familyName, fontRun.familyLength );
           defaultFont = false;
+          familyOverriden = true;
+          familyIndex = runIndex;
         }
         if( fontRun.weightDefined )
         {
-          fontDescription.weight = fontRun.weight;
           defaultFont = false;
+          weightOverriden = true;
+          weightIndex = runIndex;
         }
         if( fontRun.widthDefined )
         {
-          fontDescription.width = fontRun.width;
           defaultFont = false;
+          widthOverriden = true;
+          widthIndex = runIndex;
         }
         if( fontRun.slantDefined )
         {
-          fontDescription.slant = fontRun.slant;
           defaultFont = false;
+          slantOverriden = true;
+          slantIndex = runIndex;
         }
         if( fontRun.sizeDefined )
         {
-          fontSize = fontRun.size;
           defaultFont = false;
+          sizeOverriden = true;
+          sizeIndex = runIndex;
         }
       }
     }
@@ -93,6 +115,56 @@ void MergeFontDescriptions( const Vector<FontDescriptionRun>& fontDescriptions,
     // Get the font id if is not the default font.
     if( !defaultFont )
     {
+      if( familyOverriden )
+      {
+        const FontDescriptionRun& fontRun = *( fontDescriptionsBuffer + familyIndex );
+        fontDescription.family = std::string( fontRun.familyName, fontRun.familyLength ); // TODO Could use move constructor when switch to c++11.
+      }
+      else
+      {
+        fontDescription.family = defaultFontDescription.family;
+      }
+
+      if( weightOverriden )
+      {
+        const FontDescriptionRun& fontRun = *( fontDescriptionsBuffer + weightIndex );
+        fontDescription.weight = fontRun.weight;
+      }
+      else
+      {
+        fontDescription.weight = defaultFontDescription.weight;
+      }
+
+      if( widthOverriden )
+      {
+        const FontDescriptionRun& fontRun = *( fontDescriptionsBuffer + widthIndex );
+        fontDescription.width = fontRun.width;
+      }
+      else
+      {
+        fontDescription.width = defaultFontDescription.width;
+      }
+
+      if( slantOverriden )
+      {
+        const FontDescriptionRun& fontRun = *( fontDescriptionsBuffer + slantIndex );
+        fontDescription.slant = fontRun.slant;
+      }
+      else
+      {
+        fontDescription.slant = defaultFontDescription.slant;
+      }
+
+      if( sizeOverriden )
+      {
+        const FontDescriptionRun& fontRun = *( fontDescriptionsBuffer + sizeIndex );
+        fontSize = fontRun.size;
+      }
+      else
+      {
+        fontSize = defaultPointSize;
+      }
+
       *( fontIdsBuffer + index - startIndex ) = fontClient.GetFontId( fontDescription, fontSize );
     }
   }
index 75f117a..df86ac1 100644 (file)
@@ -90,7 +90,7 @@ public:
   struct Mesh2D
   {
     Vector< Vertex2D > mVertices;       ///< container of vertices
-    Vector< SizeType > mIndices;        ///< container of indices
+    Vector< unsigned short > mIndices;        ///< container of indices
   };
 
   /**
index 3a64c96..4da6c1f 100644 (file)
@@ -148,7 +148,7 @@ void AppendMesh( Toolkit::AtlasManager::Mesh2D& first,
                          second.mIndices.Begin(),
                          second.mIndices.End() );
 
-  for( Vector<unsigned int>::Iterator it = first.mIndices.Begin() + indicesCount,
+  for( Vector<unsigned short>::Iterator it = first.mIndices.Begin() + indicesCount,
          endIt = first.mIndices.End();
        it != endIt;
        ++it )
index 7a76534..966deff 100644 (file)
@@ -141,7 +141,6 @@ struct AtlasRenderer::Impl
     mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
     mQuadVertexFormat[ "aTexCoord" ] = Property::VECTOR2;
     mQuadVertexFormat[ "aColor" ] = Property::VECTOR4;
-    mQuadIndexFormat[ "indices" ] = Property::INTEGER;
   }
 
   bool IsGlyphUnderlined( GlyphIndex index,
@@ -166,7 +165,9 @@ struct AtlasRenderer::Impl
   void AddGlyphs( Text::ViewInterface& view,
                   const Vector<Vector2>& positions,
                   const Vector<GlyphInfo>& glyphs,
-                  const Vector<Vector4>& colors,
+                  const Vector4& defaultColor,
+                  const Vector4* const colorsBuffer,
+                  const ColorIndex* const colorIndicesBuffer,
                   int depth )
   {
     AtlasManager::AtlasSlot slot;
@@ -184,6 +185,8 @@ struct AtlasRenderer::Impl
     const Vector4& underlineColor( view.GetUnderlineColor() );
     const float underlineHeight( view.GetUnderlineHeight() );
 
+    const bool useDefaultColor = ( NULL == colorsBuffer );
+
     // Get the underline runs.
     const Length numberOfUnderlineRuns = view.GetNumberOfUnderlineRuns();
     Vector<GlyphRun> underlineRuns;
@@ -212,7 +215,6 @@ struct AtlasRenderer::Impl
     Vector< TextCacheEntry > newTextCache;
     const GlyphInfo* const glyphsBuffer = glyphs.Begin();
     const Vector2* const positionsBuffer = positions.Begin();
-    const Vector4* const colorsBuffer = colors.Begin();
 
     for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
     {
@@ -352,7 +354,8 @@ struct AtlasRenderer::Impl
         }
 
         // Get the color of the character.
-        const Vector4& color = *( colorsBuffer + i );
+        const ColorIndex colorIndex = useDefaultColor ? 0u : *( colorIndicesBuffer + i );
+        const Vector4& color = ( useDefaultColor || ( 0u == colorIndex ) ) ? defaultColor : *( colorsBuffer + colorIndex - 1u );
 
         for( unsigned int index = 0u, size = newMesh.mVertices.Count();
              index < size;
@@ -480,13 +483,11 @@ struct AtlasRenderer::Impl
   Actor CreateMeshActor( const MeshRecord& meshRecord, const Vector2& actorSize )
   {
     PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat );
-    PropertyBuffer quadIndices = PropertyBuffer::New( mQuadIndexFormat );
     quadVertices.SetData( const_cast< AtlasManager::Vertex2D* >( &meshRecord.mMesh.mVertices[ 0 ] ), meshRecord.mMesh.mVertices.Size() );
-    quadIndices.SetData(  const_cast< unsigned int* >(           &meshRecord.mMesh.mIndices[ 0 ] ),  meshRecord.mMesh.mIndices.Size() );
 
     Geometry quadGeometry = Geometry::New();
     quadGeometry.AddVertexBuffer( quadVertices );
-    quadGeometry.SetIndexBuffer( quadIndices );
+    quadGeometry.SetIndexBuffer( &meshRecord.mMesh.mIndices[0],  meshRecord.mMesh.mIndices.Size() );
 
     TextureSet textureSet( mGlyphManager.GetTextures( meshRecord.mAtlasId ) );
     Shader shader( mGlyphManager.GetShader( meshRecord.mAtlasId ) );
@@ -725,7 +726,6 @@ struct AtlasRenderer::Impl
   std::vector< MaxBlockSize > mBlockSizes;            ///> Maximum size needed to contain a glyph in a block within a new atlas
   Vector< TextCacheEntry > mTextCache;                ///> Caches data from previous render
   Property::Map mQuadVertexFormat;                    ///> Describes the vertex format for text
-  Property::Map mQuadIndexFormat;                     ///> Describes the index format for text
   int mDepth;                                         ///> DepthIndex passed by control when connect to stage
 };
 
@@ -750,23 +750,24 @@ Actor AtlasRenderer::Render( Text::ViewInterface& view, int depth )
     Vector<Vector2> positions;
     positions.Resize( numberOfGlyphs );
 
-    Vector<Vector4> colors;
-    colors.Resize( numberOfGlyphs, view.GetTextColor() );
-
     numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
                                      positions.Begin(),
-                                     colors.Begin(),
                                      0u,
                                      numberOfGlyphs );
 
     glyphs.Resize( numberOfGlyphs );
     positions.Resize( numberOfGlyphs );
-    colors.Resize( numberOfGlyphs );
+
+    const Vector4* const colorsBuffer = view.GetColors();
+    const ColorIndex* const colorIndicesBuffer = view.GetColorIndices();
+    const Vector4& defaultColor = view.GetTextColor();
 
     mImpl->AddGlyphs( view,
                       positions,
                       glyphs,
-                      colors,
+                      defaultColor,
+                      colorsBuffer,
+                      colorIndicesBuffer,
                       depth );
 
     /* In the case where AddGlyphs does not create a renderable Actor for example when glyphs are all whitespace create a new Actor. */
index 53db8fb..556a902 100644 (file)
@@ -48,6 +48,8 @@ const char* const VERTEX_SHADER_MAIN =
 "varying   mediump vec3    vNormal;\n"
 "attribute mediump vec2    aPosition;\n"
 "varying   mediump vec4    vVertex;\n"
+"attribute mediump vec4    aColor;\n"
+"varying   mediump vec4    vColor;\n"
 "varying vec4 v_glyph;\n"
 "\n"
 "vec4\n"
@@ -65,6 +67,7 @@ const char* const VERTEX_SHADER_MAIN =
 "{\n"
 "  gl_Position = uMvpMatrix * vec4 (aPosition, 0.0, 1.0);\n"
 "  v_glyph = glyph_vertex_transcode (aTexCoord);\n"
+"  vColor = aColor;\n"
 "}\n"
 ;
 
@@ -87,6 +90,7 @@ const char* const FRAGMENT_SHADER_PREFIX =
 "uniform lowp  vec4    uColor;\n"
 "varying highp vec4    vVertex;\n"
 "varying highp vec3    vNormal;\n"
+"varying mediump vec4  vColor;\n"
 "uniform vec4 u_atlas_info;\n"
 "\n"
 "#define GLYPHY_TEXTURE1D_EXTRA_DECLS , sampler2D _tex, ivec4 _atlas_info, ivec2 _atlas_pos\n"
@@ -157,7 +161,7 @@ static const char* FRAGMENT_SHADER_MAIN =
 "  vec2 dpdy = dFdy (p);\n"
 "  float m = length (vec2 (length (dpdx), length (dpdy))) * SQRT2_2;\n"
 "\n"
-"  vec4 color = uColor;\n"
+"  vec4 color = vec4( vColor.rgb * uColor.rgb, vColor.a * uColor.a );\n"
 "\n"
 "  ivec4 uu_atlas_info = ivec4( u_atlas_info );"
 "  float gsdist = glyphy_sdf (p, gi.nominal_size GLYPHY_DEMO_EXTRA_ARGS);\n"
index 816a45d..73fb666 100644 (file)
@@ -50,19 +50,21 @@ struct Vertex2D
   float y;
   float u;
   float v;
+  Vector4 color;
 };
 
-void AddVertex( Vector<Vertex2D>& vertices, float x, float y, float u, float v )
+void AddVertex( Vector<Vertex2D>& vertices, float x, float y, float u, float v, const Vector4& color )
 {
   Vertex2D meshVertex;
   meshVertex.x = x;
   meshVertex.y = y;
   meshVertex.u = u;
   meshVertex.v = v;
+  meshVertex.color = color;
   vertices.PushBack( meshVertex );
 }
 
-void AddTriangle( Vector<unsigned int>& indices, unsigned int v0, unsigned int v1, unsigned int v2 )
+void AddTriangle( Vector<unsigned short>& indices, unsigned int v0, unsigned int v1, unsigned int v2 )
 {
   indices.PushBack( v0 );
   indices.PushBack( v1 );
@@ -77,8 +79,14 @@ bool CreateGeometry( const Vector<GlyphInfo>& glyphs,
                      VectorBlobAtlas& atlas,
                      Dali::TextAbstraction::FontClient& fontClient,
                      Vector< Vertex2D >& vertices,
-                     Vector< unsigned int >& indices )
+                     Vector< unsigned short >& indices,
+                     const Vector4* const colorsBuffer,
+                     const ColorIndex* const colorIndicesBuffer,
+                     const Vector4& defaultColor )
 {
+  // Whether the default color is used.
+  const bool useDefaultColor = ( NULL == colorsBuffer );
+
   bool atlasFull( false );
 
   for( unsigned int i=0, idx=0; i<numberOfGlyphs && !atlasFull; ++i )
@@ -114,20 +122,24 @@ bool CreateGeometry( const Vector<GlyphInfo>& glyphs,
 
       if( foundBlob )
       {
+        // Get the color of the character.
+        const ColorIndex colorIndex = useDefaultColor ? 0u : *( colorIndicesBuffer + i );
+        const Vector4& color = ( useDefaultColor || ( 0u == colorIndex ) ) ? defaultColor : *( colorsBuffer + colorIndex - 1u );
+
         const float x1( xOffset + positions[i].x );
         const float x2( xOffset + positions[i].x + glyphs[i].width );
         const float y1( yOffset + positions[i].y );
         const float y2( yOffset + positions[i].y + glyphs[i].height );
 
-        AddVertex( vertices, x1, y2, blobCoords[0].u, blobCoords[0].v );
-        AddVertex( vertices, x1, y1, blobCoords[1].u, blobCoords[1].v );
-        AddVertex( vertices, x2, y2, blobCoords[2].u, blobCoords[2].v );
+        AddVertex( vertices, x1, y2, blobCoords[0].u, blobCoords[0].v, color );
+        AddVertex( vertices, x1, y1, blobCoords[1].u, blobCoords[1].v, color );
+        AddVertex( vertices, x2, y2, blobCoords[2].u, blobCoords[2].v, color );
         AddTriangle( indices, idx, idx+1, idx+2 );
         idx+=3;
 
-        AddVertex( vertices, x1, y1, blobCoords[1].u, blobCoords[1].v );
-        AddVertex( vertices, x2, y2, blobCoords[2].u, blobCoords[2].v );
-        AddVertex( vertices, x2, y1, blobCoords[3].u, blobCoords[3].v );
+        AddVertex( vertices, x1, y1, blobCoords[1].u, blobCoords[1].v, color );
+        AddVertex( vertices, x2, y2, blobCoords[2].u, blobCoords[2].v, color );
+        AddVertex( vertices, x2, y1, blobCoords[3].u, blobCoords[3].v, color );
         AddTriangle( indices, idx, idx+1, idx+2 );
         idx+=3;
       }
@@ -148,7 +160,7 @@ struct VectorBasedRenderer::Impl
 
     mQuadVertexFormat[ "aPosition" ] = Property::VECTOR2;
     mQuadVertexFormat[ "aTexCoord" ] = Property::VECTOR2;
-    mQuadIndexFormat[ "indices" ] = Property::INTEGER;
+    mQuadVertexFormat[ "aColor" ] = Property::VECTOR4;
   }
 
   Actor mActor;                            ///< The actor parent which renders the text
@@ -156,7 +168,6 @@ struct VectorBasedRenderer::Impl
   TextAbstraction::FontClient mFontClient; ///> The font client used to supply glyph information
 
   Property::Map mQuadVertexFormat;         ///> Describes the vertex format for text
-  Property::Map mQuadIndexFormat;          ///> Describes the index format for text
 
   Shader mShaderEffect;
 
@@ -177,7 +188,7 @@ Actor VectorBasedRenderer::Render( Text::ViewInterface& view, int /*depth*/ )
   mImpl->mActor = Actor::New();
   mImpl->mActor.SetParentOrigin( ParentOrigin::CENTER );
   mImpl->mActor.SetSize( view.GetControlSize() );
-  mImpl->mActor.SetColor( Color::BLACK );
+  mImpl->mActor.SetColor( Color::WHITE );
 #if defined(DEBUG_ENABLED)
   mImpl->mActor.SetName( "Text renderable actor" );
 #endif
@@ -192,19 +203,19 @@ Actor VectorBasedRenderer::Render( Text::ViewInterface& view, int /*depth*/ )
     Vector<Vector2> positions;
     positions.Resize( numberOfGlyphs );
 
-    Vector<Vector4> colors;
-    colors.Resize( numberOfGlyphs, view.GetTextColor() );
-
     numberOfGlyphs = view.GetGlyphs( glyphs.Begin(),
                                      positions.Begin(),
-                                     colors.Begin(),
                                      0u,
                                      numberOfGlyphs );
     glyphs.Resize( numberOfGlyphs );
     positions.Resize( numberOfGlyphs );
 
+    const Vector4* const colorsBuffer = view.GetColors();
+    const ColorIndex* const colorIndicesBuffer = view.GetColorIndices();
+    const Vector4& defaultColor = view.GetTextColor();
+
     Vector< Vertex2D > vertices;
-    Vector< unsigned int > indices;
+    Vector< unsigned short > indices;
 
     const Vector2& controlSize = view.GetControlSize();
     float xOffset = controlSize.width  * -0.5f;
@@ -218,7 +229,18 @@ Actor VectorBasedRenderer::Render( Text::ViewInterface& view, int /*depth*/ )
     }
 
     // First try adding the glyphs to the previous shared atlas
-    bool allGlyphsAdded = CreateGeometry( glyphs, numberOfGlyphs, positions, xOffset, yOffset, *mImpl->mAtlas, mImpl->mFontClient, vertices, indices );
+    bool allGlyphsAdded = CreateGeometry( glyphs,
+                                          numberOfGlyphs,
+                                          positions,
+                                          xOffset,
+                                          yOffset,
+                                          *mImpl->mAtlas,
+                                          mImpl->mFontClient,
+                                          vertices,
+                                          indices,
+                                          colorsBuffer,
+                                          colorIndicesBuffer,
+                                          defaultColor );
 
     if( ! allGlyphsAdded )
     {
@@ -230,21 +252,31 @@ Actor VectorBasedRenderer::Render( Text::ViewInterface& view, int /*depth*/ )
       VectorBlobAtlasShare atlasShare = VectorBlobAtlasShare::Get();
       mImpl->mAtlas = atlasShare.GetNewAtlas();
 
-      CreateGeometry( glyphs, numberOfGlyphs, positions, xOffset, yOffset, *mImpl->mAtlas, mImpl->mFontClient, vertices, indices );
+      CreateGeometry( glyphs,
+                      numberOfGlyphs,
+                      positions,
+                      xOffset,
+                      yOffset,
+                      *mImpl->mAtlas,
+                      mImpl->mFontClient,
+                      vertices,
+                      indices,
+                      colorsBuffer,
+                      colorIndicesBuffer,
+                      defaultColor );
       // Return value ignored; using more than an entire new atlas is not supported
     }
 
     if( 0 != vertices.Count() )
     {
       PropertyBuffer quadVertices = PropertyBuffer::New( mImpl->mQuadVertexFormat );
-      PropertyBuffer quadIndices = PropertyBuffer::New( mImpl->mQuadIndexFormat );
 
       quadVertices.SetData( &vertices[ 0 ], vertices.Size() );
-      quadIndices.SetData( &indices[ 0 ], indices.Size() );
+
 
       Geometry quadGeometry = Geometry::New();
       quadGeometry.AddVertexBuffer( quadVertices );
-      quadGeometry.SetIndexBuffer( quadIndices );
+      quadGeometry.SetIndexBuffer( &indices[ 0 ], indices.Size() );
 
       TextureSet texture = mImpl->mAtlas->GetTextureSet();
 
index f64c266..56820ae 100644 (file)
@@ -338,6 +338,7 @@ void Controller::Impl::CalculateTextUpdateIndices( Length& numberOfCharacters )
       numberOfCharacters = lastParagraph.characterRun.characterIndex + lastParagraph.characterRun.numberOfCharacters - mTextUpdateInfo.mParagraphCharacterIndex;
     }
   }
+
   mTextUpdateInfo.mRequestedNumberOfCharacters = numberOfCharacters + mTextUpdateInfo.mNumberOfCharactersToAdd - mTextUpdateInfo.mNumberOfCharactersToRemove;
   mTextUpdateInfo.mStartGlyphIndex = *( mVisualModel->mCharactersToGlyph.Begin() + mTextUpdateInfo.mParagraphCharacterIndex );
 }
@@ -388,7 +389,6 @@ void Controller::Impl::ClearFullModelData( OperationsMask operations )
       }
       mLogicalModel->mBidirectionalLineInfo.Clear();
 
-      mLogicalModel->mLogicalToVisualMap.Clear();
       mLogicalModel->mVisualToLogicalMap.Clear();
     }
   }
@@ -407,6 +407,11 @@ void Controller::Impl::ClearFullModelData( OperationsMask operations )
   {
     mVisualModel->mLines.Clear();
   }
+
+  if( COLOR & operations )
+  {
+    mVisualModel->mColorIndices.Clear();
+  }
 }
 
 void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations )
@@ -495,11 +500,6 @@ void Controller::Impl::ClearCharacterModelData( CharacterIndex startIndex, Chara
       mLogicalModel->mBidirectionalLineInfo.Erase( bidirectionalLineInfoBuffer + startRemoveIndex,
                                                    bidirectionalLineInfoBuffer + endRemoveIndex );
 
-      // Clear the logical to visual and the visual to logical conversion tables.
-      CharacterIndex* logicalToVisualMapBuffer = mLogicalModel->mLogicalToVisualMap.Begin();
-      mLogicalModel->mLogicalToVisualMap.Erase( logicalToVisualMapBuffer + startIndex,
-                                                logicalToVisualMapBuffer + endIndexPlusOne );
-
       CharacterIndex* visualToLogicalMapBuffer = mLogicalModel->mVisualToLogicalMap.Begin();
       mLogicalModel->mVisualToLogicalMap.Erase( visualToLogicalMapBuffer + startIndex,
                                                 visualToLogicalMapBuffer + endIndexPlusOne );
@@ -512,97 +512,100 @@ void Controller::Impl::ClearGlyphModelData( CharacterIndex startIndex, Character
   const CharacterIndex endIndexPlusOne = endIndex + 1u;
   const Length numberOfCharactersRemoved = endIndexPlusOne - startIndex;
 
-  const bool clearShape = SHAPE_TEXT & operations;
-  const bool clearLayout = LAYOUT & operations;
-
-  if( clearShape || clearLayout )
-  {
-    // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
-    GlyphIndex* charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
-    Length* glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
+  // Convert the character index to glyph index before deleting the character to glyph and the glyphs per character buffers.
+  GlyphIndex* charactersToGlyphBuffer = mVisualModel->mCharactersToGlyph.Begin();
+  Length* glyphsPerCharacterBuffer = mVisualModel->mGlyphsPerCharacter.Begin();
 
-    const GlyphIndex endGlyphIndex = *( charactersToGlyphBuffer + endIndex );
-    const GlyphIndex endGlyphIndexPlusOne = endGlyphIndex + *( glyphsPerCharacterBuffer + endIndex );
-    const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
+  const GlyphIndex endGlyphIndexPlusOne = *( charactersToGlyphBuffer + endIndex ) + *( glyphsPerCharacterBuffer + endIndex );
+  const Length numberOfGlyphsRemoved = endGlyphIndexPlusOne - mTextUpdateInfo.mStartGlyphIndex;
 
-    if( clearShape )
+  if( SHAPE_TEXT & operations )
+  {
+    // Update the character to glyph indices.
+    for( Vector<GlyphIndex>::Iterator it =  charactersToGlyphBuffer + endIndexPlusOne,
+           endIt =  charactersToGlyphBuffer + mVisualModel->mCharactersToGlyph.Count();
+         it != endIt;
+         ++it )
     {
-      // Update the character to glyph indices.
-      for( Vector<GlyphIndex>::Iterator it =  charactersToGlyphBuffer + endIndexPlusOne,
-             endIt =  charactersToGlyphBuffer + mVisualModel->mCharactersToGlyph.Count();
-           it != endIt;
-           ++it )
-      {
-        CharacterIndex& index = *it;
-        index -= numberOfGlyphsRemoved;
-      }
+      CharacterIndex& index = *it;
+      index -= numberOfGlyphsRemoved;
+    }
 
-      // Clear the character to glyph conversion table.
-      mVisualModel->mCharactersToGlyph.Erase( charactersToGlyphBuffer + startIndex,
-                                              charactersToGlyphBuffer + endIndexPlusOne );
+    // Clear the character to glyph conversion table.
+    mVisualModel->mCharactersToGlyph.Erase( charactersToGlyphBuffer + startIndex,
+                                            charactersToGlyphBuffer + endIndexPlusOne );
 
-      // Clear the glyphs per character table.
-      mVisualModel->mGlyphsPerCharacter.Erase( glyphsPerCharacterBuffer + startIndex,
-                                               glyphsPerCharacterBuffer + endIndexPlusOne );
+    // Clear the glyphs per character table.
+    mVisualModel->mGlyphsPerCharacter.Erase( glyphsPerCharacterBuffer + startIndex,
+                                             glyphsPerCharacterBuffer + endIndexPlusOne );
 
-      // Clear the glyphs buffer.
-      GlyphInfo* glyphsBuffer = mVisualModel->mGlyphs.Begin();
-      mVisualModel->mGlyphs.Erase( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                   glyphsBuffer + endGlyphIndexPlusOne );
+    // Clear the glyphs buffer.
+    GlyphInfo* glyphsBuffer = mVisualModel->mGlyphs.Begin();
+    mVisualModel->mGlyphs.Erase( glyphsBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                 glyphsBuffer + endGlyphIndexPlusOne );
 
-      CharacterIndex* glyphsToCharactersBuffer = mVisualModel->mGlyphsToCharacters.Begin();
+    CharacterIndex* glyphsToCharactersBuffer = mVisualModel->mGlyphsToCharacters.Begin();
 
-      // Update the glyph to character indices.
-      for( Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
-             endIt = glyphsToCharactersBuffer + mVisualModel->mGlyphsToCharacters.Count();
-           it != endIt;
-           ++it )
-      {
-        CharacterIndex& index = *it;
-        index -= numberOfCharactersRemoved;
-      }
+    // Update the glyph to character indices.
+    for( Vector<CharacterIndex>::Iterator it = glyphsToCharactersBuffer + endGlyphIndexPlusOne,
+           endIt = glyphsToCharactersBuffer + mVisualModel->mGlyphsToCharacters.Count();
+         it != endIt;
+         ++it )
+    {
+      CharacterIndex& index = *it;
+      index -= numberOfCharactersRemoved;
+    }
 
-      // Clear the glyphs to characters buffer.
-      mVisualModel->mGlyphsToCharacters.Erase( glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                               glyphsToCharactersBuffer  + endGlyphIndexPlusOne );
+    // Clear the glyphs to characters buffer.
+    mVisualModel->mGlyphsToCharacters.Erase( glyphsToCharactersBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                             glyphsToCharactersBuffer  + endGlyphIndexPlusOne );
 
-      // Clear the characters per glyph buffer.
-      Length* charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
-      mVisualModel->mCharactersPerGlyph.Erase( charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                               charactersPerGlyphBuffer + endGlyphIndexPlusOne );
+    // Clear the characters per glyph buffer.
+    Length* charactersPerGlyphBuffer = mVisualModel->mCharactersPerGlyph.Begin();
+    mVisualModel->mCharactersPerGlyph.Erase( charactersPerGlyphBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                             charactersPerGlyphBuffer + endGlyphIndexPlusOne );
 
-      // Clear the positions buffer.
-      Vector2* positionsBuffer = mVisualModel->mGlyphPositions.Begin();
-      mVisualModel->mGlyphPositions.Erase( positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
-                                           positionsBuffer + endGlyphIndexPlusOne );
-    }
+    // Clear the positions buffer.
+    Vector2* positionsBuffer = mVisualModel->mGlyphPositions.Begin();
+    mVisualModel->mGlyphPositions.Erase( positionsBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                         positionsBuffer + endGlyphIndexPlusOne );
+  }
 
-    if( clearLayout )
-    {
-      // Clear the lines.
-      uint32_t startRemoveIndex = mVisualModel->mLines.Count();
-      uint32_t endRemoveIndex = startRemoveIndex;
-      ClearCharacterRuns( startIndex,
-                          endIndex,
-                          mVisualModel->mLines,
-                          startRemoveIndex,
-                          endRemoveIndex );
+  if( LAYOUT & operations )
+  {
+    // Clear the lines.
+    uint32_t startRemoveIndex = mVisualModel->mLines.Count();
+    uint32_t endRemoveIndex = startRemoveIndex;
+    ClearCharacterRuns( startIndex,
+                        endIndex,
+                        mVisualModel->mLines,
+                        startRemoveIndex,
+                        endRemoveIndex );
 
-      // Will update the glyph runs.
-      uint32_t startRemoveGlyphIndex = mVisualModel->mLines.Count();
-      uint32_t endRemoveGlyphIndex = startRemoveIndex;
-      ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
-                      endGlyphIndex,
-                      mVisualModel->mLines,
-                      startRemoveGlyphIndex,
-                      endRemoveGlyphIndex );
+    // Will update the glyph runs.
+    startRemoveIndex = mVisualModel->mLines.Count();
+    endRemoveIndex = startRemoveIndex;
+    ClearGlyphRuns( mTextUpdateInfo.mStartGlyphIndex,
+                    endGlyphIndexPlusOne - 1u,
+                    mVisualModel->mLines,
+                    startRemoveIndex,
+                    endRemoveIndex );
 
-      // Set the line index from where to insert the new laid-out lines.
-      mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
+    // Set the line index from where to insert the new laid-out lines.
+    mTextUpdateInfo.mStartLineIndex = startRemoveIndex;
 
-      LineRun* linesBuffer = mVisualModel->mLines.Begin();
-      mVisualModel->mLines.Erase( linesBuffer + startRemoveIndex,
-                                  linesBuffer + endRemoveIndex );
+    LineRun* linesBuffer = mVisualModel->mLines.Begin();
+    mVisualModel->mLines.Erase( linesBuffer + startRemoveIndex,
+                                linesBuffer + endRemoveIndex );
+  }
+
+  if( COLOR & operations )
+  {
+    if( 0u != mVisualModel->mColorIndices.Count() )
+    {
+      ColorIndex* colorIndexBuffer = mVisualModel->mColorIndices.Begin();
+      mVisualModel->mColorIndices.Erase( colorIndexBuffer + mTextUpdateInfo.mStartGlyphIndex,
+                                         colorIndexBuffer + endGlyphIndexPlusOne );
     }
   }
 }
@@ -628,12 +631,9 @@ void Controller::Impl::ClearModelData( CharacterIndex startIndex, CharacterIndex
   mTextUpdateInfo.mEstimatedNumberOfLines = std::max( mVisualModel->mLines.Count(), mLogicalModel->mParagraphInfo.Count() );
 
   mVisualModel->ClearCaches();
-
-  // TODO finish the mark-up.
-  mVisualModel->mColorRuns.Clear();
 }
 
-void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
+bool Controller::Impl::UpdateModel( OperationsMask operationsRequired )
 {
   DALI_LOG_INFO( gLogFilter, Debug::General, "Controller::UpdateModel\n" );
 
@@ -643,7 +643,7 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
   if( NO_OPERATION == operations )
   {
     // Nothing to do if no operations are pending and required.
-    return;
+    return false;
   }
 
   Vector<Character>& utf32Characters = mLogicalModel->mText;
@@ -666,6 +666,9 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
 
   mTextUpdateInfo.mClearAll = false;
 
+  // Whether the model is updated.
+  bool updated = false;
+
   Vector<LineBreakInfo>& lineBreakInfo = mLogicalModel->mLineBreakInfo;
   const Length requestedNumberOfCharacters = mTextUpdateInfo.mRequestedNumberOfCharacters;
 
@@ -685,6 +688,7 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
     // Create the paragraph info.
     mLogicalModel->CreateParagraphInfo( startIndex,
                                         requestedNumberOfCharacters );
+    updated = true;
   }
 
   Vector<WordBreakInfo>& wordBreakInfo = mLogicalModel->mWordBreakInfo;
@@ -697,6 +701,7 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
                       startIndex,
                       requestedNumberOfCharacters,
                       wordBreakInfo );
+    updated = true;
   }
 
   const bool getScripts = GET_SCRIPTS & operations;
@@ -738,6 +743,7 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
                                           requestedNumberOfCharacters,
                                           validFonts );
     }
+    updated = true;
   }
 
   Vector<Character> mirroredUtf32Characters;
@@ -781,6 +787,7 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
       // There is no right to left characters. Clear the directions vector.
       mLogicalModel->mCharacterDirections.Clear();
     }
+    updated = true;
   }
 
   Vector<GlyphInfo>& glyphs = mVisualModel->mGlyphs;
@@ -809,6 +816,7 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
     // Create the 'number of glyphs' per character and the glyph to character conversion tables.
     mVisualModel->CreateGlyphsPerCharacterTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
     mVisualModel->CreateCharacterToGlyphTable( startIndex, mTextUpdateInfo.mStartGlyphIndex, requestedNumberOfCharacters );
+    updated = true;
   }
 
   const Length numberOfGlyphs = glyphs.Count() - currentNumberOfGlyphs;
@@ -828,6 +836,22 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
       glyph.width = 0.f;
       glyph.advance = 0.f;
     }
+    updated = true;
+  }
+
+  if( COLOR & operationsRequired )
+  {
+    // Set the color runs in glyphs.
+    SetColorSegmentationInfo( mLogicalModel->mColorRuns,
+                              mVisualModel->mCharactersToGlyph,
+                              mVisualModel->mGlyphsPerCharacter,
+                              startIndex,
+                              mTextUpdateInfo.mStartGlyphIndex,
+                              requestedNumberOfCharacters,
+                              mVisualModel->mColors,
+                              mVisualModel->mColorIndices );
+
+    updated = true;
   }
 
   if( ( NULL != mEventData ) &&
@@ -856,22 +880,6 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired )
 
   // Set the previous number of characters for the next time the text is updated.
   mTextUpdateInfo.mPreviousNumberOfCharacters = numberOfCharacters;
-}
-
-bool Controller::Impl::UpdateModelStyle( OperationsMask operationsRequired )
-{
-  bool updated = false;
-
-  if( COLOR & operationsRequired )
-  {
-    // Set the color runs in glyphs.
-    SetColorSegmentationInfo( mLogicalModel->mColorRuns,
-                              mVisualModel->mCharactersToGlyph,
-                              mVisualModel->mGlyphsPerCharacter,
-                              mVisualModel->mColorRuns );
-
-    updated = true;
-  }
 
   return updated;
 }
@@ -880,35 +888,52 @@ void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle )
 {
   // Sets the default text's color.
   inputStyle.textColor = mTextColor;
+  inputStyle.isDefaultColor = true;
+
+  inputStyle.familyName.clear();
+  inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
+  inputStyle.width = TextAbstraction::FontWidth::NORMAL;
+  inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
+  inputStyle.size = 0.f;
+
+  inputStyle.familyDefined = false;
+  inputStyle.weightDefined = false;
+  inputStyle.widthDefined = false;
+  inputStyle.slantDefined = false;
+  inputStyle.sizeDefined = false;
 
   // Sets the default font's family name, weight, width, slant and size.
   if( mFontDefaults )
   {
-    inputStyle.familyName = mFontDefaults->mFontDescription.family;
-    inputStyle.weight = mFontDefaults->mFontDescription.weight;
-    inputStyle.width = mFontDefaults->mFontDescription.width;
-    inputStyle.slant = mFontDefaults->mFontDescription.slant;
-    inputStyle.size = mFontDefaults->mDefaultPointSize;
+    if( mFontDefaults->familyDefined )
+    {
+      inputStyle.familyName = mFontDefaults->mFontDescription.family;
+      inputStyle.familyDefined = true;
+    }
 
-    inputStyle.familyDefined = mFontDefaults->familyDefined;
-    inputStyle.weightDefined = mFontDefaults->weightDefined;
-    inputStyle.widthDefined = mFontDefaults->widthDefined;
-    inputStyle.slantDefined = mFontDefaults->slantDefined;
-    inputStyle.sizeDefined = mFontDefaults->sizeDefined;
-  }
-  else
-  {
-    inputStyle.familyName.clear();
-    inputStyle.weight = TextAbstraction::FontWeight::NORMAL;
-    inputStyle.width = TextAbstraction::FontWidth::NORMAL;
-    inputStyle.slant = TextAbstraction::FontSlant::NORMAL;
-    inputStyle.size = 0.f;
-
-    inputStyle.familyDefined = false;
-    inputStyle.weightDefined = false;
-    inputStyle.widthDefined = false;
-    inputStyle.slantDefined = false;
-    inputStyle.sizeDefined = false;
+    if( mFontDefaults->weightDefined )
+    {
+      inputStyle.weight = mFontDefaults->mFontDescription.weight;
+      inputStyle.weightDefined = true;
+    }
+
+    if( mFontDefaults->widthDefined )
+    {
+      inputStyle.width = mFontDefaults->mFontDescription.width;
+      inputStyle.widthDefined = true;
+    }
+
+    if( mFontDefaults->slantDefined )
+    {
+      inputStyle.slant = mFontDefaults->mFontDescription.slant;
+      inputStyle.slantDefined = true;
+    }
+
+    if( mFontDefaults->sizeDefined )
+    {
+      inputStyle.size = mFontDefaults->mDefaultPointSize;
+      inputStyle.sizeDefined = true;
+    }
   }
 }
 
index 2f14702..4e566ab 100644 (file)
@@ -478,7 +478,7 @@ struct Controller::Impl
   void ClearModelData( CharacterIndex startIndex, CharacterIndex endIndex, OperationsMask operations );
 
   /**
-   * @brief Updates the logical and visual models.
+   * @brief Updates the logical and visual models. Updates the style runs in the visual model when the text's styles changes.
    *
    * When text or style changes the model is set with some operations pending.
    * When i.e. the text's size or a relayout is required this method is called
@@ -486,17 +486,10 @@ struct Controller::Impl
    * matched with the operations pending to perform the minimum number of operations.
    *
    * @param[in] operationsRequired The operations required.
-   */
-  void UpdateModel( OperationsMask operationsRequired );
-
-  /**
-   * @brief Updates the style runs in the visual model when the text's styles changes.
-   *
-   * @param[in] operationsRequired The operations required.
    *
    * @return @e true if the model has been modified.
    */
-  bool UpdateModelStyle( OperationsMask operationsRequired );
+  bool UpdateModel( OperationsMask operationsRequired );
 
   /**
    * @brief Retreieves the default style.
index b32b20e..37110dc 100644 (file)
@@ -68,15 +68,19 @@ namespace Text
  *
  * @param[in] eventData The event data pointer.
  * @param[in] logicalModel The logical model where to add the new font description run.
+ * @param[out] startOfSelectedText Index to the first selected character.
+ * @param[out] lengthOfSelectedText Number of selected characters.
  */
 FontDescriptionRun& UpdateSelectionFontStyleRun( EventData* eventData,
-                                                 LogicalModelPtr logicalModel )
+                                                 LogicalModelPtr logicalModel,
+                                                 CharacterIndex& startOfSelectedText,
+                                                 Length& lengthOfSelectedText )
 {
   const bool handlesCrossed = eventData->mLeftSelectionPosition > eventData->mRightSelectionPosition;
 
   // Get start and end position of selection
-  const CharacterIndex startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
-  const Length lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText;
+  startOfSelectedText = handlesCrossed ? eventData->mRightSelectionPosition : eventData->mLeftSelectionPosition;
+  lengthOfSelectedText = ( handlesCrossed ? eventData->mLeftSelectionPosition : eventData->mRightSelectionPosition ) - startOfSelectedText;
 
   // Add the font run.
   const VectorBase::SizeType numberOfRuns = logicalModel->mFontDescriptionRuns.Count();
@@ -115,9 +119,6 @@ void Controller::SetGlyphType( TextAbstraction::GlyphType glyphType )
   // Clear the font-specific data
   ClearFontData();
 
-  mImpl->mOperationsPending = ALL_OPERATIONS;
-  mImpl->mRecalculateNaturalSize = true;
-
   mImpl->RequestRelayout();
 }
 
@@ -160,6 +161,8 @@ void Controller::SetText( const std::string& text )
 
   if( !text.empty() )
   {
+    mImpl->mVisualModel->SetTextColor( mImpl->mTextColor );
+
     MarkupProcessData markupProcessData( mImpl->mLogicalModel->mColorRuns,
                                          mImpl->mLogicalModel->mFontDescriptionRuns );
 
@@ -322,9 +325,6 @@ void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
   // Clear the font-specific data
   ClearFontData();
 
-  mImpl->mOperationsPending = ALL_OPERATIONS;
-  mImpl->mRecalculateNaturalSize = true;
-
   mImpl->RequestRelayout();
 }
 
@@ -371,9 +371,6 @@ void Controller::SetDefaultFontWeight( FontWeight weight )
   // Clear the font-specific data
   ClearFontData();
 
-  mImpl->mOperationsPending = ALL_OPERATIONS;
-  mImpl->mRecalculateNaturalSize = true;
-
   mImpl->RequestRelayout();
 }
 
@@ -400,9 +397,6 @@ void Controller::SetDefaultFontWidth( FontWidth width )
   // Clear the font-specific data
   ClearFontData();
 
-  mImpl->mOperationsPending = ALL_OPERATIONS;
-  mImpl->mRecalculateNaturalSize = true;
-
   mImpl->RequestRelayout();
 }
 
@@ -429,9 +423,6 @@ void Controller::SetDefaultFontSlant( FontSlant slant )
   // Clear the font-specific data
   ClearFontData();
 
-  mImpl->mOperationsPending = ALL_OPERATIONS;
-  mImpl->mRecalculateNaturalSize = true;
-
   mImpl->RequestRelayout();
 }
 
@@ -467,9 +458,6 @@ void Controller::SetDefaultPointSize( float pointSize )
   // Clear the font-specific data
   ClearFontData();
 
-  mImpl->mOperationsPending = ALL_OPERATIONS;
-  mImpl->mRecalculateNaturalSize = true;
-
   mImpl->RequestRelayout();
 }
 
@@ -490,11 +478,10 @@ void Controller::UpdateAfterFontChange( const std::string& newDefaultFont )
   if( !mImpl->mFontDefaults->familyDefined ) // If user defined font then should not update when system font changes
   {
     DALI_LOG_INFO( gLogFilter, Debug::Concise, "Controller::UpdateAfterFontChange newDefaultFont(%s)\n", newDefaultFont.c_str() );
-    ClearFontData();
     mImpl->mFontDefaults->mFontDescription.family = newDefaultFont;
-    mImpl->UpdateModel( ALL_OPERATIONS );
-    mImpl->QueueModifyEvent( ModifyEvent::TEXT_REPLACED );
-    mImpl->mRecalculateNaturalSize = true;
+
+    ClearFontData();
+
     mImpl->RequestRelayout();
   }
 }
@@ -516,7 +503,9 @@ const Vector4& Controller::GetTextColor() const
   return mImpl->mTextColor;
 }
 
-bool Controller::RemoveText( int cursorOffset, int numberOfCharacters )
+bool Controller::RemoveText( int cursorOffset,
+                             int numberOfCharacters,
+                             UpdateInputStyleType type )
 {
   bool removed = false;
 
@@ -555,13 +544,16 @@ bool Controller::RemoveText( int cursorOffset, int numberOfCharacters )
 
       // Update the input style and remove the text's style before removing the text.
 
-      // Set first the default input style.
-      mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
+      if( UPDATE_INPUT_STYLE == type )
+      {
+        // Set first the default input style.
+        mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle );
 
-      // Update the input style.
-      mImpl->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
+        // Update the input style.
+        mImpl->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle );
+      }
 
-      // Remove the text's style before removing the text.
+      // Updates the text style runs by removing characters. Runs with no characters are removed.
       mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfCharacters );
 
       // Remove the characters.
@@ -670,6 +662,7 @@ void Controller::SetInputColor( const Vector4& color )
   if( NULL != mImpl->mEventData )
   {
     mImpl->mEventData->mInputStyle.textColor = color;
+    mImpl->mEventData->mInputStyle.isDefaultColor = false;
 
     if( EventData::SELECTING == mImpl->mEventData->mState )
     {
@@ -691,6 +684,10 @@ void Controller::SetInputColor( const Vector4& color )
       // Request to relayout.
       mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending | COLOR );
       mImpl->RequestRelayout();
+
+      mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
     }
   }
 }
@@ -716,8 +713,12 @@ void Controller::SetInputFontFamily( const std::string& fontFamily )
 
     if( EventData::SELECTING == mImpl->mEventData->mState )
     {
+      CharacterIndex startOfSelectedText = 0u;
+      Length lengthOfSelectedText = 0u;
       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
-                                                                            mImpl->mLogicalModel );
+                                                                            mImpl->mLogicalModel,
+                                                                            startOfSelectedText,
+                                                                            lengthOfSelectedText );
 
       fontDescriptionRun.familyLength = fontFamily.size();
       fontDescriptionRun.familyName = new char[fontDescriptionRun.familyLength];
@@ -727,10 +728,21 @@ void Controller::SetInputFontFamily( const std::string& fontFamily )
       // The memory allocated for the font family name is freed when the font description is removed from the logical model.
 
       // Request to relayout.
-      mImpl->mOperationsPending = ALL_OPERATIONS;
+      mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                               VALIDATE_FONTS            |
+                                                               SHAPE_TEXT                |
+                                                               GET_GLYPH_METRICS         |
+                                                               LAYOUT                    |
+                                                               UPDATE_ACTUAL_SIZE        |
+                                                               REORDER                   |
+                                                               ALIGN );
       mImpl->mRecalculateNaturalSize = true;
       mImpl->RequestRelayout();
 
+      mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+
       // As the font changes, recalculate the handle positions is needed.
       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
       mImpl->mEventData->mUpdateRightSelectionPosition = true;
@@ -778,17 +790,32 @@ void Controller::SetInputFontWeight( FontWeight weight )
 
     if( EventData::SELECTING == mImpl->mEventData->mState )
     {
+      CharacterIndex startOfSelectedText = 0u;
+      Length lengthOfSelectedText = 0u;
       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
-                                                                            mImpl->mLogicalModel );
+                                                                            mImpl->mLogicalModel,
+                                                                            startOfSelectedText,
+                                                                            lengthOfSelectedText );
 
       fontDescriptionRun.weight = weight;
       fontDescriptionRun.weightDefined = true;
 
       // Request to relayout.
-      mImpl->mOperationsPending = ALL_OPERATIONS;
+      mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                               VALIDATE_FONTS            |
+                                                               SHAPE_TEXT                |
+                                                               GET_GLYPH_METRICS         |
+                                                               LAYOUT                    |
+                                                               UPDATE_ACTUAL_SIZE        |
+                                                               REORDER                   |
+                                                               ALIGN );
       mImpl->mRecalculateNaturalSize = true;
       mImpl->RequestRelayout();
 
+      mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+
       // As the font might change, recalculate the handle positions is needed.
       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
       mImpl->mEventData->mUpdateRightSelectionPosition = true;
@@ -816,17 +843,32 @@ void Controller::SetInputFontWidth( FontWidth width )
 
     if( EventData::SELECTING == mImpl->mEventData->mState )
     {
+      CharacterIndex startOfSelectedText = 0u;
+      Length lengthOfSelectedText = 0u;
       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
-                                                                            mImpl->mLogicalModel );
+                                                                            mImpl->mLogicalModel,
+                                                                            startOfSelectedText,
+                                                                            lengthOfSelectedText );
 
       fontDescriptionRun.width = width;
       fontDescriptionRun.widthDefined = true;
 
       // Request to relayout.
-      mImpl->mOperationsPending = ALL_OPERATIONS;
+      mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                               VALIDATE_FONTS            |
+                                                               SHAPE_TEXT                |
+                                                               GET_GLYPH_METRICS         |
+                                                               LAYOUT                    |
+                                                               UPDATE_ACTUAL_SIZE        |
+                                                               REORDER                   |
+                                                               ALIGN );
       mImpl->mRecalculateNaturalSize = true;
       mImpl->RequestRelayout();
 
+      mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+
       // As the font might change, recalculate the handle positions is needed.
       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
       mImpl->mEventData->mUpdateRightSelectionPosition = true;
@@ -854,17 +896,32 @@ void Controller::SetInputFontSlant( FontSlant slant )
 
     if( EventData::SELECTING == mImpl->mEventData->mState )
     {
+      CharacterIndex startOfSelectedText = 0u;
+      Length lengthOfSelectedText = 0u;
       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
-                                                                            mImpl->mLogicalModel );
+                                                                            mImpl->mLogicalModel,
+                                                                            startOfSelectedText,
+                                                                            lengthOfSelectedText );
 
       fontDescriptionRun.slant = slant;
       fontDescriptionRun.slantDefined = true;
 
       // Request to relayout.
-      mImpl->mOperationsPending = ALL_OPERATIONS;
+      mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                               VALIDATE_FONTS            |
+                                                               SHAPE_TEXT                |
+                                                               GET_GLYPH_METRICS         |
+                                                               LAYOUT                    |
+                                                               UPDATE_ACTUAL_SIZE        |
+                                                               REORDER                   |
+                                                               ALIGN );
       mImpl->mRecalculateNaturalSize = true;
       mImpl->RequestRelayout();
 
+      mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+
       // As the font might change, recalculate the handle positions is needed.
       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
       mImpl->mEventData->mUpdateRightSelectionPosition = true;
@@ -891,17 +948,32 @@ void Controller::SetInputFontPointSize( float size )
 
     if( EventData::SELECTING == mImpl->mEventData->mState )
     {
+      CharacterIndex startOfSelectedText = 0u;
+      Length lengthOfSelectedText = 0u;
       FontDescriptionRun& fontDescriptionRun = UpdateSelectionFontStyleRun( mImpl->mEventData,
-                                                                            mImpl->mLogicalModel );
+                                                                            mImpl->mLogicalModel,
+                                                                            startOfSelectedText,
+                                                                            lengthOfSelectedText );
 
       fontDescriptionRun.size = static_cast<PointSize26Dot6>( size * 64.f );
       fontDescriptionRun.sizeDefined = true;
 
       // Request to relayout.
-      mImpl->mOperationsPending = ALL_OPERATIONS;
+      mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                               VALIDATE_FONTS            |
+                                                               SHAPE_TEXT                |
+                                                               GET_GLYPH_METRICS         |
+                                                               LAYOUT                    |
+                                                               UPDATE_ACTUAL_SIZE        |
+                                                               REORDER                   |
+                                                               ALIGN );
       mImpl->mRecalculateNaturalSize = true;
       mImpl->RequestRelayout();
 
+      mImpl->mTextUpdateInfo.mCharacterIndex = startOfSelectedText;
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = lengthOfSelectedText;
+      mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = lengthOfSelectedText;
+
       // As the font might change, recalculate the handle positions is needed.
       mImpl->mEventData->mUpdateLeftSelectionPosition = true;
       mImpl->mEventData->mUpdateRightSelectionPosition = true;
@@ -1117,6 +1189,7 @@ bool Controller::Relayout( const Size& size )
 
     // Not worth to relayout if width or height is equal to zero.
     DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout (skipped)\n" );
+
     return glyphsRemoved;
   }
 
@@ -1139,21 +1212,16 @@ bool Controller::Relayout( const Size& size )
   }
 
   // Whether there are modify events.
-  const bool isModifyEventsEmpty = 0u == mImpl->mModifyEvents.Count();
-
-  // Make sure the model is up-to-date before layouting.
-  ProcessModifyEvents();
-  mImpl->UpdateModel( mImpl->mOperationsPending );
-
-  // Style operations that need to be done if the text is modified.
-  if( !isModifyEventsEmpty )
+  if( 0u != mImpl->mModifyEvents.Count() )
   {
+    // Style operations that need to be done if the text is modified.
     mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
                                                              COLOR );
   }
 
-  // Apply the style runs if text is modified.
-  bool updated = mImpl->UpdateModelStyle( mImpl->mOperationsPending );
+  // Make sure the model is up-to-date before layouting.
+  ProcessModifyEvents();
+  bool updated = mImpl->UpdateModel( mImpl->mOperationsPending );
 
   // Layout the text.
   Size layoutSize;
@@ -1194,8 +1262,8 @@ bool Controller::Relayout( const Size& size )
 
   // Clear the update info. This info will be set the next time the text is updated.
   mImpl->mTextUpdateInfo.Clear();
-
   DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::Relayout\n" );
+
   return updated;
 }
 
@@ -1463,9 +1531,7 @@ bool Controller::DoRelayout( const Size& size,
           //       It's better to refactor this. Store this table per line and don't update the indices.
           //       For the cursor position probably is better to use the function instead creating a table.
           // Set the bidirectional info into the model.
-          mImpl->mLogicalModel->SetVisualToLogicalMap( layoutParameters.lineBidirectionalInfoRunsBuffer,
-                                                       layoutParameters.numberOfBidirectionalInfoRuns,
-                                                       0u,
+          mImpl->mLogicalModel->SetVisualToLogicalMap( 0u,
                                                        mImpl->mLogicalModel->mText.Count() );
 
           // Re-layout the text. Reorder those lines with right to left characters.
@@ -1812,7 +1878,9 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
   {
     const CharacterIndex offset = mImpl->mEventData->mPrimaryCursorPosition - mImpl->mEventData->mPreEditStartPosition;
 
-    removedPrevious = RemoveText( -static_cast<int>( offset ), mImpl->mEventData->mPreEditLength );
+    removedPrevious = RemoveText( -static_cast<int>( offset ),
+                                  mImpl->mEventData->mPreEditLength,
+                                  DONT_UPDATE_INPUT_STYLE );
 
     mImpl->mEventData->mPrimaryCursorPosition = mImpl->mEventData->mPreEditStartPosition;
     mImpl->mEventData->mPreEditLength = 0u;
@@ -1891,10 +1959,11 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ
 
     // Retrieve the text's style for the given index.
     InputStyle style;
+    mImpl->RetrieveDefaultInputStyle( style );
     mImpl->mLogicalModel->RetrieveStyle( styleIndex, style );
 
     // Whether to add a new text color run.
-    const bool addColorRun = style.textColor != mImpl->mEventData->mInputStyle.textColor;
+    const bool addColorRun = ( style.textColor != mImpl->mEventData->mInputStyle.textColor );
 
     // Whether to add a new font run.
     const bool addFontNameRun = style.familyName != mImpl->mEventData->mInputStyle.familyName;
@@ -2381,7 +2450,9 @@ ImfManager::ImfCallbackData Controller::OnImfEvent( ImfManager& imfManager, cons
     }
     case ImfManager::DELETESURROUNDING:
     {
-      update = RemoveText( imfEvent.cursorOffset, imfEvent.numberOfChars );
+      update = RemoveText( imfEvent.cursorOffset,
+                           imfEvent.numberOfChars,
+                           DONT_UPDATE_INPUT_STYLE );
 
       if( update )
       {
@@ -2461,7 +2532,9 @@ bool Controller::BackspaceKeyEvent()
   else if( mImpl->mEventData->mPrimaryCursorPosition > 0 )
   {
     // Remove the character before the current cursor position
-    removed = RemoveText( -1, 1 );
+    removed = RemoveText( -1,
+                          1,
+                          UPDATE_INPUT_STYLE );
   }
 
   if( removed )
@@ -2579,15 +2652,24 @@ void Controller::ClearFontData()
   {
     mImpl->mFontDefaults->mFontId = 0u; // Remove old font ID
   }
-  mImpl->mLogicalModel->mFontRuns.Clear();
-  mImpl->mVisualModel->mGlyphs.Clear();
-  mImpl->mVisualModel->mGlyphsToCharacters.Clear();
-  mImpl->mVisualModel->mCharactersToGlyph.Clear();
-  mImpl->mVisualModel->mCharactersPerGlyph.Clear();
-  mImpl->mVisualModel->mGlyphsPerCharacter.Clear();
-  mImpl->mVisualModel->mGlyphPositions.Clear();
-  mImpl->mVisualModel->mLines.Clear();
-  mImpl->mVisualModel->ClearCaches();
+
+  // Set flags to update the model.
+  mImpl->mTextUpdateInfo.mCharacterIndex = 0u;
+  mImpl->mTextUpdateInfo.mNumberOfCharactersToRemove = mImpl->mTextUpdateInfo.mPreviousNumberOfCharacters;
+  mImpl->mTextUpdateInfo.mNumberOfCharactersToAdd = mImpl->mLogicalModel->mText.Count();
+
+  mImpl->mTextUpdateInfo.mClearAll = true;
+  mImpl->mTextUpdateInfo.mFullRelayoutNeeded = true;
+  mImpl->mRecalculateNaturalSize = true;
+
+  mImpl->mOperationsPending = static_cast<OperationsMask>( mImpl->mOperationsPending |
+                                                           VALIDATE_FONTS            |
+                                                           SHAPE_TEXT                |
+                                                           GET_GLYPH_METRICS         |
+                                                           LAYOUT                    |
+                                                           UPDATE_ACTUAL_SIZE        |
+                                                           REORDER                   |
+                                                           ALIGN );
 }
 
 void Controller::ClearStyleData()
index 546389c..6a83374 100644 (file)
@@ -99,6 +99,15 @@ public:
   };
 
   /**
+   * @brief Used to specify whether to update the input style.
+   */
+  enum UpdateInputStyleType
+  {
+    UPDATE_INPUT_STYLE,
+    DONT_UPDATE_INPUT_STYLE
+  };
+
+  /**
    * @brief Create a new instance of a Controller.
    *
    * @param[in] controlInterface An interface used to request a text relayout.
@@ -157,11 +166,18 @@ public:
   /**
    * @brief Remove a given number of characters
    *
+   * When predictve text is used the pre-edit text is removed and inserted again with the new characters.
+   * The UpdateInputStyleType @type parameter if set to DONT_UPDATE_INPUT_STYLE avoids to update the input
+   * style when pre-edit text is removed.
+   *
    * @param[in] cursorOffset Start position from the current cursor position to start deleting characters.
    * @param[in] numberOfCharacters The number of characters to delete from the cursorOffset.
+   * @param[in] type Whether to update the input style.
    * @return True if the remove was successful.
    */
-  bool RemoveText( int cursorOffset, int numberOfCharacters );
+  bool RemoveText( int cursorOffset,
+                   int numberOfCharacters,
+                   UpdateInputStyleType type  );
 
   /**
    * @brief Retrieve the current cursor position.
index 0e9fb3f..2884119 100644 (file)
@@ -60,6 +60,7 @@ typedef uint32_t                         BidirectionalRunIndex;     ///< An inde
 typedef uint32_t                         BidirectionalLineRunIndex; ///< An index into an array of bidirectional line info.
 typedef uint32_t                         LineIndex;                 ///< An index into an array of lines.
 typedef uint32_t                         ParagraphRunIndex;         ///< An index into an array of paragraphs.
+typedef uint32_t                         ColorIndex;                ///< An index into an array of colors.
 
 } // namespace Text
 
index c121f77..f5f1c49 100644 (file)
@@ -87,7 +87,6 @@ public:
    *
    * @param[out] glyphs Pointer to a buffer where the glyphs are copied.
    * @param[out] glyphPositions Pointer to a buffer where the glyph's positions are copied.
-   * @param[out] colors Pointer to a buffer where the glyph's colors are copied.
    * @param[in] glyphIndex Index to the first glyph.
    * @param[in] numberOfGlyphs Number of glyphs to be copied.
    *
@@ -95,11 +94,24 @@ public:
    */
   virtual Length GetGlyphs( GlyphInfo* glyphs,
                             Vector2* glyphPositions,
-                            Vector4* glyphColors,
                             GlyphIndex glyphIndex,
                             Length numberOfGlyphs ) const = 0;
 
   /**
+   * @brief Retrieves the vector of colors.
+   *
+   * @return Pointer to the vector of colors.
+   */
+  virtual const Vector4* const GetColors() const = 0;
+
+  /**
+   * @brief Retrieves the vector of indices to the vector of colors.
+   *
+   * @return Pointer to a vector which stores for each glyph the index to the vector of colors.
+   */
+  virtual const ColorIndex* const GetColorIndices() const = 0;
+
+  /**
    * @brief Retrieves the text color
    *
    * @return The text color
index 130c8af..be6ac8f 100644 (file)
@@ -94,7 +94,6 @@ Length View::GetNumberOfGlyphs() const
 
 Length View::GetGlyphs( GlyphInfo* glyphs,
                         Vector2* glyphPositions,
-                        Vector4* glyphColors,
                         GlyphIndex glyphIndex,
                         Length numberOfGlyphs ) const
 {
@@ -132,30 +131,6 @@ Length View::GetGlyphs( GlyphInfo* glyphs,
                                                 glyphIndex,
                                                 numberOfLaidOutGlyphs );
 
-        // Set the colors.
-        const GlyphIndex lastLaidOutGlyphIndex = glyphIndex + numberOfLaidOutGlyphs;
-
-        for( Vector<ColorGlyphRun>::ConstIterator it = mImpl->mVisualModel->mColorRuns.Begin(),
-               endIt = mImpl->mVisualModel->mColorRuns.End();
-             it != endIt;
-             ++it )
-        {
-          const ColorGlyphRun& colorGlyphRun = *it;
-          const GlyphIndex lastGlyphIndex = colorGlyphRun.glyphRun.glyphIndex + colorGlyphRun.glyphRun.numberOfGlyphs;
-
-          if( ( colorGlyphRun.glyphRun.glyphIndex < lastLaidOutGlyphIndex ) &&
-              ( glyphIndex < lastGlyphIndex ) )
-          {
-            for( GlyphIndex index = glyphIndex < colorGlyphRun.glyphRun.glyphIndex ? colorGlyphRun.glyphRun.glyphIndex : glyphIndex,
-                   endIndex = lastLaidOutGlyphIndex < lastGlyphIndex ? lastLaidOutGlyphIndex : lastGlyphIndex;
-                 index < endIndex;
-                 ++index )
-            {
-              *( glyphColors + index - glyphIndex ) = colorGlyphRun.color;
-            }
-          }
-        }
-
         // Get the lines for the given range of glyphs.
         // The lines contain the alignment offset which needs to be added to the glyph's position.
         LineIndex firstLine = 0u;
@@ -310,6 +285,26 @@ Length View::GetGlyphs( GlyphInfo* glyphs,
   return numberOfLaidOutGlyphs;
 }
 
+const Vector4* const View::GetColors() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->mColors.Begin();
+  }
+
+  return NULL;
+}
+
+const ColorIndex* const View::GetColorIndices() const
+{
+  if( mImpl->mVisualModel )
+  {
+    return mImpl->mVisualModel->mColorIndices.Begin();
+  }
+
+  return NULL;
+}
+
 const Vector4& View::GetTextColor() const
 {
   if( mImpl->mVisualModel )
index 0067f94..8ec9af1 100644 (file)
@@ -75,11 +75,20 @@ public:
    */
   virtual Length GetGlyphs( GlyphInfo* glyphs,
                             Vector2* glyphPositions,
-                            Vector4* glyphColors,
                             GlyphIndex glyphIndex,
                             Length numberOfGlyphs ) const;
 
   /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetColors()
+   */
+  virtual const Vector4* const GetColors() const;
+
+  /**
+   * @copydoc Dali::Toolkit::Text::ViewInterface::GetColorIndices()
+   */
+  virtual const ColorIndex* const GetColorIndices() const;
+
+  /**
    * @copydoc Dali::Toolkit::Text::ViewInterface::GetTextColor()
    */
   virtual const Vector4& GetTextColor() const;
index 5aa90af..88e3930 100644 (file)
@@ -310,7 +310,8 @@ public:
   Vector<Vector2>        mGlyphPositions;       ///< For each glyph, the position.
   Vector<LineRun>        mLines;                ///< The laid out lines.
   Vector<GlyphRun>       mUnderlineRuns;        ///< Runs of glyphs that are underlined.
-  Vector<ColorGlyphRun>  mColorRuns;            ///< Runs of glyphs with the same color.
+  Vector<Vector4>        mColors;               ///< Colors of the glyphs.
+  Vector<ColorIndex>     mColorIndices;         ///< Indices to the vector of colors for each glyphs.
 
   Vector2                mControlSize;           ///< The size of the UI control the decorator is adding it's decorations to.
   Vector4                mTextColor;            ///< The text color
index 25d1e1c..35319bf 100644 (file)
@@ -166,7 +166,7 @@ private:
 
   /**
    * Callback function of transition animation finished
-   * Hide transition layer, show current imageActor, and set isAnimating flag to false
+   * Hide transition layer, show current image, and set isAnimating flag to false
    * @param[in] source The cube transition animation
    */
   void OnTransitionFinished(Animation& source);
index 8d11252..79c1b80 100644 (file)
@@ -66,7 +66,7 @@ class Button;
  *
  * When the button is disabled, \e background, \e button and \e selected images are replaced by their \e disabled images.
  *
- * Is not mandatory set all images. A button could be defined only by setting its \e background image or by setting its \e background and \e selected images.
+ * Is not mandatory to set all images. A button could be defined only by setting its \e background image or by setting its \e background and \e selected images.
  *
  * Signals
  * | %Signal Name     | Method                      |
@@ -165,7 +165,11 @@ public:
    */
   ~Button();
 
+  // Deprecated API
+
   /**
+   * @DEPRECATED_1_1.32 Use SetProperty DISABLED or Styling file
+   *
    * @brief Sets the button as \e disabled.
    *
    * No signals are emitted when the \e disabled property is set.
@@ -176,6 +180,8 @@ public:
   void SetDisabled( bool disabled );
 
   /**
+   * @DEPRECATED_1_1.32 Use GetProperty DISABLED
+   *
    * @brief Returns if the button is disabled.
    * @SINCE_1_0.0
    * @return \e true if the button is \e disabled.
@@ -183,6 +189,8 @@ public:
   bool IsDisabled() const;
 
   /**
+   * @DEPRECATED_1_1.32 SetProperty AUTO_REPEATING or Styling file
+   *
    * @brief Sets the \e autorepeating property.
    *
    * If the \e autorepeating property is set to \e true, then the \e togglable property is set to false
@@ -194,6 +202,8 @@ public:
   void SetAutoRepeating( bool autoRepeating );
 
   /**
+   * @DEPRECATED_1_1.32 GetProperty AUTO_REPEATING
+   *
    * @brief Returns if the autorepeating property is set.
    * @SINCE_1_0.0
    * @return \e true if the \e autorepeating property is set.
@@ -201,6 +211,8 @@ public:
   bool IsAutoRepeating() const;
 
   /**
+   * @DEPRECATED_1_1.32 SetProperty INITIAL_AUTO_REPEATING_DELAY or Styling file
+   *
    * @brief Sets the initial autorepeating delay.
    *
    * By default this value is set to 0.15 seconds.
@@ -212,6 +224,8 @@ public:
   void SetInitialAutoRepeatingDelay( float initialAutoRepeatingDelay );
 
   /**
+   * @DEPRECATED_1_1.32 GetProperty INITIAL_AUTO_REPEATING_DELAY
+   *
    * @brief Gets the initial autorepeating delay in seconds.
    * @SINCE_1_0.0
    * @return the initial autorepeating delay in seconds.
@@ -219,6 +233,8 @@ public:
   float GetInitialAutoRepeatingDelay() const;
 
   /**
+   * @DEPRECATED_1_1.32 SetProperty NEXT_AUTO_REPEATING_DELAY or Styling file
+   *
    * @brief Sets the next autorepeating delay.
    *
    * By default this value is set to 0.05 seconds.
@@ -230,6 +246,8 @@ public:
   void SetNextAutoRepeatingDelay( float nextAutoRepeatingDelay );
 
   /**
+   * @DEPRECATED_1_1.32 GetProperty NEXT_AUTO_REPEATING_DELAY
+   *
    * @brief Gets the next autorepeating delay in seconds.
    * @SINCE_1_0.0
    * @return the next autorepeating delay in seconds.
@@ -237,6 +255,8 @@ public:
   float GetNextAutoRepeatingDelay() const;
 
   /**
+   * @DEPRECATED_1_1.32 SetProperty TOGGLABLE or Styling file
+   *
    * @brief Sets the \e togglable property.
    *
    * If the \e togglable property is set to \e true, then the \e autorepeating property is set to false.
@@ -247,6 +267,8 @@ public:
   void SetTogglableButton( bool togglable );
 
   /**
+   * @DEPRECATED_1_1.32 GetProperty TOGGLABLE
+   *
    * @brief Returns if the togglable property is set.
    * @SINCE_1_0.0
    * @return \e true if the \e togglable property is set.
@@ -254,6 +276,8 @@ public:
   bool IsTogglableButton() const;
 
   /**
+   * @DEPRECATED_1_1.32 SetProperty SELECTED
+   *
    * @brief Sets the button as selected or unselected.
    *
    * \e togglable property must be set to \e true.
@@ -266,6 +290,8 @@ public:
   void SetSelected( bool selected );
 
   /**
+   * DEPRECATED_1_1.32  SetProperty SELECTED
+   *
    * @brief Returns if the selected property is set and the button is togglable.
    * @SINCE_1_0.0
    * @return \e true if the button is \e selected.
@@ -273,6 +299,8 @@ public:
   bool IsSelected() const;
 
   /**
+   * @DEPRECATED_1_1.32 Use Styling file to set animation
+   *
    * @brief Sets the animation time.
    *
    * @SINCE_1_0.0
@@ -281,6 +309,8 @@ public:
   void SetAnimationTime( float animationTime );
 
   /**
+   * DEPRECATED_1_1.32 Use Styling file to set animation
+   *
    * @brief Retrieves button's animation time.
    *
    * @SINCE_1_0.0
@@ -289,6 +319,8 @@ public:
   float GetAnimationTime() const;
 
   /**
+   * @DEPRECATED_1_1.32 SetProperty LABEL or Styling file
+   *
    * @brief Sets the button's label.
    *
    * @SINCE_1_0.0
@@ -297,6 +329,8 @@ public:
   void SetLabelText( const std::string& label );
 
   /**
+   * DEPRECATED_1_1.32 GetProperty LABEL
+   *
    * @brief Gets the label.
    *
    * @SINCE_1_0.0
@@ -305,6 +339,8 @@ public:
   std::string GetLabelText() const;
 
   /**
+   * @DEPRECATED_1_1.32 Use Styling file
+   *
    * @brief Sets the unselected button image.
    *
    * @SINCE_1_0.0
@@ -313,6 +349,8 @@ public:
   void SetUnselectedImage( const std::string& filename );
 
   /**
+   * @DEPRECATED_1_1.32 Use styling
+   *
    * @brief Sets the background image.
    *
    * @SINCE_1_0.0
@@ -321,6 +359,8 @@ public:
   void SetBackgroundImage( const std::string& filename );
 
   /**
+   * @DEPRECATED_1_1.32 Use styling file
+   *
    * @brief Sets the selected image.
    *
    * @SINCE_1_0.0
@@ -329,6 +369,8 @@ public:
   void SetSelectedImage( const std::string& filename );
 
   /**
+   * @DEPRECATED_1_1.32 Use styling file
+   *
    * @brief Sets the selected background image.
    *
    * @SINCE_1_0.0
@@ -337,6 +379,8 @@ public:
   void SetSelectedBackgroundImage( const std::string& filename );
 
   /**
+   * @DEPRECATED_1_1.32 Use styling file
+   *
    * @brief Sets the disabled background image.
    *
    * @SINCE_1_0.0
@@ -345,6 +389,8 @@ public:
   void SetDisabledBackgroundImage( const std::string& filename );
 
   /**
+   * @DEPRECATED_1_1.32 Use styling file
+   *
    * @brief Sets the disabled button image.
    *
    * @SINCE_1_0.0
@@ -353,6 +399,8 @@ public:
   void SetDisabledImage( const std::string& filename );
 
   /**
+   * @DEPRECATED_1_1.32 Use styling file
+   *
    * @brief Sets the disabled selected button image.
    *
    * @SINCE_1_0.0
@@ -360,8 +408,6 @@ public:
    */
   void SetDisabledSelectedImage( const std::string& filename );
 
-  // Deprecated API
-
   /**
    * @DEPRECATED_1_0.50. Instead, use SetLabelText.
    *
index 841e3d3..45fbe44 100644 (file)
 // INTERNAL INCLUDES
 #include <dali-toolkit/public-api/focus-manager/keyboard-focus-manager.h>
 #include <dali-toolkit/public-api/controls/control.h>
+#include <dali-toolkit/public-api/styling/style-manager.h>
 #include <dali-toolkit/devel-api/controls/control-depth-index-ranges.h>
 #include <dali-toolkit/devel-api/controls/renderer-factory/renderer-factory.h>
 #include <dali-toolkit/devel-api/focus-manager/keyinput-focus-manager.h>
-#include <dali-toolkit/devel-api/styling/style-manager.h>
 #include <dali-toolkit/internal/styling/style-manager-impl.h>
 #include <dali-toolkit/internal/controls/renderers/color/color-renderer.h>
 
@@ -674,12 +674,12 @@ Toolkit::Control::KeyEventSignalType& Control::KeyEventSignal()
   return mImpl->mKeyEventSignal;
 }
 
-Toolkit::Control::KeyInputFocusSignalType& Control:: KeyInputFocusGainedSignal()
+Toolkit::Control::KeyInputFocusSignalType& Control::KeyInputFocusGainedSignal()
 {
   return mImpl->mKeyInputFocusGainedSignal;
 }
 
-Toolkit::Control::KeyInputFocusSignalType& Control:: KeyInputFocusLostSignal()
+Toolkit::Control::KeyInputFocusSignalType& Control::KeyInputFocusLostSignal()
 {
   return mImpl->mKeyInputFocusLostSignal;
 }
@@ -720,15 +720,18 @@ void Control::Initialize()
 
   if( mImpl->mFlags & REQUIRES_STYLE_CHANGE_SIGNALS )
   {
-    Toolkit::StyleManager styleManager = Toolkit::StyleManager::Get();
+    Toolkit::StyleManager styleManager = StyleManager::Get();
+
     // if stylemanager is available
     if( styleManager )
     {
+      StyleManager& styleManagerImpl = GetImpl( styleManager );
+
       // Register for style changes
-      styleManager.StyleChangeSignal().Connect( this, &Control::OnStyleChange );
+      styleManagerImpl.ControlStyleChangeSignal().Connect( this, &Control::OnStyleChange );
 
       // Apply the current style
-      GetImpl( styleManager ).ApplyThemeStyleAtInit( Toolkit::Control( GetOwner() ) );
+      styleManagerImpl.ApplyThemeStyleAtInit( Toolkit::Control( GetOwner() ) );
     }
   }
 
index 3333289..2726af5 100644 (file)
@@ -101,7 +101,7 @@ void ImageView::SetImage( const std::string& url, ImageDimensions size )
 
 Image ImageView::GetImage() const
 {
-  return Image();
+  return Dali::Toolkit::GetImpl( *this ).GetImage();
 }
 
 ImageView::ImageView( Internal::ImageView& implementation )
index 370579a..14e3427 100644 (file)
@@ -40,13 +40,17 @@ class ImageView;
  */
 
 /**
- * @brief ImageView is a class for displaying an Image.
+ * @brief ImageView is a class for displaying an image resource.
+ *
+ * An instance of ImageView can be created using a URL or an Image instance.
+ *
  * @SINCE_1_0.0
  *
  */
 class DALI_IMPORT_API ImageView : public Control
 {
 public:
+
   /**
    * @brief The start and end property ranges for this control.
    * @SINCE_1_0.0
@@ -76,11 +80,13 @@ public:
        * @SINCE_1_0.0
        */
       RESOURCE_URL = PROPERTY_START_INDEX,
+
       /**
        * @brief name "image", type string if it is a url, map otherwise
        * @SINCE_1_0.0
        */
       IMAGE,
+
       /**
        * @brief name "preMultipliedAlpha", type Boolean
        * @SINCE_1_1.18
@@ -90,7 +96,6 @@ public:
 
       // Animatable properties
 
-
       /**
        * @brief name "pixelArea", type Vector4
        * @details Pixel area is a relative value with the whole image area as [0.0, 0.0, 1.0, 1.0].
@@ -119,18 +124,18 @@ public:
   static ImageView New();
 
   /**
-   * @brief Create an initialized ImageView from an Image.
+   * @brief Create an initialized ImageView from an Image instance.
    *
    * If the handle is empty, ImageView will not display anything.
    *
    * @SINCE_1_0.0
-   * @param[in] image The Image to display.
+   * @param[in] image The Image instance to display.
    * @return A handle to a newly allocated ImageView.
    */
   static ImageView New( Image image );
 
   /**
-   * @brief Create an initialized ImageView from an Image resource URL
+   * @brief Create an initialized ImageView from an URL to an image resource.
    *
    * If the string is empty, ImageView will not display anything.
    *
@@ -141,13 +146,13 @@ public:
   static ImageView New( const std::string& url );
 
   /**
-   * @brief Create an initialized ImageView from an Image resource URL
+   * @brief Create an initialized ImageView from a URL to an image resource.
    *
    * If the string is empty, ImageView will not display anything.
    *
    * @SINCE_1_1.10
    * @param[in] url The url of the image resource to display.
-   * @param [in] size The width and height to fit the loaded image to.
+   * @param [in] size The width and height to which to fit the loaded image.
    * @return A handle to a newly allocated ImageView.
    *
    * @note A valid size is preferable for efficiency.
@@ -194,42 +199,43 @@ public:
   static ImageView DownCast( BaseHandle handle );
 
   /**
-   * @brief Sets this ImageView from an Image
+   * @brief Sets this ImageView from an Image instance.
    *
    * If the handle is empty, ImageView will display nothing
    * @SINCE_1_0.0
-   * @param[in] image The Image to display.
+   * @param[in] image The Image instance to display.
    */
   void SetImage( Image image );
 
   /**
-   * @brief Sets this ImageView from an Image URL
+   * @brief Sets this ImageView from the given URL.
    *
    * If the URL is empty, ImageView will not display anything.
    *
    * @SINCE_1_1.4
-   * @param[in] url The Image resource to display.
+   * @param[in] url The URL to the image resource to display.
    */
   void SetImage( const std::string& url );
 
   /**
-   * @brief Sets this ImageView from an Image URL
+   * @brief Sets this ImageView from the given URL.
    *
    * If the URL is empty, ImageView will not display anything.
    *
    * @SINCE_1_1.10
-   * @param[in] url A URL to the image resource to display.
+   * @param[in] url The URL to the image resource to display.
    * @param [in] size The width and height to fit the loaded image to.
    */
   void SetImage( const std::string& url, ImageDimensions size );
 
   /**
    * @DEPRECATED_1_1.4
-   * @brief Gets the Image
+   * @brief Gets the Image instance handle used by the ImageView.
+   *
+   * A valid handle will be returned only if this instance was created with New(Image) or SetImage(Image) was called.
    *
    * @SINCE_1_0.0
-   * @remarks Calls to this method should be avoided as this may return an empty handle if the image has not been created yet.
-   * @return The Image currently set to this ImageView
+   * @return The Image instance currently used by the ImageView.
    */
   Image GetImage() const;
 
index 9f3db3b..94257ee 100644 (file)
@@ -69,11 +69,11 @@ class TableView;
  *
  * @code
  * "name":"gallery1",
- * "type":"ImageActor",
+ * "type":"ImageView",
  * "image": {
- *    "filename": "{DALI_IMAGE_DIR}gallery-small-1.jpg"
+ *    "url": "{DALI_IMAGE_DIR}gallery-small-1.jpg"
  *  },
- *  "customProperties": {
+ *  "properties": {
  *     "cellIndex":[1,1],  // property to specify the top-left cell this child occupies, if not set, the first available cell is used
  *     "rowSpan":3,        // property to specify how many rows this child occupies, if not set, default value is 1
  *     "columnSpan": 2,    // property to specify how many columns this child occupies, if nor set, default value is 1
index f0197f0..bf1d3b1 100644 (file)
@@ -31,7 +31,7 @@ namespace Toolkit
 
 const unsigned int TOOLKIT_MAJOR_VERSION = 1;
 const unsigned int TOOLKIT_MINOR_VERSION = 1;
-const unsigned int TOOLKIT_MICRO_VERSION = 31;
+const unsigned int TOOLKIT_MICRO_VERSION = 32;
 const char * const TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 73d06a4..16d923f 100755 (executable)
@@ -27,6 +27,7 @@ public_api_src_files = \
   $(public_api_src_dir)/controls/text-controls/text-label.cpp \
   $(public_api_src_dir)/controls/text-controls/text-field.cpp \
   $(public_api_src_dir)/controls/gaussian-blur-view/gaussian-blur-view.cpp \
+  $(public_api_src_dir)/styling/style-manager.cpp \
   $(public_api_src_dir)/accessibility-manager/accessibility-manager.cpp \
   $(public_api_src_dir)/focus-manager/keyboard-focus-manager.cpp \
   $(public_api_src_dir)/dali-toolkit-version.cpp \
@@ -88,6 +89,9 @@ public_api_scroll_view_header_files = \
   $(public_api_src_dir)/controls/scrollable/scroll-view/scroll-view-page-path-effect.h \
   $(public_api_src_dir)/controls/scrollable/scroll-view/scroll-view.h
 
+public_api_styling_header_files = \
+  $(public_api_src_dir)/styling/style-manager.h
+
 public_api_table_view_header_files = \
   $(public_api_src_dir)/controls/table-view/table-view.h
 
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,7 +16,7 @@
 
 // CLASS HEADER
 
-#include <dali-toolkit/devel-api/styling/style-manager.h>
+#include <dali-toolkit/public-api/styling/style-manager.h>
 
 // EXTERNAL INCLUDES
 
@@ -43,29 +43,14 @@ StyleManager StyleManager::Get()
   return Internal::StyleManager::Get();
 }
 
-void StyleManager::SetOrientationValue( int orientation )
+void StyleManager::ApplyTheme( const std::string& themeFile )
 {
-  GetImpl(*this).SetOrientationValue( orientation );
+  GetImpl(*this).ApplyTheme( themeFile );
 }
 
-int StyleManager::GetOrientationValue()
+void StyleManager::ApplyDefaultTheme()
 {
-  return GetImpl(*this).GetOrientationValue();
-}
-
-void StyleManager::SetOrientation( Orientation orientation )
-{
-  GetImpl(*this).SetOrientation( orientation );
-}
-
-std::string StyleManager::GetDefaultFontFamily() const
-{
-  return GetImpl(*this).GetDefaultFontFamily();
-}
-
-Orientation StyleManager::GetOrientation()
-{
-  return GetImpl(*this).GetOrientation();
+  GetImpl(*this).ApplyDefaultTheme();
 }
 
 void StyleManager::SetStyleConstant( const std::string& key, const Property::Value& value )
@@ -83,27 +68,16 @@ void StyleManager::ApplyStyle( Toolkit::Control control, const std::string& json
   GetImpl(*this).ApplyStyle( control, jsonFileName, styleName );
 }
 
-StyleManager::StyleManager( Internal::StyleManager *impl )
-  : BaseHandle( impl )
-{
-}
-
-StyleManager::StyleChangeSignalType& StyleManager::StyleChangeSignal()
-{
-  return GetImpl( *this ).StyleChangeSignal();
-}
-
-void StyleManager::RequestThemeChange( const std::string& themeFile )
+StyleManager::StyleChangedSignalType& StyleManager::StyleChangedSignal()
 {
-  GetImpl(*this).RequestThemeChange( themeFile );
+  return GetImpl( *this ).StyleChangedSignal();
 }
 
-void StyleManager::RequestDefaultTheme()
+StyleManager::StyleManager( Internal::StyleManager *impl )
+  : BaseHandle( impl )
 {
-  GetImpl(*this).RequestDefaultTheme();
 }
 
 } // namespace Toolkit
 
 } // namespace Dali
-
@@ -2,7 +2,7 @@
 #define __DALI_TOOLKIT_STYLE_MANAGER_H__
 
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@
  */
 
 // EXTERNAL INCLUDES
-#include <dali/devel-api/adaptor-framework/orientation.h>
 #include <dali/public-api/adaptor-framework/style-change.h>
 
 // INTERNAL INCLUDES
@@ -36,39 +35,43 @@ class StyleManager;
 }
 
 /**
- * @brief StyleManager provides the following functionalities:
+ * @addtogroup dali_toolkit_managers
+ * @{
+ */
+
+/**
+ * @brief StyleManager informs applications of system theme change,
+ * and supports application theme change at runtime.
  *
  * Applies various styles to Controls using the properties system.
- * On theme change a signal is raised that controls can be configured to listen to.
  *
- * The default theme is automatically loaded and applied.
+ * On theme change, it automatically updates all controls, then raises
+ * a signal to inform the application.
  *
- * If the application wants to customize the theme, RequestThemeChange needs to be called.
- * Also, the default orientation is Portrait, if the application wants to adapt to the orientation change, call SetOrientation or SetOrienationValue.
- * @code
- *   const char* CUSTOM_THEME = DALI_SCRIPT_DIR "tizen-dark-theme.json";
+ * The default theme is automatically loaded and applied, followed by
+ * any application specific theme defined in Application::New().
  *
- *   void OnInit(Application& app)
- *   {
- *      Toolkit::StyleManager::Get().RequestThemeChange( CUSTOM_THEME );
- *      Toolkit::StyleManager::Get().SetOrientation( ... );
- *      ...
- *   }
- * @endcode
+ * If the application wants to customize the theme, RequestThemeChange
+ * needs to be called.
  *
- * Internal::Control can be configured to register for the signals that are required from StyleManager,
- * such as theme change.
+ * Signals
+ * | %Signal Name            | Method                           |
+ * |------------------------------------------------------------|
+ * | styleChanged            | @ref StyleChangedSignal()        |
+ * @SINCE_1_1.32
  */
 class DALI_IMPORT_API StyleManager : public BaseHandle
 {
 public:
 
-  // Signals
-  typedef Signal< void ( StyleManager, StyleChange::Type ) >  StyleChangeSignalType;
+  /// @brief Style Changed signal. Emitted after controls have been updated
+  typedef Signal< void ( StyleManager, StyleChange::Type ) >  StyleChangedSignalType;
 
   /**
    * @brief Create a StyleManager handle; this can be initialised with StyleManager::Get()
+   *
    * Calling member functions with an uninitialised handle is not allowed.
+   * @SINCE_1_1.32
    */
   StyleManager();
 
@@ -76,71 +79,54 @@ public:
    * @brief Destructor
    *
    * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_1.32
    */
   ~StyleManager();
 
   /**
    * @brief Get the singleton of StyleManager object.
    *
+   * @SINCE_1_1.32
    * @return A handle to the StyleManager control.
    */
   static StyleManager Get();
 
   /**
-   * @brief Specify the orientation value directly for the style manager
-   *
-   * @param[in] orientation The orientation in degrees
-   */
-  void SetOrientationValue( int orientation );
-
-  /**
-   * @brief Return the orientation value
+   * @brief Apply a new theme to the application. This will be merged
+   * on top of the default Toolkit theme.
    *
-   * @return The orientation value
-   */
-  int GetOrientationValue();
-
-  /**
-   * @brief Set the orientation object. This will take precedence over setting the orientation value.
+   * If the application theme file doesn't style all controls that the
+   * application uses, then the default Toolkit theme will be used
+   * instead for those controls.
    *
-   * @param[in] orientation Device orientation
-   */
-  void SetOrientation( Orientation orientation );
-
-  /**
-   * @brief Return the orientation object
+   * On application startup, it is suggested that the theme file name is
+   * passed to Application::New instead of using this API to prevent
+   * controls being styled more than once.
+   * @sa Application::New()
    *
-   * @return The orientation.
-   */
-  Orientation GetOrientation();
-
-  /**
-   * @brief Retrieves the default font family.
-   * @return The default font family.
+   * @SINCE_1_1.32
+   * @param[in] themeFile If a relative path is specified, then this is relative
+   * to the directory returned by app_get_resource_path().
    */
-  std::string GetDefaultFontFamily() const;
+  void ApplyTheme( const std::string& themeFile );
 
   /**
-   * @brief Make a request to set the theme JSON file to one that exists in the Toolkit package.
+   * @brief Apply the default Toolkit theme.
    *
-   * Multiple requests per event processing cycle can be made, but only the final one will be acted
-   * on in the event processing finished callback.
+   * Request that any application specific styling is removed
+   * and that the default Toolkit theme is re-applied.
    *
-   * @param[in] themeFile This is just the JSON theme file name and not the full path.
-   */
-  void RequestThemeChange( const std::string& themeFile );
-
-  /**
-   * @brief Request a change to the default theme
+   * @SINCE_1_1.32
    */
-  void RequestDefaultTheme();
+  void ApplyDefaultTheme();
 
   /**
    * @brief Set a constant for use when building styles
    *
-   * A constant is used in JSON files e.g. "myImage":"{ROOT_PATH}/mypath/image.jpg"
-   * where the string "{ROOT_PATH}" is substituted with the value.
+   * A constant is used in JSON files e.g. "myImage":"{RELATIVE_PATH}/image.jpg"
+   * where the string "{RELATIVE_PATH}" is substituted with the value.
    *
+   * @SINCE_1_1.32
    * @param[in] key The key of the constant
    * @param[in] value The value of the constant
    */
@@ -149,6 +135,7 @@ public:
   /**
    * @brief Return the style constant set for a specific key
    *
+   * @SINCE_1_1.32
    * @param[in] key The key of the constant
    * @param[out] valueOut The value of the constant if it exists
    *
@@ -159,11 +146,11 @@ public:
   /**
    * @brief Apply the specified style to the control.
    *
-   * The JSON file will be cached and subsequent calls using the same JSON file name will
-   * use the already loaded cached values instead.
-   *
-   * @param[in] control The control to apply style.
-   * @param[in] jsonFileName The name of the JSON style file to apply.
+   * @SINCE_1_1.32
+   * @param[in] control The control to which to apply the style.
+   * @param[in] jsonFileName The name of the JSON style file to apply. If a
+   * relative path is specified, then this is relative to the directory
+   * returned by app_get_resource_path().
    * @param[in] styleName The name of the style within the JSON file to apply.
    */
   void ApplyStyle( Toolkit::Control control, const std::string& jsonFileName, const std::string& styleName );
@@ -171,26 +158,34 @@ public:
 public: // Signals
 
   /**
-   * @brief This signal is emitted whenever the style (e.g. theme/font change) is changed on device
+   * @brief This signal is emitted after the style (e.g. theme/font change) has changed
+   * and the controls have been informed.
+   *
+   * @SINCE_1_1.32
    * A callback of the following type may be connected:
    * @code
    *   void YourCallbackName( StyleManager styleManager, StyleChange change );
    * @endcode
    * @return The signal to connect to.
    */
-  StyleChangeSignalType& StyleChangeSignal();
+  StyleChangedSignalType& StyleChangedSignal();
 
 public:
 
   /**
-   * @brief Creates a new handle from the implementation.
+   * @brief Allows the creation of a StyleManager handle from an internal pointer.
    *
+   * @note Not intended for application developers
+   * @SINCE_1_1.32
    * @param[in] impl A pointer to the object.
    */
   explicit DALI_INTERNAL StyleManager( Internal::StyleManager *impl );
 
 }; // class StyleManager
 
+/**
+ * @}
+ */
 } // namespace Toolkit
 
 } // namespace Dali
index 46ee52d..4ecc335 100644 (file)
@@ -94,8 +94,8 @@
       "popupIconColor":[1.0,1.0,1.0,1.0],
       "popupPressedColor":[0.24,0.72,0.8,0.11],
       "background": {
-        "rendererType": "nPatch",
-        "imageUrl": "{DALI_IMAGE_DIR}selection-popup-bg.9.png"
+        "rendererType": "image",
+        "url": "{DALI_IMAGE_DIR}selection-popup-bg.9.png"
         },
       "popupFadeInDuration":0.25,
       "popupFadeOutDuration":0.25
index 26b3c80..ffe9326 100644 (file)
@@ -94,8 +94,8 @@
       "popupIconColor":[1.0,1.0,1.0,1.0],
       "popupPressedColor":[0.24,0.72,0.8,0.11],
       "background": {
-        "rendererType": "nPatch",
-        "imageUrl": "{DALI_IMAGE_DIR}selection-popup-bg.9.png"
+        "rendererType": "image",
+        "url": "{DALI_IMAGE_DIR}selection-popup-bg.9.png"
         },
       "popupFadeInDuration":0.25,
       "popupFadeOutDuration":0.25
index 784cb4d..d390f9a 100644 (file)
  *     @defgroup dali_toolkit_controls_text_controls Text Controls
  *     @brief Controls for displaying text or text input.
 
+ *     @defgroup dali_toolkit_controls_flex_container Flex Container
+ *     @brief FlexContainer is a container for Flexbox layout.
+
  *   @}
 
  *   @defgroup dali_toolkit_managers Managers
index dcbb47f..d0f8923 100644 (file)
@@ -67,9 +67,9 @@ public:
     // Set another property to set the image-map
     Property::Map imageMap;
     imageMap[ "rendererType" ] = "image";
-    imageMap[ "imageUrl" ]     = IMAGE_CARDS;
-    imageMap[ "width" ]        = 100;
-    imageMap[ "height" ]       = 100;
+    imageMap[ "url" ]          = IMAGE_CARDS;
+    imageMap[ "desiredWidth" ]        = 100;
+    imageMap[ "desiredHeight" ]       = 100;
     mImageView.SetProperty( ImageView::Property::IMAGE, imageMap );
 
     // Add the image view to the stage
diff --git a/docs/content/images/texture-atlas/atlas-size.jpg b/docs/content/images/texture-atlas/atlas-size.jpg
deleted file mode 100644 (file)
index 084278d..0000000
Binary files a/docs/content/images/texture-atlas/atlas-size.jpg and /dev/null differ
diff --git a/docs/content/images/texture-atlas/atlas.jpg b/docs/content/images/texture-atlas/atlas.jpg
deleted file mode 100644 (file)
index d2e03b2..0000000
Binary files a/docs/content/images/texture-atlas/atlas.jpg and /dev/null differ
diff --git a/docs/content/images/texture-atlas/compression-example.jpg b/docs/content/images/texture-atlas/compression-example.jpg
deleted file mode 100644 (file)
index 474c572..0000000
Binary files a/docs/content/images/texture-atlas/compression-example.jpg and /dev/null differ
diff --git a/docs/content/images/texture-atlas/compression-options.jpg b/docs/content/images/texture-atlas/compression-options.jpg
deleted file mode 100644 (file)
index 1540315..0000000
Binary files a/docs/content/images/texture-atlas/compression-options.jpg and /dev/null differ
diff --git a/docs/content/images/texture-atlas/example-code.jpg b/docs/content/images/texture-atlas/example-code.jpg
deleted file mode 100644 (file)
index 4e2b576..0000000
Binary files a/docs/content/images/texture-atlas/example-code.jpg and /dev/null differ
diff --git a/docs/content/images/texture-atlas/example-javascript-code.jpg b/docs/content/images/texture-atlas/example-javascript-code.jpg
deleted file mode 100644 (file)
index a4f0805..0000000
Binary files a/docs/content/images/texture-atlas/example-javascript-code.jpg and /dev/null differ
diff --git a/docs/content/images/texture-atlas/image-wall.jpg b/docs/content/images/texture-atlas/image-wall.jpg
deleted file mode 100644 (file)
index f06d258..0000000
Binary files a/docs/content/images/texture-atlas/image-wall.jpg and /dev/null differ
diff --git a/docs/content/images/texture-atlas/texture-packer-add-sprites.jpg b/docs/content/images/texture-atlas/texture-packer-add-sprites.jpg
deleted file mode 100644 (file)
index 67b65e7..0000000
Binary files a/docs/content/images/texture-atlas/texture-packer-add-sprites.jpg and /dev/null differ
diff --git a/docs/content/images/texture-atlas/texture-packer-preferences.jpg b/docs/content/images/texture-atlas/texture-packer-preferences.jpg
deleted file mode 100644 (file)
index fa0b067..0000000
Binary files a/docs/content/images/texture-atlas/texture-packer-preferences.jpg and /dev/null differ
diff --git a/docs/content/images/texture-atlas/texture-packer-publish.jpg b/docs/content/images/texture-atlas/texture-packer-publish.jpg
deleted file mode 100644 (file)
index e1564b0..0000000
Binary files a/docs/content/images/texture-atlas/texture-packer-publish.jpg and /dev/null differ
diff --git a/docs/content/images/texture-atlas/texture-packer-startup.jpg b/docs/content/images/texture-atlas/texture-packer-startup.jpg
deleted file mode 100644 (file)
index 5ed29b5..0000000
Binary files a/docs/content/images/texture-atlas/texture-packer-startup.jpg and /dev/null differ
index 41354e0..3cea028 100644 (file)
@@ -30,8 +30,6 @@
   + [Positioning](@ref positioning-actors)
   + [Event Handling](@ref event-system)
   + [Layouting](@ref size-negotiation)
-  + [Image Actor](@ref image-actor)
-  + [Image View](@ref image-view)
  + [Animation](@ref animation)
   + [Basic Framework](@ref animation-basics)
   + [Key Frame Animations](@ref animation-key-frame)
@@ -56,6 +54,7 @@
 
 ### UI Components
  + Buttons
+ + [ImageView](@ref image-view)
  + [ItemView](@ref item-view)
  + [Popup](@ref popup)
  + [Scroll View](@ref scroll-view)
@@ -93,8 +92,6 @@
  + [JavaScript Wrapping Guide for DALi developers](@ref javascriptwrapping)
 
 ### Application Optimization Guide
- + [Texture Atlases](@ref textureatlases)
- + [Texture Compression](@ref texturecompression)
  + [Rescaling Images](@ref resourceimagescaling)
  + Performance & Debugging
  + [Performance Tips](@ref performancetips)
index 6bd8a9b..05be5f1 100644 (file)
@@ -51,9 +51,8 @@ A common example is when an actor is added to a container with Dali::Actor::Add(
 // At this point we own a Dali::Actor named "container"
 // Enter a code block
 {
-  // Create an image actor
-  Image img = Image::New(SomeImageFile);
-  Actor actor = ImageActor::New(img);
+  // Create an image view
+  Actor actor = Toolkit::ImageView::New(SomeImageFile);
 
   // Add the image actor to a container
   container.Add(actor);
diff --git a/docs/content/programming-guide/image-actor.h b/docs/content/programming-guide/image-actor.h
deleted file mode 100644 (file)
index b528ef1..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*! \page image-actor Image Actors
- *
- *
- * <h1 class="pg">Overview</h1>
- * The Dali::ImageActor inherits from Dali::Actor and provide means to display resources like Images on the stage.
- * All the Dali::Actor methods can be called on them.<br>
- *
- * - <b>ImageActor:</b> An actor for displaying Images. It allows the developer to display a Dali::Image object on the stage.<br>
- *
- * <h1 class="pg">Image Actor</h1>
- *
- * <h2 class="pg">Construction</h2>
- * The Image Actor is constructed by passing a Dali::Image object.
- * Dali::Image is an abstract base class with multiple derived classes.
- * Dali::ResourceImage is used for the common case of loading an image
- * from a file.
- *
- * @code
- * Dali::Image image = ResourceImage::New( myImageFilename );
- * Dali::ImageActor myImageActor = ImageActor::New( image );
- * @endcode
- *
- * <h3 class="pg">Resizing at Load Time</h3>
- * An application loading images from an external source will often want to
- * display those images at a lower resolution than their native ones.
- * To support this, DALi can resize an image at load time so that its
- * in-memory copy uses less space and its visual quality benefits from being
- * prefiltered.
- * There are four algorithms which can be used to fit an image to a desired
- * rectangle, a desired width or a desired height
- * (see Dali::FittingMode).
- *
- * Here is an example doing rescaling:
- *
- * @code
- * Dali::Image image = Dali::ResourceImage::New( filename, ImageDimensions( 240, 240 ), FittingMode::SCALE_TO_FILL );
- * @endcode
- *
- * This example sets the size and fitting mode appropriately for a large thumbnail
- * during Dali::ResourceImage construction.
- * In general, to enable scaling on load, pass a non-zero width or height and
- * one of the four fitting modes to the Dali::ResourceImage creator function
- * as shown above.
- *
- * The fitting modes and a suggested use-case for each are as follows:
- * <ol>
- *   <li> Dali::FittingMode::SHRINK_TO_FIT Full-screen image display: Limit loaded image resolution to device resolution but show all of image.
- *   <li> Dali::FittingMode::SCALE_TO_FILL Thumbnail gallery grid: Limit loaded image resolution to screen tile, filling whole tile but losing a few pixels to match the tile shape.
- *   <li> Dali::FittingMode::FIT_WIDTH Image columns: Limit loaded image resolution to column.
- *   <li> Dali::FittingMode::FIT_HEIGHT Image rows: Limit loaded image resolution to row height.
- * </ol>
- *
- * The dali-demo project contains a full example under
- * <code>examples/image-scaling-and-filtering</code>
- * and a specific sampling mode example under
- * <code>examples/image-scaling-irregular-grid</code>.
- *
- * There are more details on this topic in the
- * \link resourceimagescaling Rescaling Images \endlink
- * section.
- *
- * <h2 class="pg">Style</h2>
- * The Actor can render an image in only as a quad. Use ImageView for nine-patch/n-patch image rendering.<br>
- * -# STYLE_QUAD: A simple flat quad style for rendering images.<br>
- * -# STYLE_NINE_PATCH: This is deprecated as of Dali 1.1.11. 
- *
- * <h2 class="pg">Pixel area</h2>
- * The area of the image to be displayed by the Image Actor can be set by setting the Pixel area. Pixel area is relative to the top-left (0,0) of the image.
- * @code
- * Rect<int> pixel1( myX, myY, myWidth, myHeight );
- * if(!myImageActor.IsPixelAreaSet())
- * {
- *   myImageActor.SetPixelArea( pixel1 );
- * }
- *
- * //Removes the pixel are set
- * myImageActor.ClearPixelArea();
- * @endcode
- *
- *
- * <h2 class="pg">Changing the image</h2>
- * The Image Actor needs a reference to a Dali::Image object on creation. However the Image object can be later changed by calling DaliActor:SetImage
- * @code
- * myImageActor.SetImage( newImage );
- * @endcode
- *
- */
index 63a1030..9b18dfc 100644 (file)
  *
  * @code
  * Property::Map imageProperty;
- * imageProperty.Insert("imageUrl", "source-image-url.png");
- * imageProperty.Insert("imageFittingMode", "scaleToFill");
- * imageProperty.Insert("fitWidth", 240);
- * imageProperty.Insert("fitHeight", 240);
+ * imageProperty.Insert("url", "source-image-url.png");
+ * imageProperty.Insert("fittingMode", "SCALE_TO_FILL");
+ * imageProperty.Insert("desiredWidth", 240);
+ * imageProperty.Insert("desiredHeight", 240);
  * Dali::Toolkit::ImageView myImageView = Dali::Toolkit::ImageView::New();
  * myImageView.SetProperty( Control::Property::IMAGE, imageProperty);
 
  *
  * The fitting modes and a suggested use-case for each are as follows:
  * <ol>
- *   <li> "shrinkToFit" Full-screen image display: Limit loaded image resolution to device resolution but show all of image.
- *   <li> "scaleToFill" Thumbnail gallery grid: Limit loaded image resolution to screen tile, filling whole tile but losing a few pixels to match the tile shape.
- *   <li> "fitWidth" Image columns: Limit loaded image resolution to column.
- *   <li> "fitHeight" Image rows: Limit loaded image resolution to row height.
+ *   <li> "SHRINK_TO_FIT" Full-screen image display: Limit loaded image resolution to device resolution but show all of image.
+ *   <li> "SCALE_TO_FILL" Thumbnail gallery grid: Limit loaded image resolution to screen tile, filling whole tile but losing a few pixels to match the tile shape.
+ *   <li> "FIT_WIDTH" Image columns: Limit loaded image resolution to column.
+ *   <li> "FIT_HEIGHT" Image rows: Limit loaded image resolution to row height.
  * </ol>
  *
  * The dali-demo project contains a full example under
  * <h2 class="pg">Changing the image</h2>
  * The Image View can be changed by calling Dali::Toolkit::ImageView::SetImage methods or by changing the IMAGE property.
  * @code
- * myImageActor.SetImage( newImage );
+ * myImageView.SetImage( newImage );
  * @endcode
  *
  */
index b445a2e..43d6419 100644 (file)
@@ -224,9 +224,9 @@ imageView.parentOrigin = dali.CENTER;
 // Set an image view property
 imageView.image = {
   "rendererType" : "image",
-  "imageUrl" : "images/icon-0.png",
-  "width" : 100,
-  "height" : 100
+  "url": "images/icon-0.png",
+  "desiredWidth" : 100,
+  "desiredHeight" : 100
 };
 
 // add to the stage
@@ -253,9 +253,9 @@ This is a basic example of a button defined in JSON by setting the default prope
       "image":
       {
         "rendererType" : "image",
-        "imageUrl" : "images/icon-0.png",
-        "width" : 100,
-        "height" : 100
+        "url" : "images/icon-0.png",
+        "desiredWidth" : 100,
+        "desiredHeight" : 100
       }
     }
   ]
index cd0307c..f236440 100644 (file)
@@ -31,9 +31,8 @@
 
    Add Actors to this ScrollView
    @code
-   Image image = Image::New(DALI_IMAGE_DIR "button-background.png");
-   ImageActor imageActor = ImageActor::New(image);
-   myScrollView.Add( imageActor );
+   Toolkit::ImageView imageView = Toolkit::ImageView::New(DALI_IMAGE_DIR "button-background.png");
+   myScrollView.Add( imageView );
    @endcode
 
    The ScrollView contents are now draggable by the user using touch (panning gestures).
index 54c8909..9fcb679 100644 (file)
@@ -45,8 +45,8 @@
  *
  * Property::Map customShader;
  *
- * customShader.Insert(“vertex-shader”, VERTEX_SHADER); //if this is not set then the default ImageView vertex shader will be used
- * customShader.Insert(“fragment-shader”, FRAGMENT_SHADER); //if this is not set then the default ImageView fragment shader will be used
+ * customShader.Insert(“vertexShader”, VERTEX_SHADER); //if this is not set then the default ImageView vertex shader will be used
+ * customShader.Insert(“fragmentShader”, FRAGMENT_SHADER); //if this is not set then the default ImageView fragment shader will be used
  *
  * Property::Map map;
  * map.Insert(“shader”, customShader);
  * @code
  * int X_SUB_DIVISIONS = 20;
  * int Y_SUB_DIVISIONS = 20;
- * customShader.Insert(“subdivide-grid-x”, X_SUB_DIVISIONS); //optional number of times to subdivide the grid horizontally, don’t add if you just want to use a quad
- * customShader.Insert(“subdivide-grid-y”, Y_SUB_DIVISIONS); //optional number of times to subdivide the grid vertically, don’t add if you just want to use a quad
+ * customShader.Insert(“subdivideGridX”, X_SUB_DIVISIONS); //optional number of times to subdivide the grid horizontally, don’t add if you just want to use a quad
+ * customShader.Insert(“subdivideGridY”, Y_SUB_DIVISIONS); //optional number of times to subdivide the grid vertically, don’t add if you just want to use a quad
  *
  * //shader hints can be an array or a string
  * optional array of shader hints
  *
  * Property::Array shaderHints;
- * shaderHints.PushBack(“requires-self-depth-test”);
- * shaderHints.PushBack(“output-is-transparent”);
- * shaderHints.PushBack(“output-is-opaque”);
- * shaderHints.PushBack(“modifies-geometry”);
+ * shaderHints.PushBack(“requiresSelfDepthTest”);
+ * shaderHints.PushBack(“outputIsTransparent”);
+ * shaderHints.PushBack(“outputIsOpaque”);
+ * shaderHints.PushBack(“modifiesGeometry”);
  * customShader.Insert(“hints”, shaderHints);
  *
  * //or optional single shader hint as a string
- * //customShader.Insert(“hints”, “output-is-transparent”);
+ * //customShader.Insert(“hints”, “outputIsTransparent”);
  * @endcode
  *
  * The value of a uniform can be set on the imageView
index 334c709..9605573 100644 (file)
@@ -49,17 +49,17 @@ Text and image actors have relayout enabled by default, while a plain Actor is d
 
 <h3>Specifying Size Policies</h3>
 
-Actors have different size policies by default. For example ImageActor is set to USE_NATURAL_SIZE. This ensures that when an image actor is
+Actors have different size policies by default. For example ImageView is set to USE_NATURAL_SIZE. This ensures that when an image actor is
 placed on the stage it will use its natural size by default. However if the user calls SetSize with non-zero sizes on the image actor then the current
 size policy is overridden by the FIXED size policy and the actor will take on the size specified.
 
 The next step is to specify how an actor will be size negotiated. The resize policies for an actor may be specified by the following method:
 @code void SetResizePolicy( ResizePolicy::Type policy, Dimension::Type dimension ) @endcode
 It is common to specifiy different policies for the different dimensions of width and height to achive different layouts. Different actors have
-different resize policies specified by default. For example ImageActors are set to use USE_NATURAL_SIZE.
+different resize policies specified by default. For example ImageViews are set to use USE_NATURAL_SIZE.
 
 The following example code snippet shows rootActor having its width policy set to ResizePolicy::FILL_TO_PARENT and its height policy set to ResizePolicy::FIT_TO_CHILDREN.
-It has an ImageActor added to it with an explicit call to USE_NATURAL_SIZE in both dimensions called on it. This will make an actor that will
+It has an ImageView added to it with an explicit call to USE_NATURAL_SIZE in both dimensions called on it. This will make an actor that will
 fill up the space of its parent in the width dimension and fit to its child in the height dimension. As the image actor child is using natural size
 the height of the root actor will fit to the height of the child image.
 
@@ -67,7 +67,7 @@ the height of the root actor will fit to the height of the child image.
 Actor rootActor = Actor::New();
 rootActor.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
 rootActor.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT );
-ImageActor image = ImageActor::New( Image::New( MY_IMAGE_PATH ) );
+Toolkit::ImageView image = Toolkit::ImageView::New( MY_IMAGE_PATH );
 image.SetResizePolicy( ResizePolicy::USE_NATURAL_SIZE, Dimension::ALL_DIMENSIONS );
 rootActor.Add( image );
 @endcode
@@ -141,7 +141,7 @@ text.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
 content.AddChild( text, Toolkit::TableView::CellPosition( 0, 0 ) );
 
 // Image
-ImageActor image = ImageActor::New( ResourceImage::New( IMAGE1 ) );
+Toolkit::ImageView image = Toolkit::ImageView::New( IMAGE_PATH );
 image.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
 image.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
 image.SetPadding( Padding( 20.0f, 0.0f, 0.0f, 0.0f ) );
index bef67d0..e9912ef 100644 (file)
@@ -184,6 +184,10 @@ bool MyControl::DoAction(
 }
 @endcode
 
+If the action is not performed by the derived class, it will be propagated to the base class.
+For example, in the above case, MyControl can perform "action1" so should return true, but it
+cannot perform "action4" so should return false and propagate the action to Control.
+
 @section register-property Registering a Property
 
 DALi has a property system which can be extended by registering more properties through the type
index 2b1c272..8f77b8d 100644 (file)
@@ -12,9 +12,7 @@ Additionaly, they respond to actor size and color change, while also providing c
 DALi provides the following renderers:
  + [Color](@ref color-renderer)
  + [Gradient](@ref gradient-renderer)
- + [Image](@ref image-renderer)
- + [N-Patch](@ref n-patch-renderer)
- + [SVG](@ref svg-renderer)
+ + [Image](@ref image-renderers)
  + [Border](@ref border-renderer)
  
 Controls can provide properties that allow users to specify the renderer type.
@@ -212,26 +210,38 @@ control.background =
 ~~~
 ___________________________________________________________________________________________________
 
-## Image Renderer {#image-renderer}
+## Image Renderers {#image-renderers}
 
 Renders an image into the control's quad.
  
+Depending on the extension of the image, different renderer is provided to render the image onto the screen.
+ + [Normal](@ref image-renderer)
+ + [N-Patch](@ref n-patch-renderer)
+ + [SVG](@ref svg-renderer)
+___________________________
+### Normal {#image-renderer}
+Renders a raster image ( jpg, png etc.) into the control's quad.
 ![ ](../assets/img/renderers/image-renderer.png)
 ![ ](renderers/image-renderer.png)
 
-### Properties Supported
+#### Properties Supported
 
 **RendererType:** "image"
 
 | Property Name      | Type     | Required | Description                                                                                                                                     |
 |--------------------|:--------:|:--------:|-------------------------------------------------------------------------------------------------------------------------------------------------|
-| imageUrl           | STRING   | Yes      | The URL of the image.                                                                                                                           |
-| [imageFittingMode](@ref resourceimagescaling-fittingmode) | STRING   | No       | *shrinkToFit*, *scaleToFill*, *fitWidth* or *fitHeight*. Default: *shrinkToFit*.                         |
-| [imageSamplingMode](@ref resourceimagescaling-scaling)    | STRING   | No       | *box*, *nearest*, *linear*, *boxThenNearest*, *boxThenLinear*, *noFilter* or *dontCare*. Default: *box*. |
-| imageDesiredWidth  | INT      | No       | The desired image width. Will use actual image width if not specified.                                                                          |
-| imageDesiredHeight | INT      | No       | The desired image height. Will use actual image height if not specified.                                                                        |
+| url           | STRING   | Yes      | The URL of the image.                                                                                                                           |
+| [fittingMode](@ref resourceimagescaling-fittingmode) | STRING   | No       | *SHRINK_TO_FIT*, *SCALE_TO_FILL*, *FIT_WIDTH* or *FIT_HEIGHT*. Default: *SHRINK_TO_FIT*.                         |
+| [samplingMode](@ref resourceimagescaling-scaling)    | STRING   | No       | *BOX*, *NEAREST*, *LINEAR*, *BOX_THEN_NEAREST*, *BOX_THEN_LINEAR*, *NO_FILTERr* or *DONT_CARE*. Default: *BOX*. |
+| desiredWidth  | INT      | No       | The desired image width. Will use actual image width if not specified.                                                                          |
+| desiredHeight | INT      | No       | The desired image height. Will use actual image height if not specified.                                                                        |
 
-### Usage
+#### Usage
 
 ~~~{.cpp}
 // C++
@@ -239,7 +249,7 @@ Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
 
 Dali::Property::Map map;
 map[ "rendererType" ] = "image";
-map[ "imageUrl" ] = "path-to-image.jpg";
+map[ "url" ] = "path-to-image.jpg";
 
 control.SetProperty( Dali::Toolkit::Control::Property::BACKGROUND, map );
 ~~~
@@ -251,28 +261,28 @@ var control = new dali.Control( "Control" );
 control.background =
 {
   rendererType : "image",
-  imageUrl : "path-to-image.jpg"
+  url : "path-to-image.jpg"
 };
 ~~~
 ___________________________________________________________________________________________________
 
-## N-Patch Renderer {#n-patch-renderer}
+### N-Patch {#n-patch-renderer}
 
 Renders an n-patch or a 9-patch image into the control's quad.
  
 ![ ](../assets/img/renderers/n-patch-renderer.png)
 ![ ](renderers/n-patch-renderer.png)
 
-### Properties Supported
+#### Properties Supported
 
-**RendererType:** "nPatch"
+**RendererType:** "image"
 
 | Property Name | Type    | Required | Description                      |
 |---------------|:-------:|:--------:|----------------------------------|
-| imageUrl      | STRING  | Yes      | The URL of the n-patch image.    |
+| url           | STRING  | Yes      | The URL of the n-patch image.    |
 | borderOnly    | BOOLEAN | No       | If true, only draws the borders. |
 
-### Usage
+#### Usage
 
 ~~~{.cpp}
 // C++
@@ -280,8 +290,8 @@ Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
 
 Dali::Property::Map map;
 
-map[ "rendererType" ] = "nPatch";
-map[ "imageUrl" ] = "path-to-image.9.png";
+map[ "rendererType" ] = "image";
+map[ "url" ] = "path-to-image.9.png";
 
 control.SetProperty( Dali::Toolkit::Control::Property::BACKGROUND, map );
 ~~~
@@ -292,17 +302,35 @@ var control = new dali.Control( "Control" );
 
 control.background =
 {
-  rendererType : "nPatch",
-  imageUrl : "path-to-image.9.png"
+  rendererType : "image",
+  url : "path-to-image.9.png"
 };
 ~~~
 
 ___________________________________________________________________________________________________
 
-## SVG Renderer {#svg-renderer}
+### SVG {#svg-renderer}
 
 Renders a svg image into the control's quad.
  
+#### Features: SVG Tiny 1.2 specification
+
+**supported:**
+  * basic shapes
+  * paths
+  * solid color fill
+  * gradient color fill
+  * solid color stroke
+**not supported:**
+  * gradient color stroke
+  * dash array stroke
+  * view box
+  * text
+  * clip path
+
 <div style="width:300px">
  
 ![ ](../assets/img/renderers/svg-renderer.svg)
@@ -314,16 +342,17 @@ Renders a svg image into the control's quad.
 ![ ](renderers/svg-renderer.svg)
  
 </div>
+
  
-### Properties Supported
+#### Properties Supported
 
-**RendererType:** "svg"
+**RendererType:** "image"
 
 | Property Name | Type    | Required | Description                      |
 |---------------|:-------:|:--------:|----------------------------------|
-| imageUrl      | STRING  | Yes      | The URL of the SVG image.    |
+| url           | STRING  | Yes      | The URL of the SVG image.    |
 
-### Usage
+#### Usage
 
 ~~~{.cpp}
 // C++
@@ -331,8 +360,8 @@ Dali::Toolkit::Control control = Dali::Toolkit::Control::New();
 
 Dali::Property::Map map;
 
-map[ "rendererType" ] = "svg";
-map[ "imageUrl" ] = "path-to-image.svg";
+map[ "rendererType" ] = "image";
+map[ "url" ] = "path-to-image.svg";
 
 control.SetSize( 200.f, 200.f );
 control.SetProperty( Dali::Toolkit::Control::Property::BACKGROUND, map );
@@ -344,8 +373,8 @@ var control = new dali.Control( "Control" );
 
 control.background =
 {
-  rendererType : "svg",
-  imageUrl : "path-to-image.svg"
+  rendererType : "image",
+  url : "path-to-image.svg"
 };
 ~~~
 ___________________________________________________________________________________________________
index 1313253..93c4816 100644 (file)
@@ -32,13 +32,12 @@ public:
   {
     // We should create the actor here that represents our item based on the itemId given.
 
-    // Here we'll create an ImageActor which uses the the itemId to parse the image in a particular directory.
+    // Here we'll create an ImageView which uses the the itemId to parse the image in a particular directory.
     std::ostringstream imageName;
     imageName << "my-image-folder/" << itemId << ".png"; // If item was 10, then this would result in my-image-folder/10.png
-    Dali::ResourceImage image = Dali::ResourceImage::New( imageName.str() );
 
-    // Create an Image Actor from the image and return
-    return Dali::ImageActor::New( image );
+    // Create the Image View from the image and return
+    return Dali::Toolkit::ImageView::New( imageName.str() );
   }
 };
 ~~~
index a86442f..02b7e59 100644 (file)
@@ -44,7 +44,7 @@ Example: Image only popup (using the content field):
 ### Example content: {#popupfieldexample}
   
 - Title:   TextLabel
-- Content: ImageActor or TextLabel
+- Content: ImageView or TextLabel
 - Footer:  PushButton or Actor containing two PushButtons
   
 ## Setting and getting the display state {#popupdisplaystate}
@@ -216,7 +216,7 @@ This example creates a Popup with:
   
 - Title:   TextLabel
 - Content: TextLabel
-- Footer:  ImageActor (an image border around the buttons)
+- Footer:  ImageView (an image border around the buttons)
             - PushButton (OK control)
             - PushButton (Cancel control)
   
@@ -237,7 +237,7 @@ contentActor.SetProperty( Toolkit::TextLabel::Property::HORIZONTAL_ALIGNMENT, "C
 popup.SetContent( contentActor );
 
 // Create the footer: Two buttons surrounded by an image.
-ImageActor footer = ImageActor::New( ResourceImage::New( DEFAULT_CONTROL_AREA_IMAGE_PATH ) );
+ImageView footer = ImageView::New( DEFAULT_CONTROL_AREA_IMAGE_PATH );
 footer.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
 footer.SetResizePolicy( ResizePolicy::FIXED, Dimension::HEIGHT );
 footer.SetSize( 0.0f, 80.0f );
index 2d68c92..3976541 100644 (file)
@@ -378,7 +378,7 @@ Upscaling can still be effected at render time by setting the size of an actor t
 
 ### Compressed Textures and Scaling {#resourceimagescaling-compressedtextures}
   
-Compressed textures cannot be scaled at load time as their formats are designed to be uploaded directly to GPU memory. To achieve scaling of compressed textures, set the desired size on the attached `ImageActor` for scaling at render time instead.
+Compressed textures cannot be scaled at load time as their formats are designed to be uploaded directly to GPU memory. To achieve scaling of compressed textures, set the desired size on the attached `ImageView` for scaling at render time instead.
   
   
 
@@ -411,7 +411,7 @@ The application can get a scaled resource image rendered correctly to screen wit
   
   1. Use one of the special cases above.
   2. Read the image header from disk, recreate the dimension deriving, fitting, and sampling logic described in this document, and use that to generate a pair of requested dimensions which match the eventual image dimensions.
-  3. Use the requested dimensions it really wants to but then read the image header from disk, recreate the dimension deriving, fitting, and sampling logic described in this document, and set the size of an `ImageActor` to that size explicitly rather than relying on the *natural size* of the image.
+  3. Use the requested dimensions it really wants to but then read the image header from disk, recreate the dimension deriving, fitting, and sampling logic described in this document, and set the size of an `ImageView` to that size explicitly rather than relying on the *natural size* of the image.
   
 
 
index 50ca99b..98c175a 100644 (file)
@@ -10,7 +10,7 @@ To create a resource image:
 ~~~{.cpp}
 Dali::ResourceImage image = Dali::ResourceImage::New( "/my-path/my-image.png" );
 ~~~
-Which can then be used with actors (e.g. ImageActor).
+Which can then be used with actors (e.g. ImageView).
 
 Resources are loaded in separate threads.
 The application can connect to the Dali::ResourceImage::LoadingFinishedSignal() to get notified when the image has loaded.
index f6887cb..2575417 100644 (file)
@@ -121,10 +121,10 @@ The constants section supports sub-string and full property replacement.
     },                                  //
     ...                                 //
     {                                   //
-      "type":"ImageActor"               // An DALi type or a template name
+      "type":"ImageView"               // An DALi type or a template name
       "image":                          //
       {                                 //
-        "filename":"{IMAGES}b.jpg"      // Image filename substring replacement
+        "url":"{IMAGES}b.jpg"      // Image filename substring replacement
       },                                //
       "size": "{SIZE}"                  //
     }                                   //  Property replacement
@@ -171,12 +171,12 @@ an optional actor sub hierarchy.
    {                                    //
    "basic-text":                        //  The template name
    {                                    //
-     "type":"ImageActor",               //  Concrete DALi Type/Class to create
+     "type":"ImageView",               //  Concrete DALi Type/Class to create
      "styles":["base-style"],           //  Style list to apply
      "name":"image",                    //  }
      "image":                           //  } property name : value
      {                                  //  }
-     "filename":"{IMAGES}/b.jpg"        //
+     "url":"{IMAGES}/b.jpg"        //
      },                                 //
      "parentOrigin": "CENTER"           //
      ...                                //
@@ -357,52 +357,6 @@ animation property.
     }                                    //
 ~~~
 
-## Shaders {#shaders}
-
-The shader section of the JSON file defines a library of shader effect
-instances that are created on demand.
-
-The shaders are referred to by name from the template, style, stage or
-animation sections.
-
-Multiple actors can set the same shader as the name refers to a single
-instance.
-
-Similarly one named shader instance can be set to several actors and can
-be animated by one animation.
-
-~~~
-    {                                             //
-    "shaderEffects":                              // Shader Effect section
-    {                                             //
-      "myshader1":                                // Shader  instance  name
-      {                                           //
-       "program":                                 //
-       {                                          // Prefixs are placed before DALi uniforms.
-         "vertexPrefix": "",                      // (Useful for \#defines.)
-         "vertex":"",                             // Glsl vertex program
-         "fragmentPrefix": "",
-         "fragment": "",                          // Glsl fragment program.
-         "geometryType": "GEOMETRY_TYPE_IMAGE",   // Geometry type(see DALi documentation)
-       },
-       "geometryHints": "HINT_NONE":              // Geometry hints (see DALi documentation)
-       "gridDensity": 0,                          // Grid density(see DALi documentation)
-       "image":
-       {
-         "filename": ""                           // Effect image available as a second texture unit.
-       }
-     },
-     ...
-    },
-    "stage":
-    [{
-     "type": "ImageActor",
-     "effect": "myshader1",
-     ...
-    }]
-    }
-~~~
-
 At least one of the vertex or fragment fields is mandatory. All
 other fields are optional will use internal defaults.
 
@@ -486,7 +440,7 @@ builder.addActors( dali.stage.getRootLayer() );
     "stage":                             \\  Stage Section Number
     [                                    \\  An array of actors
      {
-     "type": "ImageActor",
+     "type": "ImageView",
      ...
      "actors":                           \\  Each actor can have children
                                          \\ creating a tree
index 6837b33..4f64f72 100644 (file)
@@ -61,21 +61,21 @@ JSON file contains different sections:
       [
         {
           "name":"usersBackground",
-          "type":"ImageActor",
+          "type":"ImageView",
           "parentOrigin":"CENTER",
           "anchorPoint":"CENTER",
           "size":"{DEFAULT_MENU_USER_SIZE}",
           "colorMode":"USE_OWN_COLOR",
-          "image":{ "filename":"{IMAGE_PATH}white-pixel.png" },
+          "image":{ "url":"{IMAGE_PATH}white-pixel.png" },
           "color":"{DEFAULT_MENU_BACKGROUND_COLOR}"
         },
         {
           "name":"icon",
-          "type":"ImageActor",
+          "type":"ImageView",
           "parentOrigin":"TOP_CENTER",
           "anchorPoint":"TOP_CENTER",
           "position":[0,41,1],
-          "image":{ "filename":"{IMAGE_PATH}ico_man_nor.png" }
+          "image":{ "url":"{IMAGE_PATH}ico_man_nor.png" }
         },
       ]
     },
@@ -222,9 +222,9 @@ Animation anim = builder.createAnimation( "animate-show", propertyMap );
       },
       "actors": [{
           "name":"gallery-1",
-          "type":"ImageActor",
+          "type":"ImageView",
           "image": {
-            "filename": "{DALI_IMAGE_DIR}gallery-large-1.jpg"
+            "url": "{DALI_IMAGE_DIR}gallery-large-1.jpg"
           },
           "customProperties": { // properties registered dynamically
             "cellIndices": [0,0],// property to specify the top-left cell this child occupies
diff --git a/docs/content/shared-javascript-and-cpp-documentation/texture-atlas.md b/docs/content/shared-javascript-and-cpp-documentation/texture-atlas.md
deleted file mode 100644 (file)
index 36d96f8..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-<!--
-/**-->
-
-# Texture Atlases {#textureatlases}
-
-## Example demo application
-
-![ ](../assets/img/texture-atlas/image-wall.jpg)
-![ ](image-wall.jpg)
-  
-
-Application above is running slow as there are many small individual images displayed (50)
-  
-| Metric | Result | Explanation |
-|--------|--------|-------------|
-| Launch time | Slow | Has to perform: 50 file open requests and multiple reads for each image |
-| Memory consumption|  High | Has to create:50 Dali::Image objects,50 OpenGL Textures|
-| Rendering | Slow | Has to perform: 50 glBindTexture calls per frame ( each OpenGL calls takes time) 50 a frame = 3000 calls per second @60 FPS.Texture switching is a major state change in the GPU|
-  
-
-
-## Solutions to problem: Use a Texture Atlas
-
-A texture atlas is simply one larger image that contains smaller images. A texture atlas is sometimes called a
-sprite sheet, bitmap sheet or texture pack.
-
-![ ](../assets/img/texture-atlas/atlas.jpg)
-![ ](atlas.jpg)
-  
-Dali::ImageActor has the ability to display a portion of an image using ImageActor::PixelArea setting.
-For example to display the first 3 image in the atlas
-  
-![ ](../assets/img/texture-atlas/example-javascript-code.jpg)
-![ ](example-code.jpg)
-
-### Result of using an Atlas
-
-| Metric | Result | Explanation |
-|--------|--------|-------------|
-| Launch time | Fast | Has to perform: - 1 file open request  |
-| Memory consumption|  Low | Has to create: 1 Dali::Image objects 1 OpenGL Textures|
-| Rendering | Fast | HHas to perform: 1 glBindTexture calls per frame ( each OpenGL calls takes time) 1 a frame = 6- calls per second @60 FPS.|
-
-  
-## Atlas creation guide
-
-Many tools exist for creating texture atlases.
-In the following example we are using a tool called TexturePacker as DALi has an exporter script for it.
-The exporter automatically generates a source file that has the ImageActor::PixelArea pre-defined.
-  
-- Download http://www.codeandweb.com/texturepacker
-- Launch TexturePacker
-- Go to the menu File -> Preferences
-- Set the "Exporter directory" to be the location of dali-toolkit/texture-atlas-exporter
-  
-![ ](../assets/img/texture-atlas/texture-packer-preferences.jpg)
-![ ](texture-packer-preferences.jpg)
-  
-- Restart the application!
-- Select DALi 3D framework for new project
-  
-![ ](../assets/img/texture-atlas/texture-packer-startup.jpg)
-![ ](texture-packer-startup.jpg)
-  
-- Create the atlas
-![ ](../assets/img/texture-atlas/texture-packer-add-sprites.jpg)
-![ ](texture-packer-add-sprites.jpg)
-- Click publish to produce the files
-![ ](../assets/img/texture-atlas/texture-packer-publish.jpg)
-![ ](texture-packer-publish.jpg)
-
-
-
-## Using the generated cpp ( contains JavaScript code as well)
-
-The generated cpp file contains 3 different ways of describing the atlas.
-Copy and paste the section that best suits your application.
--  Lookup table. Includes code for storing the table in a std::map for fast lookup.
-- constants.
-- JavaScript property map
-
-### Using the JavaScript generated property map
-
-The property map should be cut and paste in to your application. It just looks like
-  
-~~~{.js}
-var ATLAS_IMAGE_LIST : [
-    { name: "add_user_usericon_bg", x: 2, y:109, w:105, h:105,  blendMode:dali.BLENDING_ON  },
-    { name: "app_background", x: 180, y:183, w:1, h:1,  blendMode:dali.BLENDING_OFF  },
-    { name: "btn_arrow_left", x: 141, y:183, w:11, h:20,  blendMode:dali.BLENDING_ON  },
-    { name: "btn_arrow_right", x: 154, y:183, w:11, h:20,  blendMode:dali.BLENDING_ON  },
-    { name: "icn_app_foc", x: 194, y:2, w:72, h:72,  blendMode:dali.BLENDING_ON  },
-    { name: "icn_app_nor", x: 109, y:109, w:72, h:72, blendMode:dali.BLENDING_ON  }
-    ]
-var atlas = new dali.ResourceImage( { url: "atlas_filename.png" });
-
-// display the user icon using the size / position data in the ATLAS_IMAGE_LIST
-var userIconData = ATLAS_IMAGE_LIST[0];
-var userIconRect = [ userIconData.x, userIconData.y,userIconData.w,userIconData.h];
-
-var btnArrowLeft = new dali.ImageActor( atlas, userIconRect );
-btnArrowLeft.setBlendMode(userIconData.blendMode);
-
-~~~
-
-![ ](example-javascript-code.jpg)
-
-
-### Using the lookup table in C++
-
-Cut and paste the lookup table code into your application.
-
-~~~{.cpp}
-
-// The following code is automatically generated when TexturePacker publishes to a cpp file.
-const char* ATLAS_FILE_NAME( "my_first_atlas.png" );  ///< Atlas image filename
-
-// Structure to hold image name and position within the atlas.
-struct ImageInfo
-{
-  const char* name;
-  unsigned int x,y,w,h;
-  Dali::BlendingMode::Type blendMode;  // only enable blending if image has alpha
-};
-
-
-// lookup table
-const ImageInfo ImageAtlas[]=
-{
- { "blocks-ball", 2, 198, 51, 51, BlendingMode::ON },
- { "bubble-ball", 288, 74, 32, 32, BlendingMode::ON },
- { "gallery-small-52", 2, 2, 128, 128, BlendingMode::OFF },
- { "icon-change", 219, 2, 37, 34, BlendingMode::ON },
- { "icon-cluster-carousel", 180, 2, 37, 34, BlendingMode::ON }
-};
-
-const ImageInfo* GetImageInfo(const char* name)
-{
-  typedef std::map< const char*, const ImageInfo* > LookupMap;
-  static LookupMap lookup;
-  if( lookup.empty() )
-  {
-    for( unsigned int i = 0; i < ATLAS_IMAGE_COUNT; ++i)
-    {
-      lookup[ ImageAtlas[i].name ] =  &ImageAtlas[i];
-    }
-  }
-  LookupMap::const_iterator iter = lookup.find(name);
-  if( iter != lookup.end() )
-  {
-   return (*iter).second;
-  }
-  DALI_ASSERT_ALWAYS(0 && "image name not found in atlas");
-  return NULL;
-}
-
-~~~
-
-To use the lookup table you can do something like this:
-
-~~~{.cpp}
-// Example function on how to get an image info from the table
-
-std::string fileName = std::string( DALI_IMAGE_DIR ) + ATLAS_FILE_NAME;
-Image imageImage = Image::New( fileName );
-
-const ImageInfo* info(NULL);
-
-info = GetImageInfo("blocks-ball");
-if( info)
-{
-  ImageActor ballActor = ImageActor::New( imageAtlas, ImageActor::PixelArea( info->x, info->y, info->w, info->h) );
-  ballActor->SetBlendMode( info->blendMode );
-}
-info = GetImageInfo("bubble-ball");
-if( info)
-{
-  ImageActor bubbleActor = ImageActor::New( imageAtlas, ImageActor::PixelArea( info->x, info->y, info->w, info->h) );
-  bubbleActor->SetBlendMode( info->blendMode );
-}
-
-~~~
-
-### Using the constant definitions (C++)
-
-1. Cut and paste the constant definition code into your application.
-
-You'll notice the code below won't compile because C++ variables can't have a dash character.
-E.g. BLOCKS-BALL, BUBBLE-BALL will cause errors. Do a search and replace for - and replace with underscores.
-This is one reason why using lookup table which holds the filename as a string maybe easier to use.
-  
-~~~{.cpp}
-
-// The following code is automatically generated when TexturePacker publishes to a cpp file.
-const char* ATLAS_FILE_NAME( "my_first_atlas.png" );
-
-
-// Structure to hold position / blend mode within the atlas.
-struct ImageInfo
-{
-  ImageInfo(unsigned int x,unsigned int y,unsigned int w,unsigned int h,  Dali::BlendingMode::Type mode)
-  :pixelArea(x,y,w,h),blendMode(mode)
-  {}
-  ImageActor::PixelArea pixelArea;
-  Dali::BlendingMode::Type blendMode;  // only enable blending if image has alpha
-};
-
-
-const ImageInfo BLOCKS-BALL( 2, 198, 51, 51 ,BlendingMode::ON );
-const ImageInfo BUBBLE-BALL( 288, 74, 32, 32 ,BlendingMode::ON );
-const ImageInfo GALLERY-SMALL-52( 2, 2, 128, 128 ,BlendingMode::OFF );
-~~~
-  
-  2. To use it, you can copy example code from the generated cpp file which looks
-like this
-
-~~~{.cpp}
-void LoadAtlasImages()
-{
-  std::string fileName = std::string(DALI_IMAGE_DIR) + ATLAS_FILE_NAME;
-  Image atlasImage = Image::New( fileName );
-  ImageActor Blocksball = ImageActor::New( atlasImage,  BLOCKS_BALL.pixelArea);
-  Blocksball.SetBlendMode( BLOCKS_BALL.blendMode );
-
-  ImageActor Bubbleball = ImageActor::New( atlasImage,  BUBBLE_BALL.pixelArea);
-  Bubbleball.SetBlendMode( BUBBLE_BALL.blendMode );
-  ...
-~~~
-
-
-## Atlas creation tips
-
-- Compress the atlas  - \link texturecompression Compressing Textures \endlink
-- Avoid adding large images to the Atlas.
-- E.g. don't add background images to it. Medium to large images should be kept seperate.
-  
-![ ](../assets/img/texture-atlas/atlas-size.jpg)
-![ ](atlas-size.jpg)
-  
-
-- Try to ensure the atlas contains only images that are frequently used.  There's no point in having images taking up GPU texture memory if they're not displayed.
-- Avoid very large atlases.   Try to create multiple atlases based on how they are used within your application.
-Alternatively Texture packer has the option to split atlases ( search help for Multipack)
-
-
-
-@class _Guide_TextureAtlases
-
-*/
\ No newline at end of file
diff --git a/docs/content/shared-javascript-and-cpp-documentation/texture-compression.md b/docs/content/shared-javascript-and-cpp-documentation/texture-compression.md
deleted file mode 100644 (file)
index a89212e..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-<!--
-/**-->
-
-# Texture Compression {#texturecompression}
-
-
-Using compressing the textures will:
-
-- Reduce memory bandwidth in rendering due to less texture data being transferred per frame.
-  - Reduces power consumption.
-  - Speeds up rendering.
-- Reduce texture memory usage.
-- Speed up load times. There is no CPU decoding step in loading: the file data can be copied directly to GPU memory.
-
-DALi supports the KTX file format.
-
-You load the compressed texture just like you would any other image.
-
-~~~{.cpp}
-// C++
-ResourceImage image = ResourceImage::New("my_compressed_file.ktx");
-~~~
-~~~{.js}
-// JavaScript
-var image = new dali.ResourceImage( { url:"my_compressed_file.ktx"});
-
-~~~
-
-### ARMS texture compression tool
-
-http://malideveloper.arm.com/develop-for-mali/tools/asset-creation/mali-gpu-texture-compression-tool/
-
-Here is an example of using the ARM compression tool.
-
-![ ](../assets/img/texture-atlas/compression-options.jpg)
-![ ](compression-options.jpg)
-
-![ ](../assets/img/texture-atlas/compression-example.jpg)
-![ ](compression-example.jpg)
-
-
-As shown above the ETC-1 compression format does not support alpha.
-
-As a work around the tool will export the alpha as a separate compressed image.
-
-In order to combine both the images you need to use a custom shader.
-Here is an example shader:
-
-~~~{.cpp}
-// C++ Code
-  const char* const COMPRESSED_RGB_PLUS_SEPARATE_ALPHA_FRAGMENT_SOURCE =
-    "\n"
-    "void main()\n"
-    "{\n"
-    "    vec4 v4Color  = (texture2D(sTexture, vTexCoord) * uColor);\n"
-    "    v4Color.a =  texture2D(sEffect, vTexCoord ).r;\n"
-    "   gl_FragColor = v4Color;"
-    "}\n";
-
-
-  mShaderEffect = ShaderEffect::New( "", COMPRESSED_RGB_PLUS_SEPARATE_ALPHA_FRAGMENT_SOURCE);
-
-  mAtlasImageRGB = ResourceImage::New( ATLAS_RGB_FILENAME.KTX);
-
-  mAtlasImageAlpha = ResourceImage::New( ATLAS_ALPHA_FILENAME.KTX );
-
-  mShaderEffect.SetEffectImage( mAtlasImageAlpha );
-
-
-
-  // to create Image Actor
-  ImageActor  imageActor = ImageActor::New( mAtlasImageRGB, GetImagePosition( info) );
-
-  imageActor.SetShaderEffect( mShaderEffect );
-
-  imageActor.SetBlendMode(BlendingMode::ON);
-~~~
-
-~~~{.js}
-// JavaScript code
-var fragSource = "  \
-void main()                                                   \
-{                                                             \
-    vec4 v4Color  = (texture2D(sTexture, vTexCoord) * uColor); \
-    v4Color.a =  texture2D(sEffect, vTexCoord ).r;             \
-   gl_FragColor = v4Color;                                     \
-}";
-
-var shaderEffect = new dali.ShaderEffect( "", fragSource);
-
-var atlasImageRGB = new dali.ResourceImage( { url:"ATLAS_RGB_FILENAME.KTX"} );
-
-var atlasImageAlpha = new dali.ResourceImage( { url:"ATLAS_ALPHA_FILENAME.KTX"} );
-
-shaderEffect.setEffectImage( atlasImageAlpha );
-
-// to create Image Actor
-ImageActor  imageActor = ImageActor::New( mAtlasImageRGB, GetImagePosition( info) );
-
-imageActor.setShaderEffect( shaderEffect );
-
-imageActor.setBlendMode( dali.BLENDING_ON );
-~~~
-
-@class _Guide_Texture_compression
-
-
-*/
index ac3b428..da23da5 100644 (file)
       '<(DALI_JS_DIR)/render-tasks/render-task-wrapper.cpp',
       '<(DALI_JS_DIR)/rendering/geometry-api.cpp',
       '<(DALI_JS_DIR)/rendering/geometry-wrapper.cpp',
-      '<(DALI_JS_DIR)/rendering/material-api.cpp',
-      '<(DALI_JS_DIR)/rendering/material-wrapper.cpp',
       '<(DALI_JS_DIR)/rendering/renderer-api.cpp',
       '<(DALI_JS_DIR)/rendering/renderer-wrapper.cpp',
       '<(DALI_JS_DIR)/rendering/sampler-api.cpp',
       '<(DALI_JS_DIR)/rendering/sampler-wrapper.cpp',
       '<(DALI_JS_DIR)/rendering/shader-api.cpp',
       '<(DALI_JS_DIR)/rendering/shader-wrapper.cpp',
+      '<(DALI_JS_DIR)/rendering/texture-set-api.cpp',
+      '<(DALI_JS_DIR)/rendering/texture-set-wrapper.cpp',
       '<(DALI_JS_DIR)/toolkit/builder/builder-api.cpp',
       '<(DALI_JS_DIR)/toolkit/builder/builder-wrapper.cpp',
       '<(DALI_JS_DIR)/toolkit/focus-manager/keyboard-focus-manager-api.cpp',
index b68df19..0385dae 100644 (file)
@@ -58,8 +58,6 @@ daliApp.createMeshActor = function() {
 
       var shader = new dali.Shader(shaderOptions);
 
-      var material = new dali.Material( shader );
-
       // Create vertex buffer
       var pentagonVertexFormat ={ "aPosition1" : dali.PROPERTY_VECTOR2 };
 
@@ -93,17 +91,15 @@ daliApp.createMeshActor = function() {
 
       var indexDataArray = new Uint32Array(indexData.length);
       indexDataArray.set(indexData, 0);
-      var indices = new dali.PropertyBuffer(indexFormat);
-      indices.setData(indexDataArray, 10);
 
       // Create geometry
       var geometry = new dali.Geometry();
       geometry.addVertexBuffer( pentagonVertices );
       geometry.addVertexBuffer( pentacleVertices );
-      geometry.setIndexBuffer( indices );
+      geometry.setIndexBuffer( indexDataArray, 10 );
       geometry.setGeometryType( dali.GEOMETRY_LINES );
 
-      var renderer = new dali.Renderer(geometry, material);
+      var renderer = new dali.Renderer(geometry, shader);
       renderer.depthIndex = 0;
 
       // Create mesh actor
index 7d6bc49..1f59d36 100644 (file)
@@ -60,8 +60,6 @@ daliApp.createMeshActor = function() {
 
       var shader = new dali.Shader(shaderOptions);
 
-      var material = new dali.Material( shader );
-
       // Create vertex buffer for initial positions
       var initialPositionVertexFormat = { "aInitPos" : dali.PROPERTY_VECTOR2 };
 
@@ -224,7 +222,7 @@ daliApp.createMeshActor = function() {
       geometry.addVertexBuffer( finalPositionVertices );
       geometry.addVertexBuffer( colorVertices );
 
-      var renderer = new dali.Renderer(geometry, material);
+      var renderer = new dali.Renderer(geometry, shader);
       renderer.depthIndex = 0;
 
       // Create mesh actor
index eb1c830..c5f539e 100644 (file)
@@ -79,9 +79,9 @@ daliApp.createMeshActor = function() {
 
       var shader = new dali.Shader(shaderOptions);
 
-      var material = new dali.Material( shader );
       var image = new dali.ResourceImage( {url: imageDir + "image-1.jpg"} );
-      material.addTexture(image, "sTexture");
+      var textureSet = new dali.TextureSet;
+      textureSet.setImage(0, image);
 
       // Create vertex buffer
       var polyhedraVertexFormat ={ "aPosition" : dali.PROPERTY_VECTOR2,
@@ -115,7 +115,8 @@ daliApp.createMeshActor = function() {
       geometry.addVertexBuffer( polyhedraVertices );
       geometry.setGeometryType( dali.GEOMETRY_POINTS );
 
-      var renderer = new dali.Renderer(geometry, material);
+      var renderer = new dali.Renderer(geometry, shader);
+      renderer.setTextures(textureSet);
       renderer.registerAnimatableProperty("uFadeColor", [1.0, 0.0, 1.0, 1.0]); // Green
       renderer.registerAnimatableProperty("uPointSize", 80.0);
       renderer.depthIndex = 0;
index 1161765..2016ea7 100644 (file)
@@ -16,7 +16,7 @@
           "image":
           {
             "rendererType" : "image",
-            "imageUrl": "{icon_path}"
+            "url": "{icon_path}"
           },
           "position":[20.0, 0.0, 0.0],
           "size":[70.0, 70.0, 0.0],
@@ -60,7 +60,7 @@
           "image":
           {
             "rendererType" : "image",
-            "imageUrl": "{icon_path}"
+            "url": "{icon_path}"
           },
           "position":[0.0, -10.0, 0.0],
           "size":[70.0, 70.0, 0.0],
index bacde6b..514f20c 100644 (file)
@@ -64,13 +64,13 @@ daliApp.createMeshActor = function() {
 
       var shader = new dali.Shader(shaderOptions);
 
-      var material = new dali.Material( shader );
+      var textureSet = new dali.TextureSet;
       var image = new dali.ResourceImage( {url: imageDir + "image-1.jpg"} );
-      material.addTexture(image, "sTexture");
+      textureSet.setImage(0, image);
 
-      var material2 = new dali.Material( shader );
+      var textureSet2 = new dali.TextureSet;
       var image2 = new dali.ResourceImage( {url: imageDir + "image-2.jpg"} );
-      material2.addTexture(image2, "sTexture");
+      textureSet2.setImage(0, image2);
 
       // Create vertex buffer
       var texturedQuadVertexFormat ={ "aPosition" : dali.PROPERTY_VECTOR2,
@@ -93,15 +93,14 @@ daliApp.createMeshActor = function() {
 
       var indexDataArray = new Uint32Array(indexData.length);
       indexDataArray.set(indexData, 0);
-      var indices = new dali.PropertyBuffer(indexFormat);
-      indices.setData(indexDataArray, 6);
 
       // Create geometry
       var geometry = new dali.Geometry();
       geometry.addVertexBuffer( texturedQuadVertices );
-      geometry.setIndexBuffer( indices );
+      geometry.setIndexBuffer( indexDataArray, 6 );
 
-      var renderer = new dali.Renderer(geometry, material);
+      var renderer = new dali.Renderer(geometry, shader);
+      renderer.setTextures(textureSet);
       renderer.depthIndex = 0;
 
       var meshActor = new dali.Actor();
@@ -113,7 +112,8 @@ daliApp.createMeshActor = function() {
 
       dali.stage.add( meshActor );
 
-      var renderer2 = new dali.Renderer(geometry, material2);
+      var renderer2 = new dali.Renderer(geometry, shader);
+      renderer2.setTextures(textureSet2);
       renderer2.depthIndex = 0;
 
       var meshActor2 = new dali.Actor();
index 1161765..2016ea7 100644 (file)
@@ -16,7 +16,7 @@
           "image":
           {
             "rendererType" : "image",
-            "imageUrl": "{icon_path}"
+            "url": "{icon_path}"
           },
           "position":[20.0, 0.0, 0.0],
           "size":[70.0, 70.0, 0.0],
@@ -60,7 +60,7 @@
           "image":
           {
             "rendererType" : "image",
-            "imageUrl": "{icon_path}"
+            "url": "{icon_path}"
           },
           "position":[0.0, -10.0, 0.0],
           "size":[70.0, 70.0, 0.0],
index da2e8eb..c9a388b 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali-toolkit
 Summary:    The OpenGLES Canvas Core Library Toolkit
-Version:    1.1.31
+Version:    1.1.32
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-2-Clause and MIT
index 931aee7..fbff9bd 100644 (file)
@@ -191,7 +191,7 @@ var shader = createColorShiftAndZoomEffect();
   
 var image = {
     "rendererType" : "image",
-    "imageUrl" : getImageDirectory()+"gallery-medium-50.jpg",
+    "url" : getImageDirectory()+"gallery-medium-50.jpg",
     "shader" : shader
 };
   
index 19a0502..3b61fc2 100644 (file)
@@ -46,9 +46,9 @@ dali.stage.add( imageView );
   
 var image = {
     "rendererType" : "image",
-    "imageUrl" : "myImage.jpg",
-    "width" : desiredWidth,   // The desired image width while loading (optional but preferable to set for efficiency)
-    "height" : desiredHeight,   // The desired image height while loading (optional but preferable to set for efficiency)
+    "url" : "myImage.jpg",
+    "desiredWidth" : desiredWidth,   // The desired image width while loading (optional but preferable to set for efficiency)
+    "desiredHeight" : desiredHeight,   // The desired image height while loading (optional but preferable to set for efficiency)
     "shader" : shader  // Optional
 };
   
index 228f745..8f0c3ed 100644 (file)
@@ -31,7 +31,7 @@
             "image":
             {
               "rendererType" : "image",
-              "imageUrl": "{icon_path}"
+              "url": "{icon_path}"
             },
             "position":[20.0, 0.0, 0.0],
             "size":[70.0, 70.0, 0.0],
index e20e656..3a63034 100644 (file)
@@ -825,7 +825,7 @@ void AnimationApi::Animate( const v8::FunctionCallbackInfo<v8::Value>& args )
  *
  *     // animation x position
  *     var anim = new dali.Animation( 1 );
- *     anim.animateBy( imageActor,"positionX", 30 );
+ *     anim.animateBy( actor,"positionX", 30 );
  *     anim.play();
  *
  *     // animate x,y,z position with the optional animation options
@@ -835,7 +835,7 @@ void AnimationApi::Animate( const v8::FunctionCallbackInfo<v8::Value>& args )
  *        alpha:"easeInOutSine"   // Speeds up and slows to a gradual stop
  *     }
  *
- *     anim.animateBy( imageActor,"position", [100,200,0], options );
+ *     anim.animateBy( actor,"position", [100,200,0], options );
  *
  */
 void AnimationApi::AnimateBy( const v8::FunctionCallbackInfo<v8::Value>& args )
@@ -886,7 +886,7 @@ void AnimationApi::AnimateBy( const v8::FunctionCallbackInfo<v8::Value>& args )
  * @example
  *
  *     var anim = new dali.Animation( 1 );
- *     anim.animateTo( imageActor,"positionX", 30 );
+ *     anim.animateTo( actor,"positionX", 30 );
  *     anim.play();
  *
  *
@@ -897,7 +897,7 @@ void AnimationApi::AnimateBy( const v8::FunctionCallbackInfo<v8::Value>& args )
  *        alpha:"easeInOutSine"   // Speeds up and slows to a gradual stop
  *     }
  *
- *     anim.animateTo( imageActor,"position", [100,200,0], options );
+ *     anim.animateTo( actor,"position", [100,200,0], options );
  *
  */
 void AnimationApi::AnimateTo( const v8::FunctionCallbackInfo< v8::Value >& args )
@@ -977,7 +977,7 @@ void AnimationApi::AnimateTo( const v8::FunctionCallbackInfo< v8::Value >& args
  *     } ];
  *
  *
- *     anim.animateBetween( imageActor,"position", keyframes );
+ *     anim.animateBetween( actor,"position", keyframes );
  *
  */
 void AnimationApi::AnimateBetween( const v8::FunctionCallbackInfo< v8::Value >& args )
index 01aec00..e9c35a9 100644 (file)
@@ -188,8 +188,15 @@ void GeometryApi::RemoveVertexBuffer( const v8::FunctionCallbackInfo< v8::Value
  *
  * @method setIndexBuffer
  * @for Geometry
- * @param {Object} indexBuffer PropertyBuffer to be used as a source of indices
- *                             for the geometry
+ * @param {Uint32Array} data The data that will be copied to the buffer
+ *
+ * @example
+ * var indexData = [0, 1, 1, 2, 2, 3, 3, 4, 4, 0];
+ * var indexDataArray = new Uint32Array(indexData.length);
+ * indexDataArray.set(indexData, 0);
+ *
+ * geometry.SetIndexBuffer( indexDataArray, indexDataArray.length );
+ *```
  */
 void GeometryApi::SetIndexBuffer( const v8::FunctionCallbackInfo<v8::Value>& args )
 {
@@ -199,14 +206,23 @@ void GeometryApi::SetIndexBuffer( const v8::FunctionCallbackInfo<v8::Value>& arg
   Geometry geometry = GetGeometry( isolate, args );
 
   bool found( false );
-  PropertyBuffer indexBuffer = PropertyBufferApi::GetPropertyBufferFromParams( 0, found, isolate, args );
-  if( !found )
+  void* data = V8Utils::GetArrayBufferViewParameter( PARAMETER_0, found, isolate, args);
+
+  if( ! found )
   {
-    DALI_SCRIPT_EXCEPTION( isolate, "invalid property buffer parameter" );
+    DALI_SCRIPT_EXCEPTION( isolate, "invalid data parameter" );
   }
   else
   {
-    geometry.SetIndexBuffer(indexBuffer);
+    int size = V8Utils::GetIntegerParameter( PARAMETER_1, found, isolate, args, 0);
+    if( !found )
+    {
+      DALI_SCRIPT_EXCEPTION( isolate, "missing buffer size from param 1" );
+    }
+    else
+    {
+      geometry.SetIndexBuffer( static_cast<const unsigned short*>(data), size );
+    }
   }
 }
 
index d9ea511..f57abfe 100644 (file)
@@ -58,7 +58,7 @@ const unsigned int GeometryFunctionTableCount = sizeof(GeometryFunctionTable)/si
 
 
 GeometryWrapper::GeometryWrapper( const Dali::Geometry& geometry, GarbageCollectorInterface& gc )
-:  HandleWrapper(  BaseWrappedObject::GEOMETRY , geometry, gc )
+:  BaseWrappedObject(  BaseWrappedObject::GEOMETRY, gc )
 {
     mGeometry = geometry;
 }
@@ -106,9 +106,6 @@ v8::Handle<v8::ObjectTemplate> GeometryWrapper::MakeGeometryTemplate( v8::Isolat
 
   v8::Local<v8::ObjectTemplate> objTemplate = v8::ObjectTemplate::New();
 
-  // property handle intercepts property getters and setters and signals
-  HandleWrapper::AddInterceptsToTemplate( isolate, objTemplate );
-
   objTemplate->SetInternalFieldCount( BaseWrappedObject::FIELD_COUNT );
 
   // add our function properties
index b108e6c..6272ffc 100644 (file)
@@ -36,7 +36,7 @@ namespace V8Plugin
  * A Geometry wrapper.
  * Provides access to Geometry specific functionality and V8 memory handling.
  */
-class GeometryWrapper : public HandleWrapper
+class GeometryWrapper : public BaseWrappedObject
 {
 
 public:
index 30d8d47..1c5ad39 100644 (file)
@@ -89,9 +89,7 @@ TextureSet TextureSetApi::GetTextureSetFromParams( int paramIndex,
  */
 TextureSet TextureSetApi::New( const v8::FunctionCallbackInfo< v8::Value >& args )
 {
-  v8::Isolate* isolate = args.GetIsolate();
-  v8::HandleScope handleScope( isolate );
-  return TextureSet();
+  return TextureSet::New();
 }
 
 
index 454c966..5296651 100644 (file)
@@ -54,7 +54,7 @@ const unsigned int TextureSetFunctionTableCount = sizeof(TextureSetFunctionTable
 
 
 TextureSetWrapper::TextureSetWrapper( const Dali::TextureSet& textureSet, GarbageCollectorInterface& gc )
-:  HandleWrapper(  BaseWrappedObject::TEXTURE_SET , textureSet, gc )
+:  BaseWrappedObject(  BaseWrappedObject::TEXTURE_SET, gc )
 {
     mTextureSet = textureSet;
 }
@@ -102,9 +102,6 @@ v8::Handle<v8::ObjectTemplate> TextureSetWrapper::MakeTextureSetTemplate( v8::Is
 
   v8::Local<v8::ObjectTemplate> objTemplate = v8::ObjectTemplate::New();
 
-  // property handle intercepts property getters and setters and signals
-  HandleWrapper::AddInterceptsToTemplate( isolate, objTemplate );
-
   objTemplate->SetInternalFieldCount( BaseWrappedObject::FIELD_COUNT );
 
   // add our function properties
index 5826bbf..9e0426a 100644 (file)
@@ -36,7 +36,7 @@ namespace V8Plugin
  * A TextureSet wrapper.
  * Provides access to TextureSet specific functionality and V8 memory handling.
  */
-class TextureSetWrapper : public HandleWrapper
+class TextureSetWrapper : public BaseWrappedObject
 {
 
 public: